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

namespace SpriteEditor_2017
{
    /// <summary>
    /// allows the user to edit the currenta animation's draw sequence
    /// </summary>
    public class groupboxDisjointedLimbs : GroupBox
    {
        classSpriteData cSpriteData_Prev = null;
        ListBox lbxLimbs = new ListBox();
        public classSpriteData cSpriteData
        {
            get 
            {
                if (formSpriteEditor_2017.instance != null)
                {
                    if (formSpriteEditor_2017.instance.cSpriteData != cSpriteData_Prev)
                    {
                        cSpriteData_Prev = formSpriteEditor_2017.instance.cSpriteData;
                        LimbsSelected_MasterSet();
                    }
                    return formSpriteEditor_2017.instance.cSpriteData;
                }
                else
                    return null;
            }
        }

        List<classSprite_Limb> lstSequence
        {
            get
            {
                List<classSprite_Limb> lstRetVal = new List<classSprite_Limb>();
                LimbsSelected_MasterSet();

                lstRetVal.AddRange(lstLimbSelected);
                lstRetVal.AddRange(lstLimbsAvailable);

                return lstRetVal;
            }
        }

        public List<classSprite_Limb> lstLimbSelected = new List<classSprite_Limb>();
        public List<classSprite_Limb> lstLimbsAvailable = new List<classSprite_Limb>();
        /// <summary>
        /// add a limb to the list of disjointed limbs
        /// </summary>
        /// <param name="cLimbAdd">limb to be added</param>
        public void Limb_Add(ref classSprite_Limb cLimbAdd)
        {
            if (!lstLimbSelected.Contains(cLimbAdd))
            {
                lstLimbSelected.Add(cLimbAdd);
                LimbsSelected_MasterSet();
            }
        }

        /// <summary>
        /// sub a limb from the disjointed limbs
        /// </summary>
        /// <param name="cLimbSub">limb to be removed</param>
        public void Limb_Sub(ref classSprite_Limb cLimbSub)
        {
            if (lstLimbSelected.Contains(cLimbSub))
            {
                lstLimbSelected.Remove(cLimbSub);
                LimbsSelected_MasterSet();
            }
        }

        /// <summary>
        /// ensures the MasterLimb is always listed last in the LimbSelected list
        /// </summary>
        void LimbsSelected_MasterSet()
        {
            if (lstLimbSelected.Contains(cSpriteData.cAnimationData.cSprite.cCostumeInfo_Default.cLimb_Master))
                lstLimbSelected.Remove(cSpriteData.cAnimationData.cSprite.cCostumeInfo_Default.cLimb_Master);
            lstLimbSelected.Add(cSpriteData.cAnimationData.cSprite.cCostumeInfo_Default.cLimb_Master);

            LimbsAvailable_Set();
        }


        bool bolSelectedListChanged = true;

        void LimbsAvailable_Set()
        {
            if (!bolSelectedListChanged) return;
            bolSelectedListChanged = false;

            List<classSprite_Limb> lstLimbsAvailable_new = new List<classSprite_Limb>();
            lstLimbsAvailable_new.AddRange(cSpriteData.cAnimationData.cSprite.cCostumeInfo_Default.lstLimbs);
            for (int intLimbCounter = 0; intLimbCounter < lstLimbSelected.Count; intLimbCounter++)
            {
                classSprite_Limb cLimb = lstLimbSelected[intLimbCounter];
                lstLimbsAvailable_new.Remove(cLimb);
                if (cLimb != cMasterLimb)
                {
                    List<classSprite_Limb> lstSlaveLimbs = cLimb.Slaves_Get();
                    for (int intSlavesRemove = 0; intSlavesRemove < lstSlaveLimbs.Count; intSlavesRemove++)
                    {
                        classSprite_Limb cLimbRemove = lstSlaveLimbs[intSlavesRemove];
                        if (lstLimbsAvailable_new.Contains(cLimbRemove))
                            lstLimbsAvailable_new.Remove(cLimbRemove);
                    }
                }
            }
            if (lstLimbsAvailable.Count != lstLimbsAvailable_new.Count)
            {
                lstLimbsAvailable = lstLimbsAvailable_new;
                lbxBuild();
            }
        }


