/*
 * Copyright (C) 2013 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.gallery3d.filtershow.colorpicker;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.LinearGradient;
import android.graphics.Paint;
import android.graphics.RadialGradient;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Shader;
import android.graphics.SweepGradient;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.view.MotionEvent;
import android.view.View;

import com.android.gallery3d.R;

import java.util.ArrayList;

public class ColorSVRectView extends View implements ColorListener {
    private float mDpToPix;

    private float mCtrY = 100;
    private Paint mPaint1;

    private float mCtrX = 100;
    private Paint mDotPaint = new Paint();
    private float mDotRadus;
    private float mBorder;

    private float mDotX = Float.NaN;
    private float mDotY;
    private int mSliderColor = 0xFF33B5E5;
    private float[] mHSVO = new float[]{0, 1, 1, 1};
    RectF mRect = new RectF();

    private int mWidth;
    private int mHeight;
    public final static float DOT_SIZE = 20;
    public final static float BORDER_SIZE = 20;
    Bitmap mBitmap;

    public ColorSVRectView(Context ctx, AttributeSet attrs) {
        super(ctx, attrs);

        DisplayMetrics metrics = ctx.getResources().getDisplayMetrics();
        mDpToPix = metrics.density;
        mDotRadus = DOT_SIZE * mDpToPix;
        mBorder = BORDER_SIZE * mDpToPix;

        mPaint1 = new Paint();


        mDotPaint.setStyle(Paint.Style.FILL);
        if (isInEditMode()) {
            mDotPaint.setColor(0x646464);
            mSliderColor = 0x888888;
        } else {
            mDotPaint.setColor(ctx.getResources().getColor(R.color.slider_dot_color));
            mSliderColor = ctx.getResources().getColor(R.color.slider_line_color);
        }
        mPaint1.setStyle(Paint.Style.FILL);
        mPaint1.setAntiAlias(true);
        mPaint1.setFilterBitmap(true);

        mBitmap = Bitmap.createBitmap(64, 46, Bitmap.Config.ARGB_8888);
        fillBitmap();
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, widthMeasureSpec);
    }

    void fillBitmap() {
        int w = mBitmap.getWidth();
        int h = mBitmap.getHeight();
        int[] buff = new int[w * h];
        float[] hsv = new float[3];
        hsv[0] = mHSVO[0];
        for (int i = 0; i < w * h; i++) {
            float sat = (i % w) / (float) w;
            float val = (w - i / w) / (float) w;
            hsv[1] = sat;
            hsv[2] = val;
            buff[i] = Color.HSVToColor(hsv);
        }
        mBitmap.setPixels(buff, 0, w, 0, 0, w, h);
    }

    private void setUpColorPanel() {
        updateDot();
        updateDotPaint();
        fillBitmap();

    }


    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        Rect r = canvas.getClipBounds();
        mRect.set(r);
        mRect.top += mBorder;
        mRect.bottom -= mBorder;
        mRect.left += mBorder;
        mRect.right -= mBorder;
        canvas.drawBitmap(mBitmap, null, mRect, mPaint1);

        if (!Float.isNaN(mDotX)) {
            canvas.drawCircle(mDotX, mDotY, mDotRadus, mDotPaint);
        }
    }


    public boolean onDown(MotionEvent e) {
        return true;
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {

        invalidate((int) (mDotX - mDotRadus), (int) (mDotY - mDotRadus), (int) (mDotX + mDotRadus),
                (int) (mDotY + mDotRadus));
        float x = event.getX();
        float y = event.getY();

        x = Math.max(Math.min(x, mWidth - mBorder), mBorder);
        y = Math.max(Math.min(y, mHeight - mBorder), mBorder);
        mDotX = x;
        mDotY = y;
        float sat = 1 - (mDotY - mBorder) / (mHeight - 2 * mBorder);
        if (sat > 1) {
            sat = 1;
        }

        float value = (mDotX - mBorder) / (mHeight - 2 * mBorder);
        mHSVO[2] = sat;
        mHSVO[1] = value;
        notifyColorListeners(mHSVO);
        updateDotPaint();
        invalidate((int) (mDotX - mDotRadus), (int) (mDotY - mDotRadus), (int) (mDotX + mDotRadus),
                (int) (mDotY + mDotRadus));

        return true;
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        mWidth = w;
        mHeight = h;
        mCtrY = h / 2f;
        mCtrX = w / 2f;

        setUpColorPanel();
    }


    private void updateDot() {

        double hue = mHSVO[0];
        double sat = mHSVO[1];
        double val = mHSVO[2];
        double opc = mHSVO[3];

        mDotX = (float) (mBorder + (mHeight - 2 * mBorder) * sat);
        mDotY = (float) ((1 - val) * (mHeight - 2 * mBorder) + mBorder);

    }

    private void updateDotPaint() {
        int[] colors3 = new int[]{
                mSliderColor, mSliderColor, 0x66000000, 0};
        RadialGradient g = new RadialGradient(mDotX, mDotY, mDotRadus, colors3, new float[]{
                0, .3f, .31f, 1}, Shader.TileMode.CLAMP);
        mDotPaint.setShader(g);

    }

    @Override
    public void setColor(float[] hsvo) {
        if (hsvo[0] == mHSVO[0]
                && hsvo[1] == mHSVO[1]
                && hsvo[2] == mHSVO[2]) {
            mHSVO[3] = hsvo[3]; // we don't update if color stays the same
            return;
        }
        System.arraycopy(hsvo, 0, mHSVO, 0, mHSVO.length);

        setUpColorPanel();
        invalidate();

        updateDot();
        updateDotPaint();

    }

    ArrayList<ColorListener> mColorListeners = new ArrayList<ColorListener>();

    public void notifyColorListeners(float[] hsv) {
        for (ColorListener l : mColorListeners) {
            l.setColor(hsv);
        }
    }

    public void addColorListener(ColorListener l) {
        mColorListeners.add(l);
    }

    public void removeColorListener(ColorListener l) {
        mColorListeners.remove(l);
    }
}
