using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Drawing;
using Ck_Objects;

namespace SpriteEditor_2017
{
    /// <summary>
    /// used by developer to test data during development phase
    /// </summary>
    public class panelDebug : panelMoveable
    {
        enum enuMessageLevel { heading, Editor, Sprite, animation, Animation_frame, animation_frame_data, animation_drawSequence };

        TextBox txt = new TextBox();
        Button btnAcknowledge = new Button();
        bool bolAcknowledged = false;
        string strTestResults = "";
        public panelDebug() { Init(fntStandard); }
        public panelDebug(Font fnt) { Init(fnt); }

        public classSpriteData cSpriteData;

        void Init(Font fnt)
        {
            cSpriteData = formSpriteEditor_2017.instance.cSpriteData;
            BorderStyle = BorderStyle.FixedSingle;
            pnlContainer.Controls.Add(txt);
            txt.Dock = DockStyle.Fill;
            txt.Multiline = true;
            txt.ScrollBars = ScrollBars.Vertical;

            btnAcknowledge.Text = "Ok";
            btnAcknowledge.AutoSize = true;
            btnAcknowledge.Click += BtnAcknowledge_Click;
            pnlContainer.Controls.Add(btnAcknowledge);

            Size = new Size(formSpriteEditor_2017.cPanelSizeLocations[(int)formSpriteEditor_2017.enuPanels.debugTestData].size_Width,
                            formSpriteEditor_2017.cPanelSizeLocations[(int)formSpriteEditor_2017.enuPanels.debugTestData].size_Height);
            Location = new Point(formSpriteEditor_2017.cPanelSizeLocations[(int)formSpriteEditor_2017.enuPanels.debugTestData].location_X,
                                 formSpriteEditor_2017.cPanelSizeLocations[(int)formSpriteEditor_2017.enuPanels.debugTestData].location_Y);
            if (formSpriteEditor_2017.cPanelSizeLocations[(int)formSpriteEditor_2017.enuPanels.debugTestData].Collapsed)
                Collapse();
            else
                Expand();
            ExpansionDirection = formSpriteEditor_2017.cPanelSizeLocations[(int)formSpriteEditor_2017.enuPanels.debugTestData].ExpansionDirection;
            Hide();
            SizeChanged += panelDebug_SizeChanged;
            LocationChanged += panelDebug_LocationChanged;
            Disposed += PanelDebug_Disposed;
            VisibleChanged += PanelDebug_VisibleChanged;
            
        }

        private void PanelDebug_VisibleChanged(object sender, EventArgs e)
        {
            ;
        }

        private void PanelDebug_Disposed(object sender, EventArgs e)
        {
            formSpriteEditor_2017.cPanelSizeLocations[(int)formSpriteEditor_2017.enuPanels.debugTestData].ExpansionDirection = ExpansionDirection;
        }

        private void panelDebug_LocationChanged(object sender, EventArgs e)
        {
            if (!formSpriteEditor_2017.cPanelSizeLocations[(int)formSpriteEditor_2017.enuPanels.debugTestData].bolIgnoreChanges)
            {
                formSpriteEditor_2017.cPanelSizeLocations[(int)formSpriteEditor_2017.enuPanels.debugTestData].bolInit = true;
                formSpriteEditor_2017.cPanelSizeLocations[(int)formSpriteEditor_2017.enuPanels.debugTestData].location_X = Location.X;
                formSpriteEditor_2017.cPanelSizeLocations[(int)formSpriteEditor_2017.enuPanels.debugTestData].location_Y = Location.Y;
            }
        }

        private void BtnAcknowledge_Click(object sender, EventArgs e)
        {
            bolAcknowledged = true;
            txt.BackColor = Color.White;
        }

        private void panelDebug_SizeChanged(object sender, EventArgs e)
        {
            if (!formSpriteEditor_2017.cPanelSizeLocations[(int)formSpriteEditor_2017.enuPanels.debugTestData].bolIgnoreChanges
                && !Collapsed)
            {
                formSpriteEditor_2017.cPanelSizeLocations[(int)formSpriteEditor_2017.enuPanels.debugTestData].bolInit = true;
                formSpriteEditor_2017.cPanelSizeLocations[(int)formSpriteEditor_2017.enuPanels.debugTestData].size_Width = Size.Width;
                formSpriteEditor_2017.cPanelSizeLocations[(int)formSpriteEditor_2017.enuPanels.debugTestData].size_Height = Size.Height;
            }
            placeObjects();
        }