        void lbxBuild()
        {
            List<classSprite_Limb> lstLimbs = lstSequence;
            lbxLimbs.Items.Clear();
            for (int intCounter = 0; intCounter < lstLimbs.Count; intCounter++)
            {
                classSprite_Limb cLimb = lstLimbs[intCounter];
                lbxLimbs.Items.Add(cLimb.Name);
            }
            lbxLimbs.Refresh();
        }


        /// <summary>
        /// used to identify the boolean variable array contents keeping track of which keys are depressed 
        /// </summary>
        enum enuKeys { Up, Down, PageUp, PageDown, Home, End, _numKeys };
        bool[] eKeys = new bool[(int)enuKeys._numKeys];

   
        /// <summary>
        /// initializes groupboxDisjointedLimbs with standard font
        /// </summary>
        public groupboxDisjointedLimbs()
        { Init(panelMoveable.fntStandard); }

        /// <summary>
        /// initializes groupboxDisjointedLimbs with specified font
        /// </summary>
        /// <param name="fnt"></param>
        public groupboxDisjointedLimbs(Font fnt)
        {
            Init(fnt);
        }
   
        enum enuDebugEvents { Move, Wheel, _num, Up, Down, Click };
       

        /// <summary>
        /// initializes the controls on the groupboxDisjointedLimbs
        /// </summary>
        /// <param name="fnt">font to be used to draw panel's Header text</param>
        void Init(Font fnt)
        {
            BackColor = Color.LightBlue;
            ForeColor = Color.Black;

            Controls.Add(lbxLimbs);
            lbxLimbs.MouseWheel += LbxLimbs_MouseWheel;
            lbxLimbs.KeyDown += lbxLimbs_KeyDown;
            lbxLimbs.KeyUp += lbxLimbs_KeyUp;
            lbxLimbs.SelectedIndexChanged += LbxLimbs_SelectedIndexChanged;

            if (formSpriteEditor_2017.instance != null && formSpriteEditor_2017.instance.cSpriteData.cAnimationData.cSprite != null)
                Text = "Disjointed Limbs : " + formSpriteEditor_2017.instance.cSpriteData.cAnimationData.cSprite.Name;

            // initializes the lbxLimb according to the current animation frame's lstDrawSequence content
            if (cSpriteData != null
                && cSpriteData.cAnimationData.cSprite != null
                && cSpriteData.cAnimationData.cAnimation != null)
            {
                lbxBuild();
            }

            VisibleChanged += GroupboxDisjointedLimbs_VisibleChanged;
            placeObjects();
        }

        private void LbxLimbs_SelectedIndexChanged(object sender, EventArgs e)
        {
            ListBox lbxSender = (ListBox)sender;
            if (lbxSender.SelectedIndex >= 0 && lbxSender.SelectedIndex < lbxSender.Items.Count)
                Limb_Selected = lstSequence[lbxSender.SelectedIndex];
        }

        private void LbxLimbs_MouseWheel(object sender, MouseEventArgs e)
        {
            if (e.Delta < 0)
                lbxLimbs_ShiftSelected_Down();
            else
                lbxLimbs_ShiftSelected_Up();
        }

        private void GroupboxDisjointedLimbs_VisibleChanged(object sender, EventArgs e)
        {
            if (Visible)
            {
                placeObjects();
                lbxBuild();
            }
        }

        classSprite_Limb cMasterLimb
        {
            get { return formSpriteEditor_2017.instance.cSpriteData.cAnimationData.cSprite.cCostumeInfo_Default.cLimb_Master; }
        }

        

