using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using VisimBox.Renderer;
using VisiMath;

namespace VisimBuilder
{
    public partial class LightEdit : UserControl
    {
        protected ColorByte OrigoAmbient, OrigoDiffuse, OrigoSpecular;
        protected Vector3 OrigoPos, OrigoDir, OrigoAtt;
        protected float OrigoAngle, OrigoIntensity;
        protected float OrigoRadius;
        protected LightTypes OrigoType;
        protected string OrigoName;
        
        public LightEdit()
        {
            InitializeComponent();
        }

        #region properties

        protected bool _EnableLightTypeChange = true, _EnablePosAndDir = true, _DirectChange = false;
        protected LightTypes _SelectedLightType = LightTypes.Directional;

        protected ILight _AttachedLight = null;

        public enum LightParameter{Type, Position, Direction, Color, Spot, Attenuation, Other};

        public delegate void LightParameterChanged(LightParameter param);

        public event LightParameterChanged LightChanged;

        /// <summary>
        /// Attached light object
        /// </summary>
        public ILight AttachedLight
        {
            get { return _AttachedLight; }
            set
            {
                _AttachedLight = value;
                UpdateFromLight();
            }
        }

        /// <summary>
        /// Enable changing of light type?
        /// </summary>
        public bool EnableLightTypeChange
        {
            get
            {
                return _EnableLightTypeChange;
            }
            set
            {
                _EnableLightTypeChange = value;
                EnableType();
            }
        }

        /// <summary>
        /// Enable changing of position and direction?
        /// </summary>
        public bool EnablePosAndDir
        {
            get { return _EnablePosAndDir; }
            set
            {
                _EnablePosAndDir = value;
                EnableFromType(_SelectedLightType);
            }
        }

        /// <summary>
        /// Selected light type
        /// </summary>
        public LightTypes SelectedLightType
        {
            get { return _SelectedLightType; }
            set
            {
                _SelectedLightType = value;
                EnableFromType(value);
            }
        }

        /// <summary>
        /// Position of the light
        /// </summary>
        public Vector3 Position
        {
            get
            {
                return vectorEditingPos.EditedVector;
            }

            set
            {
                vectorEditingPos.EditedVector = value;
            }
        }

        /// <summary>
        /// Direction of the light
        /// </summary>
        public Vector3 Direction
        {
            get
            {
                return vectorEditingDir.EditedVector;
            }

            set
            {
                vectorEditingDir.EditedVector = value;
            }
        }

        public Vector3 Attenuation
        {
            get
            {
                return vectorEditingAtt.EditedVector;
            }

            set
            {
                vectorEditingAtt.EditedVector = value;
            }
        }

        /// <summary>
        /// Enable direct changes to attached light?
        /// </summary>
        public bool EnableDirectChange
        {
            get
            {
                return _DirectChange;
            }

            set
            {
                _DirectChange = value;  //update changes?
            }
        }

        public float SpotIntensity
        {
            get
            {
                return (float)numericUpDownIntensity.Value;
            }
            set
            {
                numericUpDownIntensity.Value = (decimal)value;
            }
        }

        public float SpotAngle
        {
            get
            {
                return (float)numericUpDownAngle.Value;
            }
            set
            {
                numericUpDownAngle.Value = (decimal)value;
            }
        }

        public float ActiveRadius
        {
            get
            {
                return (float)numericUpDownRadius.Value;
            }
            set
            {
                numericUpDownRadius.Value = (decimal)value;
            }
        }

        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public ColorByte AmbientLight
        {
            get { return colorEditingAmbient.EditedColor; }
            set { colorEditingAmbient.EditedColor = value; }
        }

        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public ColorByte DiffuseLight
        {
            get { return colorEditingDiffuse.EditedColor; }
            set { colorEditingDiffuse.EditedColor = value; }
        }

        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public ColorByte SpecularLight
        {
            get { return colorEditingSpecular.EditedColor; }
            set { colorEditingSpecular.EditedColor = value; }
        }


        #endregion


