using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;

namespace WaterTest
{
    // Super simple, just a position.
    struct TerrainVertex : IVertexType
    {
        public TerrainVertex(Vector3 position)
        {
            Position = position;
        }

        public Vector3 Position;

        private static VertexDeclaration vd = new VertexDeclaration(
            new VertexElement(0, VertexElementFormat.Vector3, VertexElementUsage.Position, 0)
            );

        public VertexDeclaration VertexDeclaration { get { return vd; } }
    }

    class HeightMap : IDisposable
    {
        public HeightMap(Game game, Vector2 worldTopLeft, Vector2 worldBottomRight)
        {
            device = game.GraphicsDevice;
            heightMapTexture = game.Content.Load<Texture2D>(@"Textures\HeightMap");

            //width = heightMapTexture.Width;
            //height = heightMapTexture.Height;
            // We don't necessarily need to match the dimensions of the height map.
            width = 64;
            height = 64;

            Vector2 worldSize = worldBottomRight - worldTopLeft;

            worldToHeightMapOffsetAndScale = new Vector4(
                -worldTopLeft.X,
                -worldTopLeft.Y,
                1f / worldSize.X,
                1f / worldSize.Y
                );

            TerrainVertex[] vertices = new TerrainVertex[(width + 1) * (height + 1)];
            short[] indices = new short[width * height * 6];

            Vector2 squareSize = worldSize / new Vector2(width, height);
            for (int y = 0; y <= height; y++)
            {
                float zPosition = squareSize.Y * y + worldTopLeft.Y;
                for (int x = 0; x <= width; x++)
                {
                    float xPosition = squareSize.X * x + worldTopLeft.X;

                    vertices[x + y * (width + 1)] = new TerrainVertex(
                        new Vector3(xPosition, 0f, zPosition)
                        );
                }
            }

            int indexIndex = 0;
            for (int y = 0; y < height; y++)
            {
                int topRow = y * (width + 1);
                int bottomRow = (y + 1) * (width + 1);
                for (int x = 0; x < width; x++)
                {
                    int leftColumn = x;
                    int rightColumn = x + 1;

                    indices[indexIndex + 0] = (short)(bottomRow + leftColumn);
                    indices[indexIndex + 1] = (short)(topRow + leftColumn);
                    indices[indexIndex + 2] = (short)(topRow + rightColumn);
                    indices[indexIndex + 3] = (short)(bottomRow + leftColumn);
                    indices[indexIndex + 4] = (short)(topRow + rightColumn);
                    indices[indexIndex + 5] = (short)(bottomRow + rightColumn);

                    indexIndex += 6;
                }
            }

            vb = new VertexBuffer(game.GraphicsDevice, typeof(TerrainVertex), vertices.Length, BufferUsage.WriteOnly);
            vb.SetData(vertices);
            ib = new IndexBuffer(game.GraphicsDevice, IndexElementSize.SixteenBits, indices.Length, BufferUsage.WriteOnly);
            ib.SetData(indices);
        }

        public void Dispose()
        {
            vb.Dispose();
            ib.Dispose();
        }

        GraphicsDevice device;
        Vector4 worldToHeightMapOffsetAndScale;
        int width, height;
        VertexBuffer vb;
        IndexBuffer ib;
        Texture2D heightMapTexture;

        public void SetEffectParametersBeforeDraw(Effect effect)
        {
            effect.Parameters["HeightMapTexelSize"].SetValue(new Vector2(1f / 64));
            effect.Parameters["HeightMapTexture"].SetValue(heightMapTexture);
            effect.Parameters["WorldToHeightMapOffsetAndScale"].SetValue(worldToHeightMapOffsetAndScale);
        }

        public void Draw()
        {
            device.SetVertexBuffer(vb);
            device.Indices = ib;
            device.DrawIndexedPrimitives(PrimitiveType.TriangleList, 0, 0, vb.VertexCount, 0, ib.IndexCount / 3);
        }
    }
}
