using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Text.RegularExpressions;
using Newtonsoft.Json;

namespace NetVision {
    public partial class FormDeckEdit : Form {
        public FormDeckEdit() {
            InitializeComponent();
        }

        /// <summary>
        /// カードリスト
        /// </summary>
        public CardList List { get; set; }

        /// <summary>
        /// デッキレシピ
        /// </summary>
        public Dictionary<string, int> DeckRecipe { get; set; }

        /// <summary>
        /// サイドレシピ
        /// </summary>
        public Dictionary<string, int> SideRecipe { get; set; }

        /// <summary>
        /// お気に入り
        /// </summary>
        public List<string> Favorite { get; set; }

        /// <summary>
        /// 現在のファイル名
        /// </summary>
        public string FileName { get; set; }

        private void FormDeckEdit_Load( object sender, EventArgs e ) {
/*
            // カードリストのロード
            if (CardList.IsIniNew(Properties.Settings.Default.CardListIni, Properties.Settings.Default.CardListJson, Properties.Settings.Default.CardListBuf)) {
                MessageBox.Show("cardlist.iniが新しくなっているため更新します。\nこの変換処理には 60秒 程度かかります。\n[ OK ] を押してそのままお待ちください。", "Iniファイルの変換", MessageBoxButtons.OK, MessageBoxIcon.Information);
            }
            List = CardList.Load(Properties.Settings.Default.CardListIni, Properties.Settings.Default.CardListJson, Properties.Settings.Default.CardListBuf);
*/
            DeckRecipe = new Dictionary<string, int>();
            SideRecipe = new Dictionary<string, int>();
            Favorite = new List<string>();
            LoadFavorite();
        }

        // 検索実行
        private void buttonShow_Click( object sender, EventArgs e ) {
            tabControlLeft.SelectedIndex = 0;
            listViewCards.Items.Clear();

            if (textBoxNo.Text != "" && List.Items.ContainsKey(textBoxNo.Text)) {
                CardInfo info = List[textBoxNo.Text];
                listViewCards.Items.Add(new ListViewItem(new string[] { info.No, info.Name, info.Node, info.Cost, info.Skill }));
                return;
            }

            foreach (CardInfo info in List.Items.Values) {
                if (textBoxText.Text != "") {
                    string str = textBoxText.Text;
                    if (!( info.Name.Contains(str) || info.Text.Contains(str) || info.User.Contains(str) || info.Illustration.Contains(str) || info.User.Contains(str) || info.Ability.Contains(str) )) { continue; }
                }
                if (comboBoxCharacter.Text != "") { if(!(info.Name.Contains(comboBoxCharacter.Text) || info.User.Contains(comboBoxCharacter.Text))){ continue; }}
                if (comboBoxCardType.Text != "") { if (info.Type.ToString() != comboBoxCardType.Text) { continue; } }
                if (comboBoxBattleSkill.Text != "") { if (!info.Skill.Contains(comboBoxBattleSkill.Text)) { continue; } }
                if (comboBoxSkill.Text != "") { if (!info.Skill.Contains(comboBoxSkill.Text)) { continue; } }
                if (comboBoxClass.Text != "") { if (!info.Class.Contains(comboBoxClass.Text)) { continue; } }
                if (comboBoxRange.Text != "") { if (info.Range != comboBoxRange.Text) { continue; } }
                if (comboBoxTime.Text != "") { if (info.Time != comboBoxTime.Text) { continue; } }

                if (comboBoxNodeWhere.Text != "") {
                    if (comboBoxNodeWhere.Text == "に等しい") { if (info.NodeNum != numericUpDownNode.Value) { continue; } }
                    if (comboBoxNodeWhere.Text == "以上") { if (info.NodeNum < numericUpDownNode.Value) { continue; } }
                    if (comboBoxNodeWhere.Text == "以下") { if (info.NodeNum > numericUpDownNode.Value) { continue; } }
                }
                if (comboBoxCostWhere.Text != "") {
                    if (comboBoxCostWhere.Text == "に等しい") { if (info.CostNum != numericUpDownCost.Value) { continue; } }
                    if (comboBoxCostWhere.Text == "以上") { if (info.CostNum < numericUpDownCost.Value) { continue; } }
                    if (comboBoxCostWhere.Text == "以下") { if (info.CostNum > numericUpDownCost.Value) { continue; } }
                }
                if (comboBoxAttackWhere.Text != "") {
                    if (comboBoxAttackWhere.Text == "に等しい") { if (info.AttackNum != numericUpDownAttack.Value) { continue; } }
                    if (comboBoxAttackWhere.Text == "以上") { if (info.AttackNum < numericUpDownAttack.Value) { continue; } }
                    if (comboBoxAttackWhere.Text == "以下") { if (info.AttackNum > numericUpDownAttack.Value) { continue; } }
                }
                if (comboBoxToughnessWhere.Text != "") {
                    if (comboBoxToughnessWhere.Text == "に等しい") { if (info.ToughnessNum != numericUpDownToughness.Value) { continue; } }
                    if (comboBoxToughnessWhere.Text == "以上") { if (info.ToughnessNum < numericUpDownToughness.Value) { continue; } }
                    if (comboBoxToughnessWhere.Text == "以下") { if (info.ToughnessNum > numericUpDownToughness.Value) { continue; } }
                }

                ListViewItem it = new ListViewItem(new string[] { info.No, info.Name, info.Node, info.Cost, info.Skill });
                it.BackColor = info.Type == CardType.Character ? Color.FromArgb(255, 204, 204) : (info.Type == CardType.Spell ? Color.FromArgb(204, 255, 204) : Color.FromArgb(204, 204, 255));
                listViewCards.Items.Add(it);
            }

        }