        /// <summary>
        /// positions lbxLimbs listBox onto the panel
        /// </summary>
        void placeObjects()
        {
            lbxLimbs.Location = new Point(0, 0);
            lbxLimbs.Width = Width;
            lbxLimbs.Height = Height - lbxLimbs.Top;
        }

     
        classSprite_Limb cLimb_Selected = null;
        public classSprite_Limb Limb_Selected
        {
            get { return cLimb_Selected; }
            set
            {
                if (cLimb_Selected != value)
                {
                    //lstLimbsStart = getLimbSequence();

                    cLimb_Selected = value;
                    List<int> lstIndicesSelected = new List<int>();
                    classAnimation_Frame cFrame = cSpriteData.cAnimationData.cAnimation.lstFrames[cSpriteData.cAnimationData.intFrameIndex];
                    int intLimbIndex = cSpriteData.cCostumeInfo.lstLimbs.IndexOf(cLimb_Selected);
                    lstIndicesSelected.Add(cFrame.lstDrawSequence.IndexOf(intLimbIndex));
                    //mbpLimbs.Buttons_Select(lstIndicesSelected);
                }
            }
        }


        /// <summary>
        /// the boolean array eKeys[] manages which keys are pressed/released
        /// </summary>
        private void lbxLimbs_KeyUp(object sender, KeyEventArgs e)
        {
            switch (e.KeyCode)
            {
                case Keys.Up:
                    //eKeys[(int)enuKeys.Up] = false;
                    lbxLimbs_ShiftSelected_Up();
                    break;

                case Keys.Down:
                    //eKeys[(int)enuKeys.Down] = false;
                    lbxLimbs_ShiftSelected_Down();
                    break;

                case Keys.PageDown:
                    eKeys[(int)enuKeys.PageDown] = false;
                    break;

                case Keys.PageUp:
                    eKeys[(int)enuKeys.PageUp] = false;
                    break;

                case Keys.End:
                    eKeys[(int)enuKeys.End] = false;
                    break;

                case Keys.Home:
                    eKeys[(int)enuKeys.Home] = false;
                    break;

                default:
                    break;
            }
        }

        /// <summary>
        /// the boolean array eKeys[] manages which keys are pressed/released
        /// </summary>
        private void lbxLimbs_KeyDown(object sender, KeyEventArgs e)
        {
            e.SuppressKeyPress = true;
            switch (e.KeyCode)
            {
                case Keys.Up:
                    eKeys[(int)enuKeys.Up] = true;
                    break;

                case Keys.Down:
                    eKeys[(int)enuKeys.Down] = true;
                    break;

                case Keys.PageDown:
                    eKeys[(int)enuKeys.PageDown] = true;
                    break;

                case Keys.PageUp:
                    eKeys[(int)enuKeys.PageUp] = true;
                    break;

                case Keys.End:
                    eKeys[(int)enuKeys.End] = true;
                    break;

                case Keys.Home:
                    eKeys[(int)enuKeys.Home] = true;
                    break;

                default:
                    break;
            }
        }

        void lbxLimbs_ShiftSelected_Up()
        {
            if (cLimb_Selected != null && cLimb_Selected != cMasterLimb)
            {
                List<classSprite_Limb> lstLimbs = lstSequence;
                int intIndex = lstLimbs.IndexOf(cLimb_Selected);
                intIndex--;
                if (intIndex >= 0)
                {
                    if (intIndex < lstLimbSelected.Count)
                    {
                        lstLimbsAvailable.Remove(cLimb_Selected);
                        if (!lstLimbSelected.Contains(cLimb_Selected))
                            bolSelectedListChanged = true;
                        lstLimbSelected.Remove(cLimb_Selected);
                        lstLimbSelected.Insert(intIndex, cLimb_Selected);
                    }
                    else
                    {
                        intIndex = lstLimbsAvailable.IndexOf(cLimb_Selected);
                        lstLimbsAvailable.Remove(cLimb_Selected);
                        
                        lstLimbsAvailable.Insert(intIndex > 0 ? intIndex - 1 : 0, cLimb_Selected);
                    }
                    LimbsSelected_MasterSet();

                    lbxBuild();
                    lbxLimbs.SelectedIndex = lstSequence.IndexOf(cLimb_Selected);
                }
            }
        }

