// Copyright(C) 2008, 2010, 2011 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: MujinzouUpdator.cs 428 2011-08-04 06:56:06Z panacoran $

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;
using Protra.Lib.Data;

namespace Protra.Lib.Update
{
	/// <summary>
	/// 無尽蔵を利用して株価データの更新を行うクラス。
	/// </summary>
	public class MujinzouUpdator: PriceDataUpdator
	{
        /// <summary>
        /// データが存在する最初の日付を取得する。
        /// </summary>
        public override DateTime DataSince
        {
            get { return new DateTime(1996, 1, 4); }
        }

        string urlHead;
        string urlTemplate;

        static string BackslashEscape(string s)
        {
            var r = "";
            foreach (var c in s)
                r += @"\" + c;
            return r;
        }

        /// <summary>
        /// コンストラクタ。
        /// </summary>
        /// <param name="url">データのURL。</param>
        public MujinzouUpdator(string url)
        {
            var r = new Regex(@"^(?<head>.*)\d\d(?<yy>\d\d)(?<s1>.*)\k<yy>_(?<MM>\d\d)(?<s2>.*)T\k<yy>\k<MM>\d\d.lzh$");
            var m = r.Match(url);
            if (!m.Success)
                return;
            urlHead = m.Groups["head"].Value;
            urlTemplate = "yyyy" + BackslashEscape(m.Groups["s1"].Value) + "yy_MM" +
                BackslashEscape(m.Groups["s2"].Value) + "TyyMMdd";
        }

        /// <summary>
        /// 新しいデータが置かれる時刻に達しているか。
        /// </summary>
        /// <param name="time">時刻</param>
        /// <returns></returns>
        protected override bool IsDataAvailable(DateTime time)
        {
            return time.Hour >= 17;
        }

        /// <summary>
        /// データのURLを取得する。
        /// </summary>
        /// <returns>URL</returns>
        protected override string DownloadUrl()
        {
            if (urlHead == null)
                throw new ApplicationException("無尽蔵のURLが正しくありません。");
            return urlHead + Date.ToString(urlTemplate) + ".lzh";
        }

        /// <summary>
        /// 文字列を解析して価格データを返す。
        /// </summary>
        /// <param name="line">文字列</param>
        /// <returns>価格データ</returns>
		protected override Price ParseLine(string line)
		{
			string[] tokens = line.Split(new char [] {'\t', ','});
            if (tokens.Length < 9)
                return null;
			Price r = new Price();
			try
			{
				r.Date = DateTime.Parse(tokens[0]);
				r.Code = tokens[1];
                if (r.Code.CompareTo("1002") > 0 && r.Code.CompareTo("1300") < 0)
                    return null; // 各種指数を無視する。
				// 指数の値に小数が含まれているのでdouble.Parseを利用する。
				r.Open = (int)double.Parse(tokens[4]);
				r.High = (int)double.Parse(tokens[5]);
				r.Low = (int)double.Parse(tokens[6]);
				r.Close = (int)double.Parse(tokens[7]);
				r.Volume = double.Parse(tokens[8]) / 1000;
                switch (tokens[2])
                {
                    case "11":
                        r.Market = "T1";
                        break;
                    case "12":
                        r.Market = "T2";
                        break;
                    case "13":
                        r.Market = "M";
                        break;
                    case "14":
                        r.Market = "T1";
                        break;
                    case "20"://この大証は１部、２部混在しているので１部にする
                    case "21":
                        r.Market = "O1";
                        break;
                    case "22":
                        r.Market = "O2";
                        break;
                    case "23":
                    case "24":
                        r.Market = "H";
                        break;
                    case "32":
                        if (tokens[9] == "東証２部") // データのミスに対応する。
                            r.Market = "T2";
                        else
                            return null;
                        break;
                    case "91":
                        r.Market = "J";
                        break;
                    default:
                        return null;
                }

			}
			catch (FormatException)
			{
				// フォーマットエラーは全部無視する。
				return null;
			}
			return r;
		}
	}
}