        void placeObjects()
        {
            btnAcknowledge.Visible = true;
            btnAcknowledge.Location = new Point(Width - btnAcknowledge.Width - 25, Height - btnAcknowledge.Height - 45);

            btnAcknowledge.BringToFront();
        }

        //bool bolEnabled = true;
        //public bool Enabled
        //{
        //    get { return bolEnabled; }
        //    set { bolEnabled = value; }
        //}

        public void Clear()
        {
            txt.Text = "";
            bolAcknowledged = true;
            txt.BackColor = Color.White;
        }

        bool TestQuit()
        {
            int intQuitAfterMaxErrorMessages = 32;
            return intTotalErrorMessages >= intQuitAfterMaxErrorMessages;
        }

        int intTotalErrorMessages = 0;
        public void debugTestData(ref classSpriteData cSpriteData, string strMarker)
        {
            if (!Enabled) return;
            classSprite cSprite = cSpriteData.cAnimationData.cSprite;
            Text = "Debugging Sprite : " + cSprite.Name;
            strTestResults = "";
            if (cSprite == null) return;
            int intNumberLimbs = cSprite.cCostumeInfo_Default.lstLimbs.Count;
            eMsgLevel = enuMessageLevel.Editor;

            intTotalErrorMessages = 0;

            eMsgLevel = enuMessageLevel.Sprite;
            //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
            ///                                         sprite level tests
            //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
            //List<classAlphaNumTree.classTraversalReport_Record> lstLimbTreeTraversal = cSprite.cCostumeInfo_Default.cBT_Limbs.TraverseTree_InOrder();
            List<object> lstLimbTreeTraversal = cSprite.cCostumeInfo_Default.cBT_Limbs.Traverse();
            if (lstLimbTreeTraversal.Count != cSprite.cCostumeInfo_Default.lstLimbs.Count)
            {
                message("2)number of limbs in list does not match number of limbs in Bin-Tree", enuMessageLevel.Sprite);
                List<classSprite_Limb> lstTreeLimbs = new List<classSprite_Limb>();
                for (int intTreeLimbCounter = 0; intTreeLimbCounter < lstLimbTreeTraversal.Count; intTreeLimbCounter++)
                    lstTreeLimbs.Add((classSprite_Limb)lstLimbTreeTraversal[intTreeLimbCounter]);

                List<classSprite_Limb>[] lstLimbs = new List<classSprite_Limb>[2];
                string strHeaderMsg = "";
                int intPadRight_Limbs = 40;
                if (lstTreeLimbs.Count > cSprite.cCostumeInfo_Default.lstLimbs.Count)
                {
                    strHeaderMsg = "Tree Limbs".PadRight(intPadRight_Limbs) + "List Limbs";
                    lstLimbs[0] = lstTreeLimbs;
                    lstLimbs[1] = cSprite.cCostumeInfo_Default.lstLimbs;
                }
                else
                {
                    strHeaderMsg = "List Limbs".PadRight(intPadRight_Limbs) + "Tree Limbs";
                    lstLimbs[0] = cSprite.cCostumeInfo_Default.lstLimbs;
                    lstLimbs[1] = lstTreeLimbs;
                }
                message(strHeaderMsg, enuMessageLevel.heading);
                for (int intCounter = 0; intCounter < lstLimbs[0].Count; intCounter++)
                {
                    message(lstLimbs[0][intCounter].Name.PadRight(intPadRight_Limbs) + (intCounter < lstLimbs[1].Count ? lstLimbs[1][intCounter].Name : ""), enuMessageLevel.heading);
                    if (TestQuit()) goto quit;
                }

            }
            ///////////////////////////////// DEBUG ////////////////////////// FIX THIS /////////////////////////////
            if (cSpriteData.cCostumeInfo.cDrawData_current.cQT_LimbPositions != null)
            {
                List<classQuadTree.classQuadTreeData> lstQT_LimbsTraversal = cSpriteData.cCostumeInfo.cDrawData_current.cQT_LimbPositions.TraverseQuadTree();
                for (int intAnimationCounter = 0; intAnimationCounter < cSprite.lstAnimations.Count; intAnimationCounter++)
                {
                    classAnimation cAnimation = cSprite.lstAnimations[intAnimationCounter];
                    for (int intFrameCounter = 0; intFrameCounter < cAnimation.lstFrames.Count; intFrameCounter++)
                    {
                        classAnimation_Frame cFrame = cAnimation.lstFrames[intFrameCounter];
                        if (lstQT_LimbsTraversal.Count  != cFrame.lstDrawSequence.Count)
                        {
                            message("3)number of limbs in DrawSequence list of (" + cAnimation.Name + ")Frame[" + intFrameCounter.ToString() +"]="+cFrame.lstDrawSequence.Count.ToString() + " does not match number of limbs in Quad-Tree" + lstQT_LimbsTraversal.Count.ToString());
                            List<classSprite_Limb> lstQuadTreeLimbs = new List<classSprite_Limb>();
                            for (int intTreeLimbCounter = 0; intTreeLimbCounter < lstQT_LimbsTraversal.Count; intTreeLimbCounter++)
                                lstQuadTreeLimbs.Add((classSprite_Limb)lstQT_LimbsTraversal[intTreeLimbCounter].Data);

                            IEnumerable<classSprite_Limb> query1 = lstQuadTreeLimbs.OrderBy(limb => limb.Name);
                            lstQuadTreeLimbs = (List<classSprite_Limb>)query1.ToList<classSprite_Limb>();

                            List<classSprite_Limb> lstFrameDrawSequence = new List<classSprite_Limb>();
                            for (int intLimbCounter = 0; intLimbCounter < cFrame.lstDrawSequence.Count; intLimbCounter++)
                                if (cFrame.lstDrawSequence[intLimbCounter] >= 0)
                                {
                                    lstFrameDrawSequence.Add(cSprite.cCostumeInfo_Default.lstLimbs[cFrame.lstDrawSequence[intLimbCounter]]);
                                }

                            IEnumerable<classSprite_Limb> query2 = lstFrameDrawSequence.OrderBy(limb => limb.Name);
                            lstFrameDrawSequence = (List<classSprite_Limb>)query2.ToList<classSprite_Limb>();


                            List<classSprite_Limb>[] lstLimbs = new List<classSprite_Limb>[2];
                            string strHeaderMsg = "";
                            int intPadRight_Limbs = 40;
                            if (lstQuadTreeLimbs.Count > lstFrameDrawSequence.Count)
                            {
                                strHeaderMsg = "QuadTree Limbs".PadRight(intPadRight_Limbs) + "List Limbs";
                                lstLimbs[0] = lstQuadTreeLimbs;
                                lstLimbs[1] = lstFrameDrawSequence;
                            }
                            else
                            {
                                strHeaderMsg = "List Limbs".PadRight(intPadRight_Limbs) + "QuadTree Limbs";
                                lstLimbs[0] = lstFrameDrawSequence;
                                lstLimbs[1] = lstQuadTreeLimbs;
                            }
                            message("4)" + strHeaderMsg, enuMessageLevel.heading);

                            for (int intCounter = 0; intCounter < lstLimbs[0].Count; intCounter++)
                            {
                                message((lstLimbs[0][intCounter] != null ? lstLimbs[0][intCounter].Name : "null").PadRight(intPadRight_Limbs)   
                                               + (intCounter < lstLimbs[1].Count 
                                                             ? (lstLimbs[1][intCounter] != null 
                                                                                        ? lstLimbs[1][intCounter].Name 
                                                                                        : "null")
                                                             : ""), enuMessageLevel.heading);
                                if (TestQuit()) goto quit;
                            }
                        }
                        if (TestQuit()) goto quit;
                    }
                }
            }
            else
            {
                if (cSprite.cCostumeInfo_Default.lstLimbs.Count > 0)
                    message("5)LimbsQuadTree = null && limbs.Count=" + cSprite.cCostumeInfo_Default.lstLimbs.Count.ToString());
                if (TestQuit()) goto quit;

            }
            
        
            /////////////////////////////////////// test limbs
            for (int intLimbCounter = 0; intLimbCounter < cSprite.cCostumeInfo_Default.lstLimbs.Count; intLimbCounter++)
            {
                classSprite_Limb cLimbInList = cSprite.cCostumeInfo_Default.lstLimbs[intLimbCounter];
                if (cLimbInList != null)
                {
                    string strLimbHeader = "Limb " + cLimbInList.Name;
                    classSprite_Limb cLimbInTree = (classSprite_Limb)cSprite.cCostumeInfo_Default.cBT_Limbs.Search(cLimbInList.Name);
                    if (cLimbInList.cSprite != cSprite) message("7)" + strLimbHeader + ".cSprite \"" + cLimbInList.cSprite != null ? cLimbInList.cSprite.Name : "null" + "\" does not mathc sprite");

                    if (cLimbInList != cLimbInTree) message("8)" + strLimbHeader + " in list does not match limb in tree");
                    if (cLimbInList.lstImages[cLimbInList.intImageList_Index].bmpImages == null) message("9)" + strLimbHeader + "has not bitmaps");
                    if (cLimbInList.Hinge == null && cLimbInList != cSprite.cCostumeInfo_Default.cLimb_Master) message("10)" + strLimbHeader + " has no hinge");
                    if (cLimbInList.lstHinge_Slaves != null)
                    {
                        for (int intHingeCounter = 0; intHingeCounter < cLimbInList.lstHinge_Slaves.Count; intHingeCounter++)
                        {
                            classSprite_Hinge cHinge = cLimbInList.lstHinge_Slaves[intHingeCounter];
                            if (cHinge.Limb_Master != cLimbInList) message(strLimbHeader + " slave hinge\"" + cHinge.Limb_Slave.Name + "\" does not point to it as master");
                            if (cHinge.Limb_Slave == null) message(strLimbHeader + " save hinge\"" + cHinge.Limb_Slave.Name + "\" is null");
                        }
                    }
                }
                else
                {
                    message("11)sprite's lstLimbs[" + intLimbCounter.ToString() + "] is null", enuMessageLevel.Sprite);
                }
                if (TestQuit()) goto quit;
            }
       

            if (cSprite.cCostumeInfo_Default.cLimb_Master == null) message("18)" + cSprite.Name + "'s master limb == null");
            if (TestQuit()) goto quit;

            //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
            ///                                         Animation level tests
            //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
            /// all animations must have an equal number of drawlimbs 
            /// all frames of each animation must have a number of data equal to the number of limbs

            for (int intAnimationCounter = 0; intAnimationCounter < cSprite.lstAnimations.Count; intAnimationCounter++)
            {
                eMsgLevel = enuMessageLevel.animation;
                classAnimation cAnimation = cSprite.lstAnimations[intAnimationCounter];
                if  (cSprite.lstAnimations[intAnimationCounter] == cSpriteData.cAnimationData.cAnimation 
                        && cSpriteData.cAnimationData.intFrameIndex  >= cAnimation.lstFrames.Count) message("19)" + cSprite.Name + " intAnimationFrame is greater than the number of frames in animation " + cAnimation.Name, enuMessageLevel.animation);
                string strAnimationMsgHeader = "Animation " + cAnimation.Name + "'s ";
                if (cAnimation.cSprite != cSprite)
                    message("20)" + strAnimationMsgHeader + "sprite does not match.", enuMessageLevel.animation);
 
                for (int intFrameCounter = 0; intFrameCounter < cAnimation.lstFrames.Count; intFrameCounter++)
                {
                    
                     classSprite_Limb cLimbRelTo = (cAnimation.lstFrames[intFrameCounter].Limb_DrawRelativeTo >= 0)
                                                                    ? cSpriteData.cCostumeInfo.lstLimbs[ cAnimation.lstFrames[intFrameCounter].Limb_DrawRelativeTo]
                                                                    : null;
                    if (cLimbRelTo != null)
                    {
                        if (!cSpriteData.cCostumeInfo.lstLimbs.Contains(cLimbRelTo))
                            message("21)" + strAnimationMsgHeader + ".Frame[" + intFrameCounter.ToString() + "]" + cLimbRelTo.Name +" is not found in cSprite.lstLimbs");
                        if (cSpriteData.cCostumeInfo.cBT_Limbs.Search(cLimbRelTo.Name) != cLimbRelTo)
                            message("22)" + strAnimationMsgHeader + ".Frame[" + intFrameCounter.ToString() + "]" + cLimbRelTo.Name + " is not found in cSprite.cBT_Limbs");
                    }
                    if (cAnimation.lstFrames[intFrameCounter].lstDrawSequence.Count != cSprite.cCostumeInfo_Default.lstLimbs.Count)
                        message("23)" 
                            + strAnimationMsgHeader 
                            +  ".Frame[" + intFrameCounter.ToString() + "].lstDrawSequence.Count(=" 
                            + cAnimation.lstFrames[intFrameCounter].lstDrawSequence.Count .ToString() 
                            +  ") != cSprite.lstLimbs.Count(=" + cSprite.cCostumeInfo_Default.lstLimbs.Count.ToString() + ")");
                    if (TestQuit()) goto quit;
                }
                //////////////////////////////////////////////                  test frames of animation
                for (int intFrameCounter = 0; intFrameCounter < cAnimation.lstFrames.Count; intFrameCounter++)
                {
                    eMsgLevel = enuMessageLevel.Animation_frame;
                    classAnimation_Frame cFrame = cAnimation.lstFrames[intFrameCounter];
                    if (cFrame == null)
                        message("Animation:" + cAnimation.Name + "'s frame#" + intFrameCounter.ToString() + " is null");
                    else
                    {
                        string strFrameHeader = strAnimationMsgHeader + "lstFrame[" + intFrameCounter.ToString() + "] ";
                        if (cFrame.ptBR.X < cFrame.ptTL.X) message(strFrameHeader + " ptTL.x < ptBR.x");
                        if (cFrame.ptBR.Y < cFrame.ptTL.Y) message(strFrameHeader + " ptTL.y < ptBR.y");

                        ///////////////////////////////////////////                 test data of frames of animation\
                        if (cFrame.lstData.Count != cSprite.cCostumeInfo_Default.lstLimbs.Count) message("24)" + strFrameHeader + " lstData.Count(" +cFrame.lstData.Count.ToString() +") != cSprite.lstLimbs.Count(" + cSprite.cCostumeInfo_Default.lstLimbs.Count.ToString() + ")");
                        for (int intDataCounter = 0; intDataCounter < cFrame.lstData.Count; intDataCounter++)
                        {
                            eMsgLevel = enuMessageLevel.animation_frame_data;
                            classAnimation_Frame_LimbData cData = cFrame.lstData[intDataCounter];
                            if (cData.intLimbIndex  <0) message(strFrameHeader + " .lstData[" + intDataCounter.ToString() + "] is null");
                        }
                    }
                    if (TestQuit()) goto quit;
                }
                if (TestQuit()) goto quit;
                //       message("I need to see my debugger", enuMessageLevel.Editor);
            }

            quit:
            if (strTestResults.Length > 0)
            {
                strTestResults = strMarker + strTestResults;
                if (string.Compare(strTestResults, txt.Text) != 0)// || !bolAcknowledged )
                {
                    txt.Text = strTestResults;
                    txt.BackColor = System.Drawing.Color.Yellow;

                    Expand();

                    formSpriteEditor_2017.instance.mnuPanels_DataTester.Checked = true;

                    BringToFront();
                    return;
                }
            }
            else if (bolAcknowledged)
            {
                txt.BackColor = Color.White;
                txt.Text = "";
                Collapse();
            }
        }

        enuMessageLevel eMsgLevel = enuMessageLevel.Sprite;
        void message(string msg) { message(msg, eMsgLevel); }
        void message(string msg, enuMessageLevel _eMsgLevel)
        {
            intTotalErrorMessages++;
            switch (_eMsgLevel)
            {
                case enuMessageLevel.heading:
                    strTestResults += "\r\n" + msg;
                    break;

                default:
                    strTestResults += "\r\n" + _eMsgLevel.ToString() + " error"
                            + "\r\n\t" + msg;
                    break;

            }


        }
    }

}
