package jp.sblo.pandora.jota;

import android.app.Dialog;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.LinearGradient;
import android.graphics.Paint;
import android.graphics.RectF;
import android.graphics.Shader;
import android.graphics.SweepGradient;
import android.os.Bundle;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams;

public class ColorPickerDialog extends Dialog {

    public interface OnColorChangedListener {
        void colorChanged(int fg , int bg);
    }

    private OnColorChangedListener mListener;
    private String mTitle;
    private boolean mBgMode;
    private int mBgColor;
    private int mFgColor;


    private static class ColorPickerView extends View {

    	private Paint mPaint, mPaintC;
        private Paint mOKPaint;
        private Paint mTextPaint;
        private final int[] mColors;
        private int[] mChroma;
        private OnColorChangedListener mListener;
        private Shader sg, lg;
        private int selectColor;
        private float selectHue = 0;
        private String mLabelOk;
        int bgColor;
        int fgColor;
        boolean mBgMode;


        ColorPickerView(Context c, OnColorChangedListener l, int fg , int bg , boolean bgmode) {
            super(c);
            mListener = l;
            bgColor = bg;
            fgColor = fg;
            mBgMode = bgmode;

            if ( mBgMode ){
                selectColor = bg;
            }else{
                selectColor = fg;
            }

            selectHue = getHue(selectColor);
            mColors = new int[] {
                0xFFFF0000, 0xFFFF00FF, 0xFF0000FF, 0xFF00FFFF, 0xFF00FF00,
                0xFFFFFF00, 0xFFFF0000
            };

            mChroma = new int[] {
            		0xFF000000, 0xFF888888, 0xFFFFFFFF
            };

            sg = new SweepGradient(0, 0, mColors, null);
            lg = new LinearGradient(OK_X0, 0, OK_X1, 0, mChroma, null, Shader.TileMode.CLAMP);

            mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
            mPaint.setStyle(Paint.Style.STROKE);
            mPaint.setShader(sg);
            mPaint.setStrokeWidth(CENTER_RADIUS);

            mPaintC = new Paint(Paint.ANTI_ALIAS_FLAG);
            mPaintC.setStyle(Paint.Style.FILL);
            mPaintC.setShader(lg);
            mPaintC.setStrokeWidth(2);

            mOKPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
            mOKPaint.setStyle(Paint.Style.FILL);
            mOKPaint.setColor(bgColor);
            mOKPaint.setStrokeWidth(5);

            mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
            mTextPaint.setColor(fgColor);
            mTextPaint.setTextSize(20);

            mLabelOk = getContext().getString(R.string.label_ok);


            float colorickersize = getContext().getResources().getDimension(R.dimen.color_picker_size);

            CENTER_X = (int)colorickersize;
            CENTER_Y = (int)colorickersize;
            CENTER_RADIUS = 24;
            OK_X0 = - CENTER_X/2;
            OK_X1 =   CENTER_X/2;
            OK_Y0 = (float) (CENTER_X * 1.2);
            OK_Y1 = (float) (CENTER_X * 1.5);
}

        private boolean mTrackingOK;
        private boolean mHighlightOK;

        private int CENTER_X = 150;
        private int CENTER_Y = 150;
        private int CENTER_RADIUS = 24;
        private float OK_X0 = - CENTER_X/2;
        private float OK_X1 =   CENTER_X/2;
        private float OK_Y0 = (float) (CENTER_X * 1.2);
        private float OK_Y1 = (float) (CENTER_X * 1.5);

        private void drawSVRegion(Canvas canvas) {
        	final float RESOLUTION = (float)0.01;

        	for(float y = 0; y < 1; y += RESOLUTION) {
            	mChroma = new int[10];

            	int i = 0;
            	for(float x = 0; i < 10; x += 0.1, i+=1) {
            		mChroma[i] = setHSVColor(selectHue, x, y);
            	}
                lg = new LinearGradient(OK_X0, 0, OK_X1, 0, mChroma, null, Shader.TileMode.CLAMP);
                mPaintC.setShader(lg);

                //canvas.drawRect(OK_X0, OK_X0 + (CENTER_X * y), OK_X1, OK_X0 + (float)(CENTER_X * (y)), mPaintC);
            	canvas.drawLine(OK_X0, OK_X0 + (CENTER_X * y), OK_X1, OK_X0 + (float)(CENTER_X * (y)), mPaintC);
            }
        }

