//>>> _using
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using SharpDX;
using SharpDX.Direct3D11;
using SharpDX.Windows;
//<<< _using
using Framefield.Core;
using Framefield.Core.Rendering;
using SharpDX.D3DCompiler;

namespace Framefield.Core.ID10784262_b8dd_4af1_95db_54046d6c6972
{
    public class Class_Layer2d : OperatorPart.Function
    {
     
        //>>> _inputids
        private enum InputId
        {
            Image = 0,
            MultiplyColorR = 1,
            MultiplyColorG = 2,
            MultiplyColorB = 3,
            MultiplyColorA = 4,
            PositionX = 5,
            PositionY = 6,
            Rotate = 7,
            ScaleX = 8,
            ScaleY = 9,
            PivotX = 10,
            PivotY = 11,
            RotationMode = 12
        }
        //<<< _inputids
    
        class Renderer : BaseRenderer
        {
        }
    
        public Class_Layer2d()
        {
            try {
                using (var bytecode = ShaderBytecode.CompileFromFile("assets-common/fx/Layer2d.fx", "fx_5_0", ShaderFlags.Debug, EffectFlags.None, null, null))
                    _effect = new Effect(D3DDevice.Device, bytecode);
                    
                var rasterizerDescription = new RasterizerStateDescription
                                   {
                                       FillMode = FillMode.Solid,
                                       CullMode = CullMode.None,
                                       IsDepthClipEnabled = false
                                   };
                _bothSidedRasterizerState = new RasterizerState(D3DDevice.Device, rasterizerDescription);                    
            }
            catch (Exception e) {
                Logger.Error(this,"error loading laye2d fx: {0} ", e.Message);
            }
        }


        public override void  Dispose()
        {
            Utilities.DisposeObj(ref _effect);
            Utilities.DisposeObj(ref _renderer);
            Utilities.DisposeObj(ref _bothSidedRasterizerState);
        }
        

        public override OperatorPartContext Eval(OperatorPartContext context, List<OperatorPart> inputs, int outputIdx)
        {
        
            //>>> _params
            var Image = inputs[(int)InputId.Image].Eval(context).Image; // Needs to be checked for null!
            var MultiplyColorR = inputs[(int)InputId.MultiplyColorR].Eval(context).Value;
            var MultiplyColorG = inputs[(int)InputId.MultiplyColorG].Eval(context).Value;
            var MultiplyColorB = inputs[(int)InputId.MultiplyColorB].Eval(context).Value;
            var MultiplyColorA = inputs[(int)InputId.MultiplyColorA].Eval(context).Value;
            var MultiplyColor = new Color4(MultiplyColorR, MultiplyColorG, MultiplyColorB, MultiplyColorA);
            var PositionX = inputs[(int)InputId.PositionX].Eval(context).Value;
            var PositionY = inputs[(int)InputId.PositionY].Eval(context).Value;
            var Position = new Vector2(PositionX, PositionY);
            var Rotate = inputs[(int)InputId.Rotate].Eval(context).Value;
            var ScaleX = inputs[(int)InputId.ScaleX].Eval(context).Value;
            var ScaleY = inputs[(int)InputId.ScaleY].Eval(context).Value;
            var Scale = new Vector2(ScaleX, ScaleY);
            var PivotX = inputs[(int)InputId.PivotX].Eval(context).Value;
            var PivotY = inputs[(int)InputId.PivotY].Eval(context).Value;
            var Pivot = new Vector2(PivotX, PivotY);
            var RotationMode = (int) inputs[(int)InputId.RotationMode].Eval(context).Value;
            //<<< _params
            
            if(Image == null)
                return context;
                    
            var subContext = new OperatorPartContext(context);
            subContext.Effect = _effect;
            subContext.Renderer = _renderer;
            subContext.InputLayout = context.Renderer.ScreenQuadInputLayout;
            subContext.CameraProjection = Matrix.OrthoLH(1, 1, -100, 100);
            subContext.WorldToCamera = Matrix.LookAtLH(new Vector3(0, 0, -5), new Vector3(0, 0, 0), new Vector3(0, 1, 0));
            
            subContext.RasterizerState = _bothSidedRasterizerState;

            var pivot3 = new Vector3( Pivot.X, Pivot.Y, 0 );
            
            subContext.ObjectTWorld = Matrix.Identity;
            
            var aspectRation = RotationMode < 0.5f ? context.Viewport.AspectRatio : 1f;

            var scaleToQuad = Matrix.Scaling(aspectRation,1,1);
            subContext.ObjectTWorld *= scaleToQuad;
                       
            var translateToPivot = Matrix.Translation(-Pivot.X * aspectRation, -Pivot.Y,0);
            subContext.ObjectTWorld *= translateToPivot;
            
            var scale = Matrix.Scaling(ScaleX, ScaleY,1);
            subContext.ObjectTWorld *= scale;


            var rotate = Matrix.RotationZ(Rotate * 3.141578f / 180);
            subContext.ObjectTWorld *= rotate;


            var translateBackFromPivot = Matrix.Translation(aspectRation * Pivot.X, Pivot.Y,0);
            subContext.ObjectTWorld *= translateBackFromPivot;


            var scaleToScreen = Matrix.Scaling(1/aspectRation,1,1);
            subContext.ObjectTWorld *= scaleToScreen;

            
            var translate = Matrix.Translation(Position.X, Position.Y,0);
            subContext.ObjectTWorld *= translate;
            
            using (var textureView = new ShaderResourceView(context.D3DDevice, Image))
            {
                _effect.GetVariableByName("hasDepth").AsScalar().Set(false);
                _effect.GetVariableByName("multiplyColor").AsVector().Set(MultiplyColor);

                var depthStencilDescription = new DepthStencilStateDescription();
                depthStencilDescription.IsDepthEnabled = false;
                using (var depthStencilState = new DepthStencilState(context.D3DDevice, depthStencilDescription))
                {
                    subContext.DepthStencilState = depthStencilState;
                    subContext.Texture0 = textureView;
                    subContext.Renderer.SetupEffect(subContext);
    
                    subContext.Renderer.Render(subContext.Renderer._screenQuadMesh, subContext);
                }            
            }    

            return context;
        }

        Effect _effect;
        Renderer _renderer = new Renderer();
        private RasterizerState _bothSidedRasterizerState = null;

    }
}

