using System;
using System.Collections.Generic;
using System.Drawing;
using System.Text;
using System.Windows.Forms;

namespace NetVision {

    /// <summary>
    /// プレイヤークラス（分割）
    /// </summary>
    public partial class Player {

        #region 初期処理


        /// <summary>
        /// コマンド用メソッドのデリゲート型
        /// </summary>
        /// <param name="command"></param>
        private delegate void CommandFunc( Command command );

        /// <summary>
        /// コマンド関数群
        /// </summary>
        private Dictionary<CommandType, CommandFunc> CommandFuncs;

        /// <summary>
        /// 初期処理
        /// </summary>
        protected override void OnCreateControl() {
            base.OnCreateControl();

            // エリアコントロール
            Areas = new Dictionary<AreaType, AreaControl> {
                {AreaType.Hands , Hands},
                {AreaType.Nodes , Nodes},
                {AreaType.Deck, Deck},
                {AreaType.Field, BattleField},
                {AreaType.Grave, Grave},
                {AreaType.Removed, Removes},
                {AreaType.SideBord, Sidebord}
            };

            // コマンド関数群
            CommandFuncs = new Dictionary<CommandType, CommandFunc> {
                { CommandType.Jump, CommandJump },
                { CommandType.Play, CommandPlay },
                { CommandType.Change, CommandChange },
                { CommandType.PayCost, CommandPayCost },
                { CommandType.Move, CommandMove },
                { CommandType.Attack, CommandAttack },
                { CommandType.Defend, CommandDefend },
                { CommandType.ManaCharge, CommandManaCharge },
                { CommandType.StartEffect, CommandStartEffect },
                { CommandType.AutoEffect, CommandAutoEffect },
                { CommandType.Draw, CommandDraw },
                { CommandType.TurnStart, CommandTurnStart},
                { CommandType.TurnEnd, CommandTurnEnd},
                { CommandType.Life, CommandLife},
                { CommandType.ViewDeck, CommandViewDeck },
                { CommandType.UnViewDeck, CommandUnViewDeck },
                { CommandType.BackNameDefine, CommandBackNameDefine },
                { CommandType.Shuffle, CommandShuffle },
                { CommandType.ShuffleEnemy, CommandShuffleEnemy },
                { CommandType.Shuffled, CommandShuffled },
                { CommandType.LayerChange, CommandLayerChange },
                { CommandType.MoveToEnemy, CommandMoveToEnemy },
                { CommandType.UpdateAll, CommandUpdateAll },
                { CommandType.DeckLoad, CommandLoadDeck },
                { CommandType.Rand, CommandRand },
                { CommandType.Clear, CommandClear },
            };

            // ツールリンクの有効
            Grave.ToolLink.Click += new EventHandler(ToolLink_Click);
            Sidebord.ToolLink.Click += new EventHandler(ToolLink_Click);
            Deck.ToolLink.Click += new EventHandler(ToolLink_Click);
            Removes.ToolLink.Click += new EventHandler(ToolLink_Click);
            Life.LifeChange += new EventHandler<LifeEventArgs>(Life_LifeChange);
            StartButton.Click += new EventHandler(StartButton_Click);
            CardListViews.ListClose += new EventHandler(CardListViews_ListClose);

        }




        #endregion



        #region コマンド送受信

        /// <summary>
        /// コマンドを受けた時
        /// </summary>
        public event EventHandler<MessageEventArgs> CommandReceiving;
        protected void OnCommandReceiving( object sender, MessageEventArgs e ) {
            if (CommandReceiving != null) { CommandReceiving(sender, e); }
        }

        /// <summary>
        /// コマンドを発行
        /// </summary>
        public void SendCommand( Command command ) {
            ReceiveCommand(command);
            Command send_com = command;
            send_com.FlipPlayer();
            OnCommandSending(this, new MessageEventArgs(send_com));
        }


        /// <summary>
        /// コマンドを受信
        /// </summary>
        public void ReceiveCommand( Command command ) {
            OnCommandReceiving(this, new MessageEventArgs(command));
            if (CommandFuncs.ContainsKey(command.Type)) {
                CommandFunc func = CommandFuncs[command.Type];
                func(command);
            }
        }


        #endregion





        #region コマンドの実行

