/*
 * 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;

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() {
			Hashtable[] newdata = new Hashtable[_dates.Length];
			//データをまずダウンロード
			for(int i=0; i<_dates.Length; i++) {
				newdata[i] = FillData(_dates[i]);
				SendMessage(AsyncConst.WM_ASYNCPROCESS, _dates[i] | DATE_MASK, AsyncConst.LPARAM_PROGRESS_SUCCESSFUL);
			}

			//各データの追加と保存
			IDictionaryEnumerator ie = Env.BrandCollection.GetEnumerator();
			while(ie.MoveNext()) {
				AbstractBrand br = (AbstractBrand)ie.Value;
				if((br.Market==MarketType.B && !IsMujinzouSupportedIndices(br.Code)) || br.Market==MarketType.Custom) continue;
			
				bool trace_flag = false;
				using(DailyDataFarm f = (DailyDataFarm)br.CreateDailyFarm(_dates.Length)) {
					for(int i=0; i<_dates.Length; i++) {
						NewDailyData td = (NewDailyData)newdata[i][br.Code];
						if(td==null) {
							if(!trace_flag) {
								trace_flag = true;
								Debug.WriteLine("Data not found(mujinzou) : code="+br.Code+" market="+br.Market.ToString());
							}
						}
						else
							f.UpdateDataFarm(_dates[i], td);
					}
					f.Save(Util.GetDailyDataFileName(br.Code));
				}
				SendMessage(AsyncConst.WM_ASYNCPROCESS, br.Code, AsyncConst.LPARAM_PROGRESS_SUCCESSFUL);
			}
		}


		//ある日付に対して、コードのint値からPanRollingTradeDataへのハッシュテーブルを構築して返す
		private Hashtable FillData(int date) {
			TextReader r = null;
			try {
				Hashtable result = new Hashtable();
				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}";
				r = new StreamReader(Util.ExtractData(url), Encoding.Default);

				string line = r.ReadLine();
				while(line!=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) {
						int code = ParseCode(t[1]);

						BasicBrand br = Env.BrandCollection.FindBrand(code) as BasicBrand;
						if(br!=null && CheckMarket(br, Util.ParseInt(t[2], 0))) {

							double vv = 1, pv = 10; // 株価は10倍で記録
							//倍率調整
							if(IsDomesticIndex(code)) {
								vv = 0.001; //DreamVisorのものにあわせる格好で。1000株単位かな
								pv = 100;
							}
							if(code==(int)BuiltInIndex.TOPIX_F) { //TOPIX先物は整数単位で記録されている
								pv = 10;
							}

							NewDailyData td = new NewDailyData();
						    try {
						        td.volume = (int)(Double.Parse(t[8]) * vv);
						        NewDailyData existing = (NewDailyData)result[code];
						        //Debug.WriteLine(line);
						        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);
						    }
						    catch (FormatException) {
						    }
						    result[code] = td;
						}
					}
					line = r.ReadLine();
				}
				return result;
			}
			finally {
				if(r!=null) r.Close();
			}
		}

		private static bool CheckMarket(BasicBrand br, int muj) {
			MarketType mt = br.Market;
			switch(mt) {
                //2006/12/26のデータより、東証はすべてコード11, 大証１・２部は21, ヘラクレスは23に変更になった。旧データを読んだときでも大丈夫なように古い判定も残しておく
				case MarketType.B:
					return muj==11; //指数は東証一部として記録されている
				case MarketType.T1:
					return muj==11;
				case MarketType.T2:
					return muj==11 || muj==12;
				case MarketType.O1:
					return muj==21;
				case MarketType.O2:
					return muj==21 || muj==22;
				case MarketType.M:
                    return muj==21 || muj==13;
				case MarketType.J:
					return muj==91;
				case MarketType.H:
					return muj==23 || muj==24;
				default:
					return false;
			}
		}
		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;
		}

	}
}