        private void numericUpDownNode_ValueChanged( object sender, EventArgs e ) {
            if (comboBoxNodeWhere.Text == "") { comboBoxNodeWhere.Text = "に等しい"; }
        }

        private void numericUpDownCost_ValueChanged( object sender, EventArgs e ) {
            if (comboBoxCostWhere.Text == "") { comboBoxCostWhere.Text = "に等しい"; }
        }

        private void numericUpDownAttack_ValueChanged( object sender, EventArgs e ) {
            if (comboBoxAttackWhere.Text == "") { comboBoxAttackWhere.Text = "に等しい"; }
        }

        private void numericUpDownToughness_ValueChanged( object sender, EventArgs e ) {
            if (comboBoxToughnessWhere.Text == "") { comboBoxToughnessWhere.Text = "に等しい"; }
        }

        private void button12_Click( object sender, EventArgs e ) {
            textBoxNo.Text = "";
            textBoxText.Text = "";
            comboBoxAttackWhere.Text = "";
            comboBoxBattleSkill.Text = "";
            comboBoxCardSet.Text = "";
            comboBoxCardType.Text = "";
            comboBoxCharacter.Text = "";
            comboBoxClass.Text = "";
            comboBoxCostWhere.Text = "";
            comboBoxNodeWhere.Text = "";
            comboBoxRange.Text = "";
            comboBoxSkill.Text = "";
            comboBoxTime.Text = "";
            comboBoxToughnessWhere.Text = "";
            numericUpDownAttack.Value = 0;
            numericUpDownCost.Value = 0;
            numericUpDownNode.Value = 0;
            numericUpDownToughness.Value = 0;
        }

        private void textBoxNo_KeyDown( object sender, KeyEventArgs e ) {
            if (e.KeyCode == Keys.Enter) { buttonShow_Click(sender, e); }
        }

        private void 新規作成NToolStripMenuItem_Click( object sender, EventArgs e ) {
            DeckRecipe = new Dictionary<string, int>();
            SideRecipe = new Dictionary<string, int>();
            RefreshListView(listViewDeck, DeckRecipe);
            RefreshListView(listViewSidebord, SideRecipe);
            RefreshCardNum();
        }
        private void デッキを開くOToolStripMenuItem_Click( object sender, EventArgs e ) {
            openFileDialogDeck.FileName = Properties.Settings.Default.DeckFolder;
            if (openFileDialogDeck.ShowDialog() != DialogResult.OK) { return; }
            FileName = openFileDialogDeck.FileName;
            LoadRecipe(FileName);

            RefreshListView(listViewDeck, DeckRecipe);
            RefreshListView(listViewSidebord, SideRecipe);
            RefreshCardNum();
        }
        private void 名前を付けて保存RToolStripMenuItem_Click( object sender, EventArgs e ) {
            if (saveFileDialogDeck.ShowDialog() != DialogResult.OK) { return; }
            FileName = saveFileDialogDeck.FileName;
            SaveRecipe(FileName);
        }

