#pragma once

#include "roam_landscape.h"

#define DEFAULT_XYSCALE 20.0
#define DEFAULT_ZSCALE  0.8
//#define DEFAULT_ZSCALE  5

#define HALFSQRT2 0.70710678118654752440084436210485

typedef vec<4,unsigned char> vec4ub;
typedef array2<vec4ub> rgba_image_type;

struct treeInfoType {
	vec2f pos;
	bool onFireAndGonnaDieAHorribleFlamingDeath;
	float lifeleft;
};

class MapObject {
	protected:
		glh::array2<float> heightmap;
		glh::array2<glh::vec3f> normalmap;
		glh::array2<glh::vec3ub> gradientmap;
		glh::array2<glh::vec3ub> textureimage;

	public:
		vector<treeInfoType> treeInfo;
		unsigned int treePosSeed;
		unsigned int numTrees;
		rgba_image_type treeTex;
		tex_object_2D treeTexOb;
	protected:

		//gs_image_type						tilemap;
		/*
		vector<rgb_image_type>			tiletex;
		vector<tex_object_2D>			tiletexob;
		//*/

		gs_image_type oriHeightMap;
		Landscape roamLandscape;

		int width;
		int length;
		display_list dlist;
		tex_object_2D texob;
		bool height_data_loaded;
		bool texture_data_loaded;
		float grid_XY_scale;
		float grid_Z_scale;
		float min_height, max_height;
		float mapwidth,maplength;
		BYTE mapID;
	public:
		void DrawTrees();

		void GenTrees(unsigned int newPosSeed, unsigned int nTrees);
		unsigned int GetTreeSeed() { return treePosSeed; };
		unsigned int GetNumTrees() { return numTrees; };

		vec3f GetStartingLocation(int nLoc = -1);
		bool LoadMapByID(BYTE mapID);
		MapObject();
		~MapObject();
		inline float GetWidth()					// Gets width in world coordinates (WC)
			{ return mapwidth; }
		inline float GetLength()				// Gets length in WC
			{ return maplength; }
		inline float GetXYScale()				// Gets the scale factor between grid points
			{ return grid_XY_scale; }
		inline float GetZScale()				// Gets the Z scale factor per grid point
			{ return grid_Z_scale; }
		inline int GetGridWidth()				// Gets grid width
			{ return width; }
		inline int GetGridLength()				// Gets grid length
			{ return length; }
		inline float GetMaxHeight()
			{ return max_height; }
		inline float GetMinHeight()
			{ return min_height; }
		inline BYTE GetMapID()
			{ return mapID; }

		inline bool IsUnderground(vec3f pt)		// Checks the height of the point vs the ground
			{	return pt[Z] <= GetHeight(pt[X],pt[Y]);	}
		inline bool IsWithinBounds(vec3f pt)	// Checks if point within all map bounds
			{	return (pt[X]>=0)&&(pt[X]<mapwidth)&&(pt[Y]>=0)&&(pt[Y]<maplength);	}
		inline bool InLeftBound(vec3f pt)		// Checks against each individual bound
			{	return pt[X] >= 0;	}
		inline bool InRightBound(vec3f pt)
			{	return pt[X] < mapwidth;	}
		inline bool InBottomBound(vec3f pt)
			{	return pt[Y] >= 0;	}
		inline bool InTopBound(vec3f pt)
			{	return pt[Y] < maplength;	}
		vec3f GetBoundsNorm(vec3f pt)				// Checks if point is beyond any of the
			{												// boundaries and returns the correct normal
				if (!InLeftBound(pt))				// if it is.
				{
					if (!InBottomBound(pt))
						return vec3f(HALFSQRT2,HALFSQRT2,0);
					if (!InTopBound(pt))
						return vec3f(HALFSQRT2,-HALFSQRT2,0);
					return vec3f(1,0,0);
				}
				if (!InRightBound(pt))
				{
					if (!InBottomBound(pt))
						return vec3f(-HALFSQRT2,HALFSQRT2,0);
					if (!InTopBound(pt))
						return vec3f(-HALFSQRT2,-HALFSQRT2,0);
					return vec3f(-1,0,0);
				}
				if (!InBottomBound(pt))
					return vec3f(0,1,0);
				if (!InTopBound(pt))
					return vec3f(0,-1,0);
				return vec3f(0,0,0);
			}
		inline float GetHeight(vec3f pos)
			{ return GetHeight(pos[X],pos[Y]); }
		inline vec3f GetNormal(vec3f pos)
			{ return GetNormal(pos[X],pos[Y]); }
		vec3f GetNormal(float x, float y);
		inline vec3f GetNormal(int x, int y)
			{ return normalmap(x/grid_XY_scale,y/grid_XY_scale); }


		float GetHeight(float x, float y);		// Gets interpolated height in WC at specified point
		float GetHeight(int x, int y);			// Gets height in WC at exact point
		//void SetScale(float XYscale, float Zscale);	// Change the scaling factor

		bool  LoadHeightData(char* fname,		// Load height data from the .png file
				 float xyscale=DEFAULT_XYSCALE,	// specifying the map scaling at the same time
				 float zscale=DEFAULT_ZSCALE);	
		bool  LoadTextureData(char* fname);		// Load texture data from the .png file

		void ReleaseModelData();
		void RegisterModelData();					// Registers model data w/ OpenGL (texture/vertices/etc)

		display_list& CreateDisplayList();		// Create a new (or return the current) display list
		void DrawMap();							// Draw the map
		void DrawMapMesh();						// Draws only the map mesh w/o setting colors/tex/etc
};

//extern MapObject map;
