using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using nft.framework.drawing;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using System.Diagnostics;
using DefaultEffect = StockEffects.DefaultEffect;
using XnaRect = Microsoft.Xna.Framework.Rectangle;

namespace nft.xna
{

    public class Structure : X3DObject, ICubicStructure
    {
        //private static RasterizerState state = new RasterizerState();
        private Vector3 size;
        private Vector3 pos;
        private XnaRect region;
        private VertexPositionTexture[] vertices;
        private VertexBuffer vertexBuffer;
        private bool polygonDirty = true;

        public Structure(UInt32 id, XnaTexture texture, Vector3 size3d)
            : this(id, texture, new Vector2(0), size3d)
        {
        }

        public Structure(UInt32 id, XnaTexture texture, Vector2 offset, Vector3 size3d)
            : base(id, texture)
        {
            this.size = size3d;
            this.region = CalcClipRect(offset, size3d);
            BuildCube();
        }

        public Vector3 Size3D
        {
            get { return size; }
        }

        public Vector3 Position3D
        {
            get { return pos; }
            set {
                if (pos.Equals(value)) return;
                pos = value;
                //polygonDirty = true;
            }
        }

        public GraphicsDevice GraphicsDevice
        {
            get { return Texture.GraphicsDevice; }
        }

        /*
        public void Draw(DefaultEffect effect)
        {
            effect.Texture = this.Texture;
            effect.SetTextureRegion(this.region);
            //effect.TextureEnabled = true;
            GraphicsDevice.SetVertexBuffer(vertexBuffer);
            
            // 平行移動を適用
            Matrix wback = effect.World;
            Matrix trans = Matrix.CreateTranslation(Position3D)*wback;
            effect.World = trans;
            foreach (var pass in effect.CurrentTechnique.Passes)
            {
                pass.Apply();
                GraphicsDevice.DrawPrimitives(PrimitiveType.TriangleList, 0, vertices.Length / 3);
            }
            // ワールド変換を元に戻す
            effect.World = wback;
        }
         */

        public override void RenderSelf(XnaSurface surface, DefaultEffect effect) {
            effect.Texture = this.Texture;
            effect.SetTextureRegion(this.region);
            //effect.VertexColorEnabled = false;
            //effect.TextureEnabled = true;
            GraphicsDevice.SetVertexBuffer(vertexBuffer);
            if (_bias > 0f) {
                RasterizerState state = new RasterizerState();
                state.DepthBias = this._bias;
                GraphicsDevice.RasterizerState = state;
            } else {
                GraphicsDevice.RasterizerState = RasterizerState.CullCounterClockwise;
            }

            // 平行移動を適用
            Matrix wback = effect.World;
            effect.World = Matrix.CreateTranslation(Position3D);
            effect.HitTestID = this.ID;
            foreach (var pass in effect.CurrentTechnique.Passes) {
                pass.Apply();
                GraphicsDevice.DrawPrimitives(PrimitiveType.TriangleList, 0, vertices.Length / 3);
            }
        }

        static protected Vector3 ConvertIsometric(float l, float r, float h)
        {
            return new Vector3(r, h, l);
        }

        static protected XnaRect CalcClipRect(Vector2 offset, Vector3 size)
        {
            float width = size.X + size.Z;
            float height = size.Y + width / 2;
            XnaRect rct = new XnaRect((int)offset.X, (int)offset.Y, (int)width, (int)height);
            return rct;
        }

