using System;
using System.IO;
using System.Collections.Generic;
using System.Windows.Forms;

using Zanetti.Commands;

namespace Zanetti.Data
{
    internal abstract class DataImporter
    {
        private const int SHIFT = 10;//株価10倍格納する場合
        private const int RECORD_LENGTH = 32;
        public static void ImportData(string[] fileName)
        {
            var code = -1;
            DataFarm farm = null;
            var dicCsv = new SortedDictionary<int, NewDailyData2>();//読み込みCSVファイル情報
            var dicFarm = new SortedDictionary<int, NewDailyData2>();//OmegaChartのdataフォルダ配下の情報
            var dicResult = new SortedDictionary<int, NewDailyData2>();//比較結果格納

            if (fileName.Length == 0) return;
            var path = fileName[0];
            if (IsTextFile(path))//複数ファイルNG
            {
                ReadCsv(path, ref dicCsv);
                DecisionCodeAndFarm(path, ref code, ref farm);
                if (farm.RawDataImage!=null)
                    ReadFarm(farm, ref dicFarm);
                CompareCsvFarm(farm, dicCsv, dicFarm, ref dicResult);
                UpdateFarm(dicResult, ref dicFarm);
                WriteFarm(code, dicResult, dicFarm);
            }
        }
        private static void DecisionCodeAndFarm(string path, ref int code, ref DataFarm farm)
        {
            farm = Env.Frame.ChartCanvas.GetBrand().ReserveFarm();
            code = Path2IntCode(path);
            if (code < 0)//パス名が数字じゃなかったら、表示中の銘柄にインポートするものとする
            {
                code = farm.Brand.Code;
            }
            else//パス名が数字4文字含みだったら銘柄コードと決めつける
            {
                AbstractBrand br = Env.BrandCollection.FindBrand(code);
                if (br == null)//銘柄コードじゃなかったら戻す farmは最初から表示中のfarmを入れてある
                    code = farm.Brand.Code;
                else
                    farm = Env.BrandCollection.ReserveFarm(br);
            }
        }
        private static int Path2IntCode(string path)
        {
            var code = -1;
            var s = Path.GetFileName(path.Trim());
            if (s == string.Empty) return code;
            var sp = s.Split('.');
            if (sp[0].Length == 4)
                int.TryParse(sp[0], out code);
            return code;
        }
        private static void MakeBackupFile(int code)
        {
            var source = Util.GetDailyDataFileName(code);
            var dest = string.Format("{0}\\{1}.bak", Path.GetDirectoryName(source), code);
            File.Copy(source, dest, true);
        }
        private static void UpdateFarm(SortedDictionary<int, NewDailyData2> dicResult, ref SortedDictionary<int, NewDailyData2> dicFarm)
        {
            List<int> keyListResult = new List<int>(dicResult.Keys);
            foreach (var e in keyListResult)
            {
                if (dicFarm.ContainsKey(e))//キー(日付)が重複、かつ変更された日付の情報
                {
                    //dicFarm[e] = dicResult[e];
                    dicFarm[e].open = dicResult[e].open;
                    dicFarm[e].high = dicResult[e].high;
                    dicFarm[e].low = dicResult[e].low;
                    dicFarm[e].close = dicResult[e].close;
                    dicFarm[e].volume = dicResult[e].volume;
                }
                else//新規データ
                {
                    dicFarm.Add(e, dicResult[e]);
                }
            }
        }
        private static void WriteFarm(int code, SortedDictionary<int, NewDailyData2> dicResult, SortedDictionary<int, NewDailyData2> dicFarm)
        {
            if (dicResult.Count > 0)
            {
                var message = string.Empty;
                message = string.Format("OmegaChartのデータを変更しますか?\n\n銘柄コード:{0:D4} 変更箇所数:{1}\n", code, dicResult.Count);
                List<int> keyListResult = new List<int>(dicResult.Keys);
                var cnt = 0;
                foreach (var key in keyListResult)
                {
                    message += string.Format("{0:D8},{1},{2},{3},{4},{5}\n"
                        , key
                            , dicResult[key].open / SHIFT
                                , dicResult[key].high / SHIFT
                                    , dicResult[key].low / SHIFT
                                        , dicResult[key].close / SHIFT
                                            , dicResult[key].volume);
                    cnt++;
                    if (cnt > 3)
                    {
                        message += "・・・以下略・・・";
                        break;
                    }
                }
                DialogResult result = MessageBox.Show(message, "質問", MessageBoxButtons.OKCancel, MessageBoxIcon.Exclamation, MessageBoxDefaultButton.Button2);
                if (result == DialogResult.OK)
                {
                    MakeBackupFile(code);
                    UpdateDataFarm(code, dicFarm);
                    AbstractBrand br = Env.BrandCollection.FindBrand(code);
                    CommandExec.ShowBrand(br);
                    //CommandExec.RefreshChart();
                }
            }
        }
        private static void ReadFarm(DataFarm farm, ref SortedDictionary<int, NewDailyData2> dic)
        {
            for (var i = 0; i < farm.RawDataImage.Length / 32; i++)
            {
                var date = BitConverter.ToInt32(farm.RawDataImage, i * 32);
                NewDailyData2 ndd = new NewDailyData2();
                ndd.open = BitConverter.ToInt32(farm.RawDataImage, i * 32 + 4);
                ndd.high = BitConverter.ToInt32(farm.RawDataImage, i * 32 + 8);
                ndd.low = BitConverter.ToInt32(farm.RawDataImage, i * 32 + 12);
                ndd.close = BitConverter.ToInt32(farm.RawDataImage, i * 32 + 16);
                ndd.volume = BitConverter.ToInt32(farm.RawDataImage, i * 32 + 20);
                ndd.creditlong = BitConverter.ToInt32(farm.RawDataImage, i * 32 + 24);
                ndd.creditshort = BitConverter.ToInt32(farm.RawDataImage, i * 32 + 28);
                dic.Add(date, ndd);
            }
        }
        private static void CompareCsvFarm(DataFarm farm, SortedDictionary<int, NewDailyData2> dicCsv, SortedDictionary<int, NewDailyData2> dicFarm, ref SortedDictionary<int, NewDailyData2> dicResult)
        {
            List<int> keyList = new List<int>(dicCsv.Keys);
            foreach (var key in keyList)
            {
                if (dicCsv[key].volume == 0)
                {//個別銘柄で出来高ゼロの場合は特別作業が必要。OmegaChartは出来高がない日は前の日の値で埋められているため
                    if (farm.Brand != null && farm.Brand.Market != MarketType.B && farm.Brand.Market != MarketType.Custom)
                    {
                        NewDailyData2 ndd = new NewDailyData2();
                        ndd.open = 0;
                        ndd.high = 0;
                        ndd.low = 0;
                        ndd.close = 0;
                        ndd.volume = 0;
                        dicCsv[key] = ndd;
                    }
                }
                if (!dicFarm.ContainsKey(key))
                    dicResult.Add(key, dicCsv[key]);
                else
                {
                    if (dicFarm[key].open != dicCsv[key].open
                        || dicFarm[key].high != dicCsv[key].high
                            || dicFarm[key].low != dicCsv[key].low
                                || dicFarm[key].close != dicCsv[key].close
                                    || dicFarm[key].volume != dicCsv[key].volume)
                        dicResult.Add(key, dicCsv[key]);
                }
            }
        }
        private static void ReadCsv(string filename, ref SortedDictionary<int, NewDailyData2> dic)
        {
            System.Text.Encoding enc = System.Text.Encoding.GetEncoding("shift_jis");
            var str = System.IO.File.ReadAllText(filename, enc).Replace("\r", "");
            var lines = str.Split('\n');
            for (var i = 0; i < lines.Length; i++)
            {
                var sp = lines[i].Split(',');
                if (sp.Length != 6) continue;
                var dt = DateTime.MinValue;
                NewDailyData2 ndd = new NewDailyData2();
                double open = .0;
                double high = .0;
                double low = .0;
                double close = .0;
                if (DateTime.TryParse(sp[0], out dt)
                    && double.TryParse(sp[1], out open)
                        && double.TryParse(sp[2], out high)
                            && double.TryParse(sp[3], out low)
                                && double.TryParse(sp[4], out close)
                                    && int.TryParse(sp[5], out ndd.volume))
                {
                    ndd.open = (int)(open * SHIFT);
                    ndd.high = (int)(high * SHIFT);
                    ndd.low = (int)(low * SHIFT);
                    ndd.close = (int)(close * SHIFT);
                    if (dt != DateTime.MinValue)
                        dic.Add(int.Parse(dt.ToString("yyyyMMdd")), ndd);
                }
            }
        }

        private static void UpdateDataFarm(int code, SortedDictionary<int, NewDailyData2> prices)
        {
            var farm = (DailyDataFarm)Env.BrandCollection.FindBrand(code).CreateDailyFarm(prices.Count);
            var empty = farm.IsEmpty;
            var skip = true;
            foreach (var pair in prices)
            {
                if (empty && skip && pair.Value.volume == 0)
                    continue;
                skip = false;
                farm.UpdateDataFarm(pair.Key, pair.Value);
            }
            farm.Save(Util.GetDailyDataFileName(code));
        }
        private static bool IsTextFile(string filePath)
        {
            var file = new System.IO.FileStream(filePath, FileMode.Open, FileAccess.Read);
            var byteData = new byte[1];
            while (file.Read(byteData, 0, byteData.Length) > 0)
            {
                if (byteData[0] == 0)
                    return false;
            }
            return true;
        }
    }
}