        private void 上書き保存SToolStripMenuItem_Click( object sender, EventArgs e ) {
            if (FileName == null || FileName == "") { return; }
            SaveRecipe(FileName);
        }
        /// <summary>
        /// デッキレシピをロード
        /// </summary>
        /// <param name="filename">デッキファイル名</param>
        private void LoadRecipe( string filename ) {
            DeckRecipe = new Dictionary<string, int>();
            SideRecipe = new Dictionary<string, int>();
            using (StreamReader fs = new StreamReader(filename, Encoding.GetEncoding("Shift_JIS"))) {
                Regex reg = new Regex(@"^(\d),(\w+),");
                Regex splitter = new Regex(@"^--$");
                bool on_side = false;
                while (!fs.EndOfStream) {
                    string line = fs.ReadLine();
                    if (splitter.IsMatch(line)) { on_side = true; continue; }
                    if (reg.IsMatch(line)) {
                        Match m = reg.Match(line);
                        string id = m.Groups[2].Value;
                        if (!List.Items.ContainsKey(id)) { throw new Exception("存在しないカードが指定されました。"); }
                        int num = int.Parse(m.Groups[1].Value);
                        if (!on_side) { DeckRecipe[id] = num; } else { SideRecipe[id] = num; }
                    }
                }
            }
        }

        /// <summary>
        /// デッキレシピをセーブ
        /// </summary>
        /// <param name="filename"></param>
        private void SaveRecipe( string filename ) {
            using (StreamWriter sw = new StreamWriter(filename, false, Encoding.GetEncoding("Shift_JIS"))) {
                foreach (CardType type in new CardType[] { CardType.Character, CardType.Spell, CardType.Command }) {
                    var kvps = DeckRecipe.OrderBy(( kvp ) => kvp.Key);
                    foreach (KeyValuePair<string, int> kv in kvps) {
                        if (List[kv.Key].Type != type) { continue; }
                        CardInfo info = List[kv.Key];
                        sw.WriteLine(kv.Value.ToString() + "," + info.No + "," + info.Name);
                    }
                }

                sw.WriteLine("--");
                foreach (KeyValuePair<string, int> kv in SideRecipe) {
                    CardInfo info = List[kv.Key];
                    sw.WriteLine(kv.Value.ToString() + "," + info.No + "," + info.Name);
                }
            }
        }

        /// <summary>
        /// ひとつ追加
        /// </summary>
        private void buttonAddOne_Click( object sender, EventArgs e ) {
            List<string> selected = new List<string>();
            ListView fromView = tabControlLeft.SelectedIndex == 0 ? listViewCards : listViewFavorite;
            foreach (ListViewItem it in fromView.SelectedItems) {
                selected.Add(it.SubItems[0].Text);
            }

            ListView view = (tabControlRight.SelectedIndex == 0) ? listViewDeck : listViewSidebord;
            Dictionary<string, int> recipe = ( tabControlRight.SelectedIndex == 0 ) ? DeckRecipe : SideRecipe;

            foreach(string no in selected){
                if (( (Button)sender ).Text.Length == 3) { recipe[no] = 3; }
                else if (recipe.ContainsKey(no)) {
                    if (recipe[no] < 3) { recipe[no]++; }
                }
                else { recipe[no] = 1; }
            }
            RefreshListView(view, recipe);
            RefreshCardNum();
        }

        /// <summary>
        /// リストビューを再描画
        /// </summary>
        private void RefreshListView(ListView view, Dictionary<string, int> recipe) {
            view.Items.Clear();
            foreach (CardType type in new CardType[] { CardType.Character, CardType.Spell, CardType.Command }) {
                var kvps = recipe.OrderBy(( kvp ) => kvp.Key);
                foreach (KeyValuePair<string, int> kv in kvps) {
                    if (!List.Items.ContainsKey(kv.Key)) { continue; }
                    if (List[kv.Key].Type != type) { continue; }
                    AddItem(view, List[kv.Key], kv.Value);
                }
            }
        }