        private void BuildCube()
        {
            if (!polygonDirty) return;
            polygonDirty = false;
            Vector3 pos = Position3D;
            Vector3 size = Size3D;
            Vector3 pos2 = pos + size;
            pos2 += new Vector3(0, 1f, 0);
            float imgw = size.X + size.Z;
            float imgh = imgw * 0.5f + size.Y;
            float dh = 0.5f / imgh;
            if (vertices == null || vertices.Length != 18)
            {
                vertices = new VertexPositionTexture[18];
                // 頂点バッファ作成
                vertexBuffer = new VertexBuffer(GraphicsDevice, typeof(VertexPositionTexture), vertices.Length, BufferUsage.None);
            }
            int i = 0;

            // 右側面
            vertices[i++] = new VertexPositionTexture(new Vector3(pos.X, pos2.Y, pos.Z), new Vector2(size.X / imgw, (imgh - size.Y) / imgh - dh));
            vertices[i++] = new VertexPositionTexture(new Vector3(pos.X, pos2.Y, pos2.Z), new Vector2(1f, size.X * 0.5f / imgh - dh));
            vertices[i++] = new VertexPositionTexture(new Vector3(pos.X, pos.Y, pos.Z), new Vector2(size.X / imgw, 1f + dh));

            vertices[i++] = new VertexPositionTexture(new Vector3(pos.X, pos2.Y, pos2.Z), new Vector2(1f, size.X * 0.5f / imgh - dh));
            vertices[i++] = new VertexPositionTexture(new Vector3(pos.X, pos.Y, pos2.Z), new Vector2(1f, (imgh - size.Z * 0.5f) / imgh + dh));
            vertices[i++] = new VertexPositionTexture(new Vector3(pos.X, pos.Y, pos.Z), new Vector2(size.X / imgw, 1f + dh));

            // 左側面
            vertices[i++] = new VertexPositionTexture(new Vector3(pos.X, pos2.Y, pos.Z), new Vector2(size.X / imgw, (imgh - size.Y) / imgh - dh));
            vertices[i++] = new VertexPositionTexture(new Vector3(pos.X, pos.Y, pos.Z), new Vector2(size.X / imgw, 1f + dh));
            vertices[i++] = new VertexPositionTexture(new Vector3(pos2.X, pos2.Y, pos.Z), new Vector2(0, size.Z * 0.5f / imgh - dh));

            vertices[i++] = new VertexPositionTexture(new Vector3(pos2.X, pos2.Y, pos.Z), new Vector2(0, size.Z * 0.5f / imgh - dh));
            vertices[i++] = new VertexPositionTexture(new Vector3(pos.X, pos.Y, pos.Z), new Vector2(size.X / imgw, 1f + dh));
            vertices[i++] = new VertexPositionTexture(new Vector3(pos2.X, pos.Y, pos.Z), new Vector2(0, (imgh - size.X * 0.5f) / imgh + dh));

            // 上面 
            vertices[i++] = new VertexPositionTexture(new Vector3(pos.X, pos2.Y, pos.Z), new Vector2(size.X / imgw, (imgh - size.Y) / imgh - dh));
            vertices[i++] = new VertexPositionTexture(new Vector3(pos2.X, pos2.Y, pos.Z), new Vector2(0, size.Z * 0.5f / imgh - dh));
            vertices[i++] = new VertexPositionTexture(new Vector3(pos.X, pos2.Y, pos2.Z), new Vector2(1f, size.X * 0.5f / imgh - dh));

            vertices[i++] = new VertexPositionTexture(new Vector3(pos2.X, pos2.Y, pos.Z), new Vector2(0, size.Z * 0.5f / imgh - dh));
            vertices[i++] = new VertexPositionTexture(new Vector3(pos2.X, pos2.Y, pos2.Z), new Vector2(size.Z / imgw, 0 - dh));
            vertices[i++] = new VertexPositionTexture(new Vector3(pos.X, pos2.Y, pos2.Z), new Vector2(1f, size.X * 0.5f / imgh - dh));

            //頂点データを頂点バッファに書き込む
            vertexBuffer.SetData<VertexPositionTexture>(vertices);
        }