        void lbxLimbs_ShiftSelected_Down()
        {

            if (cLimb_Selected != null && cLimb_Selected != cMasterLimb)
            {
                List<classSprite_Limb> lstLimbs = lstSequence;
                int intIndex = lstLimbs.IndexOf(cLimb_Selected);
                    intIndex++;
                if (intIndex >= lstLimbSelected.Count)
                { // in the available list
                    intIndex = lstLimbsAvailable.IndexOf(cLimb_Selected) + 1;
                    lstLimbsAvailable.Remove(cLimb_Selected);
                    if (lstLimbSelected.Contains(cLimb_Selected))
                    {
                        lstLimbSelected.Remove(cLimb_Selected);
                        bolSelectedListChanged = true;
                    }
                    lstLimbsAvailable.Insert(intIndex, cLimb_Selected);
                }
                else
                { // already in the selected list
                    if (!lstLimbsAvailable.Contains(cLimb_Selected))
                        bolSelectedListChanged = true;
                    lstLimbSelected.Remove(cLimb_Selected);
                    if (intIndex < lstLimbSelected.IndexOf(cMasterLimb))
                        lstLimbSelected.Insert(intIndex, cLimb_Selected);
                    else
                        lstLimbsAvailable.Insert(0, cLimb_Selected);
                }
                LimbsSelected_MasterSet();
                lbxBuild();

                lbxLimbs.SelectedIndex = lstSequence.IndexOf(cLimb_Selected);
            }
        }


        /// <summary>
        /// triggered by keyPress or MouseClick timer moves selected items according to the UI input
        /// </summary>
        private void TmrKeyDown_Service_Tick(object sender, EventArgs e)
        {
            bool bolRefreshImage = false;
            if (eKeys[(int)enuKeys.Up])
            {
                lbxLimbs_ShiftSelected_Up();
                bolRefreshImage = true;
            }
            if (eKeys[(int)enuKeys.Down])
            {
                lbxLimbs_ShiftSelected_Down();
                bolRefreshImage = true;
            }

            if (false && MouseButtons == MouseButtons.Right)
            {
                /*
                int intStep = mbpLimbs.Font.Height;
                int intDelta = ptMouse.Y - ptMouseDown.Y;
                do
                {
                    if (intDelta < -intStep)
                    {
                        lbxLimbs_ShiftSelected_Up();
                        bolRefreshImage = true;
                        ptMouseDown.Y -= intStep;
                    }
                    else if (intDelta > intStep)
                    {
                        lbxLimbs_ShiftSelected_Down();
                        bolRefreshImage = true;
                        ptMouseDown.Y += intStep;
                    }
                    intDelta = ptMouse.Y - ptMouseDown.Y;
                } while (Math.Abs(intDelta) > intStep);
                */
            }

            if (bolRefreshImage)
            {
                /*
                classAnimation cAnimation = formSpriteEditor_2017.instance.cSpriteData.cAnimationData.cAnimation;
                classAnimation_Frame cFrame = cAnimation.lstFrames[cSpriteData.cAnimationData.intFrameIndex];
                cFrame.lstDrawSequence.Clear();
                for (int intItemCounter = 0; intItemCounter < mbpLimbs.cMap.lstElements.Count; intItemCounter++)
                {
                    classMultiButtonPic.classButton cButton = (classMultiButtonPic.classButton)mbpLimbs.cMap.lstElements[intItemCounter].obj;
                    if (string.Compare((cButton.Text), classSprite.conDrawSequenceDoNotDraw) == 0)
                    { // stop drawing at null-limb
                        cFrame.lstDrawSequence.Add(-1);
                    }
                    else
                    {
                        classSprite_Limb cLimb = (classSprite_Limb)cSpriteData.cAnimationData.cSprite.cCostumeInfo_Default.cBT_Limbs.Search(cButton.Text);
                        int intLimbIndex = cSpriteData.cAnimationData.cSprite.cCostumeInfo_Default.lstLimbs.IndexOf(cLimb);
                        cFrame.lstDrawSequence.Add(intLimbIndex);
                    }
                }
                formSpriteEditor_2017.instance.Draw_Sprite();
                */
            }
        }
    }
}
