using System;
using System.Collections.Generic;
using System.Text;
using IronPython.Hosting;
using IronPython.Modules;
using System.Threading;

namespace shuchancontrol
{
    public class ShuchanHardSequence : IDisposable
    {
        public readonly ShuchanHardDriver ShuchanInstance;
        /// <summary>
        /// 駒移動の際のアームの物理的な角度を与えるPythonスクリプトのパス。
        /// </summary>
        public string PyScriptMovePositionPath { get; set; }
        int currentArmH = 0, currentArmV = 0;   //現在のアームの角度。

        public ShuchanHardSequence(ShuchanHardDriver shuchanhard)
        {
            ShuchanInstance = shuchanhard;
        }

        public void UpdateMoveNotation(int MoveNumber, string whitemove, string blackmove)
        {
            string line = string.Format("{0}. {1} {2}", MoveNumber.ToString(), whitemove != null ? whitemove : "...",
                blackmove != null ? blackmove : "");
            ShuchanInstance.WriteLine(line, 0);
        }

        public void UpdateMessageFromChessEngine(string message)
        {
            ShuchanInstance.WriteLine(message, 1);
        }

        public void UpdateOperationMethodMessage(string message)
        {
            ShuchanInstance.WriteLine(message, 3);
        }

        /// <summary>
        /// プロモーション先をユーザーに選択させる。
        /// </summary>
        /// <returns></returns>
        public ShuchanChessBoard.PieceType SelectPromotionTarget()
        {
            ShuchanInstance.WriteLine("ﾌﾟﾛﾓｰｼｮﾝﾀｲｼｮｳｦｾﾝﾀｸ:", 2);
            ShuchanInstance.WriteLine("T:ｸｲｰﾝ,K:ﾅｲﾄ,P:ｿﾉﾀ", 3);
            bool page1 = true;
            ShuchanChessBoard.PieceType result = ShuchanChessBoard.PieceType.None;
            while (true)
            {
                if (ShuchanInstance.GetSWIfOncePressed((int)ShuchanHardDriver.SWName.SWA))
                {
                    if (page1)
                    {
                        result = ShuchanChessBoard.PieceType.Queen;
                        break;
                    }
                    else
                    {
                        result = ShuchanChessBoard.PieceType.Rook;
                        break;
                    }
                }
                else if (ShuchanInstance.GetSWIfOncePressed((int)ShuchanHardDriver.SWName.SWB))
                {
                    if (page1)
                    {
                        result = ShuchanChessBoard.PieceType.Knight;
                        break;
                    }
                    else
                    {
                        result = ShuchanChessBoard.PieceType.Bishop;
                        break;
                    }
                }
                else if (ShuchanInstance.GetSWIfOncePressed((int)ShuchanHardDriver.SWName.SWC))
                {
                    if (page1)
                    {
                        page1 = false;
                        ShuchanInstance.WriteLine("T:ﾙｰｸ,K:ﾋﾞｼｮｯﾌﾟ,P:ｿﾉﾀ", 3);
                    }
                    else
                    {
                        page1 = true;
                        ShuchanInstance.WriteLine("T:ｸｲｰﾝ,K:ﾅｲﾄ,P:ｿﾉﾀ", 3);
                    }
                }

                Thread.Sleep(100);
            }

            ShuchanInstance.WriteLine("", 3);

            return result;
        }

        public void UpdatePromotionList(ShuchanChessBoard board)
        {
            string line = "";

            for (int i = 0; i < 8; i++)
            {
                if (board.ExtraPieceBlack[i] != ShuchanChessBoard.PieceType.None)
                {
                    line += "Black " + (char)('A' + i) + "=";
                    switch (board.ExtraPieceBlack[i])
                    {
                        case ShuchanChessBoard.PieceType.Queen:
                            line += "Q";
                            break;
                        case ShuchanChessBoard.PieceType.Rook:
                            line += "R";
                            break;
                        case ShuchanChessBoard.PieceType.Bishop:
                            line += "B";
                            break;
                        case ShuchanChessBoard.PieceType.Knight:
                            line += "K";
                            break;
                        default:
                            line += "?";
                            break;
                    }
                    line += " ";
                }
                else
                {
                    break;
                }
            }

            for (int i = 0; i < 8; i++)
            {
                if (board.ExtraPieceWhite[i] != ShuchanChessBoard.PieceType.None)
                {
                    line += "White " + (char)('A' + i) + "=";
                    switch (board.ExtraPieceWhite[i])
                    {
                        case ShuchanChessBoard.PieceType.Queen:
                            line += "Q";
                            break;
                        case ShuchanChessBoard.PieceType.Rook:
                            line += "R";
                            break;
                        case ShuchanChessBoard.PieceType.Bishop:
                            line += "B";
                            break;
                        case ShuchanChessBoard.PieceType.Knight:
                            line += "K";
                            break;
                        default:
                            line += "?";
                            break;
                    }
                    line += " ";
                }
                else
                {
                    break;
                }
            }

            ShuchanInstance.WriteLine(line, 2);
        }