        /// <summary>
        /// カード数を再描画
        /// </summary>
        private void RefreshCardNum() {
            Dictionary<string, int> counts = new Dictionary<string, int>() { { "deck", 0 }, { "char", 0 }, { "spell", 0 }, { "command", 0 }, { "side", 0 } };
            foreach (KeyValuePair<string, int> kv in DeckRecipe) {
                CardInfo info = List[kv.Key];
                counts["deck"] += kv.Value;
                if (info.Type == CardType.Character) { counts["char"] += kv.Value; }
                else if (info.Type == CardType.Spell) { counts["spell"] += kv.Value; }
                else if (info.Type == CardType.Command) { counts["command"] += kv.Value; }
            }
            foreach (KeyValuePair<string, int> kv in SideRecipe) {
                counts["side"] += kv.Value;
            }
            labelDeckAll.Text = counts["deck"].ToString();
            labelDeckChar.Text = counts["char"].ToString();
            labelDeckSpell.Text = counts["spell"].ToString();
            labelDeckCommand.Text = counts["command"].ToString();
            labelSidebord.Text = counts["side"].ToString();
        }

        private void AddItem( ListView view, CardInfo info, int num ) {
            ListViewItem it = new ListViewItem(new string[] { num.ToString(), info.No, info.Name, info.Node, info.Cost, info.Skill });
            it.BackColor = info.Type == CardType.Character ? Color.FromArgb(255, 204, 204) : ( info.Type == CardType.Spell ? Color.FromArgb(204, 255, 204) : Color.FromArgb(204, 204, 255) );
            view.Items.Add(it);
        }

        /// <summary>
        /// ひとつ削除
        /// </summary>
        private void buttonRemoveOne_Click( object sender, EventArgs e ) {
            ListView view = ( tabControlRight.SelectedIndex == 0 ) ? listViewDeck : listViewSidebord;
            Dictionary<string, int> recipe = ( tabControlRight.SelectedIndex == 0 ) ? DeckRecipe : SideRecipe;

            List<string> selected = new List<string>();
            foreach (ListViewItem it in view.SelectedItems) {
                selected.Add(it.SubItems[1].Text);
            }

            foreach (string no in selected) {
                if (!recipe.ContainsKey(no)) { continue; }
                if (( (Button)sender ).Text.Length == 3 || recipe[no] == 1) { recipe.Remove(no); }
                else { recipe[no]--; }
            }
            RefreshListView(view, recipe);
            RefreshCardNum();
            if (tabControlLeft.SelectedIndex == 1) {
                foreach (string no in selected) { if (!Favorite.Contains(no)) { Favorite.Add(no); } }
                RefreshFavView();
            }
        }

        private void listViewDeck_ItemActivate( object sender, EventArgs e ) {
        }

        private void listViewDeck_SelectedIndexChanged( object sender, EventArgs e ) {
            ListView view = (ListView)sender;
            if (view.SelectedItems.Count > 0) {
                string no = view.SelectedItems[view.SelectedItems.Count - 1].SubItems[ view.Columns.Count - 5 ].Text;
                panelCardInfo.ShowInfo(List[no]);
            }

        }

        private void 終了WToolStripMenuItem_Click( object sender, EventArgs e ) {
            Close();
        }

        private void buttonDeckTrunOne_Click( object sender, EventArgs e ) {
            ListView view1 = ( tabControlRight.SelectedIndex == 0 ) ? listViewDeck : listViewSidebord;
            Dictionary<string, int> recipe1 = ( tabControlRight.SelectedIndex == 0 ) ? DeckRecipe : SideRecipe;
            ListView view2 = ( tabControlRight.SelectedIndex == 1 ) ? listViewDeck : listViewSidebord;
            Dictionary<string, int> recipe2 = ( tabControlRight.SelectedIndex == 1 ) ? DeckRecipe : SideRecipe;

            List<string> selected = new List<string>();
            foreach (ListViewItem it in view1.SelectedItems) {
                selected.Add(it.SubItems[1].Text);
            }

            foreach (string no in selected) {
                if (( (Button)sender ).Text.Length == 5) { recipe2[no] = 3; }
                else if (recipe2.ContainsKey(no)) {
                    if (recipe2[no] < 3) { recipe2[no]++; }
                }
                else { recipe2[no] = 1; }

                if (( (Button)sender ).Text.Length == 5) { recipe1.Remove(no); }
                else if(recipe1[no] == 1) { recipe1.Remove(no); }
                else { recipe1[no]--; }
            }
            RefreshListView(view1, recipe1);
            RefreshListView(view2, recipe2);
            RefreshCardNum();
        }