        /// <summary>
        /// カードの場を移動
        /// </summary>
        private void CommandJump( Command com ) {
            CardBox card = CardTable[com.CardId];

            AreaControl from = Areas[card.Area];

            AreaControl to = com.ToArea == AreaType.UnderDeck ? Areas[AreaType.Deck] : Areas[com.ToArea];

            Dictionary<AreaType, string> mes_by_area = new Dictionary<AreaType, string> { 
                { AreaType.Nodes, "に加えた"},
                { AreaType.Hands, "に加えた"},
                { AreaType.Removed, "に追放した" },
                { AreaType.Deck, "に戻した"},
                { AreaType.Grave, "に置いた" },
                { AreaType.SideBord, "に戻した" },
                { AreaType.Field , "に出した"},
                { AreaType.UnderDeck, "山札の一番下に入れた"},
            };

            if (com.ToArea == AreaType.Hands && card.Area == AreaType.Deck) {
                OnLogMessage(this, new LogMessageArgs("デッキから1枚ドロー", Color.Green, "draw.wav"));
                }
            else if (com.ToArea == AreaType.Nodes && card.Area == AreaType.Hands && com.Active) {
                OnLogMessage(this, new LogMessageArgs("手札からアクティブノードをセット", Color.Blue, "node.wav"));
            }
            else if (com.ToArea == AreaType.Field && !com.FaceSide) {
                OnLogMessage(this, new LogMessageArgs(from.NickName + "のカードを裏向きで" + to.NickName + mes_by_area[to.Type], Color.Green, "set.wav"));
            }
            //            else if (!from.IsPublic && !to.IsPublic || !card.Public && !to.IsPublic || com.ToArea == AreaType.Nodes && card.Area == AreaType.Field && !card.FaceSide) {
            else if (!from.IsPublic && !to.IsPublic || !card.Public && !to.IsPublic || com.ToArea == AreaType.Nodes && card.Area == AreaType.Field && !card.FaceSide) {
                OnLogMessage(this, new LogMessageArgs(from.NickName + "の" + ( ( card.Area == AreaType.Field && !card.FaceSide ) ? "裏向き" : "" ) + "カードを" + to.NickName + mes_by_area[to.Type], Color.Green, "set.wav"));
            }
            else {
                OnLogMessage(this, new LogMessageArgs(from.NickName + "の" + card.NickName + "を" + to.NickName + mes_by_area[to.Type], Color.Green, "set.wav") { Card = card.Info.Name });
            }
            if (com.ToArea == AreaType.Nodes && card.Area == AreaType.Hands) { NodeSet.Checked = true; }
            card.Visible = false;
            card.Active = com.Active;
            card.Transformed = false;
            card.FaceSide = com.FaceSide;
            from.Remove(card);
            if (com.ToArea == AreaType.UnderDeck) { ( (DeckControl)to ).Last = card; }
            else { to.Add(card); }
            if (com.ToArea == AreaType.Field && com.Location != new PointF()) { card.MoveVirtualPoint( com.Location ); }
            if (com.ToArea == AreaType.Nodes) { card.MoveVirtualPoint(com.Location); }
            if (com.ToArea != AreaType.Removed && com.ToArea != AreaType.SideBord) { card.Visible = true; }
            Hands.RedrawCards();
        }


        /// <summary>
        /// プレイ
        /// </summary>
        private void CommandPlay( Command com ) {
            CardBox card = CardTable[com.CardId];
            card.Visible = false;
            Areas[card.Area].Remove(card);
            BattleField.PlayInto(card);
            if (com.Location != new Point()) { card.MoveVirtualPoint( com.Location ); }
            card.Visible = true;
            if (card.Info.Type == CardType.Character && !card.Info.Skill.Contains("奇襲") && !card.Info.Skill.Contains("人形")) { SummonChar.Checked = true; }
            if (card.Info.Skill.Contains("人形")) { SummonDoll.Checked = true; }
            Hands.RedrawCards();
            OnLogMessage(this, new LogMessageArgs(card.Info.Name + "をプレイ", Color.Blue) { Card = card.Info.Name, Sound = ( ( card.Info.PlayingType == PlayingType.Character ) ? "play.wav" : "play2.wav" ) });
        }

