using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework;
using GraphiXNA.Cameras;
using GraphiXNA.Graphics;

namespace GraphiXNA.Materials
{
    public class Water : MaterialEffect
    {
        EffectParameter parameter_gWorld = null;
        EffectParameter parameter_gWorldInv = null;
        EffectParameter parameter_gWVP = null;
        EffectParameter parameter_gEyePosW = null;
        EffectParameter parameter_gWaveMapOffset0 = null;
        EffectParameter parameter_gWaveMapOffset1 = null;
        EffectParameter parameter_gWaveMap0 = null;
        EffectParameter parameter_gWaveMap1 = null;
        EffectParameter parameter_gRefractBias = null;
        EffectParameter parameter_gRefractPower = null;
        EffectParameter parameter_gRippleScale = null;
        EffectParameter parameter_gReflectMap = null;
        EffectParameter parameter_gRefractMap = null;

        EffectParameter parameter_MaterialAmbient = null;
        EffectParameter parameter_MaterialDiffuse = null;
        EffectParameter parameter_MaterialSpecular = null;
        EffectParameter parameter_MaterialSpecularPower = null;
        EffectParameter parameter_LightAmbient = null;
        EffectParameter parameter_LightDiffuse = null;
        EffectParameter parameter_LightSpecular = null;
        EffectParameter parameter_LightDirection = null;


        public float RefractBias = 1.5f;
        public float RippleScale = 0;
        public float RefractPower = 0;

        public Texture2D RefractMap = null;
        public TextureCube ReflectMap = null;

        Vector2 mWaveMapOffset0 = Vector2.Zero;
        Vector2 mWaveMapOffset1 = Vector2.Zero;

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

        public Water(GraphicsDevice graphicsDevice)
            : base(graphicsDevice)
        {
            LoadContent();
        }

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

                _Light = value;
            }
        }

        public override void SetWorld(Camera camera, ref Matrix world)
        {
            parameter_gWorld.SetValue(world);
            parameter_gWorldInv.SetValue(Matrix.Invert(world));
            parameter_gWVP.SetValue(world * camera._ViewProjection);
            parameter_gEyePosW.SetValue(camera.Position);
        }

        private void LoadContent()
        {
            _Effect = ResourceManager.GetWaterEffect(GraphicsDevice, false);
            parameter_gWorld = _Effect.Parameters["gWorld"];
            parameter_gWorldInv = _Effect.Parameters["gWorldInv"];
            parameter_gWVP = _Effect.Parameters["gWVP"];
            parameter_gEyePosW = _Effect.Parameters["gEyePosW"];
            parameter_gWaveMapOffset0 = _Effect.Parameters["gWaveMapOffset0"];
            parameter_gWaveMapOffset1 = _Effect.Parameters["gWaveMapOffset1"];
            parameter_gWaveMap0 = _Effect.Parameters["gWaveMap0"];
            parameter_gWaveMap1 = _Effect.Parameters["gWaveMap1"];
            parameter_gRefractBias = _Effect.Parameters["gRefractBias"];
            parameter_gRefractPower = _Effect.Parameters["gRefractPower"];
            parameter_gRippleScale = _Effect.Parameters["gRippleScale"];
            parameter_gReflectMap = _Effect.Parameters["gReflectMap"];
            parameter_gRefractMap = _Effect.Parameters["gRefractMap"];

            parameter_MaterialAmbient = _Effect.Parameters["MaterialAmbient"];
            parameter_MaterialDiffuse = _Effect.Parameters["MaterialDiffuse"];
            parameter_MaterialSpecular = _Effect.Parameters["MaterialSpecular"];
            parameter_MaterialSpecularPower = _Effect.Parameters["MaterialSpecularPower"];
            parameter_LightAmbient = _Effect.Parameters["LightAmbient"];
            parameter_LightDiffuse = _Effect.Parameters["LightDiffuse"];
            parameter_LightSpecular = _Effect.Parameters["LightSpecular"];
            parameter_LightDirection = _Effect.Parameters["LightDirection"];

            parameter_gWaveMap0.SetValue(ResourceManager.GetNormal0Texture(GraphicsDevice));
            parameter_gWaveMap1.SetValue(ResourceManager.GetNormal1Texture(GraphicsDevice));

            RefractBias = parameter_gRefractBias.GetValueSingle();
            //RippleScale = parameter_gRippleScale.GetValueSingle();
            RefractPower = parameter_gRefractPower.GetValueSingle();

            _Light.Direction = parameter_LightDirection.GetValueVector3();
        }

        internal override void OnBegin()
        {
            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();
            }

            parameter_gReflectMap.SetValue(ReflectMap);
            parameter_gWaveMapOffset0.SetValue(mWaveMapOffset0);
            parameter_gWaveMapOffset1.SetValue(mWaveMapOffset1);
            parameter_gRefractBias.SetValue(RefractBias);
            //parameter_gRippleScale.SetValue(RippleScale);
            parameter_gRefractPower.SetValue(RefractPower);
            parameter_gRefractMap.SetValue(RefractMap);
        }

        public override void Update(GameTime gameTime)
        {
            Random rnd = new Random();
            mWaveMapOffset0 += new Vector2((float)gameTime.ElapsedGameTime.TotalMinutes / (-1 + (float)rnd.NextDouble() / 10f));
            mWaveMapOffset1 += new Vector2((float)gameTime.ElapsedGameTime.TotalMinutes * (float)rnd.NextDouble());

            // Textures repeat every 1.0 unit, so reset back down to zero
            // so the coordinates do not grow too large.
            if (mWaveMapOffset0.X >= 1.0f || mWaveMapOffset0.X <= -1.0f)
                mWaveMapOffset0.X = 0.0f;
            if (mWaveMapOffset1.X >= 1.0f || mWaveMapOffset1.X <= -1.0f)
                mWaveMapOffset1.X = 0.0f;
            if (mWaveMapOffset0.Y >= 1.0f || mWaveMapOffset0.Y <= -1.0f)
                mWaveMapOffset0.Y = 0.0f;
            if (mWaveMapOffset1.Y >= 1.0f || mWaveMapOffset1.Y <= -1.0f)
                mWaveMapOffset1.Y = 0.0f;
        }

    }
}
