using System;
using System.Collections.Generic;
using System.Text;

namespace StarEngine.Core
{
    /// <summary>
    /// 色調を表します。
    /// </summary>
    public struct Tone
    {
        /// <summary>
        /// 色調に影響を与えない、空の Tone を取得します。
        /// </summary>
        public static Tone Empty
        {
            get { return new Tone(0, 0, 0); }
        }

        /// <summary>
        /// 二つの Tone が同値かどうかを判断します。
        /// </summary>
        /// <param name="t1">Tone オブジェクト。</param>
        /// <param name="t2">Tone オブジェクト。</param>
        /// <returns>t1 と t2 が同値の場合は true。それ以外の場合は false。</returns>
        public static bool operator ==(Tone t1, Tone t2)
        {
            return t1.Red == t2.Red && t1.Green == t2.Green &&
                t1.Blue == t2.Blue && t1.Saturation == t2.Saturation;
        }

        /// <summary>
        /// 二つの Tone が異なるかどうかを判断します。
        /// </summary>
        /// <param name="t1">Tone オブジェクト。</param>
        /// <param name="t2">Tone オブジェクト。</param>
        /// <returns>t1 と t2 が異なる場合は true。それ以外の場合は false。</returns>
        public static bool operator !=(Tone t1, Tone t2)
        {
            return !(t1 == t2);
        }

        /// <summary>
        /// 色成分を指定して、 Tone オブジェクトを初期化します。
        /// </summary>
        /// <param name="red">赤成分 (-255〜255)。</param>
        /// <param name="green">緑成分 (-255〜255)。</param>
        /// <param name="blue">青成分 (-255〜255)。</param>
        public Tone(int red, int green, int blue)
            : this(red, green, blue, 255)
        {
        }

        /// <summary>
        /// 色成分と彩度を指定して、 Tone オブジェクトを初期化します。
        /// </summary>
        /// <param name="red">赤成分 (-255〜255)。</param>
        /// <param name="green">緑成分 (-255〜255)。</param>
        /// <param name="blue">青成分 (-255〜255)。</param>
        /// <param name="saturation">彩度 (0〜255)。</param>
        public Tone(int red, int green, int blue, byte saturation)
        {
            this = new Tone();
            this.Red = red;
            this.Green = green;
            this.Blue = blue;
            this.Saturation = saturation;
        }

        /// <summary>
        /// 青成分を取得または設定します。
        /// 取り得る値の範囲は -255〜255 です。範囲外の値は自動的に調整されます。
        /// </summary>
        public int Blue
        {
            get { return this.blue; }
            set { this.blue = Math.Max(Math.Min(value, 255), -255); }
        }
        private int blue;

        /// <summary>
        /// 二つのオブジェクトが同値かどうかを判断します。
        /// </summary>
        /// <param name="obj">オブジェクト。</param>
        /// <returns>このインスタンスと obj が同値の場合は true。それ以外の場合は false。</returns>
        public override bool Equals(object obj)
        {
            return obj is Tone && this == (Tone)obj;
        }

        /// <summary>
        /// この Tone のハッシュコードを返します。
        /// </summary>
        /// <returns>32 ビット符号付き整数ハッシュコード。</returns>
        public override int GetHashCode()
        {
            return this.Red.GetHashCode() ^ this.Green.GetHashCode() ^
                this.Blue.GetHashCode() ^ this.Saturation.GetHashCode();
        }

        /// <summary>
        /// 緑成分を取得または設定します。
        /// 取り得る値の範囲は -255〜255 です。範囲外の値は自動的に調整されます。
        /// </summary>
        public int Green
        {
            get { return this.green; }
            set { this.green = Math.Max(Math.Min(value, 255), -255); }
        }
        private int green;

        /// <summary>
        /// 赤成分を取得または設定します。
        /// 取り得る値の範囲は -255〜255 です。範囲外の値は自動的に調整されます。
        /// </summary>
        public int Red
        {
            get { return this.red; }
            set { this.red = Math.Max(Math.Min(value, 255), -255); }
        }
        private int red;

        /// <summary>
        /// 彩度を取得または設定します。
        /// </summary>
        public byte Saturation
        {
            get { return this.saturation; }
            set { this.saturation = value; }
        }
        private byte saturation;

        /// <summary>
        /// この Tone の文字列表現を返します。
        /// </summary>
        /// <returns>Tone の文字列表現。</returns>
        public override string ToString()
        {
            return string.Format("Tone(Red:{0},Green:{1},Blue:{2},Saturation:{3})",
                this.Red, this.Green, this.Blue, this.Saturation);
        }
    }
}
