/*
 * Copyright (c) Daisuke OKAJIMA    All rights reserved.
 * 
 * $Id$
 */
// This file is modified by panacoran.
// Copyright (c) 2014 panacoran <panacoran@users.sourceforge.jp>
// This program is part of OmegaChart.
// OmegaChart is licensed under the Apache License, Version 2.0.

using System;
using System.Text;
using System.IO;
using System.Collections;
using System.Diagnostics;
using Zanetti.Data;
using System.Collections.Generic;

namespace Zanetti.DataSource.Specialized {
	internal class MujinzouDataSource : DailyDataSource {

		private bool _includesDomesticIndices;

		public MujinzouDataSource(int[] dates) : base(dates) {
		}

		public bool IncludesDomesticIndices {
			get {
				return _includesDomesticIndices;
			}
			set {
				_includesDomesticIndices = value;
			}
		}

		public override void Run() {
            var newdata = new Dictionary<int, Dictionary<int, NewDailyData>>();
			            foreach (var date in _dates)
            {
                newdata[date] = FillData(date);
                SendMessage(AsyncConst.WM_ASYNCPROCESS, (date | DATE_MASK), AsyncConst.LPARAM_PROGRESS_SUCCESSFUL);
            }
            foreach (AbstractBrand br in Env.BrandCollection.Values)
            {
                if (br.Market == MarketType.B && !IsDomesticIndex(br.Code) || br.Market == MarketType.Custom)
                    continue;
                using (var farm = (DailyDataFarm)br.CreateDailyFarm(_dates.Length))
                {
                    var traceFlag = false;
                    foreach (var date in _dates)
                    {
                        NewDailyData td;
                        if (newdata[date].TryGetValue(br.Code, out td))
                        {
                            farm.UpdateDataFarm(date, td);
                        }
                        else
                        {
                            if (traceFlag)
                                continue;
                            traceFlag = true;
                            Debug.WriteLine("Data not found(mujinzou) : code=" + br.Code + " market=" + br.Market);
                        }
                    }
                    farm.Save(Util.GetDailyDataFileName(br.Code));
                    SendMessage(AsyncConst.WM_ASYNCPROCESS, br.Code, AsyncConst.LPARAM_PROGRESS_SUCCESSFUL);
                }
            }
		}


		//ある日付に対して、コードのint値からPanRollingTradeDataへのハッシュテーブルを構築して返す
		private Dictionary<int, NewDailyData> FillData(int date) {
			TextReader r = null;
			try {
				var result = new Dictionary<int, NewDailyData>();
				DateTime d2 = Util.IntToDate(date);
				//無尽蔵にはデータが２種類あり、日経先物等の有無、名証銘柄の有無、出来高０のときの扱い、が異なるようだ。先物のデータがとれるようにこちらを使用する
                //2007/3/1, eonetからのデータが入手不能になる。標準をinfoseekに切り替えるとともに、ついでに設定ファイルで切り替え可能にした。相場が大荒れの時期に面倒くさいことが起きたものだ。
                //2007/3/31, さらにinfoseekが移動
                var domain = d2.Year < 2020 ? "souba-data.com" : "mujinzou.com";
                var path = Env.Options.MujinzouUsesKakoData
                    ? "k_data/" + d2.ToString(@"yyyy/yy_MM/TyyMMdd")
                    : "d_data/" + d2.ToString(@"yyyy\d/yy_MM\d/TyyMMdd");
				var ext = d2.Year >= 2015 ? ".zip" : ".lzh";
                var url = $"http://{domain}/{path}{ext}";
				using (var reader = new StreamReader(Util.ExtractData(url), Encoding.Default))
				{
					string line;
					while ((line = reader.ReadLine()) != null)
					{
						string[] t = line.Split(',');
						//例      0    1  2             3     4     5     6     7,         8,       9
						//2005/5/20,1001,11,1001 日経平均,11104,11110,11034,11037,1257840000,東証１部
						if (t.Length != 10 || t[1].Length != 4)
							continue;
						int code = ParseCode(t[1]);
                        if (!(Env.BrandCollection.FindBrand(code) is BasicBrand))
                            continue;
                        try
						{
							var vv = IsDomesticIndex(code) ? 0.001 : 1;
							var pv = IsDomesticIndex(code) ? 100 : 10; // 指数は100倍、株価は10倍で記録。
							var td = new NewDailyData
							{
								volume = (int)(double.Parse(t[8]) * vv)
							};
							// 複数市場に上場している銘柄には複数のエントリがある。出来高の多いほうをとる。
							if (!result.TryGetValue(code, out var existing) || existing.volume < td.volume)
							{
								result[code] = td;
								td.open = (int)(double.Parse(t[4]) * pv);
								td.high = (int)(double.Parse(t[5]) * pv);
								td.low = (int)(double.Parse(t[6]) * pv);
								td.close = (int)(double.Parse(t[7]) * pv);
								td.volume = (int)(double.Parse(t[8]) * vv);						
							}
						}
						catch (FormatException)
						{
						}
					}
				}
				return result;
			}
			finally {
				if(r!=null) r.Close();
			}
		}

		private static bool IsMujinzouSupportedIndices(int code) {
			return code==(int)BuiltInIndex.Nikkei225 ||
				code==(int)BuiltInIndex.TOPIX ||
				code==(int)BuiltInIndex.JASDAQ ||
				code==(int)BuiltInIndex.Nikkei225_F ||
				code==(int)BuiltInIndex.TOPIX_F;
		}
		private static int ParseCode(string code) {
			int t = Util.ParseInt(code);
			//以下に該当するものでなければデータの取り込みは行われない
			if(t<1300) {
				switch(t) {
					case 1001: return (int)BuiltInIndex.Nikkei225;
					case 1002: return (int)BuiltInIndex.TOPIX;
					case 1004: return (int)BuiltInIndex.Nikkei225_F;
					case 1005: return (int)BuiltInIndex.JASDAQ;
					case 1006: return (int)BuiltInIndex.TOPIX_F;
					default: return 0;
				}
			}
			else
				return t; //ふつうの銘柄
		}
		private static bool IsDomesticIndex(int code) {
			return code==(int)BuiltInIndex.Nikkei225 || code==(int)BuiltInIndex.TOPIX || code==(int)BuiltInIndex.JASDAQ;
		}

	}
}
