using UnityEngine;
using System.Collections;
using System.Security.Cryptography;

/****
 * 	Magic Class By Kcm :)
 */


public class PW_Color
{
	float _r;
	float _g;
	float _b;

	float _h;
	float _s;
	float _v;

	float _H;
	float _S;
	float _L;

	// Accessors -------------------------------------------------------------

	public float r
	{
		get { if (!rgb) ComputeRGB(); return _r; }
		set { if (!rgb) ComputeRGB(); _r = value; hsv = false; hsl = false; }
	}
	public float g
	{
		get { if (!rgb) ComputeRGB(); return _g; }
		set { if (!rgb) ComputeRGB(); _g = value; hsv = false; hsl = false; }
	}
	public float b
	{
		get { if (!rgb) ComputeRGB(); return _b; }
		set { if (!rgb) ComputeRGB(); _b = value; hsv = false; hsl = false; }
	}

	public float h
	{
		get { if (!hsv) ComputeHSV(); return _h; }
		set { if (!hsv) ComputeHSV(); _h = value; rgb = false; hsl = false; }
	}
	public float s
	{
		get { if (!hsv) ComputeHSV(); return _s; }
		set { if (!hsv) ComputeHSV(); _s = value; rgb = false; hsl = false; }
	}
	public float v
	{
		get { if (!hsv) ComputeHSV(); return _v; }
		set { if (!hsv) ComputeHSV(); _v = value; rgb = false; hsl = false; }
	}

	public float H
	{
		get { if (!hsl) ComputeHSL(); return _H; }
		set { if (!hsl) ComputeHSL(); _H = value; rgb = false; hsv = false; }
	}
	public float S
	{
		get { if (!hsl) ComputeHSL(); return _S; }
		set { if (!hsl) ComputeHSL(); _S = value; rgb = false; hsv = false; }
	}
	public float L
	{
		get { if (!hsl) ComputeHSL(); return _L; }
		set { if (!hsl) ComputeHSL(); _L = value; rgb = false; hsv = false; }
	}

	bool hsv;
	bool rgb;
	bool hsl;

	// -------------------------------------------------------------

	public PW_Color()
	{
		_r = 0.0f;
		_g = 0.0f;
		_b = 0.0f;

		_h = 0.0f;
		_s = 0.0f;
		_v = 0.0f;

		_H = 0.0f;
		_S = 0.0f;
		_L = 0.0f;
		
		rgb = true;
		hsv = true;
		hsl = true;
	}

	// -------------------------------------------------------------

	public PW_Color(Color32 color32)
	{
		_r = ((float)color32.r) / 255.0f;
		_g = ((float)color32.g) / 255.0f;
		_b = ((float)color32.b) / 255.0f;

		rgb = true;
		hsv = false;
		hsl = false;
	}

	// -------------------------------------------------------------

	public PW_Color(PW_Color _t)
	{
		rgb = _t.rgb;
		_r = _t._r;
		_g = _t._g;
		_b = _t._b;

		hsv = _t.hsv;
		_h = _t._h;
		_s = _t._s;
		_v = _t._v;

		hsl = _t.hsl;
		_H = _t._H;
		_S = _t._S;
		_L = _t._L;
	}

	// -------------------------------------------------------------