        /// <summary>
        /// カード状態の変更
        /// </summary>
        private void CommandChange( Command com ) {
            CardBox card = CardTable[com.CardId];
            if (card.Active != com.Active) { OnLogMessage(this, new LogMessageArgs(card.NickName + "を" + (( com.Active ) ? "アクティブ" : "スリープ"), Color.Green) { Card = card.NickName, Sound = com.Active ? "active.wav" : "sleep.wav" }); }
            if (card.FaceSide != com.FaceSide) { OnLogMessage(this, new LogMessageArgs(card.NickName + "を" + ( ( com.FaceSide ) ? "表向き" : "裏向き" ) + "にした", Color.Green) { Card = card.NickName }); }
            if (card.Transformed != com.Transformed) { OnLogMessage(this, new LogMessageArgs(card.NickName + "を" + ( ( com.Transformed ) ? "変身" : "変身解除" ) + "させた", Color.Green, "transform.wav") { Card = card.NickName }); }
            card.Active = com.Active;
            card.FaceSide = com.FaceSide;
            card.Transformed = com.Transformed;
            card.Redraw();
            CardHovering(card);
            if (card.Area == AreaType.Nodes) { Nodes.RedrawCards(); }
        }

        /// <summary>
        /// カードの移動
        /// </summary>
        private void CommandMove( Command com ) {
            CardBox card = CardTable[com.CardId];
            if (card.Area == AreaType.Hands) {
                Hands.Cards.Remove(card);
                Hands.Cards.Insert(com.Value, card);
                Hands.RedrawCards();
            }
            else {
                card.MoveVirtualPoint(com.Location);
            }
            OnLogMessage(this, new LogMessageArgs(""){ Sound = "move.wav" });
        }

        /// <summary>
        /// 攻撃
        /// </summary>
        private void CommandAttack( Command com ) {
            CardBox card = CardTable[com.CardId];
            OnLogMessage(this, new LogMessageArgs(card.NickName + "の攻撃！", Color.Red, "nc10325.wav") { Card = card.NickName });
            card.Active = false;
            CardHovering(card);
            card.Redraw();
        }

        /// <summary>
        /// 防御
        /// </summary>
        private void CommandDefend( Command com ) {
            CardBox card = CardTable[com.CardId];
            OnLogMessage(this, new LogMessageArgs(card.NickName + "の防御！", Color.Red, "guard.wav") { Card = card.NickName });
            card.Active = false;
            CardHovering(card);
            card.Redraw();
        }

        /// <summary>
        /// マナチャージ
        /// </summary>
        private void CommandManaCharge( Command com ) {
            CardBox card = CardTable[com.CardId];
            OnLogMessage(this, new LogMessageArgs(card.NickName + "のマナチャージ", Color.Blue) { Card = card.NickName, Sound = "mana_charge.wav" });
            card.Active = false;
            CardBox mana = Deck.First;
            mana.Visible = false;
            Deck.Remove(mana);
            mana.Active = false;
            Nodes.Add(mana);
            mana.Redraw();
            card.Redraw();
            CardHovering(card);
            Hands.RedrawCards();
            mana.Visible = true;
        }

        /// <summary>
        /// 起動効果
        /// </summary>
        private void CommandStartEffect( Command com ) {
            CardBox card = CardTable[com.CardId];
            OnLogMessage(this, new LogMessageArgs(card.NickName + "の起動効果を使用", Color.Blue, "nc22266.wav") { Card = card.NickName });
            if (com.Active) { card.Active = false; card.Redraw(); }
        }

        /// <summary>
        /// 自動効果
        /// </summary>
        private void CommandAutoEffect( Command com ) {
            CardBox card = CardTable[com.CardId];
            OnLogMessage(this, new LogMessageArgs(card.NickName + "の自動効果が発動", Color.Green, "nc10324.wav") { Card = card.NickName });
        }

