package com.android.email.activity.setup;

import android.content.Context;
import android.os.Bundle;
import android.os.Parcelable;
import android.text.Editable;
import android.text.TextUtils;
import android.text.TextWatcher;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.TextView;

import com.android.email.R;
import com.android.email.activity.UiUtilities;
import com.android.emailcommon.VendorPolicyLoader.OAuthProvider;
import com.android.emailcommon.provider.Credential;
import com.android.emailcommon.provider.HostAuth;
import com.google.common.annotations.VisibleForTesting;

public class AuthenticationView extends LinearLayout implements OnClickListener {

    private final static String SUPER_STATE = "super_state";
    private final static String SAVE_PASSWORD = "save_password";
    private final static String SAVE_OFFER_OAUTH = "save_offer_oauth";
    private final static String SAVE_USE_OAUTH = "save_use_oauth";
    private final static String SAVE_OAUTH_PROVIDER = "save_oauth_provider";

    // Views
    private TextView mAuthenticationHeader;
    private View mPasswordWrapper;
    private View mOAuthWrapper;
    private View mNoAuthWrapper;
    private TextView mPasswordLabel;
    private EditText mPasswordEdit;
    private TextView mOAuthLabel;
    private View mClearPasswordView;
    private View mClearOAuthView;
    private View mAddAuthenticationView;

    private boolean mOfferOAuth;
    private boolean mUseOAuth;
    private String mOAuthProvider;

    private boolean mAuthenticationValid;
    private AuthenticationCallback mAuthenticationCallback;

    public interface AuthenticationCallback {
        public void onValidateStateChanged();

        public void onRequestSignIn();
    }

    public AuthenticationView(Context context) {
        this(context, null);
    }

    public AuthenticationView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public AuthenticationView(Context context, AttributeSet attrs, int defstyle) {
        super(context, attrs, defstyle);
        LayoutInflater.from(context).inflate(R.layout.authentication_view, this, true);
    }


    @Override
    public void onFinishInflate() {
        super.onFinishInflate();
        mPasswordWrapper = UiUtilities.getView(this, R.id.password_wrapper);
        mOAuthWrapper = UiUtilities.getView(this, R.id.oauth_wrapper);
        mPasswordEdit = UiUtilities.getView(this, R.id.password_edit);
        mOAuthLabel =  UiUtilities.getView(this, R.id.oauth_label);
        mClearPasswordView = UiUtilities.getView(this, R.id.clear_password);
        mClearOAuthView = UiUtilities.getView(this, R.id.clear_oauth);
        mAddAuthenticationView = UiUtilities.getView(this, R.id.add_authentication);
        // Don't use UiUtilities here, in some configurations, these view doesn't exist and
        // UiUtilities throws an exception in this case.
        mPasswordLabel = (TextView)findViewById(R.id.password_label);
        mAuthenticationHeader = (TextView)findViewById(R.id.authentication_header);

        mClearPasswordView.setOnClickListener(this);
        mClearOAuthView.setOnClickListener(this);
        mAddAuthenticationView.setOnClickListener(this);

        final TextWatcher validationTextWatcher = new PasswordTextWatcher();
        mPasswordEdit.addTextChangedListener(validationTextWatcher);
    }

    private class PasswordTextWatcher implements TextWatcher {

        @Override
        public void afterTextChanged(Editable s) {
            validateFields();
        }

        @Override
        public void beforeTextChanged(CharSequence s, int start, int count, int after) { }
        @Override
        public void onTextChanged(CharSequence s, int start, int before, int count) { }
    }

    public void setAuthenticationCallback(final AuthenticationCallback host) {
        mAuthenticationCallback = host;
    }

    public boolean getAuthValid() {
        if (mOfferOAuth & mUseOAuth) {
            return mOAuthProvider != null;
        } else {
            return !TextUtils.isEmpty(mPasswordEdit.getText());
        }
    }

    @VisibleForTesting
    public void setPassword(final String password) {
        mPasswordEdit.setText(password);
    }

    public String getPassword() {
        return mPasswordEdit.getText().toString();
    }

    public String getOAuthProvider() {
        return mOAuthProvider;
    }

    private void validateFields() {
        boolean valid = getAuthValid();
        if (valid != mAuthenticationValid) {
            mAuthenticationCallback.onValidateStateChanged();
            mAuthenticationValid = valid;
        }
    }

