using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using SharpDX;
using SharpDX.Direct3D11;
using SharpDX.DXGI;

namespace Framefield.Core.ID2f210b31_bf39_4c12_9721_f42585bdc3f1
{
    public class Class_RenderToImageNoAA : OperatorPart.Function
    {
        // >>> _inputids
        private enum InputId
        {
            Scene = 0,
            SizeX = 1,
            SizeY = 2,
            ColorR = 3,
            ColorG = 4,
            ColorB = 5,
            ColorA = 6,
            ClearBackground = 7
        }
        // <<< _inputids
        public override void Dispose() {
            ResourceManager.Dispose(_renderTargetResource);
            Utilities.DisposeObj(ref _renderTargetView);
            ResourceManager.Dispose(_renderDepthResource);
            Utilities.DisposeObj(ref _renderTargetDepthView);
        }

        private bool BuildRenderTarget(int width, int height, SharpDX.Direct3D11.Device device) {
            var renderTargetResourceChanged = ResourceManager.ValidateRenderTargetResource(ref _renderTargetResource, OperatorPart, device, width, height);
            if (renderTargetResourceChanged) {
                Utilities.DisposeObj(ref _renderTargetView);
                _renderTargetView = new RenderTargetView(device, _renderTargetResource.Texture);
            }

            var depthStencilResourceChanged = ResourceManager.ValidateDepthStencilResource(ref _renderDepthResource, OperatorPart, device, width, height);
            if (depthStencilResourceChanged) {
                Utilities.DisposeObj(ref _renderTargetDepthView);

                var depthViewDesc = new DepthStencilViewDescription();
                depthViewDesc.Format = Format.D32_Float;
                depthViewDesc.Dimension = DepthStencilViewDimension.Texture2D;

                _renderTargetDepthView = new DepthStencilView(device, _renderDepthResource.Texture, depthViewDesc);
            }

            return renderTargetResourceChanged || depthStencilResourceChanged;
        }

        public override OperatorPartContext Eval(OperatorPartContext context, List<OperatorPart> inputs, int outputIdx) {
            var Scene = inputs[0];

            int SizeX = (int) inputs[1].Eval(context).Value;
            int SizeY = (int) inputs[2].Eval(context).Value;
            float ColorR = inputs[3].Eval(context).Value;
            float ColorG = inputs[4].Eval(context).Value;
            float ColorB = inputs[5].Eval(context).Value;
            float ColorA = inputs[6].Eval(context).Value;
            bool ClearBackground = inputs[(int)InputId.ClearBackground].Eval(context).Value > 0.5f;
            int SampleCount = (int) inputs[7].Eval(context).Value;

            if (SizeX == 0 || SizeY == 0) {
                SizeX = (int) context.Viewport.Width;
                SizeY = (int) context.Viewport.Height;
            }

            if (BuildRenderTarget(SizeX, SizeY, context.D3DDevice))
                Changed = true;

            if (Changed) {
                var subContext = new OperatorPartContext(context);
                
                var D3DDevice = context.D3DDevice;

                float aspect = (float) SizeX / (float) SizeY;
                subContext.CameraProjection = Matrix.PerspectiveFovLH(3.1415f / 4.0f, aspect, 0.01f, 1000);
                subContext.WorldToCamera = Matrix.LookAtLH(new Vector3(0, 0, -2.415f), new Vector3(0, 0, 0), new Vector3(0, 1, 0));
                subContext.ObjectTWorld = Matrix.Identity;
                subContext.TextureMatrix = Matrix.Identity;
                subContext.Renderer = OperatorPartContext.DefaultRenderer;
                subContext.RenderTargetView = _renderTargetView;
                subContext.DepthStencilView = _renderTargetDepthView;
                subContext.Objects[OperatorPartContext.MATERIAL_ID] = new DefaultMaterial();

                subContext.DepthStencilState = OperatorPartContext.DefaultRenderer.DefaultDepthStencilState;
                subContext.RasterizerState = OperatorPartContext.DefaultRenderer.DefaultRasterizerState;
                subContext.BlendState = OperatorPartContext.DefaultRenderer.DefaultBlendState;
                subContext.BlendFactor = OperatorPartContext.DefaultRenderer.DefaultBlendFactor;
                subContext.Viewport = new Viewport(0, 0, SizeX, SizeY, 0.0f, 1.0f);
                
                subContext.InputLayout = OperatorPartContext.DefaultRenderer.SceneDefaultInputLayout;
                subContext.Effect = OperatorPartContext.DefaultRenderer.SceneDefaultEffect;

                D3DDevice.ImmediateContext.ClearDepthStencilView(_renderTargetDepthView, DepthStencilClearFlags.Depth | DepthStencilClearFlags.Stencil, 1.0f, 0);
                if (ClearBackground) {
                    D3DDevice.ImmediateContext.ClearRenderTargetView(_renderTargetView, new SharpDX.Color4(ColorR, ColorG, ColorB, ColorA));
                }

                Scene.Eval(subContext);

                Changed = false;
            }

            context.Image = _renderTargetResource.Texture;
            context.DepthImage = _renderDepthResource.Texture;

            return context;
        }

        Resource _renderTargetResource;
        RenderTargetView _renderTargetView;
        Resource _renderDepthResource;
        DepthStencilView _renderTargetDepthView;
    }
}

