package com.github.premnirmal.textcounter;

import android.annotation.TargetApi;
import android.content.Context;
import android.content.res.TypedArray;
import android.os.Build;
import android.util.AttributeSet;
import android.widget.TextView;

import com.github.premnirmal.textcounter.formatters.CommaSeparatedDecimalFormatter;
import com.github.premnirmal.textcounter.formatters.DecimalFormatter;
import com.github.premnirmal.textcounter.formatters.IntegerFormatter;
import com.github.premnirmal.textcounter.formatters.NoFormatter;

/**
 * Created by prem on 10/28/14.
 *
 * A TextView that counts values depending on the attributes set via xml or via java.
 * Depending on the value set in {@link #setAutoStart(boolean)}, the counter will start.
 * You may call {@link #start()} to start manually at any time.
 */
public class CounterView extends TextView {

    /**
     * 5 milliseconds
     */
    public static final long DEFAULT_INTERVAL = 5l;

    /**
     * increment by 10 units for each time interval
     */
    public static final float DEFAULT_INCREMENT = 10f;


    protected String text, prefix, suffix;

    /**
     * Using floats because android's attributes do not support longs
     */
    protected long timeInterval;
    protected float increment, startValue, endValue;

    protected CounterType counterType;

    protected boolean autoStart, autoFormat;

    protected Counter counter;

    protected Formatter formatter;

    public CounterView(Context context) {
        super(context);
        init(context, null, 0, 0);
    }

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

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

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

    protected void init(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        if (attrs == null) {
            this.prefix = "";
            this.suffix = "";
            this.text = "";
            this.timeInterval = DEFAULT_INTERVAL;
            this.increment = DEFAULT_INCREMENT;
            this.startValue = 0f;
            this.endValue = 0f;
            this.autoStart = false;
            this.autoFormat = true;
            this.counterType = CounterType.NUMBER;
            return;
        }

        final TypedArray typedArray = context.obtainStyledAttributes(
                attrs,
                R.styleable.CounterView,
                defStyleAttr, defStyleRes);

        try {
            final CharSequence prefix = typedArray.getText(R.styleable.CounterView_prefix);
            if (prefix != null) {
                this.prefix = prefix.toString();
            } else {
                this.prefix = "";
            }

            final CharSequence suffix = typedArray.getText(R.styleable.CounterView_suffix);
            if (suffix != null) {
                this.suffix = suffix.toString();
            } else {
                this.suffix = "";
            }

            final CharSequence text = typedArray.getText(R.styleable.CounterView_android_text);
            if (text != null) {
                this.text = text.toString();
            } else {
                this.text = "";
            }

            this.timeInterval = (long) typedArray.getFloat(R.styleable.CounterView_timeInterval, DEFAULT_INTERVAL);
            this.increment = typedArray.getFloat(R.styleable.CounterView_incrementValue, DEFAULT_INCREMENT);
            this.startValue = typedArray.getFloat(R.styleable.CounterView_startValue, 0f);
            this.endValue = typedArray.getFloat(R.styleable.CounterView_endValue, 0f);
            this.autoStart = typedArray.getBoolean(R.styleable.CounterView_autoStart, true);
            this.autoFormat = typedArray.getBoolean(R.styleable.CounterView_formatText, true);

            final int type = typedArray.getInteger(R.styleable.CounterView_type, 0);
            switch(type) {
                case 0:
                    counterType = CounterType.NUMBER;
                    break;
                case 1:
                    counterType = CounterType.DECIMAL;
                    break;
                case 2:
                    counterType = CounterType.BOTH;
                    break;
            }
        } finally {
            typedArray.recycle();
        }

        counter = new Counter(this, startValue, endValue, timeInterval, increment);

        updateCounterType();
    }

    protected void updateCounterType() {
        switch(counterType) {
            case NUMBER:
                formatter = new IntegerFormatter();
                break;
            case DECIMAL:
                formatter = new DecimalFormatter();
                break;
            case BOTH:
                formatter = new CommaSeparatedDecimalFormatter();
                break;
        }
    }

    void setCurrentTextValue(final float number) {
        text = formatter.format(prefix, suffix, number);
        setText(text);
    }

    @Override
    protected void onAttachedToWindow() {
        super.onAttachedToWindow();
        if (autoStart) {
            start();
        }
    }

    /**
     * Start the counter. This method will be called if autostart is set to true
     */
    public void start() {
        removeCallbacks(counter);
        post(counter);
    }

    /**
     * Set the prefix for the number
     * @param prefix
     */
    public void setPrefix(String prefix) {
        this.prefix = prefix;
    }

    /**
     * Set the suffix for the number
     * @param suffix
     */
    public void setSuffix(String suffix) {
        this.suffix = suffix;
    }

    /**
     * Set the time interval between each increment. Default is {@link #DEFAULT_INTERVAL}
     * @param timeInterval
     */
    public void setTimeInterval(long timeInterval) {
        this.timeInterval = timeInterval;
        counter = new Counter(this, startValue, endValue, timeInterval, increment);
    }

    /**
     * Set the increment between the two values. Can be negative or positive. Default is
     * {@link #DEFAULT_INCREMENT}
     * @param increment
     */
    public void setIncrement(float increment) {
        this.increment = increment;
        counter = new Counter(this, startValue, endValue, timeInterval, increment);
    }

    /**
     * Set the value the counter should start at
     * @param startValue
     */
    public void setStartValue(float startValue) {
        this.startValue = startValue;
        counter = new Counter(this, startValue, endValue, timeInterval, increment);
    }

    /**
     * Set the value the counter should end at
     * @param endValue
     */
    public void setEndValue(float endValue) {
        this.endValue = endValue;
        counter = new Counter(this, startValue, endValue, timeInterval, increment);
    }


    /**
     * Set the counterType. See {@link com.github.premnirmal.textcounter.CounterType} for further details
     * @param counterType
     */
    public void setCounterType(CounterType counterType) {
        this.counterType = counterType;
        updateCounterType();
    }

    public void setAutoStart(boolean autoStart) {
        this.autoStart = autoStart;
    }


    /**
     * Allow the view to auto format the number depending on the {@link com.github.premnirmal.textcounter.CounterType}
     * set using {@link #setCounterType(CounterType)}
     * @param formatText
     */
    public void setAutoFormat(boolean formatText) {
        if(autoFormat) {
            if (counterType == CounterType.NUMBER) {
                formatter = new IntegerFormatter();
            } else {
                formatter = new DecimalFormatter();
            }
        } else {
            formatter = new NoFormatter();
        }

        this.autoFormat = formatText;
    }

    /**
     * Set a custom {@link com.github.premnirmal.textcounter.Formatter} to format the text before
     * {@link #setText(CharSequence)} is called
     * @param formatter
     */
    public void setFormatter(Formatter formatter) {
        this.formatter = formatter;
    }
}