        @Override
        protected void onDraw(Canvas canvas) {
            float r = CENTER_X - mPaint.getStrokeWidth() * 0.5f;

            canvas.translate(CENTER_X, CENTER_X);
            canvas.drawOval(new RectF(-r, -r, r, r), mPaint);

            drawSVRegion(canvas);

            canvas.drawRoundRect(new RectF(OK_X0, OK_Y0, OK_X1, OK_Y1), 5, 5, mOKPaint);

            canvas.drawText( mLabelOk , 0 - 14, (float) (CENTER_X * 1.4) + 2, mTextPaint);

            if (mTrackingOK) {
                int c = mOKPaint.getColor();
                mOKPaint.setStyle(Paint.Style.STROKE);

                if (mHighlightOK)
                    mOKPaint.setAlpha(0xFF);
                else
                    mOKPaint.setAlpha(0x80);

                float padding = 5;
                //canvas.drawCircle(0, 0, CENTER_RADIUS + mOKPaint.getStrokeWidth(), mOKPaint);
                canvas.drawRoundRect(new RectF(OK_X0 - padding, OK_Y0 - padding, OK_X1 + padding, OK_Y1 + padding), 5, 5, mOKPaint);
                mOKPaint.setStyle(Paint.Style.FILL);
                mOKPaint.setColor(c);
            }
        }

        @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            setMeasuredDimension(CENTER_X * 2, (int)(CENTER_Y * 2.8));
        }

//        private int floatToByte(float x) {
//            int n = java.lang.Math.round(x);
//            return n;
//        }
//
//        private int pinToByte(int n) {
//            if (n < 0)
//                n = 0;
//            else if (n > 255)
//                n = 255;
//            return n;
//        }

        private float getHue(int color) {
        	float hsv[] = new float[3];
        	Color.colorToHSV(color, hsv);
        	return hsv[0];
        }

        private int ave(int s, int d, float p) {
            return s + java.lang.Math.round(p * (d - s));
        }

        private int interpColor(int colors[], float unit) {
            if (unit <= 0) {
                return colors[0];
            }
            if (unit >= 1) {
                return colors[colors.length - 1];
            }

            float p = unit * (colors.length - 1);
            int i = (int)p;
            p -= i;

            // now p is just the fractional part [0...1) and i is the index
            int c0 = colors[i];
            int c1 = colors[i+1];
            int a = ave(Color.alpha(c0), Color.alpha(c1), p);
            int r = ave(Color.red(c0),   Color.red(c1),   p);
            int g = ave(Color.green(c0), Color.green(c1), p);
            int b = ave(Color.blue(c0),  Color.blue(c1),  p);

            return Color.argb(a, r, g, b);
        }

//        private int rotateColor(int color, float rad) {
//            float deg = rad * 180 / PI;
//            int r = Color.red(color);
//            int g = Color.green(color);
//            int b = Color.blue(color);
//
//            ColorMatrix cm  = new ColorMatrix();
//            ColorMatrix tmp = new ColorMatrix();
//
//            cm.setRGB2YUV();
//            tmp.setRotate(0, deg);
//            cm.postConcat(tmp);
//            tmp.setYUV2RGB();
//            cm.postConcat(tmp);
//
//            final float[] a = cm.getArray();
//
//            int ir = floatToByte(a[0] * r +  a[1] * g +  a[2] * b);
//            int ig = floatToByte(a[5] * r +  a[6] * g +  a[7] * b);
//            int ib = floatToByte(a[10] * r + a[11] * g + a[12] * b);
//
//            return Color.argb(Color.alpha(color), pinToByte(ir), pinToByte(ig), pinToByte(ib));
//        }