        /// <summary>
        /// ドロー
        /// </summary>
        private void CommandDraw(Command com){
            AreaControl area = Areas[com.ToArea];
            Dictionary<AreaType, string> mes_by_area = new Dictionary<AreaType, string> { 
                { AreaType.Nodes, "ノードに加えた"},
                { AreaType.Hands, "ドロー"},
                { AreaType.Removed, "除外した" },
                { AreaType.Grave, "破棄した" },
                { AreaType.SideBord, "サイドボードに置いた" },
                { AreaType.Field , "場に出した"},
                { AreaType.UnderDeck, "山札の一番下に入れた"},
            };
            if (com.CardId != 0 && com.CardIds == null) { com.CardIds = new List<int>(); com.CardIds.Add(com.CardId); }
            if (com.Value >= 1) {
                for (int i = 0; i < com.Value; i++) {
                    if (Deck.Count == 0) { break; }
                    OnLogMessage(this, new LogMessageArgs("") { Sound = "draw.wav" });
                    CardBox card = CardTable[com.CardIds[i]];
                    card.Visible = false;
                    Deck.Remove(card);
                    card.FaceSide = com.FaceSide;
                    card.Active = com.Active;
                    area.Add(card);
                    if (com.ToArea == AreaType.Nodes) { card.MoveVirtualPoint(Nodes.GetEmptyLocation(card)); }
                    card.Visible = (com.ToArea != AreaType.Removed) && (com.ToArea != AreaType.SideBord);
                }
            }
            Hands.RedrawCards();
            OnLogMessage(this, new LogMessageArgs("デッキから" + com.Value.ToString() + "枚を" + ( com.ToArea == AreaType.Field && !com.FaceSide ? "裏向きで" : "" ) + mes_by_area[com.ToArea], Color.Green));
        }

        /// <summary>
        /// デッキロード
        /// </summary>
        private void CommandLoadDeck( Command com ) {
            OnLogMessage(this, new LogMessageArgs("デッキがロードされました", Color.Red, "setup.wav"));
            if (com.Remote) {
            }
            NodeSet.Checked = false;
            SummonChar.Checked = false;
            SummonDoll.Checked = false;
        }

        /// <summary>
        /// ターン開始
        /// </summary>
        private void CommandTurnStart( Command com ) {
            OnLogMessage(this, new LogMessageArgs("ターン開始", Color.Red, "start.wav"));
            foreach (CardBox card in BattleField.Cards) {
                if (card.FaceSide || card.BackCardInfo.No != "000") {
                    card.Active = true;
                    card.Redraw();
                }
            }
            if (Enemy.State != PlayerState.UnLoad) {
                foreach (CardBox card in Enemy.BattleField.Cards) {
                    if (card.FaceSide && card.Info.Skill.Contains("警戒")) {
                        card.Active = true;
                        card.Redraw();
                    }
                }
            }
            State = PlayerState.MyTurn;
            Hands.RedrawCards();
            SummonChar.Checked = false;
            SummonDoll.Checked = false;
            NodeSet.Checked = false;
        }

        /// <summary>
        /// ターン終了
        /// </summary>
        private void CommandTurnEnd( Command com ) {
            OnLogMessage(this, new LogMessageArgs("ターン終了", Color.Red, "turn.wav"));
            State = PlayerState.YourTurn;
            Hands.RedrawCards();
            SummonChar.Checked = false;
            SummonDoll.Checked = false;
            NodeSet.Checked = false;
        }

        /// <summary>
        /// ライフ変動
        /// </summary>
        private void CommandLife( Command com ) {
            if (Type != PlayerType.Control) { Life.Value += com.Value; }
            if (com.Value > 0) {
                OnLogMessage(this, new LogMessageArgs("ライフが " + com.Value + " 回復", Color.Purple, "nc10323.wav"));
            }
            else if (com.Value < 0 && Life.Value > 0) {
                OnLogMessage(this, new LogMessageArgs("ライフに " + -com.Value + " のダメージ受けた", Color.Purple, ( Life.Value > 5 ) ? "nc1456.wav" : "nc8477.wav"));
            }
            else if(com.Value < 0 && Life.Value <= 0){
                OnLogMessage(this, new LogMessageArgs( -com.Value + " のダメージ受けた。ライフが無くなった！", Color.Purple, "hit81.wav"));
            }
        }

        /// <summary>
        /// コストの支払い
        /// </summary>
        private void CommandPayCost( Command com ) {
            CardBox card = CardTable[com.CardId];
            if (com.Active) {
                Nodes.ChangeNode(card, false);
                OnLogMessage(this, new LogMessageArgs("アクティブノードからコスト支払い", Color.Gray, "cost.wav"));
            }
            else {
                OnLogMessage(this, new LogMessageArgs("スリープノードからコスト支払い(" + card.Info.Name + ")", Color.Gray, "cost.wav") { Card = card.Info.Name });
                card.Visible = false;
                Nodes.Remove(card);
                Grave.Add(card);
                card.Visible = true;
            }
            card.Redraw();
            CardHovering(card);
            Hands.RedrawCards();
        }

