// 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: ProfitList.cs 306 2010-03-19 13:21:22Z panacoran $

using System;
using System.Collections;

namespace PtSim
{
	/// <summary>
	/// 利益のリストを表すクラスです。
	/// DateTimeをキーとしてProfitを格納する整列済みリストとなります。
	/// </summary>
	public class ProfitList
	{
		/// <summary>
		/// 日付をキーとした利益のリスト
		/// </summary>
		private SortedList list = new SortedList();

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

		/// <summary>
		/// 最大ドローダウンを計算します。
		/// </summary>
		/// <returns>
		/// Profit.BookProfitには簿価による計算結果、
		/// Profit.MarketProfitには時価による計算結果がセットされます。
		/// </returns>
		public Profit MaxDrawDown()
		{
			float ddBook = 0, pBook = 0;
			float ddMarket = 0, pMarket = 0;
			for(int i = 0; i < list.Count; i++)
			{
				Profit profit = (Profit)list.GetByIndex(i);
				if(profit.BookProfit > pBook)
					pBook = profit.BookProfit;
				else if(profit.BookProfit - pBook < ddBook)
					ddBook = profit.BookProfit - pBook;
				if(profit.MarketProfit > pMarket)
					pMarket = profit.MarketProfit;
				else if(profit.MarketProfit - pMarket < ddMarket)
					ddMarket = profit.MarketProfit - pMarket;
			}

			return new Profit(ddBook, ddMarket);
		}

		/// <summary>
		/// このProfitListを累積利益リストに変換します。
		/// </summary>
		public void Accumulate()
		{
			for(int i = 1; i < list.Count; i++)
			{
				Profit p1 = (Profit)list.GetByIndex(i - 1);
				Profit p2 = (Profit)list.GetByIndex(i);
				p2.BookProfit += p1.BookProfit;
				p2.MarketProfit += p1.MarketProfit;
			}
		}

		/// <summary>
		/// 日付のリストを取得します。
		/// </summary>
		/// <returns>日付のリストです。</returns>
		public DateTime[] GetDateList()
		{
			ArrayList array = new ArrayList(list.GetKeyList());
			return (DateTime[])array.ToArray(typeof(DateTime));
		}

		/// <summary>
		/// 指定された日付の利益を取得または設定します。
		/// </summary>
		public Profit this[DateTime date]
		{
			get
			{
				if(! list.ContainsKey(date))
					list.Add(date, new Profit());
				return (Profit)list[date];
			}
			set { list[date] = value; }
		}

		/// <summary>
		/// 指定されたインデックスの利益を取得します。
		/// </summary>
		public Profit this[int index]
		{
			get { return (Profit)list.GetByIndex(index); }
		}

		/// <summary>
		/// 要素の数を取得します。
		/// </summary>
		public int Count
		{
			get { return list.Count; }
		}

		/// <summary>
		/// 最大の日付を取得します。
		/// </summary>
		public DateTime MaxDate
		{
			get
			{
				if(list.Count > 0)
					return (DateTime)list.GetKeyList()[list.Count - 1];
				else
					return new DateTime();
			}
		}

		/// <summary>
		/// 最小の日付を取得します。
		/// </summary>
		public DateTime MinDate
		{
			get
			{
				if(list.Count > 0)
					return (DateTime)list.GetKeyList()[0];
				else
					return new DateTime();
			}
		}
	}

	/// <summary>
	/// 利益を表すクラスです。
	/// </summary>
	public class Profit
	{
		/// <summary>
		/// 簿価による利益
		/// </summary>
		public float BookProfit;
		/// <summary>
		/// 時価による利益
		/// </summary>
		public float MarketProfit;

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

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