	void ComputeHSV()
	{
		if (hsv) return;		
		
		if (hsl)
		{			
			// Error here ?
			_h = _H;
			float L = _L;
			float S = _S;
			L *= 2.0f;
			S *= (L <= 1.0f) ? L : 2.0f - L;
			_v = (L + S) / 2.0f;

			if (L + S > 0.0f)
			{
				_s = (2.0f * S) / (L + S);
			}
			else
			{
				_s = 0.0f;
			}
		}
		else if (rgb)
		{
			float max = Mathf.Max(_r, Mathf.Max(_g, _b));
			float min = Mathf.Min(_r, Mathf.Min(_g, _b));
			float delta = max - min;

			_v = max;

			if (max != 0.0f)
				_s = delta / max;
			else
				_s = 0.0f;

			if (_s == 0.0f)
			{
				_h = 0.0f;
			}
			else
			{
				if (_r == max)			_h = (_g - _b) / delta;
				else if (_g == max)		_h = 2.0f + (_b - _r) / delta;
				else if (_b == max)		_h = 4.0f + (_r - _g) / delta;

				_h /= 6.0f;

				if (_h < 0.0f)			_h += 1.0f;
			}
		}
		else
		{
			_h = 0.0f;
			_s = 0.0f;
			_v = 0.0f;
		}

		hsv = true;

	}

	// -------------------------------------------------------------

	void ComputeRGB()
	{
		if (rgb) return;

		if (hsv == false) ComputeHSV();

		int i = (int)Mathf.Floor(_h * 6.0f);
		float f = _h * 6.0f - i;
		float p = _v * (1.0f - _s);
		float q = _v * (1.0f - f * _s);
		float t = _v * (1.0f - (1.0f - f) * _s);

		switch (i % 6)
		{
			case 0: _r = _v; _g = t; _b = p; break;
			case 1: _r = q; _g = _v; _b = p; break;
			case 2: _r = p; _g = _v; _b = t; break;
			case 3: _r = p; _g = q; _b = _v; break;
			case 4: _r = t; _g = p; _b = _v; break;
			case 5: _r = _v; _g = p; _b = q; break;
		}

		rgb = true;
	}

	// -------------------------------------------------------------

	void ComputeHSL()
	{
		if (hsl) return;
		if (hsv == false) ComputeHSV();

		_H = _h;
		_L = (2.0f - _s) * _v;
		_S = _s * _v;

		if (_L > 0.0f)
		{
			_S /= (_L <= 1) ? _L : 2.0f - _L;
		}
		else
		{
			_S = 0.0f;
		}
		_L /= 2.0f;

		hsl = true;
	}