        /// <summary>
        /// デッキを見る
        /// </summary>
        private void CommandViewDeck( Command com ) {
            OnLogMessage(this, new LogMessageArgs("山札" + (com.Value > 0 ? "の上から" + com.Value.ToString()  + "枚": "全て") + "を見ています...", Color.Green));
        }

        /// <summary>
        /// デッキを見るのをやめる
        /// </summary>
        private void CommandUnViewDeck( Command com ) {
            OnLogMessage(this, new LogMessageArgs("山札を見るのを終えました", Color.Green));
        }

        /// <summary>
        /// 裏向きカードの定義
        /// </summary>
        private void CommandBackNameDefine( Command com ) {
            CardBox card = CardTable[com.CardId];
            OnLogMessage(this, new LogMessageArgs(card.NickName + "を" + BackList[com.Message].Name + "と定義した", Color.Green) { Card = BackList[com.Message].Name });
            card.BackCardInfo = BackList[com.Message];
            card.Redraw();
        }

        /// <summary>
        /// シャッフルする
        /// </summary>
        private void CommandShuffle( Command com ) {
            if (Type == PlayerType.Control) {
                Deck.Shuffle();
                PlayerShadow pl = GetShadow();
                SendCommand(new Command { Type = CommandType.Shuffled, Cards = Deck.Cards });
                OnLogMessage(this, new LogMessageArgs("山札をシャッフルした", Color.Green, "shuffle.wav"));

            }
        }

        /// <summary>
        /// 敵をシャッフル
        /// </summary>
        private void CommandShuffleEnemy( Command com ) {
            if (com.Remote) {
                Enemy.Deck.Shuffle();
                PlayerShadow pl = Enemy.GetShadow();
                Enemy.SendCommand(new Command { Type = CommandType.Shuffled, Cards = Enemy.Deck.Cards });
            }
        }

        /// <summary>
        /// シャッフルされた
        /// </summary>
        private void CommandShuffled( Command com ) {
            if (com.Remote) {
                for (int i = 0; i < com.CardIds.Count; i++) {
                    CardBox card = CardTable[com.CardIds[i]];
                    Deck.Remove(card);
                    Deck.Last = card;
                }
                Deck.RedrawCards();
                OnLogMessage(this, new LogMessageArgs("山札はシャッフルされた", Color.Green, "shuffle.wav"));
            }
        }

        /// <summary>
        /// 表示順序の変更
        /// </summary>
        private void CommandLayerChange( Command com ) {
            CardBox card = CardTable[com.CardId];
            if (com.Active) { card.BringToFront(); }
            else { card.SendToBack(); }
        }

        /// <summary>
        /// 相手の場へ移動
        /// </summary>
        private void CommandMoveToEnemy( Command com ) {
            if (Enemy.State == PlayerState.UnLoad) { return; }
            CardBox card = this.CardTable[com.CardId];
            card.Visible = false;
            card.Player = Enemy;
            this.Areas[card.Area].Remove(card);

            if (com.ToArea == AreaType.UnderDeck) { Enemy.Deck.Last = card; }
            else { Enemy.Areas[com.ToArea].Add(card); }

            this.CardTable.Remove(card.Id);
            card.Id = -card.Id;
            Enemy.CardTable[card.Id] = card;
            if (com.Location != new PointF()) { card.MoveVirtualPoint(com.Location); }
            card.Visible = true;
            OnLogMessage(this, new LogMessageArgs(card.NickName + "は対戦相手の" + ( ( com.ToArea == AreaType.UnderDeck ) ? "山札の下" : Enemy.Areas[com.ToArea].NickName ) + "に移動", Color.Green, "rihan.wav") { Card = card.NickName });
            Hands.RedrawCards();
        }

        /// <summary>
        /// 場のクリア
        /// </summary>
        private void CommandClear( Command com ) {
            if (!com.Remote) { Enemy.Clear(); }
            Clear();
            OnLogMessage(this, new LogMessageArgs("場を全てクリアした", Color.Red, "shuffle.wav"));
        }

        /// <summary>
        /// 同期
        /// </summary>
        private void CommandUpdateAll( Command com ) {
            if (com.Remote) {
                LoadFromShadow(com.Player);
            }
        }

        /// <summary>
        /// 乱数の表示
        /// </summary>
        private void CommandRand( Command com ) {
            OnLogMessage(this, new LogMessageArgs("乱数： " + com.Message));
        }



        #endregion
    }
}
