using System;
using System.Collections.Generic;
using SharpDX.Direct3D11;
using Framefield.Core.Rendering;

namespace Framefield.Core.ID7546dabe_f6cd_4e84_9e7c_dcc13f73e24c
{
    public class Class_ParallaxMapper : FXSourceCodeFunction, IFXSceneSourceCode
    {
        #region Renderer
        public class Renderer : BaseRenderer
        {
            public override void Dispose() {
                Utilities.DisposeObj(ref _normalMap);
                Utilities.DisposeObj(ref _heightMap);
                Utilities.DisposeObj(ref _irradiance);
                base.Dispose();
            }

            public ShaderResourceView NormalMap
            {
                set {
                    Utilities.DisposeObj(ref _normalMap);
                    _normalMap = value;
                }
            }

            public ShaderResourceView HeightMap
            {
                set {
                    Utilities.DisposeObj(ref _heightMap);
                    _heightMap = value;
                }
            }

            public ShaderResourceView Irradiance
            {
                set
                {
                    Utilities.DisposeObj(ref _irradiance);
                    _irradiance = value;
                }
            }
            
            public float ParallaxScale
            {
                set { _parallaxScale = value; }
            }

            public override void SetupEffect(OperatorPartContext context) {
                base.SetupEffect(context);
                var resourceVariable = context.Effect.GetVariableByName("txNormalMap").AsShaderResource();
                resourceVariable.SetResource(_normalMap);
                resourceVariable = context.Effect.GetVariableByName("heightMap").AsShaderResource();
                resourceVariable.SetResource(_heightMap);
                resourceVariable = context.Effect.GetVariableByName("irradiance").AsShaderResource();
                resourceVariable.SetResource(_irradiance);
                var scalarVariable = context.Effect.GetVariableByName("parallaxScale").AsScalar();
                scalarVariable.Set(_parallaxScale);

                try
                {
                    SetupMaterialConstBuffer(context);
                    SetupFogSettingsConstBuffer(context);
                    SetupPointLightsConstBuffer(context);
                }
                catch (Exception e) {
                    Logger.Error(ParentFunc, "Error building constant buffer: {0} - Source: {1}", e.Message, e.Source);
                }
            }

            private ShaderResourceView _normalMap;
            private ShaderResourceView _heightMap;
            private ShaderResourceView _irradiance;
            private float _parallaxScale;
            public OperatorPart.Function ParentFunc {get;set;}
        }
        #endregion

        public Class_ParallaxMapper() {
            _renderer = new Renderer(){ParentFunc = this};
        }

        public override void Dispose() {
            Utilities.DisposeObj(ref _renderer);
            Utilities.DisposeObj(ref _image);
            base.Dispose();
        }

        //>>> _inputids
        private enum InputId
        {
            Code = 0,
            Scene = 1,
            Image = 2,
            NormalMap = 3,
            Irradiance = 4,
            HeightMap = 5,
            ParallaxScale = 6
        }
        //<<< _inputids

        bool _firstEval = true;
        public override OperatorPartContext Eval(OperatorPartContext context, List<OperatorPart> inputs, int outputIdx) {
            if (_firstEval) {
                for (int i = 0; i < NumCodes(); ++i)
                    Compile(i);
                _firstEval = false;
                Changed = true;
            }

            var Scene = inputs[1];
            if (Changed) 
            {
                Utilities.DisposeObj(ref _image);
                var image = inputs[2].Eval(context).Image;
                if (image != null)
                    _image = new ShaderResourceView(context.D3DDevice, image);

                var normalMap = inputs[3].Eval(context).Image;
                if (normalMap != null)
                    _renderer.NormalMap = new ShaderResourceView(context.D3DDevice, normalMap);

                var irradiance = inputs[(int)InputId.Irradiance].Eval(context).Image;
                if (irradiance != null)
                    _renderer.Irradiance= new ShaderResourceView(context.D3DDevice, irradiance);

                var heightMap = inputs[(int)InputId.HeightMap].Eval(context).Image;
                if (heightMap != null)
                    _renderer.HeightMap = new ShaderResourceView(context.D3DDevice, heightMap);

                _renderer.ParallaxScale = inputs[(int)InputId.ParallaxScale].Eval(context).Value;

                Changed = false;
            }

            var D3DDevice = context.D3DDevice;

            using (new PropertyStasher<OperatorPartContext>(context, "Effect", "Renderer", "Texture0")) {
                context.Effect = _effect;
                context.Renderer = _renderer;
                context.Texture0 = _image;
                Scene.Eval(context);
            }

            return context;
        }

        Renderer _renderer;
        ShaderResourceView _image;
    }
}


