using System;
using System.Collections.Generic;
using SharpDX;
using SharpDX.Direct3D11;
using Buffer = SharpDX.Direct3D11.Buffer;


namespace Framefield.Core.ID646f08f2_ee11_4de1_a6f1_f1263dddb13b
{
    public class Class_BorderRect : OperatorPart.Function
    {
        public override void Dispose() {
            Utilities.DisposeObj(ref _planeMesh);
        }

        Vector3 _normal;
        Vector4 _color;
        Vector3 _tangent;
        Vector3 _binormal;
        Vector4 _border;
        Vector2 _texture;
        Vector4 _borderTexture;
        float _height;
        float _width;
        

        // >>> _inputids
        private enum InputId
        {
            Height = 0,
            Width = 1,
            ColorA = 2,
            ColorB = 3,
            ColorG = 4,
            ColorR = 5,
            BorderTop = 6,
            BorderRight = 7,
            BorderBottom = 8,
            BorderLeft = 9,
            TextureWidth = 10,
            TextureHeight = 11,
            BorderTextureTop = 12,
            BorderTextureRight = 13,
            BorderTextureBottom = 14,
            BorderTextureLeft = 15
        }
        // <<< _inputids

        public override OperatorPartContext Eval(OperatorPartContext context, List<OperatorPart> inputs, int outputIdx) {
            // >>> _params
            var Height = inputs[(int)InputId.Height].Eval(context).Value;
            var Width = inputs[(int)InputId.Width].Eval(context).Value;
            var ColorA = inputs[(int)InputId.ColorA].Eval(context).Value;
            var ColorB = inputs[(int)InputId.ColorB].Eval(context).Value;
            var ColorG = inputs[(int)InputId.ColorG].Eval(context).Value;
            var ColorR = inputs[(int)InputId.ColorR].Eval(context).Value;
            var Color = new Vector4(ColorA, ColorB, ColorG, ColorR);
            var BorderTop = inputs[(int)InputId.BorderTop].Eval(context).Value;
            var BorderRight = inputs[(int)InputId.BorderRight].Eval(context).Value;
            var BorderBottom = inputs[(int)InputId.BorderBottom].Eval(context).Value;
            var BorderLeft = inputs[(int)InputId.BorderLeft].Eval(context).Value;
            var Border = new Vector4(BorderTop, BorderRight, BorderBottom, BorderLeft);
            var TextureWidth = inputs[(int)InputId.TextureWidth].Eval(context).Value;
            var TextureHeight = inputs[(int)InputId.TextureHeight].Eval(context).Value;
            var Texture = new Vector2(TextureWidth, TextureHeight);
            var BorderTextureTop = inputs[(int)InputId.BorderTextureTop].Eval(context).Value;
            var BorderTextureRight = inputs[(int)InputId.BorderTextureRight].Eval(context).Value;
            var BorderTextureBottom = inputs[(int)InputId.BorderTextureBottom].Eval(context).Value;
            var BorderTextureLeft = inputs[(int)InputId.BorderTextureLeft].Eval(context).Value;
            var BorderTexture = new Vector4(BorderTextureTop, BorderTextureRight, BorderTextureBottom, BorderTextureLeft);
            // <<< _params
            
            
            var somethingChanged = false;

            if( _border != Border ) {
                _border = Border;
                somethingChanged = true;                
            }
            
            if( _texture != Texture) {
                _texture = Texture;
                somethingChanged = true;
            }
            
            if( _borderTexture != BorderTexture) {
                _borderTexture = BorderTexture;
                somethingChanged = true;
            }
            
            if( _height != Height) {
                _height = Height;
                somethingChanged = true;
            }

            if( _width != Width) {
                _width = Width;
                somethingChanged = true;
            }

            

            try {
                if (_planeMesh == null || somethingChanged) {
                    // Function>>> 
                    _normal = new Vector3(0.0f, 0.0f, -1.0f);
                    _color = new Vector4(ColorR, ColorG, ColorB, ColorA);
                    _tangent = new Vector3(1.0f, 0.0f, 0.0f);
                    _binormal = new Vector3(0.0f, -1.0f, 0.0f);
                    
                    var inputElements = new InputElement[] {
                        new InputElement("POSITION", 0, SharpDX.DXGI.Format.R32G32B32A32_Float, 0, 0),
                        new InputElement("NORMAL", 0, SharpDX.DXGI.Format.R32G32B32_Float, 16, 0),
                        new InputElement("COLOR", 0, SharpDX.DXGI.Format.R32G32B32A32_Float, 28, 0),
                        new InputElement("TEXCOORD", 0, SharpDX.DXGI.Format.R32G32_Float, 44, 0),
                        new InputElement("TANGENT", 0, SharpDX.DXGI.Format.R32G32B32_Float, 52, 0),
                        new InputElement("BINORMAL", 0, SharpDX.DXGI.Format.R32G32B32_Float, 64, 0)
                    };
                    
                    int numQuads = 9; 
                    const int attributesSize = 76;
                    int numTriangles = numQuads * 2;
                    int streamSize = numTriangles * 3 * attributesSize;

                    if (_planeMesh == null || streamSize != _planeMesh.NumTriangles*3*_planeMesh.AttributesSize) 
                    {
                        Utilities.DisposeObj(ref _planeMesh);
                        using (var stream = new DataStream(streamSize, true, true))
                        {
                            var vertices = new Buffer(context.D3DDevice, stream, new BufferDescription
                                                                                     {
                                                                                         BindFlags = BindFlags.VertexBuffer,
                                                                                         CpuAccessFlags = CpuAccessFlags.Write,
                                                                                         OptionFlags = ResourceOptionFlags.None,
                                                                                         SizeInBytes = streamSize,
                                                                                         Usage = ResourceUsage.Dynamic
                                                                                     });
                            _planeMesh = new Mesh
                                             {
                                                 InputElements = inputElements,
                                                 Vertices = vertices,
                                                 NumTriangles = numTriangles,
                                                 AttributesSize = attributesSize
                                             };
                        }
                    }
                    DataStream vertexStream;
                    context.D3DDevice.ImmediateContext.MapSubresource(_planeMesh.Vertices, MapMode.WriteDiscard, MapFlags.None, out vertexStream);
                    using (vertexStream)
                    {
                        vertexStream.Position = 0;

                       
                        float TopOuter = Height / 2.0f;
                        float TopInner = Height / 2.0f - BorderTop;
                        float BottomInner = -Height / 2.0f + BorderBottom;
                        float BottomOuter = -Height / 2.0f;

                        float LeftOuter = -Width / 2.0f;
                        float LeftInnter = -Width / 2.0f + BorderLeft;
                        float RightInner = Width / 2.0f - BorderRight;
                        float RightOuter = Width / 2.0f;

                        float uvTopOuter = 1;
                        float uvTopInner =  1- BorderTextureTop / TextureHeight;
                        float uvBottomInner = BorderTextureBottom / TextureHeight;
                        float uvBottomOuter = 0;

                        float uvLeftOuter = 0;
                        float uvLeftInner = BorderTextureLeft / TextureWidth;
                        float uvRightInner = 1 - BorderTextureRight / TextureWidth;
                        float uvRightOuter = 1;


                        //AddRectToStream(vertexStream,    uvLower,         bottom,         uvUpper,       top,         uvLeft,         left,       uvRight,       right);
                        AddRectToStream(vertexStream,      uvBottomOuter,   BottomOuter,    uvBottomInner, BottomInner, uvLeftOuter,    LeftOuter,   uvLeftInner,  LeftInnter);
                        AddRectToStream(vertexStream,      uvBottomOuter,   BottomOuter,    uvBottomInner, BottomInner, uvLeftInner,    LeftInnter,  uvRightInner, RightInner);
                        AddRectToStream(vertexStream,      uvBottomOuter,   BottomOuter,    uvBottomInner, BottomInner, uvRightInner,   RightInner,  uvRightOuter,  RightOuter);

                        AddRectToStream(vertexStream, uvBottomInner, BottomInner, uvTopInner, TopInner, uvLeftInner, LeftInnter, uvRightInner, RightInner);
                        AddRectToStream(vertexStream, uvBottomInner, BottomInner, uvTopInner, TopInner, uvRightInner, RightInner, uvRightOuter, RightOuter);
                        AddRectToStream(vertexStream, uvBottomInner, BottomInner, uvTopInner, TopInner, uvLeftOuter, LeftOuter, uvLeftInner, LeftInnter);

                        AddRectToStream(vertexStream, uvTopInner, TopInner, uvTopOuter, TopOuter, uvLeftInner, LeftInnter, uvRightInner, RightInner);
                        AddRectToStream(vertexStream, uvTopInner, TopInner, uvTopOuter, TopOuter, uvRightInner, RightInner, uvRightOuter, RightOuter);
                        AddRectToStream(vertexStream, uvTopInner, TopInner, uvTopOuter, TopOuter, uvLeftOuter, LeftOuter, uvLeftInner, LeftInnter);

                    }
                    context.D3DDevice.ImmediateContext.UnmapSubresource(_planeMesh.Vertices, 0);
                    // <<< Function

                    Changed = false;
                }

                context.Renderer.SetupEffect(context);
                context.Renderer.Render(_planeMesh, context);
            }
            catch (Exception) {
                //Logger.Debug("error");
            }

            return context;
        }

