using System;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using GraphiXNA.Cameras;
using GraphiXNA.Utils;
using GraphiXNA.Graphics;

namespace GraphiXNA.Materials
{
    public class Lambertian : MaterialEffect
    {
        public Texture2D Texture = null;

        public Vector4 MaterialAmbient = new Vector4(0.2f, 0.2f, 0.2f, 1.0f);
        public Vector4 MaterialDiffuse = new Vector4(0.8f, 0.8f, 0.8f, 1.0f);
        public Vector4 MaterialSpecular = Vector4.Zero;
        public float MaterialShininess = 0;

        public TextureCube Environment = null;
        public float Reflectivity = 0.2f;
        public bool EnableReflection = true;

        public Vector4 LightAmbient = Vector4.One;
        public Vector4 LightDiffuse = Vector4.One;
        public Vector4 LightSpecular = Vector4.One;

        private EffectParameter parameter_LightDirection = null;
        private EffectParameter parameter_LightPosition = null;
        private EffectParameter parameter_LightAmbient = null;
        private EffectParameter parameter_LightDiffuse = null;
        private EffectParameter parameter_LightSpecular = null;
        private EffectParameter parameter_LightSpotInnerCone = null;
        private EffectParameter parameter_LightSpotOuterCone = null;
        private EffectParameter parameter_LightRadius = null;
        private EffectParameter parameter_MaterialAmbient = null;
        private EffectParameter parameter_MaterialDiffuse = null;
        private EffectParameter parameter_MaterialSpecular = null;
        private EffectParameter parameter_MaterialShininess = null;
        private EffectParameter parameter_World = null;
        private EffectParameter parameter_WorldIT = null;
        private EffectParameter parameter_WorldViewProjection = null;
        private EffectParameter parameter_CameraPosition = null;
        private EffectParameter parameter_DiffuseTexture = null;
        private EffectParameter parameter_LightType = null;
        private EffectParameter parameter_Reflectivity = null;
        private EffectParameter parameter_Environment = null;
        private EffectParameter parameter_EnableReflection = null;

        private Light _Light = new Light(new Vector3(0, -1, -1));

        public Lambertian(Texture2D diffuseTexture)
            : base(diffuseTexture.GraphicsDevice)
        {
            Texture = diffuseTexture;
            LoadContent();
        }

        public Light Light
        {
            get
            {
                return _Light;
            }
            set
            {
                if (value == null)
                {
                    throw new ArgumentNullException();
                }

                _Light = value;
            }
        }

        internal override void OnBegin()
        {
            parameter_DiffuseTexture.SetValue(Texture);

            parameter_LightAmbient.SetValue(LightAmbient);
            parameter_LightDiffuse.SetValue(LightDiffuse);
            parameter_LightSpecular.SetValue(LightSpecular);

            parameter_MaterialAmbient.SetValue(MaterialAmbient);
            parameter_MaterialDiffuse.SetValue(MaterialDiffuse);
            parameter_MaterialSpecular.SetValue(MaterialSpecular);
            parameter_MaterialShininess.SetValue(MaterialShininess);

            parameter_EnableReflection.SetValue(EnableReflection);
            parameter_Environment.SetValue(Environment);
            parameter_Reflectivity.SetValue(Reflectivity);

            parameter_LightType.SetValue((int)_Light.LightT);

            if (_Light.LightT == Light.LightType.Directional)
            {
                parameter_LightDirection.SetValue(_Light.Direction);
            }
            else if (_Light.LightT == Light.LightType.Point)
            {
                parameter_LightPosition.SetValue(_Light.Position);
                parameter_LightRadius.SetValue(_Light.Range);
            }
            else if (_Light.LightT == Light.LightType.Spot)
            {
                parameter_LightPosition.SetValue(_Light.Position);
                parameter_LightDirection.SetValue(_Light.Direction);
                parameter_LightSpotInnerCone.SetValue(_Light.SpotInnerCone);
                parameter_LightSpotOuterCone.SetValue(_Light.SpotOuterCone);
                parameter_LightRadius.SetValue(_Light.Range);
            }
            else
            {
                throw new Exception();
            }
        }

        public override void SetWorld(Camera camera, ref Matrix world)
        {
            parameter_World.SetValue(world);
            parameter_WorldViewProjection.SetValue(world * camera._ViewProjection);
            parameter_WorldIT.SetValueTranspose(Matrix.Invert(world));
            parameter_CameraPosition.SetValue(camera.Position);
         
        }

        private void LoadContent()
        {
            _Effect = ResourceManager.GetLambertianEffect(GraphicsDevice, false);

            parameter_LightDirection = _Effect.Parameters["LightDirection"];
            parameter_LightPosition = _Effect.Parameters["LightPosition"];
            parameter_LightAmbient = _Effect.Parameters["LightAmbient"];
            parameter_LightDiffuse = _Effect.Parameters["LightDiffuse"];
            parameter_LightSpecular = _Effect.Parameters["LightSpecular"];
            parameter_LightSpotInnerCone = _Effect.Parameters["LightSpotInnerCone"];
            parameter_LightSpotOuterCone = _Effect.Parameters["LightSpotOuterCone"];
            parameter_LightRadius = _Effect.Parameters["LightRange"];
            parameter_MaterialAmbient = _Effect.Parameters["MaterialAmbient"];
            parameter_MaterialDiffuse = _Effect.Parameters["MaterialDiffuse"];
            parameter_MaterialSpecular = _Effect.Parameters["MaterialSpecular"];
            parameter_MaterialShininess = _Effect.Parameters["MaterialShininess"];
            parameter_World = _Effect.Parameters["World"];
            parameter_WorldIT = _Effect.Parameters["WorldIT"];
            parameter_WorldViewProjection = _Effect.Parameters["WorldViewProjection"];
            parameter_CameraPosition = _Effect.Parameters["CameraPosition"];
            parameter_DiffuseTexture = _Effect.Parameters["DiffuseTexture"];
            parameter_LightType = _Effect.Parameters["LightType"];
            parameter_Reflectivity = _Effect.Parameters["Reflectivity"];
            parameter_Environment = _Effect.Parameters["Environment"];
            parameter_EnableReflection = _Effect.Parameters["EnableReflection"];
        }
    }
}
