//>>> _using
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using SharpDX;
using SharpDX.Direct3D11;
using SharpDX.Windows;
//<<< _using
using SharpDX.Direct3D;
using Framefield.Core.OperatorPartTraits;
using Framefield.Core.Rendering;
using Buffer = SharpDX.Direct3D11.Buffer;

namespace Framefield.Core.ID076eed96_398d_4ad4_88e6_089af155920c
{
    public class Class_GroupMesh : FXSourceCodeFunction, IFXSceneSourceCode
    {
        //>>> _inputids
        private enum InputId
        {
            Code = 0,
            InputMeshes = 1
        }
        //<<< _inputids

        public Class_GroupMesh()
        {
        }

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

        public override OperatorPartContext Eval(OperatorPartContext context, List<OperatorPart> inputs, int outputIdx)
        {
            try
            {
                UpdateMesh(context, inputs);
                context.Mesh = _bakedMesh;
            }
            catch (Exception exception)
            {
                Logger.Error(this, "Failed: {0}", exception.Message);
            }
            return context;
        }

        bool _firstEval = true;
        private void UpdateMesh(OperatorPartContext context, List<OperatorPart> inputs)
        {
            if (_firstEval) 
            {
                for (int i = 0; i < NumCodes(); ++i)
                    Compile(i);
                _firstEval = false;
                Changed = true;
            }


            if (!Changed && _bakedMesh.Vertices != null)
                return;

            var Code = inputs[(int)InputId.Code].Eval(context).Text;
            var InputMeshes = inputs[(int)InputId.InputMeshes];
            

            if( InputMeshes.Connections.Count == 0) {
                Utilities.DisposeObj(ref _bakedMesh.Vertices);
                return;            
            }
                        
            _bakedMesh.NumTriangles = 0;
            Mesh mesh = null;
            
            var evaluatedMeshes = new List<Mesh>();
            
            foreach( var input in InputMeshes.Connections) 
            {
                mesh = input.Eval(context).Mesh;
                evaluatedMeshes.Add( mesh);
                _bakedMesh.NumTriangles += mesh.NumTriangles;
            }
            
            _bakedMesh.AttributesSize = mesh.AttributesSize;
            _bakedMesh.InputElements = mesh.InputElements;

            if (_bakedMesh.Vertices == null || _bakedMesh.Vertices.Description.SizeInBytes != mesh.Vertices.Description.SizeInBytes)
            {
                Utilities.DisposeObj(ref _bakedMesh.Vertices);
                _bakedMesh.Vertices = new Buffer(D3DDevice.Device, new BufferDescription()
                                                                  {
                                                                      BindFlags = BindFlags.StreamOutput | BindFlags.VertexBuffer,
                                                                      CpuAccessFlags = CpuAccessFlags.None,
                                                                      OptionFlags = ResourceOptionFlags.None,
                                                                      SizeInBytes = _bakedMesh.NumTriangles*_bakedMesh.AttributesSize*3,
                                                                      Usage = ResourceUsage.Default
                                                                  });
            }

            var byteOffset = 0;
            foreach( var evaluatedMesh in evaluatedMeshes) 
            {                
                //CopySubresourceRegion(Resource source, int sourceSubresource, ResourceRegion? sourceRegion, Resource destination, int destinationSubResource, int dstX = 0, int dstY = 0, int dstZ = 0);
                context.D3DDevice.ImmediateContext.CopySubresourceRegion(evaluatedMesh.Vertices, 0, null,  _bakedMesh.Vertices, 0, byteOffset);
                byteOffset += evaluatedMesh.NumTriangles * evaluatedMesh.AttributesSize * 3;
                
            }


/*
            var rotation = Quaternion.RotationYawPitchRoll(MathUtil.DegreesToRadians(RotateY),
                                                           MathUtil.DegreesToRadians(RotateX),
                                                           MathUtil.DegreesToRadians(RotateZ));

            var transform = Matrix.Transformation(Pivot, Quaternion.Zero, Scale, Pivot, rotation, Translate);

            var matrixEffectVariable = _effect.GetVariableByName("objectToWorldMatrix").AsMatrix();
            matrixEffectVariable.SetMatrix(transform);

            context.D3DDevice.ImmediateContext.OutputMerger.DepthStencilState = new DepthStencilState(context.D3DDevice,
                                                                                                        new DepthStencilStateDescription()
                                                                                                            {
                                                                                                                IsDepthEnabled = false,
                                                                                                                IsStencilEnabled = false
                                                                                                            });
            context.D3DDevice.ImmediateContext.InputAssembler.InputLayout = context.InputLayout;
            context.D3DDevice.ImmediateContext.InputAssembler.PrimitiveTopology = PrimitiveTopology.TriangleList;

            int streamOutputOffset = 0;

            context.D3DDevice.ImmediateContext.StreamOutput.SetTargets(new [] { new StreamOutputBufferBinding(_bakedMesh.Vertices, streamOutputOffset) });
            context.D3DDevice.ImmediateContext.InputAssembler.SetVertexBuffers(0, new VertexBufferBinding(inputMesh.Vertices, inputMesh.AttributesSize, 0));
            var technique = _effect.GetTechniqueByIndex(0);
            technique.GetPassByIndex(0).Apply(context.D3DDevice.ImmediateContext);
            context.D3DDevice.ImmediateContext.Draw(inputMesh.NumTriangles*3, 0);
            streamOutputOffset += inputMesh.AttributesSize*inputMesh.NumTriangles*3;

            context.D3DDevice.ImmediateContext.StreamOutput.SetTargets(new [] { new StreamOutputBufferBinding(null, 0) });
*/

            Changed = false;
        }

        private Mesh _bakedMesh = new Mesh();
    }
}


