using System;
using Volpe.Cafe.Generic;
namespace Volpe.Cafe.Data
{
    [Serializable]
    public class RCDouble : RCValue<double>, ICloneable
    {
        #region 
        public RCDouble() : base() { }
        public RCDouble(double initialValue) : base(initialValue, initialValue, initialValue) { }
        public RCDouble(double passengerCar, double lightTruck, double lightTruck2b3) : base(passengerCar, lightTruck, lightTruck2b3) { }
        #endregion
        #region 
        #region 
        public static RCDouble operator +(RCDouble value1, RCDouble value2)
        {
            RCDouble result = new RCDouble();
            for (int i = 0; i < result.Items.Length; i++)
            {
                result.Items[i] = value1.Items[i] + value2.Items[i];
            }
            return result;
        }
        public static RCDouble operator +(RCDouble value1, double value2)
        {
            return value1 + new RCDouble(value2);
        }
        public static RCDouble operator +(double value1, RCDouble value2)
        {
            return new RCDouble(value1) + value2;
        }
        public static RCDouble operator +(RCDouble value1, int value2)
        {
            return value1 + new RCDouble(value2);
        }
        public static RCDouble operator +(int value1, RCDouble value2)
        {
            return new RCDouble(value1) + value2;
        }
        public static RCDouble operator -(RCDouble value1, RCDouble value2)
        {
            RCDouble result = new RCDouble();
            for (int i = 0; i < result.Items.Length; i++)
            {
                result.Items[i] = value1.Items[i] - value2.Items[i];
            }
            return result;
        }
        public static RCDouble operator -(RCDouble value1, double value2)
        {
            return value1 - new RCDouble(value2);
        }
        public static RCDouble operator -(double value1, RCDouble value2)
        {
            return new RCDouble(value1) - value2;
        }
        public static RCDouble operator -(RCDouble value1, int value2)
        {
            return value1 - new RCDouble(value2);
        }
        public static RCDouble operator -(int value1, RCDouble value2)
        {
            return new RCDouble(value1) - value2;
        }
        public static RCDouble operator *(RCDouble value1, RCDouble value2)
        {
            RCDouble result = new RCDouble();
            for (int i = 0; i < result.Items.Length; i++)
            {
                result.Items[i] = value1.Items[i] * value2.Items[i];
            }
            return result;
        }
        public static RCDouble operator *(RCDouble value1, double value2)
        {
            return value1 * new RCDouble(value2);
        }
        public static RCDouble operator *(double value1, RCDouble value2)
        {
            return new RCDouble(value1) * value2;
        }
        public static RCDouble operator *(RCDouble value1, int value2)
        {
            return value1 * new RCDouble(value2);
        }
        public static RCDouble operator *(int value1, RCDouble value2)
        {
            return new RCDouble(value1) * value2;
        }
        public static RCDouble operator /(RCDouble value1, RCDouble value2)
        {
            RCDouble result = new RCDouble();
            for (int i = 0; i < result.Items.Length; i++)
            {
                result.Items[i] = value1.Items[i] / value2.Items[i];
            }
            return result;
        }
        public static RCDouble operator /(RCDouble value1, double value2)
        {
            return value1 / new RCDouble(value2);
        }
        public static RCDouble operator /(double value1, RCDouble value2)
        {
            return new RCDouble(value1) / value2;
        }
        public static RCDouble operator /(RCDouble value1, int value2)
        {
            return value1 / new RCDouble(value2);
        }
        public static RCDouble operator /(int value1, RCDouble value2)
        {
            return new RCDouble(value1) / value2;
        }
        public static RCDouble operator +(RCDouble value)
        {
            return RCDouble.Zero + value;
        }
        public static RCDouble operator -(RCDouble value)
        {
            return RCDouble.Zero - value;
        }
        public static RCDouble operator ++(RCDouble value)
        {
            return value + RCDouble.One;
        }
        public static RCDouble operator --(RCDouble value)
        {
            return value - RCDouble.One;
        }
        #endregion
        #region 
        object ICloneable.Clone()
        {
            return this.Clone();
        }
        public new RCDouble Clone()
        {
            RCDouble value = new RCDouble();
            this.CopyTo(value);
            return value;
        }
        #endregion
        public string ToString(string format)
        {
            string s = string.Empty;
            for (int i = 0; i < this.Items.Length; i++)
            {
                if (i > 0) { s += ", "; }
                s += (Names[i] + "=" + this.Items[i].ToString(format));
            }
            return "{" + s + "}";
        }
        public string ToString(int digits)
        {
            string s = string.Empty;
            for (int i = 0; i < this.Items.Length; i++)
            {
                if (i > 0) { s += ", "; }
                s += (Names[i] + "=" + Math.Round(this.Items[i], digits).ToString());
            }
            return "{" + s + "}";
        }
        public double GetValue(RegulatoryClass regClass)
        {
            return (regClass == RegulatoryClass.All) ? this.Total : this[regClass];
        }
        public RCDouble CreateRounded(int digits)
        {
            RCDouble result = new RCDouble();
            for (int i = 0; i < this.Items.Length; i++)
            {
                result.Items[i] = Math.Round(this.Items[i], digits);
            }
            return result;
        }
        public double ArithmeticMean()
        {
            return this.ArithmeticMean(RCDouble.One);
        }
        public double ArithmeticMean(RCDouble weight)
        {
            double result = 0;
            for (int i = 0; i < this.Items.Length; i++)
            {
                result += weight.Items[i] * this.Items[i];
            }
            return result / weight.Total;
        }
        public double GeometricMean()
        {
            return this.GeometricMean(RCDouble.One);
        }
        public double GeometricMean(RCDouble weight)
        {
            double result = 0;
            for (int i = 0; i < this.Items.Length; i++)
            {
                if (this.Items[i] != 0)
                {
                    result += weight.Items[i] * Math.Log(this.Items[i]);
                }
            }
            return Math.Exp(result / weight.Total);
        }
        public double HarmonicMean()
        {
            return this.HarmonicMean(RCDouble.One);
        }
        public double HarmonicMean(RCDouble weight)
        {
            double result = 0;
            for (int i = 0; i < this.Items.Length; i++)
            {
                if (this.Items[i] != 0)
                {
                    result += weight.Items[i] / this.Items[i];
                }
            }
            return (result == 0) ? 0 : weight.Total / result;
        }
        #endregion
        #region 
        public static RCDouble Zero { get { return new RCDouble(0); } }
        public static RCDouble One { get { return new RCDouble(1); } }
        public double Total
        {
            get
            {
                double total = 0;
                for (int i = 0; i < this.Items.Length; i++)
                {
                    total += this.Items[i];
                }
                return total;
            }
        }
        #endregion
    }
}