        private int setHSVColor(float hue, float saturation, float value) {
            float[] hsv = new float[3];
            if(hue >= 360)
            	hue = 359;
            else if(hue < 0)
            	hue = 0;

            if(saturation > 1)
            	saturation = 1;
            else if(saturation < 0)
            	saturation = 0;

            if(value > 1)
            	value = 1;
            else if(value < 0)
            	value = 0;

            hsv[0] = hue;
            hsv[1] = saturation;
            hsv[2] = value;

            return Color.HSVToColor(hsv);
        }

        private static final float PI = 3.1415927f;

        @Override
        public boolean onTouchEvent(MotionEvent event) {
            float x = event.getX() - CENTER_X;
            float y = event.getY() - CENTER_Y;
            float r = (float)(java.lang.Math.sqrt(x*x + y*y));
            boolean inOK = false;
            boolean inOval = false;
            boolean inRect = false;

            if(r <= CENTER_X) {
            	if(r > CENTER_X - CENTER_RADIUS)
            		inOval = true;
            	else if(x >= OK_X0 && x < OK_X1 && y >= OK_X0 && y < OK_X1)
            		inRect = true;
            }
            else if(x >= OK_X0 && x < OK_X1 && y >= OK_Y0 && y < OK_Y1){
            	inOK = true;
            }

            switch (event.getAction()) {
                case MotionEvent.ACTION_DOWN:
                    mTrackingOK = inOK;
                    if (inOK) {
                        mHighlightOK = true;
                        invalidate();
                        break;
                    }
                case MotionEvent.ACTION_MOVE:
                    if (mTrackingOK) {
                        if (mHighlightOK != inOK) {
                            mHighlightOK = inOK;
                            invalidate();
                        }
                    }
                    else if(inOval) {
                        float angle = (float)java.lang.Math.atan2(y, x);
                        // need to turn angle [-PI ... PI] into unit [0....1]
                        float unit = angle/(2*PI);
                        if (unit < 0) {
                            unit += 1;
                        }
                        selectColor = interpColor(mColors, unit);
                        if ( mBgMode ){
                            mOKPaint.setColor(selectColor);
                            bgColor = selectColor;
                        }else{
                            mTextPaint.setColor(selectColor);
                            fgColor = selectColor;
                        }
                        //mChroma[1] = selectColor;
                        selectHue = getHue(selectColor);
                        //lg = new LinearGradient(OK_X0, 0, OK_X1, 0, mChroma, null, Shader.TileMode.CLAMP);
                        //mPaintC.setShader(lg);
                        invalidate();
                    }
                    else if(inRect){
                    	int selectColor2 = setHSVColor(selectHue, (x - OK_X0)/CENTER_X, (y - OK_X0)/CENTER_Y);
                    	selectColor = selectColor2;
                        if ( mBgMode ){
                            mOKPaint.setColor(selectColor);
                            bgColor = selectColor;
                        }else{
                            mTextPaint.setColor(selectColor);
                            fgColor = selectColor;
                        }
                        invalidate();
                    }
                    break;
                case MotionEvent.ACTION_UP:
                    if (mTrackingOK) {
                        if (inOK) {
                            mListener.colorChanged(fgColor , bgColor);
                        }
                        mTrackingOK = false;    // so we draw w/o halo
                        invalidate();
                    }
                    break;
            }
            return true;
        }
    }


    public ColorPickerDialog(Context context, OnColorChangedListener listener, int fgColor , int bgColor , boolean bgmode , String title ) {
    	super(context);
    	mListener = listener;
    	mBgMode = bgmode;
    	mBgColor = bgColor;
    	mFgColor = fgColor;
    	mTitle = title;
    }

    @SuppressWarnings("deprecation")
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        OnColorChangedListener l = new OnColorChangedListener() {
            public void colorChanged(int fg , int bg) {
                mListener.colorChanged( fg , bg );
                dismiss();
            }
        };

        ViewGroup.LayoutParams lp = new ViewGroup.LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT);
        setContentView(new ColorPickerView(getContext(), l, mFgColor ,  mBgColor , mBgMode ), lp);
        setTitle(mTitle);
    }

}