// 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.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Text;
using Zanetti.Data;

namespace Zanetti.DataSource.Specialized
{
    internal class EdatalabDataSource : DailyDataSource
    {
        public EdatalabDataSource(int[] dates) : base(dates)
        {
        }

        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 && !IsIndex(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(edatalab.net) : code=" + br.Code + " market=" + br.Market);
                        }
                    }
                    farm.Save(Util.GetDailyDataFileName(br.Code));
                    SendMessage(AsyncConst.WM_ASYNCPROCESS, br.Code, AsyncConst.LPARAM_PROGRESS_SUCCESSFUL);
                }
            }
        }

        private Dictionary<int, NewDailyData> FillData(int date)
        {
            var result = new Dictionary<int, NewDailyData>();
            var d2 = Util.IntToDate(date);
            var url = "http://www.edatalab.sakura.ne.jp/data" +
                      d2.ToString(d2.Year < 2006 ? "yyyy/yyyyMMdd" : "yyyy/DyyMMdd") + ".LZH";
            using (var reader = new StreamReader(Util.ExtractData(url), Encoding.GetEncoding("shift_jis")))
            {
                string line;
                while ((line = reader.ReadLine()) != null)
                {
                    var tokens = line.Split(',');
                    var code = int.Parse(tokens[1]);
                    if (code > 1002 && code < 1300) // 各種指数を無視する。
                        continue;
                    code = code == 1001 ? (int)BuiltInIndex.Nikkei225 : code == 1002 ? (int)BuiltInIndex.TOPIX : code;
                    if (!(Env.BrandCollection.FindBrand(code) is BasicBrand))
                        continue;
                    try
                    {
                        var vv = IsIndex(code) ? 0.001 : 1;
                        var pv = IsIndex(code) ? 100 : 10; // 指数は100倍、株価は10倍で記録。
                        var td = new NewDailyData
                        {
                            volume = (int)(double.Parse(tokens[7]) * vv)
                        };
					    // 複数市場に上場している銘柄には複数のエントリがある。出来高の多いほうをとる。
                        if (!result.TryGetValue(code, out var existing) || existing.volume < td.volume)
                        {
						    result[code] = td;
                            td.open = (int)(double.Parse(tokens[3]) * pv);
                            td.high = (int)(double.Parse(tokens[4]) * pv);
                            td.low = (int)(double.Parse(tokens[5]) * pv);
                            td.close = (int)(double.Parse(tokens[6]) * pv);
                            td.volume = (int)(double.Parse(tokens[7]) * vv);
					    }
                    }
                    catch (FormatException)
                    {
                    }
                }
            }
            return result;
        }

        private bool IsIndex(int code)
        {
            return code == (int)BuiltInIndex.Nikkei225 ||
                   code == (int)BuiltInIndex.TOPIX;
        }
    }
}