        private void AddRectToStream(DataStream vertexStream, float uvBottom, float bottom, float uvTop, float top, float uvLeft, float left, float uvRight, float right)
        {
            // tri 1 vert 1
            vertexStream.Write(new Vector4(right, top, 0, 1));
            vertexStream.Write(_normal);
            vertexStream.Write(_color);
            vertexStream.Write(new Vector2(uvRight, 1.0f - uvTop));
            vertexStream.Write(_tangent);
            vertexStream.Write(_binormal);

            // tri 1 vert 2
            vertexStream.Write(new Vector4(right, bottom, 0, 1));
            vertexStream.Write(_normal);
            vertexStream.Write(_color);
            vertexStream.Write(new Vector2(uvRight, 1.0f - uvBottom));
            vertexStream.Write(_tangent);
            vertexStream.Write(_binormal);

            // tri 1 vert 3
            vertexStream.Write(new Vector4(left, bottom, 0, 1));
            vertexStream.Write(_normal);
            vertexStream.Write(_color);
            vertexStream.Write(new Vector2(uvLeft, 1.0f - uvBottom));
            vertexStream.Write(_tangent);
            vertexStream.Write(_binormal);

            // tri 2 vert 1
            vertexStream.Write(new Vector4(left, bottom, 0, 1));
            vertexStream.Write(_normal);
            vertexStream.Write(_color);
            vertexStream.Write(new Vector2(uvLeft, 1.0f - uvBottom));
            vertexStream.Write(_tangent);
            vertexStream.Write(_binormal);

            // tri 2 vert 2
            vertexStream.Write(new Vector4(left, top, 0, 1));
            vertexStream.Write(_normal);
            vertexStream.Write(_color);
            vertexStream.Write(new Vector2(uvLeft, 1.0f - uvTop));
            vertexStream.Write(_tangent);
            vertexStream.Write(_binormal);

            // tri 2 vert 3
            vertexStream.Write(new Vector4(right, top, 0, 1));
            vertexStream.Write(_normal);
            vertexStream.Write(_color);
            vertexStream.Write(new Vector2(uvRight, 1.0f - uvTop));
            vertexStream.Write(_tangent);
            vertexStream.Write(_binormal);

        }

        private Mesh _planeMesh;
    }
}