using CodeWalker.GameFiles;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace CodeWalker.Project.Panels
{
    public partial class EditYbnBoundPolyPanel : ProjectPanel
    {
        public ProjectForm ProjectForm;
        public BoundPolygon CollisionPoly { get; set; }
        public BoundPolygonTriangle CollisionTriangle { get; set; }
        public BoundPolygonSphere CollisionSphere { get; set; }
        public BoundPolygonCapsule CollisionCapsule { get; set; }
        public BoundPolygonBox CollisionBox { get; set; }
        public BoundPolygonCylinder CollisionCylinder { get; set; }

        private bool populatingui = false;
        private bool waschanged = false;

        public EditYbnBoundPolyPanel(ProjectForm projectForm)
        {
            ProjectForm = projectForm;
            InitializeComponent();

            LoadDropDowns();
        }

        private void LoadDropDowns()
        {
            MatTypeCombo.Items.Clear();
            if (BoundsMaterialTypes.Materials == null) return;
            foreach (var mat in BoundsMaterialTypes.Materials)
            {
                MatTypeCombo.Items.Add(mat);
            }
        }

        public void SetCollisionPoly(BoundPolygon b)
        {
            CollisionPoly = b;
            CollisionTriangle = b as BoundPolygonTriangle;
            CollisionSphere = b as BoundPolygonSphere;
            CollisionCapsule = b as BoundPolygonCapsule;
            CollisionBox = b as BoundPolygonBox;
            CollisionCylinder = b as BoundPolygonCylinder;
            Tag = b;
            UpdateFormTitle();
            UpdateUI();
            waschanged = b?.Owner?.HasChanged ?? false;
        }

        public void UpdateFormTitleYbnChanged()
        {
            bool changed = CollisionPoly?.Owner?.HasChanged ?? false;
            if (!waschanged && changed)
            {
                UpdateFormTitle();
                waschanged = true;
            }
            else if (waschanged && !changed)
            {
                UpdateFormTitle();
                waschanged = false;
            }
        }
        private void UpdateFormTitle()
        {
            string fn = CollisionPoly?.Title ?? "untitled";
            Text = fn + ((CollisionPoly?.Owner?.HasChanged ?? false) ? "*" : "");
        }


        public void UpdateUI()
        {
            if (CollisionPoly == null)
            {
                AddToProjectButton.Enabled = false;
                DeleteButton.Enabled = false;
                PolyTabControl.TabPages.Clear();
                TriVertex1TextBox.Text = string.Empty;
                TriVertex2TextBox.Text = string.Empty;
                TriVertex3TextBox.Text = string.Empty;
                TriFlag1CheckBox.Checked = false;
                TriFlag2CheckBox.Checked = false;
                TriFlag3CheckBox.Checked = false;
                SphPositionTextBox.Text = string.Empty;
                SphRadiusTextBox.Text = string.Empty;
                CapVertex1TextBox.Text = string.Empty;
                CapVertex2TextBox.Text = string.Empty;
                CapRadiusTextBox.Text = string.Empty;
                BoxVertex1TextBox.Text = string.Empty;
                BoxVertex2TextBox.Text = string.Empty;
                BoxVertex3TextBox.Text = string.Empty;
                BoxVertex4TextBox.Text = string.Empty;
                CylVertex1TextBox.Text = string.Empty;
                CylVertex2TextBox.Text = string.Empty;
                CylRadiusTextBox.Text = string.Empty;
                MatTypeCombo.Text = string.Empty;
                MatColourUpDown.Value = 0;
                MatProceduralIDUpDown.Value = 0;
                MatRoomIDUpDown.Value = 0;
                MatPedDensityUpDown.Value = 0;
                MatUnkUpDown.Value = 0;
                SetCheckedListBoxValues(MatFlagsCheckedListBox, 0);
            }
            else
            {
                populatingui = true;

                if (CollisionTriangle != null)
                {
                    TriVertex1TextBox.Text = FloatUtil.GetVector3String(CollisionTriangle.Vertex1);
                    TriVertex2TextBox.Text = FloatUtil.GetVector3String(CollisionTriangle.Vertex2);
                    TriVertex3TextBox.Text = FloatUtil.GetVector3String(CollisionTriangle.Vertex3);
                    TriFlag1CheckBox.Checked = CollisionTriangle.vertFlag1;
                    TriFlag2CheckBox.Checked = CollisionTriangle.vertFlag2;
                    TriFlag3CheckBox.Checked = CollisionTriangle.vertFlag3;
                    if (!PolyTabControl.TabPages.Contains(TriangleTabPage)) PolyTabControl.TabPages.Add(TriangleTabPage);
                }
                else
                {
                    PolyTabControl.TabPages.Remove(TriangleTabPage);
                }

                if (CollisionSphere != null)
                {
                    SphPositionTextBox.Text = FloatUtil.GetVector3String(CollisionSphere.Position);
                    SphRadiusTextBox.Text = FloatUtil.ToString(CollisionSphere.sphereRadius);
                    if (!PolyTabControl.TabPages.Contains(SphereTabPage)) PolyTabControl.TabPages.Add(SphereTabPage);
                }
                else
                {
                    PolyTabControl.TabPages.Remove(SphereTabPage);
                }

                if (CollisionCapsule != null)
                {
                    CapVertex1TextBox.Text = FloatUtil.GetVector3String(CollisionCapsule.Vertex1);
                    CapVertex2TextBox.Text = FloatUtil.GetVector3String(CollisionCapsule.Vertex2);
                    CapRadiusTextBox.Text = FloatUtil.ToString(CollisionCapsule.capsuleRadius);
                    if (!PolyTabControl.TabPages.Contains(CapsuleTabPage)) PolyTabControl.TabPages.Add(CapsuleTabPage);
                }
                else
                {
                    PolyTabControl.TabPages.Remove(CapsuleTabPage);
                }

                if (CollisionBox != null)
                {
                    BoxVertex1TextBox.Text = FloatUtil.GetVector3String(CollisionBox.Vertex1);
                    BoxVertex2TextBox.Text = FloatUtil.GetVector3String(CollisionBox.Vertex2);
                    BoxVertex3TextBox.Text = FloatUtil.GetVector3String(CollisionBox.Vertex3);
                    BoxVertex4TextBox.Text = FloatUtil.GetVector3String(CollisionBox.Vertex4);
                    if (!PolyTabControl.TabPages.Contains(BoxTabPage)) PolyTabControl.TabPages.Add(BoxTabPage);
                }
                else
                {
                    PolyTabControl.TabPages.Remove(BoxTabPage);
                }

                if (CollisionCylinder != null)
                {
                    CylVertex1TextBox.Text = FloatUtil.GetVector3String(CollisionCylinder.Vertex1);
                    CylVertex2TextBox.Text = FloatUtil.GetVector3String(CollisionCylinder.Vertex2);
                    CylRadiusTextBox.Text = FloatUtil.ToString(CollisionCylinder.cylinderRadius);
                    if (!PolyTabControl.TabPages.Contains(CylinderTabPage)) PolyTabControl.TabPages.Add(CylinderTabPage);
                }
                else
                {
                    PolyTabControl.TabPages.Remove(CylinderTabPage);
                }

                var m = CollisionPoly.Material;
                MatTypeCombo.SelectedIndex = m.Type.Index;
                MatColourUpDown.Value = m.MaterialColorIndex;
                MatProceduralIDUpDown.Value = m.ProceduralId;
                MatRoomIDUpDown.Value = m.RoomId;
                MatPedDensityUpDown.Value = m.PedDensity;
                MatUnkUpDown.Value = m.Unk4;
                SetCheckedListBoxValues(MatFlagsCheckedListBox, (ushort)m.Flags);

                var ybn = CollisionPoly.Owner?.GetRootYbn();
                AddToProjectButton.Enabled = (ybn != null) ? !ProjectForm.YbnExistsInProject(ybn) : false;
                DeleteButton.Enabled = !AddToProjectButton.Enabled;

                populatingui = false;
            }
        }

        private void SetCheckedListBoxValues(CheckedListBox clb, uint flags)
        {
            for (int i = 0; i < clb.Items.Count; i++)
            {
                var c = ((flags & (1 << i)) > 0);
                clb.SetItemCheckState(i, c ? CheckState.Checked : CheckState.Unchecked);
            }
        }
        private uint GetCheckedListBoxValues(CheckedListBox clb, ItemCheckEventArgs e)
        {
            uint r = 0;
            for (int i = 0; i < clb.Items.Count; i++)
            {
                if ((e != null) && (e.Index == i))
                {
                    if (e.NewValue == CheckState.Checked)
                    {
                        r += (uint)(1 << i);
                    }
                }
                else
                {
                    bool v = clb.GetItemChecked(i);// == CheckState.Checked;
                    r = BitUtil.UpdateBit(r, i, v);
                }
            }
            return r;
        }


        private void UpdatePolyMaterial(BoundMaterial_s mat)
        {
            if (CollisionPoly == null) return;
            var shared = UpdateSharedMaterialCheckBox.Checked && (CollisionPoly.Owner != null);
            lock (ProjectForm.ProjectSyncRoot)
            {
                if (shared)
                {
                    CollisionPoly.Owner.SetMaterial(CollisionPoly.Index, mat);
                }
                else
                {
                    CollisionPoly.Material = mat;
                }
                ProjectForm.SetYbnHasChanged(true);
            }
            if ((ProjectForm.WorldForm != null) && (CollisionPoly.Owner != null))
            {
                ProjectForm.WorldForm.UpdateCollisionBoundsGraphics(CollisionPoly.Owner);
            }
        }



        private void TriVertex1TextBox_TextChanged(object sender, EventArgs e)
        {
            if (CollisionTriangle == null) return;
            if (populatingui) return;
            var v = FloatUtil.ParseVector3String(TriVertex1TextBox.Text);
            lock (ProjectForm.ProjectSyncRoot)
            {
                if (CollisionTriangle.Vertex1 != v)
                {
                    CollisionTriangle.Vertex1 = v;
                    ProjectForm.SetYbnHasChanged(true);
                }
            }
        }

        private void TriVertex2TextBox_TextChanged(object sender, EventArgs e)
        {
            if (CollisionTriangle == null) return;
            if (populatingui) return;
            var v = FloatUtil.ParseVector3String(TriVertex2TextBox.Text);
            lock (ProjectForm.ProjectSyncRoot)
            {
                if (CollisionTriangle.Vertex2 != v)
                {
                    CollisionTriangle.Vertex2 = v;
                    ProjectForm.SetYbnHasChanged(true);
                }
            }
        }

        private void TriVertex3TextBox_TextChanged(object sender, EventArgs e)
        {
            if (CollisionTriangle == null) return;
            if (populatingui) return;
            var v = FloatUtil.ParseVector3String(TriVertex3TextBox.Text);
            lock (ProjectForm.ProjectSyncRoot)
            {
                if (CollisionTriangle.Vertex3 != v)
                {
                    CollisionTriangle.Vertex3 = v;
                    ProjectForm.SetYbnHasChanged(true);
                }
            }
        }

        private void TriFlag1CheckBox_CheckedChanged(object sender, EventArgs e)
        {
            if (CollisionTriangle == null) return;
            if (populatingui) return;
            var v = TriFlag1CheckBox.Checked;
            lock (ProjectForm.ProjectSyncRoot)
            {
                if (CollisionTriangle.vertFlag1 != v)
                {
                    CollisionTriangle.vertFlag1 = v;
                    ProjectForm.SetYbnHasChanged(true);
                }
            }
        }

        private void TriFlag2CheckBox_CheckedChanged(object sender, EventArgs e)
        {
            if (CollisionTriangle == null) return;
            if (populatingui) return;
            var v = TriFlag2CheckBox.Checked;
            lock (ProjectForm.ProjectSyncRoot)
            {
                if (CollisionTriangle.vertFlag2 != v)
                {
                    CollisionTriangle.vertFlag2 = v;
                    ProjectForm.SetYbnHasChanged(true);
                }
            }
        }

        private void TriFlag3CheckBox_CheckedChanged(object sender, EventArgs e)
        {
            if (CollisionTriangle == null) return;
            if (populatingui) return;
            var v = TriFlag3CheckBox.Checked;
            lock (ProjectForm.ProjectSyncRoot)
            {
                if (CollisionTriangle.vertFlag3 != v)
                {
                    CollisionTriangle.vertFlag3 = v;
                    ProjectForm.SetYbnHasChanged(true);
                }
            }
        }

        private void SphPositionTextBox_TextChanged(object sender, EventArgs e)
        {
            if (CollisionSphere == null) return;
            if (populatingui) return;
            var v = FloatUtil.ParseVector3String(SphPositionTextBox.Text);
            lock (ProjectForm.ProjectSyncRoot)
            {
                if (CollisionSphere.Position != v)
                {
                    CollisionSphere.Position = v;
                    ProjectForm.SetYbnHasChanged(true);
                }
            }
        }

        private void SphRadiusTextBox_TextChanged(object sender, EventArgs e)
        {
            if (CollisionSphere == null) return;
            if (populatingui) return;
            var v = FloatUtil.Parse(SphRadiusTextBox.Text);
            lock (ProjectForm.ProjectSyncRoot)
            {
                if (CollisionSphere.sphereRadius != v)
                {
                    CollisionSphere.sphereRadius = v;
                    ProjectForm.SetYbnHasChanged(true);
                }
            }
        }

        private void CapVertex1TextBox_TextChanged(object sender, EventArgs e)
        {
            if (CollisionCapsule == null) return;
            if (populatingui) return;
            var v = FloatUtil.ParseVector3String(CapVertex1TextBox.Text);
            lock (ProjectForm.ProjectSyncRoot)
            {
                if (CollisionCapsule.Vertex1 != v)
                {
                    CollisionCapsule.Vertex1 = v;
                    ProjectForm.SetYbnHasChanged(true);
                }
            }
        }

        private void CapVertex2TextBox_TextChanged(object sender, EventArgs e)
        {
            if (CollisionCapsule == null) return;
            if (populatingui) return;
            var v = FloatUtil.ParseVector3String(CapVertex2TextBox.Text);
            lock (ProjectForm.ProjectSyncRoot)
            {
                if (CollisionCapsule.Vertex2 != v)
                {
                    CollisionCapsule.Vertex2 = v;
                    ProjectForm.SetYbnHasChanged(true);
                }
            }
        }

        private void CapRadiusTextBox_TextChanged(object sender, EventArgs e)
        {
            if (CollisionCapsule == null) return;
            if (populatingui) return;
            var v = FloatUtil.Parse(CapRadiusTextBox.Text);
            lock (ProjectForm.ProjectSyncRoot)
            {
                if (CollisionCapsule.capsuleRadius != v)
                {
                    CollisionCapsule.capsuleRadius = v;
                    ProjectForm.SetYbnHasChanged(true);
                }
            }
        }

        private void BoxVertex1TextBox_TextChanged(object sender, EventArgs e)
        {
            if (CollisionBox == null) return;
            if (populatingui) return;
            var v = FloatUtil.ParseVector3String(BoxVertex1TextBox.Text);
            lock (ProjectForm.ProjectSyncRoot)
            {
                if (CollisionBox.Vertex1 != v)
                {
                    CollisionBox.Vertex1 = v;
                    ProjectForm.SetYbnHasChanged(true);
                }
            }
        }

        private void BoxVertex2TextBox_TextChanged(object sender, EventArgs e)
        {
            if (CollisionBox == null) return;
            if (populatingui) return;
            var v = FloatUtil.ParseVector3String(BoxVertex2TextBox.Text);
            lock (ProjectForm.ProjectSyncRoot)
            {
                if (CollisionBox.Vertex2 != v)
                {
                    CollisionBox.Vertex2 = v;
                    ProjectForm.SetYbnHasChanged(true);
                }
            }
        }

        private void BoxVertex3TextBox_TextChanged(object sender, EventArgs e)
        {
            if (CollisionBox == null) return;
            if (populatingui) return;
            var v = FloatUtil.ParseVector3String(BoxVertex3TextBox.Text);
            lock (ProjectForm.ProjectSyncRoot)
            {
                if (CollisionBox.Vertex3 != v)
                {
                    CollisionBox.Vertex3 = v;
                    ProjectForm.SetYbnHasChanged(true);
                }
            }
        }

        private void BoxVertex4TextBox_TextChanged(object sender, EventArgs e)
        {
            if (CollisionBox == null) return;
            if (populatingui) return;
            var v = FloatUtil.ParseVector3String(BoxVertex4TextBox.Text);
            lock (ProjectForm.ProjectSyncRoot)
            {
                if (CollisionBox.Vertex4 != v)
                {
                    CollisionBox.Vertex4 = v;
                    ProjectForm.SetYbnHasChanged(true);
                }
            }
        }

        private void CylVertex1TextBox_TextChanged(object sender, EventArgs e)
        {
            if (CollisionCylinder == null) return;
            if (populatingui) return;
            var v = FloatUtil.ParseVector3String(CylVertex1TextBox.Text);
            lock (ProjectForm.ProjectSyncRoot)
            {
                if (CollisionCylinder.Vertex1 != v)
                {
                    CollisionCylinder.Vertex1 = v;
                    ProjectForm.SetYbnHasChanged(true);
                }
            }
        }

        private void CylVertex2TextBox_TextChanged(object sender, EventArgs e)
        {
            if (CollisionCylinder == null) return;
            if (populatingui) return;
            var v = FloatUtil.ParseVector3String(CylVertex2TextBox.Text);
            lock (ProjectForm.ProjectSyncRoot)
            {
                if (CollisionCylinder.Vertex2 != v)
                {
                    CollisionCylinder.Vertex2 = v;
                    ProjectForm.SetYbnHasChanged(true);
                }
            }
        }

        private void CylRadiusTextBox_TextChanged(object sender, EventArgs e)
        {
            if (CollisionCylinder == null) return;
            if (populatingui) return;
            var v = FloatUtil.Parse(CylRadiusTextBox.Text);
            lock (ProjectForm.ProjectSyncRoot)
            {
                if (CollisionCylinder.cylinderRadius != v)
                {
                    CollisionCylinder.cylinderRadius = v;
                    ProjectForm.SetYbnHasChanged(true);
                }
            }
        }

        private void MatTypeCombo_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (CollisionPoly == null) return;
            if (populatingui) return;
            var mat = CollisionPoly.Material;
            var v = (byte)MatTypeCombo.SelectedIndex;
            if (mat.Type != v)
            {
                mat.Type = v;
                UpdatePolyMaterial(mat);
            }
        }

        private void MatColourUpDown_ValueChanged(object sender, EventArgs e)
        {
            if (CollisionPoly == null) return;
            if (populatingui) return;
            var mat = CollisionPoly.Material;
            var v = (byte)MatColourUpDown.Value;
            if (mat.MaterialColorIndex != v)
            {
                mat.MaterialColorIndex = v;
                UpdatePolyMaterial(mat);
            }
        }

        private void MatProceduralIDUpDown_ValueChanged(object sender, EventArgs e)
        {
            if (CollisionPoly == null) return;
            if (populatingui) return;
            var mat = CollisionPoly.Material;
            var v = (byte)MatProceduralIDUpDown.Value;
            if (mat.ProceduralId != v)
            {
                mat.ProceduralId = v;
                UpdatePolyMaterial(mat);
            }
        }

        private void MatRoomIDUpDown_ValueChanged(object sender, EventArgs e)
        {
            if (CollisionPoly == null) return;
            if (populatingui) return;
            var mat = CollisionPoly.Material;
            var v = (byte)MatRoomIDUpDown.Value;
            if (mat.RoomId != v)
            {
                mat.RoomId = v;
                UpdatePolyMaterial(mat);
            }
        }

        private void MatPedDensityUpDown_ValueChanged(object sender, EventArgs e)
        {
            if (CollisionPoly == null) return;
            if (populatingui) return;
            var mat = CollisionPoly.Material;
            var v = (byte)MatPedDensityUpDown.Value;
            if (mat.PedDensity != v)
            {
                mat.PedDensity = v;
                UpdatePolyMaterial(mat);
            }
        }

        private void MatUnkUpDown_ValueChanged(object sender, EventArgs e)
        {
            if (CollisionPoly == null) return;
            if (populatingui) return;
            var mat = CollisionPoly.Material;
            var v = (ushort)MatUnkUpDown.Value;
            if (mat.Unk4 != v)
            {
                mat.Unk4 = v;
                UpdatePolyMaterial(mat);
            }
        }

        private void MatFlagsCheckedListBox_ItemCheck(object sender, ItemCheckEventArgs e)
        {
            if (CollisionPoly == null) return;
            if (populatingui) return;
            var mat = CollisionPoly.Material;
            var v = (EBoundMaterialFlags)GetCheckedListBoxValues(MatFlagsCheckedListBox, e);
            if (mat.Flags != v)
            {
                mat.Flags = v;
                UpdatePolyMaterial(mat);
            }
        }

        private void AddToProjectButton_Click(object sender, EventArgs e)
        {
            ProjectForm.SetProjectItem(CollisionPoly);
            ProjectForm.AddCollisionPolyToProject();
        }

        private void DeleteButton_Click(object sender, EventArgs e)
        {
            ProjectForm.SetProjectItem(CollisionPoly);
            ProjectForm.DeleteCollisionPoly();
        }
    }
}