        private void GetOrigoFromLight()
        {
            if (_AttachedLight == null)
                return;

            OrigoAmbient = _AttachedLight.Ambient;
            OrigoDiffuse = _AttachedLight.Diffuse;
            OrigoSpecular = _AttachedLight.Specular;
            OrigoPos = _AttachedLight.Position;
            OrigoDir = _AttachedLight.Direction;
            OrigoType = _AttachedLight.LightType;
            OrigoName = _AttachedLight.Name;
            OrigoRadius = _AttachedLight.Radius;
            OrigoIntensity = _AttachedLight.SpotIntensity;
            OrigoAngle = _AttachedLight.SpotAngle;
        }

        private void SaveLightFromOrigo()
        {
            if (_AttachedLight == null)
                return;

            _AttachedLight.Ambient = OrigoAmbient;
            _AttachedLight.Diffuse = OrigoDiffuse;
            _AttachedLight.Specular = OrigoSpecular;
            if (_EnablePosAndDir)
            {
                _AttachedLight.Position = OrigoPos;
                _AttachedLight.Direction = OrigoDir;
            }
            _AttachedLight.LightType = OrigoType;
            _AttachedLight.Name = OrigoName;
            _AttachedLight.Radius = OrigoRadius;
            _AttachedLight.SpotIntensity = OrigoIntensity;
            _AttachedLight.SpotAngle = OrigoAngle;
        }

        private void UpdateFromOrigo()
        {
            colorEditingAmbient.EditedColor = OrigoAmbient;
            colorEditingDiffuse.EditedColor = OrigoDiffuse;
            colorEditingSpecular.EditedColor = OrigoSpecular;
            if (_EnablePosAndDir)
            {
                vectorEditingPos.EditedVector = OrigoPos;
                vectorEditingDir.EditedVector = OrigoDir;
            }
            vectorEditingAtt.EditedVector = OrigoAtt;
            numericUpDownAngle.Value = (decimal)OrigoAngle;
            numericUpDownIntensity.Value = (decimal)OrigoIntensity;
            numericUpDownRadius.Value = (decimal)OrigoRadius;
            SelectedLightType = OrigoType;
        }


        private void SaveOrigoFromData()
        {
            OrigoAmbient = colorEditingAmbient.EditedColor;
            OrigoDiffuse = colorEditingDiffuse.EditedColor;
            OrigoSpecular = colorEditingSpecular.EditedColor;
            OrigoPos = vectorEditingPos.EditedVector;
            OrigoDir = vectorEditingDir.EditedVector;
            OrigoAtt = vectorEditingAtt.EditedVector;
            OrigoAngle = (float)numericUpDownAngle.Value;
            OrigoIntensity = (float)numericUpDownIntensity.Value;
            OrigoRadius = (float)numericUpDownRadius.Value;
            OrigoType = SelectedLightType;
        }