        private void listViewDeck_ItemSelectionChanged( object sender, ListViewItemSelectionChangedEventArgs e ) {
            ListView view = (ListView)sender;
            if (view.SelectedItems.Count > 0) {
                string no = view.SelectedItems[0].SubItems[0].Text;
//                numericUpDownCardNum.Value = int.Parse( view.SelectedItems[0].SubItems[0].Text );
            }
        }

        private void saveFileDialogDeck_FileOk( object sender, CancelEventArgs e ) {

        }

        private void saveFavorite() {
            string path = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData) + @"\VisionNET\favorite.json";
            string output = JsonConvert.SerializeObject(Favorite, Formatting.Indented);
            using (StreamWriter sw = new StreamWriter(path)) {
                sw.Write(output);
            }
        }

        /// <summary>
        /// JSONファイルからロード
        /// </summary>
        public void LoadFavorite() {
            string path = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData) + @"\VisionNET\favorite.json";
            if (!File.Exists(path)) { return; }
            using (StreamReader sr = new StreamReader(path)) {
               this.Favorite = JsonConvert.DeserializeObject<List<string>>(sr.ReadToEnd());
            }
            RefreshFavView();
        }

        private void FormDeckEdit_FormClosed( object sender, FormClosedEventArgs e ) {
        }

        private void buttonFavTurn_Click( object sender, EventArgs e ) {
            List<string> selected = new List<string>();
            ListView view = tabControlLeft.SelectedIndex == 0 ? listViewCards : listViewFavorite;
            foreach (ListViewItem it in view.SelectedItems) {
                selected.Add(it.SubItems[0].Text);
            }

            // お気に入りに追加
            if (tabControlLeft.SelectedIndex == 0) {
                foreach (string no in selected) {if (!Favorite.Contains(no)) { Favorite.Add(no); }}
            }
            else {
                foreach (string no in selected) { if (Favorite.Contains(no)) { Favorite.Remove(no); } }
            }
            RefreshFavView();
            
        }


        private void FormDeckEdit_FormClosing( object sender, FormClosingEventArgs e ) {
            saveFavorite();

        }

        private void tabControlRight_SelectedIndexChanged( object sender, EventArgs e ) {
            buttonDeckTrunOne.Text = tabControlRight.SelectedIndex == 0 ? "<サイドに移動" : "<デッキに移動";
            buttonDeckTurnAll.Text = tabControlRight.SelectedIndex == 0 ? "<<<全てサイドへ" : "<<<全てデッキへ";

        }
        /// <summary>
        /// リストビューを再描画
        /// </summary>
        private void RefreshFavView() {
            listViewFavorite.Items.Clear();
            foreach (string no in Favorite) {
                CardInfo info = List[no];
                ListViewItem it = new ListViewItem(new string[] { info.No, info.Name, info.Node, info.Cost, info.Skill });
                it.BackColor = info.Type == CardType.Character ? Color.FromArgb(255, 204, 204) : ( info.Type == CardType.Spell ? Color.FromArgb(204, 255, 204) : Color.FromArgb(204, 204, 255) );
                listViewFavorite.Items.Add(it);
            }
        }

        private void tabControlLeft_SelectedIndexChanged( object sender, EventArgs e ) {
            buttonFavTurn.Text = tabControlLeft.SelectedIndex == 0 ? "<<お気に入りに追加" : "<<お気に入りを削除";
        }

        // リストビューから枚数変更
        private void listViewDeck_AfterLabelEdit( object sender, LabelEditEventArgs e ) {
            ListView view = (ListView)sender;
            int new_num = 0;
            if (!int.TryParse(e.Label, out new_num)) { e.CancelEdit = true; return; }
            string no = view.Items[e.Item].SubItems[1].Text;
            if (new_num == 0) {
                DeckRecipe.Remove(no);
                view.Items[e.Item].Remove();
                e.CancelEdit = true;
            }
            else if (new_num >= 1 && new_num <= 3) {
                DeckRecipe[no] = new_num;
            }
            else { e.CancelEdit = true; return; }
            RefreshCardNum();
        }

    }
}
