#pragma once

#include "Common.h"
#include <vector>
#include "BWAPI.h"
//#include "DistanceMap.hpp"
#include "GridDistances.h"

namespace UAlbertaBot
{
	struct ChokeData
	{
		int width;
		bool blocked;

		bool isRamp;
		BWAPI::TilePosition highElevationTile;

		bool requiresMineralWalk;
		BWAPI::Unit firstMineralPatch;
		BWAPI::Unit secondMineralPatch;

		ChokeData(const BWEM::ChokePoint* choke)
			: width(0)
			, blocked(false)
			, isRamp(false)
			, highElevationTile(BWAPI::TilePosition(choke->Center()))
			, requiresMineralWalk(false)
			, firstMineralPatch(nullptr)
			, secondMineralPatch(nullptr)
		{};
	};

	// provides useful tools for analyzing the starcraft map
	// calculates connectivity and distances using flood fills
	class MapTools
	{
		const size_t allMapsSize = 40;           // store this many distance maps in _allMaps
		std::map<BWAPI::TilePosition, GridDistances>
			_allMaps;			// a cache of already computed distance maps
		std::vector< std::vector<bool> >
			_terrainWalkable;	// walkable considering terrain only
		std::vector< std::vector<bool> >
			_walkable;			// walkable considering terrain and neutral units
		std::vector< std::vector<bool> >
			_buildable;
		std::vector< std::vector<bool> >
			_depotBuildable;

		bool						_hasIslandBases;
		/*
		std::map<BWAPI::Position,
			DistanceMap>			_allMaps;    // a cache of already computed distance maps
		
		std::vector<bool>           _map;        // the map stored at TilePosition resolution, values are 0/1 for walkable or not walkable
		std::vector<bool>           _units;      // UNUSED map that stores whether a unit is on this position
		std::vector<short int>      _fringe;     // the fringe vector which is used as a sort of 'open list'
		int                         _rows;
		int                         _cols;
		*/

		MapTools();

		//int                     getIndex(int row, int col);		// return the index of the 1D array from (row,col)
		//bool                    unexplored(DistanceMap & dmap, const int index) const;
		void                    setBWAPIMapData();				// reads in the map data from bwapi and stores it in our map format
		void					setChokepointData();
		//void                    resetFringe();
		//void                    computeDistance(DistanceMap & dmap, const BWAPI::Position p); // computes walk distance from Position P to all other points on the map
		//BWAPI::TilePosition     getTilePosition(int index);

		BWTA::BaseLocation *    nextExpansion(bool hidden, bool minOnlyOK);

	public:

		static MapTools &       Instance();

		//void                    search(DistanceMap & dmap, const int sR, const int sC);
		int						getGroundTileDistance(BWAPI::TilePosition from, BWAPI::TilePosition to);
		int                     getGroundTileDistance(BWAPI::Position from, BWAPI::Position to);
		int                     getGroundDistance(BWAPI::Position from, BWAPI::Position to);

		// Pass only valid tiles to these routines!
		bool	isTerrainWalkable(BWAPI::TilePosition tile) const { return _terrainWalkable[tile.x][tile.y]; };
		bool	isWalkable(BWAPI::TilePosition tile) const { return _walkable[tile.x][tile.y]; };
		bool	isBuildable(BWAPI::TilePosition tile) const { return _buildable[tile.x][tile.y]; };
		bool	isDepotBuildable(BWAPI::TilePosition tile) const { return _depotBuildable[tile.x][tile.y]; };
		bool	isBuildable(BWAPI::TilePosition tile, BWAPI::UnitType type) const;

		BWAPI::TilePosition     getNextExpansion(bool hidden = false, bool minOnlyOK = false);
		BWAPI::TilePosition     reserveNextExpansion(bool hidden = false, bool minOnlyOK = false);

		//const std::vector<BWAPI::TilePosition> & getClosestTilesTo(BWAPI::Position pos);
		const std::vector<BWAPI::TilePosition> & getClosestTilesTo(BWAPI::TilePosition pos);
		const std::vector<BWAPI::TilePosition> & getClosestTilesTo(BWAPI::Position pos);

		void                    drawHomeDistanceMap();

		bool					hasIslandBases(){ return _hasIslandBases; }
	};

}