        // 視界占有はBuildCubeと同じだが、手前側をなくし背後側の面のみで構成されたポリゴンを作る
        private void BuildLot()
        {
            if (!polygonDirty) return;
            polygonDirty = false;
            Vector3 pos = Position3D;
            Vector3 size = Size3D;
            Vector3 pos2 = pos + size;
            pos2 += new Vector3(0, 1f, 0);
            float imgw = size.X + size.Z;
            float imgh = imgw * 0.5f + size.Y;
            float dh = 0.5f / imgh;
            if (vertices == null || vertices.Length != 18)
            {
                vertices = new VertexPositionTexture[18];
                // 頂点バッファ作成
                vertexBuffer = new VertexBuffer(GraphicsDevice, typeof(VertexPositionTexture), vertices.Length, BufferUsage.None);
            }
            int i = 0;
            // 左手奥面
            vertices[i++] = new VertexPositionTexture(new Vector3(pos2.X, pos2.Y, pos.Z), new Vector2(0, size.Z * 0.5f / imgh - dh));
            vertices[i++] = new VertexPositionTexture(new Vector3(pos2.X, pos2.Y, pos2.Z), new Vector2(size.Z / imgw, 0 - dh));
            vertices[i++] = new VertexPositionTexture(new Vector3(pos2.X, pos.Y, pos.Z), new Vector2(0, (imgh - size.X * 0.5f) / imgh + dh));

            vertices[i++] = new VertexPositionTexture(new Vector3(pos2.X, pos2.Y, pos2.Z), new Vector2(size.Z / imgw, 0 - dh));
            vertices[i++] = new VertexPositionTexture(new Vector3(pos2.X, pos.Y, pos2.Z), new Vector2(size.Z / imgw, size.Y / imgh + dh));
            vertices[i++] = new VertexPositionTexture(new Vector3(pos2.X, pos.Y, pos.Z), new Vector2(0, (imgh - size.X * 0.5f) / imgh + dh));

            // 右手奥面
            vertices[i++] = new VertexPositionTexture(new Vector3(pos.X, pos2.Y, pos2.Z), new Vector2(1f, size.X * 0.5f / imgh - dh));
            vertices[i++] = new VertexPositionTexture(new Vector3(pos.X, pos.Y, pos2.Z), new Vector2(1f, (imgh - size.Z * 0.5f) / imgh + dh));
            vertices[i++] = new VertexPositionTexture(new Vector3(pos2.X, pos2.Y, pos2.Z), new Vector2(size.Z / imgw, 0 - dh));

            vertices[i++] = new VertexPositionTexture(new Vector3(pos2.X, pos2.Y, pos2.Z), new Vector2(size.Z / imgw, 0 - dh));
            vertices[i++] = new VertexPositionTexture(new Vector3(pos.X, pos.Y, pos2.Z), new Vector2(1f, (imgh - size.Z * 0.5f) / imgh + dh));
            vertices[i++] = new VertexPositionTexture(new Vector3(pos2.X, pos.Y, pos2.Z), new Vector2(size.Z / imgw, size.Y / imgh + dh));

            // 底面 
            vertices[i++] = new VertexPositionTexture(new Vector3(pos.X, pos.Y, pos.Z), new Vector2(size.X / imgw, 1f + dh));
            vertices[i++] = new VertexPositionTexture(new Vector3(pos2.X, pos.Y, pos.Z), new Vector2(0, (imgh - size.X * 0.5f) / imgh + dh));
            vertices[i++] = new VertexPositionTexture(new Vector3(pos.X, pos.Y, pos2.Z), new Vector2(1f, (imgh - size.Z * 0.5f) / imgh + dh));

            vertices[i++] = new VertexPositionTexture(new Vector3(pos2.X, pos.Y, pos.Z), new Vector2(0, (imgh - size.X * 0.5f) / imgh + dh));
            vertices[i++] = new VertexPositionTexture(new Vector3(pos2.X, pos.Y, pos2.Z), new Vector2(size.Z / imgw, size.Y / imgh + dh));
            vertices[i++] = new VertexPositionTexture(new Vector3(pos.X, pos.Y, pos2.Z), new Vector2(1f, (imgh - size.Z * 0.5f) / imgh + dh));

            //頂点データを頂点バッファに書き込む
            vertexBuffer.SetData<VertexPositionTexture>(vertices);
        }