        public void Move(ShuchanPiecePosition from, ShuchanPiecePosition to, bool escape)
        {
            //最初の位置の水平座標、垂直座標、巻き上げ座標、最後の位置の水平座標、垂直座標、巻き上げ座標、退避位置の水平座標、垂直座標、最高巻上げ点
            int FromH = 0, FromV = 0, FromR = 0, ToH = 0, ToV = 0, ToR = 0, EscH = 0, EscV = 0, MaxRoll = 0;
            int FromRank = from.Rank, FromFile = from.File, ToRank = to.Rank, ToFile = to.File;
            //駒を持った状態で一回の操作で動かしてよい最大の変化角度。
            int MoveHStepAtOnce = 100, MoveVStepAtOnce = 100;
            //pythonスクリプトを使って物理座標を取得し、そのとおりに動かす。
            PythonEngine pe = new PythonEngine();
            pe.Globals.Add("FromRank", FromRank);
            pe.Globals.Add("FromFile", FromFile);
            pe.Globals.Add("ToRank", ToRank);
            pe.Globals.Add("ToFile", ToFile);
            pe.ExecuteFile(PyScriptMovePositionPath);
            FromH = pe.EvaluateAs<int>("FromH");
            FromV = pe.EvaluateAs<int>("FromV");
            FromR = pe.EvaluateAs<int>("FromR");
            ToH = pe.EvaluateAs<int>("ToH");
            ToV = pe.EvaluateAs<int>("ToV");
            ToR = pe.EvaluateAs<int>("ToR");
            EscH = pe.EvaluateAs<int>("EscH");
            EscV = pe.EvaluateAs<int>("EscV");
            MaxRoll = pe.EvaluateAs<int>("MaxRoll");
            MoveHStepAtOnce = pe.EvaluateAs<int>("MoveHStepAtOnce");
            MoveVStepAtOnce = pe.EvaluateAs<int>("MoveVStepAtOnce");

            /* 移動順序
             * 最初の位置の水平座標、垂直座標に移動。
             * 最初の位置の巻き上げ座標に移動。
             * 駒を吸い上げる。
             * 最高巻上げ点に巻き上げる。
             * 最後の位置の水平座標、垂直座標に移動。
             * 最後の位置の巻き上げ座標に移動。
             * 駒を開放する。
             * 最高巻上げ点に巻き上げる。
             * 退避水平座標、垂直座標に移動。
             */
            //駒を持ったままの移動のとき、高速移動すると駒が外れることがあるので、複数回に分けて少しずつ動かす。
            //駒を持っていないときも激しく移動すると電磁石がアームの上に巻きついてしまったりするのでゆっくり動かす。
            moveSlowly(true, currentArmH, FromH, MoveHStepAtOnce);
            moveSlowly(false, currentArmV, FromV, MoveVStepAtOnce);
            //揺れが収まるのを待つため無駄に命令を送る。
            for (int i = 0; i < 20; i++)
            {
                ShuchanInstance.VerticalMove(FromV);
            }
            ShuchanInstance.RollMagnet(FromR);
            ShuchanInstance.CapturePiece(true);
            ShuchanInstance.RollMagnet(MaxRoll);
            moveSlowly(true, FromH, ToH, MoveHStepAtOnce);
            moveSlowly(false, FromV, ToV, MoveVStepAtOnce);
            for (int i = 0; i < 20; i++)
            {
                ShuchanInstance.VerticalMove(ToV);
            }
            ShuchanInstance.RollMagnet(ToR);
            ShuchanInstance.CapturePiece(false);
            ShuchanInstance.RollMagnet(MaxRoll);
            currentArmH = ToH;
            currentArmV = ToV;
            if (escape)
            {
                moveSlowly(true, currentArmH, EscH, MoveHStepAtOnce);
                moveSlowly(false, currentArmV, EscV, MoveVStepAtOnce);
                currentArmH = EscH;
                currentArmV = EscV;
            }
        }

        /// <summary>
        /// アームをゆっくり動かす。
        /// </summary>
        /// <param name="horizontal">横移動のときtrue、縦移動のときfalse。</param>
        /// <param name="fromAngle">移動を開始する角度。</param>
        /// <param name="toAngle">移動先の角度。</param>
        /// <param name="stepAngle">1回の操作で動かす最大の角度。</param>
        void moveSlowly(bool horizontal, int fromAngle, int toAngle, int stepAngle)
        {
            int movetime = (Math.Abs(toAngle - fromAngle) + stepAngle - 1) / stepAngle;    //動かすのに要する回数(切り上げている)。
            int[] targetposes = new int[movetime];  //各回の移動後の角度。
            for (int i = 0; i < movetime; i++)
            {
                targetposes[i] = fromAngle + (toAngle - fromAngle) * (i + 1) / movetime;
            }
            for (int i = 0; i < targetposes.Length; i++)
            {
                if (horizontal)
                {
                    ShuchanInstance.HorizontalMove(targetposes[i]);
                }
                else
                {
                    ShuchanInstance.VerticalMove(targetposes[i]);
                }
            }

        }

        #region IDisposable メンバ

        public void Dispose()
        {
            ShuchanInstance.Dispose();
        }

        #endregion
    }

}
