package app.ltaps.materialedittext;

import android.annotation.TargetApi;
import android.content.Context;
import android.content.res.TypedArray;
import android.os.Build;
import android.support.annotation.NonNull;
import android.support.design.widget.TextInputLayout;
import android.support.v4.content.ContextCompat;
import android.text.Editable;
import android.text.InputFilter;
import android.text.TextWatcher;
import android.util.AttributeSet;
import android.view.ViewTreeObserver;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.TextView;

import app.ltaps.materialedittext.utils.Constants;

/**
 * Created by Christian on 16-11-2016.
 * Edited by Christian on 17-11-2016.
 */

@SuppressWarnings("unused FieldCanBeLocal")
public class MaterialEditText extends LinearLayout {
    private TextView helperTextTextView;
    private TextInputLayout textInputLayout;
    private EditText editTextTextView;
    private String helperText = "";
    private Integer textColor;
    private Integer errorColor;
    private int helperTextColor;

    public MaterialEditText(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context, attrs);
    }

    public MaterialEditText(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context, attrs);
    }

    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    public MaterialEditText(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
        init(context, attrs);
    }

    /**
     * Method called in every constructor. Responsible for creating and styling the views.
     *
     * @param context the current context.
     * @param attrs   attributes for the view.
     */
    private void init(Context context, AttributeSet attrs) {
        inflate(getContext(), R.layout.view_material_edit_text, this);

        //TODO: Make it possible to use all common EditText attributes.
        TypedArray styledAttributes = context.getTheme().obtainStyledAttributes(attrs, R.styleable.MaterialEditText, 0, 0);
        try {
            initHelperTextTextView(styledAttributes);
            initEditTextTextView(styledAttributes);
            initTextInputLayout(styledAttributes);
        } finally {
            styledAttributes.recycle();
        }
    }

    private void initEditTextTextView(TypedArray styledAttributes) {
        int inputTypeAttribute = styledAttributes.getInt(R.styleable.MaterialEditText_android_inputType, Constants.DEFAULT_INPUT_TYPE);
        int maxLengthAttribute = styledAttributes.getInt(R.styleable.MaterialEditText_android_maxLength, Constants.DEFAULT_MAX_LENGTH);
        boolean focusableAttribute = styledAttributes.getBoolean(R.styleable.MaterialEditText_android_focusable, Constants.DEFAULT_FOCUSABLE);
        boolean clickableAttribute = styledAttributes.getBoolean(R.styleable.MaterialEditText_android_clickable, Constants.DEFAULT_CLICKABLE);
        textColor = styledAttributes.getColor(R.styleable.MaterialEditText_textColor, ContextCompat.getColor(getContext(), R.color.default_primaryText));
        errorColor = styledAttributes.getColor(R.styleable.MaterialEditText_errorColor, ContextCompat.getColor(getContext(), R.color.default_errorText));

        editTextTextView = (EditText) findViewById(R.id.editText);

        editTextTextView.setInputType(inputTypeAttribute);
        editTextTextView.setFocusable(focusableAttribute);
        editTextTextView.setClickable(clickableAttribute);
        editTextTextView.setInputType(inputTypeAttribute);
        editTextTextView.setTextColor(textColor);

        editTextTextView.setFilters(new InputFilter[]{new InputFilter.LengthFilter(maxLengthAttribute)});
    }

    private void initHelperTextTextView(TypedArray styledAttributes) {
        String helperTextAttribute = styledAttributes.getString(R.styleable.MaterialEditText_helperText);
        helperTextColor = styledAttributes.getColor(R.styleable.MaterialEditText_helperTextColor, ContextCompat.getColor(getContext(), R.color.default_secondaryText));

        helperTextTextView = (TextView) findViewById(R.id.helperText);
        helperTextTextView.setText(helperTextAttribute);
        helperTextTextView.setTextColor(helperTextColor);
    }

    private void initTextInputLayout(TypedArray styledAttributes) {
        String hintAttribute = styledAttributes.getString(R.styleable.MaterialEditText_hint);
        boolean hintEnabledAttribute = styledAttributes.getBoolean(R.styleable.MaterialEditText_hintEnabled, true);

        textInputLayout = (TextInputLayout) findViewById(R.id.textInputLayout);
        textInputLayout.setHint(hintAttribute);
        textInputLayout.setHintEnabled(hintEnabledAttribute);

        if (!hintEnabledAttribute) {
            editTextTextView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
                @Override
                public void onGlobalLayout() {
                    editTextTextView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
                    int height = editTextTextView.getMeasuredHeight();
                    LinearLayout.LayoutParams textInputLayoutParams = new LinearLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, height);
                    textInputLayout.setLayoutParams(textInputLayoutParams);
                }
            });
        }

        this.editTextTextView.addTextChangedListener(new TextWatcher() {
            @Override
            public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {

            }

            @Override
            public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {

            }

            @Override
            public void afterTextChanged(Editable editable) {
                clearError(editable);
            }
        });

        this.helperText = this.helperTextTextView.getText().toString();
    }

    public EditText getEditTextTextView() {
        return this.editTextTextView;
    }

    //TODO: Remove
    public EditText getEditText() {
        return getEditTextTextView();
    }

    public Editable getText() {
        if (!isNull(editTextTextView)) {
            return this.editTextTextView.getText();
        }
        return null;
    }

    public void setError(String error) {
        if (!isNull(helperTextTextView)) {
            if (error != null) {
                setHelperText(error);
                activateError(error);
            } else {
                deactivateError();
            }
        }
    }

    public void append(@NonNull String text) {
        if (this.editTextTextView != null) {
            this.editTextTextView.append(text);
        }
    }

    public void setSelection(int index) {
        if (this.editTextTextView != null) {
            this.editTextTextView.setSelection(index);
        }
    }

    public void setText(@NonNull String text) {
        if (this.editTextTextView != null) {
            this.editTextTextView.setText(text);
        }
    }

    public void clearFocus() {
        if (editTextTextView != null) {
            editTextTextView.clearFocus();
        }
    }

    public void setFocusable(boolean focusable) {
        if (editTextTextView != null) {
            editTextTextView.setFocusable(focusable);
        }
    }

    public void setFocusableInTouchMode(boolean focusableInTouchMode) {
        if (editTextTextView != null) {
            editTextTextView.setFocusableInTouchMode(focusableInTouchMode);
        }
    }

    private void clearError(Editable editable) {
        if (editable.length() == 0) {
            deactivateError();
        }
    }

    private void setHelperText(String error) {
        if (!this.helperTextTextView.getText().toString().equals(error)) {
            this.helperText = this.helperTextTextView.getText().toString();
        }
    }

    /**
     * @param text the error text
     */
    private void activateError(String text) {
        helperTextTextView.setText(text);
        this.helperTextTextView.setTextColor(errorColor);
    }

    /**
     *
     */
    private void deactivateError() {
        this.helperTextTextView.setTextColor(helperTextColor);
        this.helperTextTextView.setText(this.helperText);
    }

    /**
     * @param object the object to check for nullity
     * @return whether the object is null or not
     */
    private static boolean isNull(Object object) {
        return object == null;
    }

}

