// Copyright (C) 2003 Daisuke Arai <darai@users.sourceforge.jp>
// Copyright (C) 2004-2007 panacorn <panacoran@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: Split.cs,v 1.8 2007-12-27 08:34:39 panacoran Exp $

using System;
using System.Data.OleDb;
using System.Collections;

namespace Protra.Lib.Db
{
	/// <summary>
	/// Splitテーブルのレコードを表すクラスです。
	/// </summary>
	public class Split: IRecord
	{
		private int code;
		private DateTime date;
		private double ratio;

		/// <summary>
		/// 既定のコンストラクタ
		/// </summary>
		public Split() {}

		/// <summary>
		/// コンストラクタ
		/// </summary>
		public Split(int code, DateTime date, double ratio)
		{
			this.code = code;
			this.date = date;
			this.ratio = ratio;
		}

		/// <summary>
		/// 銘柄コードを取得する。
		/// </summary>
		public int Code
		{
			get { return code; }
		}

		/// <summary>
		/// 日付を取得する。
		/// </summary>
		public DateTime Date
		{
			get { return date; }
		}

		/// <summary>
		/// 分割比率を取得する。
		/// </summary>
		public double Ratio
		{
			get { return ratio; }
		}

		/// <summary>
		/// データベースのレコードをオブジェクトに変換する。
		/// </summary>
		/// <param name="values">ネイティブ形式の値の配列</param>
		/// <returns>変換後のSplitオブジェクトを返す。</returns>
		public Object ToObject(Object[] values)
		{
			return new Split((int)values[0], // @Code
							  (DateTime)values[1], // @Date
							  (double)values[2]); // @Ratio
		}

		/// <summary>
		/// インスタンスを文字列表現に変換する。
		/// </summary>
		/// <returns>文字列表現を返す。</returns>
		public override string ToString()
		{
			return string.Format(
				"Split[Code={0}, {1}, Ratio={2}]",
				code, date.ToString("d"), ratio);
		}
	}

	/// <summary>
	/// Splitテーブルを操作する。
	/// </summary>
	public class SplitTable
	{
		private static Connection conn;
		private static Connection Conn
		{
			get 
			{
				if (conn != null)
					return conn;
				conn = new Connection("protra");
				string sql = "SELECT FIRST(@Code) FROM Split";
				try
				{
					conn.ThrowException = true;
					conn.QueryScalar(sql);
					conn.ThrowException = false;
				}
				catch (OleDbException)
				{
					// Splitテーブルを作り直す。
					conn.ThrowException = false;
					conn.Execute("DROP TABLE Split");
					conn.Execute(@"
						CREATE TABLE Split(
							@Code INTEGER NOT NULL,
							@Date DATETIME NOT NULL,
							@Ratio DOUBLE NOT NULL,
							PRIMARY KEY(@Code, @Date))");
				}
				return conn;
			}
		}

		/// <summary>
		/// 銘柄コードに対応するデータを取得する。
		/// </summary>
		/// <param name="code">銘柄コードを指定する。</param>
		/// <returns>Splitの配列を返す。</returns>
		public static Split[] GetRecords(int code)
		{
			string sql = string.Format(
				"SELECT * FROM Split WHERE @Code={0} ORDER BY @Date", code);
			ArrayList list = Conn.Query(sql, new Split());
			return (Split[])list.ToArray(typeof(Split));
		}

		/// <summary>
		/// テーブルにデータを追加する。
		/// </summary>
		/// <param name="code">銘柄コード</param>
		/// <param name="date">日付</param>
		/// <param name="ratio">比率</param>
		/// <returns>追加したレコードのCodeオブジェクト。</returns>
		public static Split Add(int code, DateTime date, double ratio)
		{
			Conn.Execute(string.Format("INSERT INTO Split VALUES({0}, #{1}#, {2})",
				code, date.ToString("d"), ratio));
			return new Split(code, date, ratio);
		}

		/// <summary>
		/// すべてのレコードの日付のうち最も新しいものを返す。
		/// </summary>
		/// <returns>最も新しい日付。レコードが存在しない場合にはDateTime.MinValue。</returns>
		public static DateTime MaxDate()
		{
			object o = Conn.QueryScalar("SELECT MAX(@Date) FROM Split");
			return o == DBNull.Value ? DateTime.MinValue : (DateTime)o;
		}

		/// <summary>
		/// 全データを削除する。
		/// </summary>
		public static void Delete()
		{
			Conn.Execute("DELETE From Split");
		}
	}
}