    public void setAuthInfo(final boolean offerOAuth, final HostAuth hostAuth) {
        mOfferOAuth = offerOAuth;

        if (mOfferOAuth) {
            final Credential cred = hostAuth.getCredential(getContext());
            if (cred != null) {
                // We're authenticated with OAuth.
                mUseOAuth = true;
                mOAuthProvider = cred.mProviderId;
            } else {
                mUseOAuth = false;
            }
        } else {
            // We're using a POP or Exchange account, which does not offer oAuth.
            mUseOAuth = false;
        }
        mPasswordEdit.setText(hostAuth.mPassword);

        if (mOfferOAuth && mUseOAuth) {
            // We're authenticated with OAuth.
            final OAuthProvider provider = AccountSettingsUtils.findOAuthProvider(
                    getContext(), mOAuthProvider);
            mOAuthLabel.setText(getContext().getString(R.string.signed_in_with_service_label,
                    provider.label));
        }

        updateVisibility();
        validateFields();
    }

    private void updateVisibility() {
        if (mOfferOAuth) {
            if (mAuthenticationHeader != null) {
                mAuthenticationHeader.setVisibility(View.VISIBLE);
                mAuthenticationHeader.setText(R.string.authentication_label);
            }
            if (mUseOAuth) {
                // We're authenticated with OAuth.
                mOAuthWrapper.setVisibility(View.VISIBLE);
                mPasswordWrapper.setVisibility(View.GONE);
                mAddAuthenticationView.setVisibility(View.GONE);
                if (mPasswordLabel != null) {
                    mPasswordLabel.setVisibility(View.VISIBLE);
                }
            } else if (!TextUtils.isEmpty(getPassword())) {
                // We're authenticated with a password.
                mOAuthWrapper.setVisibility(View.GONE);
                mPasswordWrapper.setVisibility(View.VISIBLE);
                mAddAuthenticationView.setVisibility(View.GONE);
                if (TextUtils.isEmpty(mPasswordEdit.getText())) {
                    mPasswordEdit.requestFocus();
                }
                mClearPasswordView.setVisibility(View.VISIBLE);
            } else {
                // We have no authentication, we need to allow either password or oauth.
                mOAuthWrapper.setVisibility(View.GONE);
                mPasswordWrapper.setVisibility(View.GONE);
                mAddAuthenticationView.setVisibility(View.VISIBLE);
            }
        } else {
            // We're using a POP or Exchange account, which does not offer oAuth.
            if (mAuthenticationHeader != null) {
                mAuthenticationHeader.setVisibility(View.VISIBLE);
                mAuthenticationHeader.setText(R.string.account_setup_incoming_password_label);
            }
            mOAuthWrapper.setVisibility(View.GONE);
            mPasswordWrapper.setVisibility(View.VISIBLE);
            mAddAuthenticationView.setVisibility(View.GONE);
            mClearPasswordView.setVisibility(View.GONE);
            if (TextUtils.isEmpty(mPasswordEdit.getText())) {
                mPasswordEdit.requestFocus();
            }
            if (mPasswordLabel != null) {
                mPasswordLabel.setVisibility(View.GONE);
            }
        }
    }

    @Override
    public Parcelable onSaveInstanceState() {
        Bundle bundle = new Bundle();
        bundle.putParcelable(SUPER_STATE, super.onSaveInstanceState());
        bundle.putBoolean(SAVE_OFFER_OAUTH, mOfferOAuth);
        bundle.putBoolean(SAVE_USE_OAUTH, mUseOAuth);
        bundle.putString(SAVE_PASSWORD, getPassword());
        bundle.putString(SAVE_OAUTH_PROVIDER, mOAuthProvider);
        return bundle;
    }

    @Override
    public void onRestoreInstanceState(Parcelable parcelable) {
        if (parcelable instanceof Bundle) {
            Bundle bundle = (Bundle)parcelable;
            super.onRestoreInstanceState(bundle.getParcelable(SUPER_STATE));
            mOfferOAuth = bundle.getBoolean(SAVE_OFFER_OAUTH);
            mUseOAuth = bundle.getBoolean(SAVE_USE_OAUTH);
            mOAuthProvider = bundle.getString(SAVE_OAUTH_PROVIDER);

            final String password = bundle.getString(SAVE_PASSWORD);
            mPasswordEdit.setText(password);
            if (!TextUtils.isEmpty(mOAuthProvider)) {
                final OAuthProvider provider = AccountSettingsUtils.findOAuthProvider(
                        getContext(), mOAuthProvider);
                if (provider != null) {
                    mOAuthLabel.setText(getContext().getString(R.string.signed_in_with_service_label,
                            provider.label));
                }
            }
            updateVisibility();
        }
    }

    @Override
    public void onClick(View view) {
        if (view == mClearPasswordView) {
            mPasswordEdit.setText(null);
            updateVisibility();
            validateFields();
        } else if (view == mClearOAuthView) {
            mUseOAuth = false;
            mOAuthProvider = null;
            updateVisibility();
            validateFields();
        } else if (view == mAddAuthenticationView) {
            mAuthenticationCallback.onRequestSignIn();
        }
    }
}