        /*
        private Vector2 FromPixelOffset(float x, float y)
        {
            x += region.X;
            y += region.Y;
            return new Vector2(x / Texture.Width, y / Texture.Height);
        }

        private void BuildPolygons2()
        {
            if (!polygonDirty) return;
            polygonDirty = false;
            Vector3 pos = Position3D;
            Vector3 size = Size3D;
            Vector3 pos2 = pos + size;
            pos2 += new Vector3(0, 1f, 0);
            float imgw = region.Width;
            float imgh = region.Height;
            float dh = 0.5f;
            Debug.WriteLine("x="+region.X);
            if (vertices == null || vertices.Length != 18)
            {
                vertices = new VertexPositionTexture[18];
                // 頂点バッファ作成
                vertexBuffer = new VertexBuffer(GraphicsDevice, typeof(VertexPositionTexture), vertices.Length, BufferUsage.None);
            }
            int i = 0;
            // 右側面
            vertices[i++] = new VertexPositionTexture(new Vector3(pos.X, pos2.Y, pos.Z), FromPixelOffset(size.X, imgh - size.Y - dh));
            vertices[i++] = new VertexPositionTexture(new Vector3(pos.X, pos2.Y, pos2.Z), FromPixelOffset(imgw, size.X * 0.5f - dh));
            vertices[i++] = new VertexPositionTexture(new Vector3(pos.X, pos.Y, pos.Z), FromPixelOffset(size.X, imgh + dh));

            vertices[i++] = new VertexPositionTexture(new Vector3(pos.X, pos2.Y, pos2.Z), FromPixelOffset(imgw, size.X * 0.5f - dh));
            vertices[i++] = new VertexPositionTexture(new Vector3(pos.X, pos.Y, pos2.Z), FromPixelOffset(imgw, imgh - size.Z * 0.5f + dh));
            vertices[i++] = new VertexPositionTexture(new Vector3(pos.X, pos.Y, pos.Z), FromPixelOffset(size.X, imgh + dh));

            // 左側面
            vertices[i++] = new VertexPositionTexture(new Vector3(pos.X, pos2.Y, pos.Z), FromPixelOffset(size.X, imgh - size.Y - dh));
            vertices[i++] = new VertexPositionTexture(new Vector3(pos.X, pos.Y, pos.Z), FromPixelOffset(size.X, imgh + dh));
            vertices[i++] = new VertexPositionTexture(new Vector3(pos2.X, pos2.Y, pos.Z), FromPixelOffset(0, size.Z * 0.5f - dh));

            vertices[i++] = new VertexPositionTexture(new Vector3(pos2.X, pos2.Y, pos.Z), FromPixelOffset(0, size.Z * 0.5f - dh));
            vertices[i++] = new VertexPositionTexture(new Vector3(pos.X, pos.Y, pos.Z), FromPixelOffset(size.X, imgh + dh));
            vertices[i++] = new VertexPositionTexture(new Vector3(pos2.X, pos.Y, pos.Z), FromPixelOffset(0, imgh - size.X * 0.5f + dh));

            // 上面 
            vertices[i++] = new VertexPositionTexture(new Vector3(pos.X, pos2.Y, pos.Z), FromPixelOffset(size.X, imgh - size.Y - dh));
            vertices[i++] = new VertexPositionTexture(new Vector3(pos2.X, pos2.Y, pos.Z), FromPixelOffset(0, size.Z * 0.5f - dh));
            vertices[i++] = new VertexPositionTexture(new Vector3(pos.X, pos2.Y, pos2.Z), FromPixelOffset(imgw, size.X * 0.5f - dh));

            vertices[i++] = new VertexPositionTexture(new Vector3(pos2.X, pos2.Y, pos.Z), FromPixelOffset(0, size.Z * 0.5f - dh));
            vertices[i++] = new VertexPositionTexture(new Vector3(pos2.X, pos2.Y, pos2.Z), FromPixelOffset(size.Z, 0 - dh));
            vertices[i++] = new VertexPositionTexture(new Vector3(pos.X, pos2.Y, pos2.Z), FromPixelOffset(imgw, size.X * 0.5f - dh));

            //頂点データを頂点バッファに書き込む
            vertexBuffer.SetData<VertexPositionTexture>(vertices);
        }
         */

        #region IStructure implementation
        public PointF3D Location
        {
            get
            {
                return XnaUtil.ToPointF(pos);
            }
            set
            {
                pos = XnaUtil.ToVector3(value);
            }
        }
        #endregion

        protected override void Dispose(Boolean disposing)
        {
            base.Dispose(disposing);
            // Unmanaged cleanup code here
            if (disposing && vertexBuffer!=null)
            {
                // Managed cleanup code here, while managed refs
                vertexBuffer.Dispose();
                vertexBuffer = null;
                vertices = null;
            }
        }
    }

}