        private void UpdateFromLight()
        {
            if (_AttachedLight == null)
            {
                buttonRefresh.Enabled = false;
                buttonSave.Enabled = false;
                return;
            }

            GetOrigoFromLight();

            buttonRefresh.Enabled = true;
            buttonSave.Enabled = true;

            textBoxName.Text = _AttachedLight.Name;


            _SelectedLightType = _AttachedLight.LightType;

            EnableFromType(_SelectedLightType);

            //update all values
            colorEditingAmbient.EditedColor = _AttachedLight.Ambient;
            colorEditingSpecular.EditedColor = _AttachedLight.Specular;
            colorEditingDiffuse.EditedColor = _AttachedLight.Diffuse;
            vectorEditingPos.EditedVector = _AttachedLight.Position;
            vectorEditingDir.EditedVector = _AttachedLight.Direction;
            vectorEditingAtt.EditedVector = _AttachedLight.Attenuation;
            float angle = _AttachedLight.SpotAngle;
            MathTools.Clamp(ref angle, 0, 180);
            float intensity = _AttachedLight.SpotIntensity;
            MathTools.Clamp(ref intensity, 0, 128);
            numericUpDownAngle.Value = (decimal)angle;
            numericUpDownIntensity.Value = (decimal)intensity;

            /*
            switch (_SelectedLightType)
            {
                case LightTypes.Ambient:
                    //ambient value only
                    colorEditingAmbient.EditedColor = _AttachedLight.Ambient;
                    break;
                case LightTypes.Directional:
                    colorEditingAmbient.EditedColor = _AttachedLight.Ambient;
                    colorEditingSpecular.EditedColor = _AttachedLight.Specular;
                    colorEditingDiffuse.EditedColor = _AttachedLight.Diffuse;
                    vectorEditingDir.EditedVector = _AttachedLight.Direction;
                    break;
                case LightTypes.Position:
                    colorEditingAmbient.EditedColor = _AttachedLight.Ambient;
                    colorEditingSpecular.EditedColor = _AttachedLight.Specular;
                    colorEditingDiffuse.EditedColor = _AttachedLight.Diffuse;
                    vectorEditingPos.EditedVector = _AttachedLight.Position;
                    vectorEditingAtt.EditedVector = _AttachedLight.Attenuation;
                    break;
                case LightTypes.Spot:
                    colorEditingAmbient.EditedColor = _AttachedLight.Ambient;
                    colorEditingSpecular.EditedColor = _AttachedLight.Specular;
                    colorEditingDiffuse.EditedColor = _AttachedLight.Diffuse;
                    vectorEditingPos.EditedVector = _AttachedLight.Position;
                    vectorEditingDir.EditedVector = _AttachedLight.Direction;
                    vectorEditingAtt.EditedVector = _AttachedLight.Attenuation;
                    numericUpDownAngle.Value = (decimal)_AttachedLight.SpotAngle;
                    numericUpDownIntensity.Value = (decimal)_AttachedLight.SpotIntensity;
                    break;
            }*/
        }

        private void EnableType()
        {
            radioButtonAmb.Enabled = radioButtonCone.Enabled = radioButtonDir.Enabled = radioButtonPoint.Enabled = _EnableLightTypeChange;
        }

        private void LightEdit_Load(object sender, EventArgs e)
        {
            EnableFromType(GetTypeFromRadio());
            buttonRefresh.Enabled = false;
            buttonSave.Enabled = false;
            vectorEditingDir.EditedVector = new Vector3(0, 0, -1);
            vectorEditingAtt.EditedVector = new Vector3(1, 0, 0);
        }

        private void ColorsChanged(ColorEditing sender, VisiMath.ColorByte newcolor)
        {
            //colors changed
            if ((_AttachedLight != null) && (_DirectChange))
            {
                //directly apply light change to light

                if (sender == colorEditingAmbient)
                {
                    _AttachedLight.Ambient = newcolor;
                }
                else if (sender == colorEditingDiffuse)
                {
                    _AttachedLight.Diffuse = newcolor;
                }
                else if (sender == colorEditingSpecular)
                {
                    _AttachedLight.Specular = newcolor;
                }                
            }

            if (LightChanged != null)
                LightChanged(LightParameter.Color);
        }

        LightTypes GetTypeFromRadio()
        {
            if (radioButtonCone.Checked)
                return LightTypes.Spot;
            if (radioButtonDir.Checked)
                return LightTypes.Directional;
            if (radioButtonPoint.Checked)
                return LightTypes.Position;
            return LightTypes.Ambient;
        }

