using System;
using System.Collections.Generic;
using System.IO;
using Newtonsoft.Json;
using ProtoBuf;


namespace NetVision {


    /// <summary>
    /// カードリスト
    /// </summary>
    [ProtoContract]
    public class CardList {

        /// <summary>
        /// カード
        /// </summary>
        [ProtoMember(1)]
        public Dictionary<string, CardInfo> Items { get; set; }


        /// <summary>
        /// インデクサ
        /// </summary>
        /// <param name="id">カードID</param>
        /// <returns>カードデータ</returns>
        public CardInfo this[string id] {
            get { return Items[id]; }
            set { Items[id] = value; }
        }

        /// <summary>
        /// Iniファイルからロード
        /// </summary>
        /// <param name="filename">ファイル名</param>
        public static CardList LoadFromIni( string filename ) {
            CardList list = new CardList();
            list.Items = new Dictionary<string, CardInfo>();
            IniFile ini = new IniFile(filename);
            for (int i = 1; i < 2000; i++) {

                string id = String.Format("{0:D3}", i); // 3桁のID
                if (ini[id, "Name"] == "") { break; } // 存在しないカード

                list[id] = CardList.parseCardData(ini, id); // 取得

            }
            for (int i = 1; i < 200; i++) {
                string id = String.Format("P{0:D2}", i); // 2桁のID
                if (ini[id, "Name"] == "") { break; } // 存在しないカード

                list[id] = CardList.parseCardData(ini, id); // 取得
            }
            return list;
        }


        /// <summary>
        /// iniファイルから指定されたIDのカードデータを展開
        /// </summary>
        /// <param name="ini">IniFileオブジェクト</param>
        /// <param name="id">ID</param>
        /// <returns>カードデータ</returns>
        private static CardInfo parseCardData( IniFile ini, string id ) {
            CardInfo card = new CardInfo();

            card.No = id;
            card.Name = ini[id, "Name"];
            card.Skill = ini[id, "Skill"];
            card.Class = ini[id, "Class"];
            card.Text = ini[id, "Text"];
            card.Ability = ini[id, "Ability"];
            card.User = ini[id, "User"];
            card.Illustration = ini[id, "Illustration"];
            card.FileName = ini[id, "File"];
            card.Node = ini[id, "Node"];
            card.Cost = ini[id, "Cost"];
            card.Attack = ini[id, "Attack"];
            card.Toughness = ini[id, "Toughness"];
            card.Upkeep = ini[id, "Upkeep"];
            card.Glaze = ini[id, "Glaze"];
            card.Range = ini[id, "Range"];
            card.Time = ini[id, "Time"];
            string ctype = ini[id, "Type"];
            card.Type = ( ctype == "Character" ) ? CardType.Character : ( ctype == "Spell" ) ? CardType.Spell : ( ctype == "Command" ) ? CardType.Command : CardType.Undef;
            

            return card;
        }

        /// <summary>
        /// ProtoBufでファイルにダンプ
        /// </summary>
        /// <param name="filename">ファイル名</param>
        public void SaveOnBuf( string filename ) {
            using (FileStream fs = new FileStream(filename, FileMode.Create, FileAccess.Write)) {
                ProtoBuf.Serializer.Serialize<CardList>(fs, this);
            }
        }

        /// <summary>
        /// Protobufでファイルからロード
        /// </summary>
        /// <param name="filename">ファイル名</param>
        public static CardList LoadOnBuf( string filename ) {
            using (FileStream fs = new FileStream(filename, FileMode.Open, FileAccess.Read)) {
                return ProtoBuf.Serializer.Deserialize<CardList>(fs);
            }
        }


        /// <summary>
        /// JSONファイルにダンプ
        /// </summary>
        /// <param name="filename"></param>
        public void SaveOnJson( string filename ) {
            string output = JsonConvert.SerializeObject(this, Formatting.Indented);
            using (StreamWriter sw = new StreamWriter(filename)) {
                sw.Write(output);
            }

        }

        /// <summary>
        /// JSONファイルからロード
        /// </summary>
        /// <param name="filename"></param>
        public static CardList LoadOnJson( string filename ) {
            using (StreamReader sr = new StreamReader(filename)) {
                return JsonConvert.DeserializeObject<CardList>( sr.ReadToEnd() );
            }
        }

        /// <summary>
        /// Iniファイルが新しくなっているかチェック
        /// </summary>
        /// <param name="ini_path">iniファイルのパス</param>
        /// <param name="json_path">jsonファイルのパス</param>
        /// <param name="buf_path">bufファイルのパス</param>
        public static bool IsIniNew( string ini_path, string json_path, string buf_path ) {
            return ( ini_path != null && File.GetLastWriteTime(ini_path) > File.GetLastWriteTime(json_path) );
        }

        /// <summary>
        /// カードデータをロード（キャッシュがあればそこから）
        /// </summary>
        /// <param name="ini_file">iniファイルのパス</param>
        /// <param name="dat_file">jsonファイルのパス</param>
        /// <param name="buf_path">bufファイルのパス</param>
        /// <returns>カードリスト</returns>
        public static CardList Load(string ini_path, string json_path, string buf_path) {
            CardList list;

            if (ini_path != null && File.GetLastWriteTime(ini_path) > File.GetLastWriteTime(json_path)) {
                list = CardList.LoadFromIni(ini_path);
                list.SaveOnJson(json_path);
                list.SaveOnBuf(buf_path);
            }
            else if (File.GetLastWriteTime(json_path) > File.GetLastWriteTime(buf_path)) {
                list = CardList.LoadOnJson(json_path);
                list.SaveOnBuf(buf_path);
            }
            else {
                list = CardList.LoadOnBuf(buf_path);
            }

            return list;

        }



    }


}