	// -------------------------------------------------------------
    /*
    public PW_Shape.SHAPE_TYPE GetShapeColor()
    {
        if (!hsl) ComputeHSL();

        float precisionH = 0.2f;
        float precisionS = 0.4f;

        if (_L < 0.25f || (_S < 0.3f && _L < 0.5f))
        {
            //Debug.Log(ToString());
            return PW_Shape.SHAPE_TYPE.BLACK;
        }
		
        if (_S < 0.25f || _L > 0.7f) return PW_Shape.SHAPE_TYPE.NONE;

      //
        if (0.5f - Mathf.Abs(_H - 0.5f) < precisionH)
        {
			
            return PW_Shape.SHAPE_TYPE.RED;
        }
        if (Mathf.Abs(_H - 0.3333f) < precisionH) return PW_Shape.SHAPE_TYPE.GREEN;
        if (Mathf.Abs(_H - 0.6666f) < precisionH) return PW_Shape.SHAPE_TYPE.BLUE;
 
        return PW_Shape.SHAPE_TYPE.BLACK;
    }

    // -------------------------------------------------------------

    public bool IsColor(PW_Shape.SHAPE_TYPE colorType, float precision)
    {
        if (!hsl) ComputeHSL();

        if (colorType == PW_Shape.SHAPE_TYPE.BLACK)
        {
            return _L < 0.25f || (_S < 0.3f && _L < 0.5f);
        }

        if (_S < 0.25f || _L > 0.8f || _L < 0.3f) return false;

        precision = 0.22f;
        switch (colorType)
        {
            case PW_Shape.SHAPE_TYPE.RED: return 0.5f - Mathf.Abs(_H - 0.5f) < precision; // other solution : return Mathf.Abs(((_h + 0.5f) % 1.0f) - 0.5f) < precision;
            case PW_Shape.SHAPE_TYPE.GREEN: return Mathf.Abs(_H - 0.3333f) < precision;
            case PW_Shape.SHAPE_TYPE.BLUE: return Mathf.Abs(_H - 0.6666f) < precision;
        }

        return false;
    }

	
	 
    public PW_Shape.SHAPE_TYPE GetShapeColor()
    {
        if (!hsv) ComputeHSV();

        float precisionH = 0.2f;
        float precisionS = 0.4f;

        if (_s < 0.25f && _v > 0.6f) return PW_Shape.SHAPE_TYPE.INVALID;

        if (Mathf.Abs(_h - 0.6666f) < precisionH && _s > precisionS) return PW_Shape.SHAPE_TYPE.BLUE;

        if (_v < 0.28f) return PW_Shape.SHAPE_TYPE.BLACK;

        if (0.5f - Mathf.Abs(_h - 0.5f) < precisionH && _s > precisionS) return PW_Shape.SHAPE_TYPE.RED;
        if (Mathf.Abs(_h - 0.3333f) < precisionH && _s > precisionS) return PW_Shape.SHAPE_TYPE.GREEN;

 
        return PW_Shape.SHAPE_TYPE.BLACK;
    }

    // -------------------------------------------------------------

    public bool IsColor(PW_Shape.SHAPE_TYPE colorType, float precision)
    {
        if (!hsv) ComputeHSV();

        precision = 0.22f;

        switch (colorType)
        {
            case PW_Shape.SHAPE_TYPE.BLACK: return _v < 0.55f && _s < 0.55f;
            case PW_Shape.SHAPE_TYPE.RED: return 0.5f - Mathf.Abs(_h - 0.5f) < precision && _s > 0.25f && _v > 0.28f; // other solution : return Mathf.Abs(((_h + 0.5f) % 1.0f) - 0.5f) < precision;
            case PW_Shape.SHAPE_TYPE.GREEN: return Mathf.Abs(_h - 0.3333f) < precision && _s > 0.25f && _v > 0.28f;
            case PW_Shape.SHAPE_TYPE.BLUE: return Mathf.Abs(_h - 0.6666f) < precision && _s > 0.25f && _v > 0.28f;
        }

        return false;
    }
    */

    // -------------------------------------------------------------

	public Color GetColor()
	{
		if (!rgb) ComputeRGB();
		return new Color(_r, _g, _b);
	}

	// -------------------------------------------------------------

	public bool IsClose(PW_Color color)
	{
		if (((Mathf.Abs(h - color.h) < 0.19f) && (Mathf.Abs(L - color.L) < 0.17f)) ||
			((Mathf.Abs(s - color.s) < 0.2f) && (Mathf.Abs(v - color.v) < 0.15f)) ||
			(Mathf.Abs(L - color.L) < 0.15f))
		{
			return true;
		}

		return false;
	}

	// -------------------------------------------------------------

	public void SetWhite()
	{
		rgb = true;
		_r = 1.0f;
		_g = 1.0f;
		_b = 1.0f;

		hsv = true;
		_h = 0.0f;
		_s = 0.0f;
		_v = 1.0f;

		hsl = true;
		_H = 0.0f;
		_S = 0.0f;
		_L = 1.0f;

	}

	// -------------------------------------------------------------

	public override string ToString()
	{
		return (rgb ? "RGB(" + _r + ", " + _g + ", " + _b + ")\n" : "") + (hsv ? "HSV(" + _h + ", " + _s + ", " + _v + ")\n" : "") + (hsl ? "HSL(" + _H + ", " + _S + ", " + _L + ")\n" : "");
	}


	// ------------------------------------------------------------------------------------------

	public static PW_Color red
	{
		get
		{
			return new PW_Color(new Color32(255, 0, 0, 0));
		}
	}

    // ------------------------------------------------------------------------------------------

    public static PW_Color green
    {
        get
        {
            return new PW_Color(new Color32(0, 255, 0, 0));
        }
    }

}