        void EnableFromType(LightTypes ltype)
        {            
            switch (ltype)
            {
                case LightTypes.Ambient:
                    colorEditingDiffuse.Enabled = false;
                    colorEditingSpecular.Enabled = false;
                    vectorEditingDir.Enabled = false;
                    vectorEditingPos.Enabled = false;
                    numericUpDownAngle.Enabled = false;
                    numericUpDownIntensity.Enabled = false;
                    vectorEditingAtt.Enabled = false;
                    break;
                case LightTypes.Directional:
                    colorEditingDiffuse.Enabled = true;
                    colorEditingSpecular.Enabled = true;
                    vectorEditingDir.Enabled = _EnablePosAndDir;
                    vectorEditingPos.Enabled = false;
                    numericUpDownAngle.Enabled = false;
                    numericUpDownIntensity.Enabled = false;
                    vectorEditingAtt.Enabled = false;
                    break;
                case LightTypes.Position:
                    colorEditingDiffuse.Enabled = true;
                    colorEditingSpecular.Enabled = true;
                    vectorEditingDir.Enabled = false;
                    vectorEditingPos.Enabled = _EnablePosAndDir;
                    numericUpDownAngle.Enabled = false;
                    numericUpDownIntensity.Enabled = false;
                    vectorEditingAtt.Enabled = true;
                    break;
                case LightTypes.Spot:
                    colorEditingDiffuse.Enabled = true;
                    colorEditingSpecular.Enabled = true;
                    vectorEditingDir.Enabled = _EnablePosAndDir;
                    vectorEditingPos.Enabled = _EnablePosAndDir;
                    numericUpDownAngle.Enabled = true;
                    numericUpDownIntensity.Enabled = true;
                    vectorEditingAtt.Enabled = true;
                    break;
            }

        }

        private void LTypeChanged(object sender, EventArgs e)
        {
            SelectedLightType = GetTypeFromRadio();

            if ((_AttachedLight != null) && (_DirectChange))
            {
                _AttachedLight.LightType = _SelectedLightType;
            }

            if (LightChanged != null)
                LightChanged(LightParameter.Type);

        }

        private void PositionVectorChanged(VectorEditing sender, VisiMath.Vector3 newvalue)
        {
            //position vector changed
            if ((_AttachedLight != null) && (_DirectChange))
            {
                _AttachedLight.Position = newvalue;
            }
            if (LightChanged != null)
                LightChanged(LightParameter.Position);


        }

        private void RotationVectorChanged(VectorEditing sender, VisiMath.Vector3 newvalue)
        {
            //rotation vector changed
            if ((_AttachedLight != null) && (_DirectChange))
            {
                _AttachedLight.Direction = newvalue;
            }
            if (LightChanged != null)
                LightChanged(LightParameter.Direction);

        }

        private void AngleChanged(object sender, EventArgs e)
        {
            if ((_AttachedLight != null) && (_DirectChange))
            {
                _AttachedLight.SpotAngle = (float)numericUpDownAngle.Value;
            }
            if (LightChanged != null)
                LightChanged(LightParameter.Spot);


        }

        private void IntensityChanged(object sender, EventArgs e)
        {
            if ((_AttachedLight != null) && (_DirectChange))
            {
                _AttachedLight.SpotIntensity = (float)numericUpDownIntensity.Value;
            }
            if (LightChanged != null)
                LightChanged(LightParameter.Spot);

        }

        private void AttenuationChanged(VectorEditing sender, Vector3 newvalue)
        {
            if ((_AttachedLight != null) && (_DirectChange))
            {
                _AttachedLight.Attenuation = newvalue;
            }
            if (LightChanged != null)
                LightChanged(LightParameter.Other);
        }

        private void buttonSave_Click(object sender, EventArgs e)
        {
            SaveOrigoFromData();
            if (!_DirectChange)
                SaveLightFromOrigo();
        }

        private void buttonRefresh_Click(object sender, EventArgs e)
        {
            if (_AttachedLight != null)
                UpdateFromLight();
        }

        private void buttonReset_Click(object sender, EventArgs e)
        {
            UpdateFromOrigo();
            if (_DirectChange)
                SaveLightFromOrigo();
        }

        private void buttonActiveArea_Click(object sender, EventArgs e)
        {
            MessageBox.Show("Changing active area directly in light is disabled, used Active area setting in LightNode Editor");
        }

        private void ActiveAreaTypeChanged(object sender, EventArgs e)
        {
            //active area
        }

        private void RadiusValueChanged(object sender, EventArgs e)
        {
            if (_DirectChange && _AttachedLight != null)
                _AttachedLight.Radius = ActiveRadius;
            if (LightChanged != null)
                LightChanged(LightParameter.Other);
        }
    }
}
