// Copyright (C) 2013 panacoran <panacoran@users.sourceforge.jp>
// Copyright (C) 2003 Daisuke Arai <darai@users.sourceforge.jp>
// 
// This program is part of Protra.
//
// Protra is free software: you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, see <http://www.gnu.org/licenses/>.
// 
// $Id$

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

namespace PtSim
{
    /// <summary>
    /// 時価と簿価の利益の集計値の日付順のリスト
    /// </summary>
    public class CumultiveProfitList : IEnumerable<CumultiveProfit>
    {
        private readonly SortedList<DateTime, CumultiveProfit> _sortedList =
            new SortedList<DateTime, CumultiveProfit>();

        /// <summary>
        /// リストの要素数を取得する。
        /// </summary>
        public int Count
        {
            get { return _sortedList.Count; }
        }

        /// <summary>
        /// 指定された日付のCumultiveProfitを取得または設定する。
        /// </summary>
        /// <param name="date">日付</param>
        /// <returns></returns>
        public CumultiveProfit this[DateTime date]
        {
            get
            {
                if (!_sortedList.ContainsKey(date))
                    _sortedList[date] = new CumultiveProfit();
                return _sortedList[date];
            }
            set { _sortedList[date] = value; }
        }

        /// <summary>
        /// 指定されたインデックスのCumultiveProfitを取得する。
        /// </summary>
        /// <param name="i">インデックス</param>
        /// <returns></returns>
        public CumultiveProfit this[int i]
        {
            get { return _sortedList.Values[i]; }
        }

        /// <summary>
        /// 日付のリストを取得する。
        /// </summary>
        public IList<DateTime> Dates
        {
            get { return _sortedList.Keys; }
        }

        /// <summary>
        /// 前日比ではなく積算値のCumultiveProfitListを取得する。
        /// </summary>
        public CumultiveProfitList AccumulatedList
        {
            get
            {
                var list = new CumultiveProfitList();
                var sum = new CumultiveProfit();
                foreach (var date in _sortedList.Keys)
                {
                    sum += _sortedList[date];
                    list[date] = sum;
                }
                return list;
            }
        }

        /// <summary>
        /// CumultiveProfitListを反復処理する列挙子を返す。
        /// </summary>
        /// <returns>列挙子</returns>
        public IEnumerator<CumultiveProfit> GetEnumerator()
        {
            return _sortedList.Values.GetEnumerator();
        }

        /// <summary>
        /// CumultiveProfitListを反復処理する列挙子を返す。
        /// </summary>
        /// <returns>列挙子</returns>
        IEnumerator IEnumerable.GetEnumerator()
        {
            return _sortedList.Values.GetEnumerator();
        }
    }

    /// <summary>
    /// 時価と簿価の利益の集計値を持つクラス
    /// </summary>
    public class CumultiveProfit
    {
        /// <summary>
        /// 時価による利益を取得または設定する。
        /// </summary>
        public float MarketProfit { get; private set; }

        /// <summary>
        /// 簿価による利益を取得または設定する。
        /// </summary>
        public float BookProfit { get; private set; }

        /// <summary>
        /// コンストラクタ
        /// </summary>
        public CumultiveProfit()
        {
        }

        /// <summary>
        /// コンストラクタ
        /// </summary>
        /// <param name="market">時価による利益</param>
        /// <param name="book">簿価による利益</param>
        public CumultiveProfit(float market, float book)
        {
            MarketProfit = market;
            BookProfit = book;
        }

        /// <summary>
        /// 時価による利益を加算する。
        /// </summary>
        /// <param name="profit">時価による利益</param>
        public void AddMarketProfit(float profit)
        {
            MarketProfit += profit;
        }

        /// <summary>
        /// 時価による利益を加算する。
        /// </summary>
        /// <param name="profit">時価による利益</param>
        public void AddBookProfit(float profit)
        {
            BookProfit += profit;
        }

        /// <summary>
        /// 二つの値を加算する。
        /// </summary>
        /// <param name="v1">最初の値</param>
        /// <param name="v2">二つ目の値</param>
        /// <returns></returns>
        public static CumultiveProfit operator +(CumultiveProfit v1, CumultiveProfit v2)
        {
            return new CumultiveProfit(v1.MarketProfit + v2.MarketProfit, v1.BookProfit + v2.BookProfit);
        }

        /// <summary>
        /// 最初の値から二つ目の値を減算する。
        /// </summary>
        /// <param name="v1">最初の値</param>
        /// <param name="v2">二つ目の値</param>
        /// <returns></returns>
        public static CumultiveProfit operator -(CumultiveProfit v1, CumultiveProfit v2)
        {
            return new CumultiveProfit(v1.MarketProfit - v2.MarketProfit, v1.BookProfit - v2.BookProfit);
        }

        /// <summary>
        /// 二つの値の時価と簿価それぞれについて大きいほうを格納した値を返す。
        /// </summary>
        /// <param name="v1">最初の値</param>
        /// <param name="v2">二つ目の値</param>
        /// <returns></returns>
        public static CumultiveProfit Max(CumultiveProfit v1, CumultiveProfit v2)
        {
            return new CumultiveProfit(Math.Max(v1.MarketProfit, v2.MarketProfit),
                                       Math.Max(v1.BookProfit, v2.BookProfit));
        }

        /// <summary>
        /// 二つの値の時価と簿価それぞれについて小さいほうを格納した値を返す。
        /// </summary>
        /// <param name="v1">最初の値</param>
        /// <param name="v2">二つ目の値</param>
        /// <returns></returns>
        public static CumultiveProfit Min(CumultiveProfit v1, CumultiveProfit v2)
        {
            return new CumultiveProfit(Math.Min(v1.MarketProfit, v2.MarketProfit),
                                       Math.Min(v1.BookProfit, v2.BookProfit));
        }
    }
}