/* 
 *----------------------------------------------------------------------
 * Microwave
 *----------------------------------------------------------------------
 */

#include "Common.h"
#include "UAlbertaBotModule.h"
#include "JSONTools.h"
#include "ParseUtils.h"
#include "UnitUtil.h"

using namespace UAlbertaBot;

// This gets called when the bot starts!
void UAlbertaBotModule::onStart()
{
	gameEnded = false;

	// Initialize BWEM
	//BWAPI::Broodwar->printf("BWEM initialization...");
	BWEMmap.Initialize();
	BWEMmap.EnableAutomaticPathAnalysis();
	bool startingLocationsOK = BWEMmap.FindBasesForStartingLocations();
	UAB_ASSERT(startingLocationsOK, "BWEM map analysis failed");

	// Initialize BWEB
	//BWAPI::Broodwar->printf("BWEB initialization...");
	BWEBmap.onStart();

	// Make BWEB wall
	if (BWAPI::Broodwar->self()->getRace() == BWAPI::Races::Zerg)
	{
		std::vector<BWAPI::UnitType> types{
			BWAPI::UnitTypes::Zerg_Hatchery,
			BWAPI::UnitTypes::Zerg_Evolution_Chamber
		};

		std::vector<BWAPI::UnitType> defenses{
			BWAPI::UnitTypes::Zerg_Sunken_Colony,
			BWAPI::UnitTypes::Zerg_Sunken_Colony,
			BWAPI::UnitTypes::Zerg_Sunken_Colony,
			BWAPI::UnitTypes::Zerg_Sunken_Colony, 
			BWAPI::UnitTypes::Zerg_Sunken_Colony,
			BWAPI::UnitTypes::Zerg_Sunken_Colony,
			BWAPI::UnitTypes::Zerg_Spore_Colony
		};

		//BWEBmap.createWall(types, BWEBmap.getNaturalArea(), BWEBmap.getMainChoke(), BWAPI::UnitTypes::None, defenses, true, false);
	}

	else if (BWAPI::Broodwar->self()->getRace() == BWAPI::Races::Terran)
	{
		std::vector<BWAPI::UnitType> types{
			BWAPI::UnitTypes::Terran_Barracks,
			BWAPI::UnitTypes::Terran_Supply_Depot,
			BWAPI::UnitTypes::Terran_Supply_Depot
		};

		std::vector<BWAPI::UnitType> defenses{
		};

		BWAPI::UnitType wallTight = BWAPI::Broodwar->enemy()->getRace() == BWAPI::Races::Protoss ? BWAPI::UnitTypes::Protoss_Zealot : BWAPI::UnitTypes::Zerg_Zergling;
		//BWEBmap.createWall(types, BWEBmap.getNaturalArea(), BWEBmap.getNaturalChoke(), wallTight, defenses);
	}

	else if (BWAPI::Broodwar->self()->getRace() == BWAPI::Races::Protoss)
	{
		std::vector<BWAPI::UnitType> types{
			BWAPI::UnitTypes::Protoss_Gateway,
			BWAPI::UnitTypes::Protoss_Forge,
			BWAPI::UnitTypes::Protoss_Pylon,
		};

		std::vector<BWAPI::UnitType> defenses{
			BWAPI::UnitTypes::Protoss_Photon_Cannon,
			BWAPI::UnitTypes::Protoss_Photon_Cannon,
			BWAPI::UnitTypes::Protoss_Photon_Cannon,
			BWAPI::UnitTypes::Protoss_Photon_Cannon,
			BWAPI::UnitTypes::Protoss_Photon_Cannon,
			BWAPI::UnitTypes::Protoss_Photon_Cannon
		};

		//BWEBmap.createWall(types, BWEBmap.getNaturalArea(), BWEBmap.getNaturalChoke(), BWAPI::UnitTypes::None, defenses, true);
	}

	// Parse the bot's configuration file if it has one, change this file path to where your config file is
    // Any relative path name will be relative to Starcraft installation folder
    ParseUtils::ParseConfigFile(Config::ConfigFile::ConfigFileLocation);

    // Set our BWAPI options here
	BWAPI::Broodwar->setLocalSpeed(Config::BWAPIOptions::SetLocalSpeed);
	BWAPI::Broodwar->setFrameSkip(Config::BWAPIOptions::SetFrameSkip);
	//BWAPI::Broodwar->setLatCom(false);

    if (Config::BWAPIOptions::EnableCompleteMapInformation)
    {
        BWAPI::Broodwar->enableFlag(BWAPI::Flag::CompleteMapInformation);
    }

    if (Config::BWAPIOptions::EnableUserInput)
    {
        BWAPI::Broodwar->enableFlag(BWAPI::Flag::UserInput);
    }

	int latencyFrames = BWAPI::Broodwar->getLatencyFrames();
	Log().Get() << Config::BotInfo::BotName << " (" << Config::BotInfo::Version << ") vs " << BWAPI::Broodwar->enemy()->getName() 
		<< " on " << BWAPI::Broodwar->mapFileName() << " (LF: " << latencyFrames << ")";
	
	if (Config::BotInfo::PrintInfoOnStart)
    {
		BWAPI::Broodwar->sendText("%s (%s) by %s, based on Steamhammer. (LF: %d)",
			Config::BotInfo::BotName.c_str(), Config::BotInfo::Version.c_str(), Config::BotInfo::Authors.c_str(), latencyFrames);
    }
	
    if (Config::Modules::UsingStrategyIO)
    {
        StrategyManager::Instance().readResults();
		StrategyManager::Instance().readHistory();
        StrategyManager::Instance().setLearnedStrategy();
    }

	if (Config::Modules::UsingAutoObserver)
	{
		// krasi0 Auto Observer
		_autoObserver.toggle();
	}
}

void UAlbertaBotModule::onEnd(bool isWinner) 
{
	if (gameEnded) return;

	if (Config::Modules::UsingGameCommander)
	{
		StrategyManager::Instance().onEnd(isWinner);
	}

	gameEnded = true;
}

void UAlbertaBotModule::onFrame()
{
	if (gameEnded) return;

    char red = '\x08';
    char green = '\x07';
    char white = '\x04';

    if (!Config::ConfigFile::ConfigFileFound)
    {
        BWAPI::Broodwar->drawBoxScreen(0,0,450,100, BWAPI::Colors::Black, true);
        BWAPI::Broodwar->setTextSize(BWAPI::Text::Size::Huge);
        BWAPI::Broodwar->drawTextScreen(10, 5, "%c%s Config File Not Found", red, Config::BotInfo::BotName.c_str());
        BWAPI::Broodwar->setTextSize(BWAPI::Text::Size::Default);
        BWAPI::Broodwar->drawTextScreen(10, 30, "%c%s will not run without its configuration file", white, Config::BotInfo::BotName.c_str());
        BWAPI::Broodwar->drawTextScreen(10, 45, "%cCheck that the file below exists. Incomplete paths are relative to Starcraft directory", white);
        BWAPI::Broodwar->drawTextScreen(10, 60, "%cYou can change this file location in Config::ConfigFile::ConfigFileLocation", white);
        BWAPI::Broodwar->drawTextScreen(10, 75, "%cFile Not Found (or is empty): %c %s", white, green, Config::ConfigFile::ConfigFileLocation.c_str());
        return;
    }
    else if (!Config::ConfigFile::ConfigFileParsed)
    {
        BWAPI::Broodwar->drawBoxScreen(0,0,450,100, BWAPI::Colors::Black, true);
        BWAPI::Broodwar->setTextSize(BWAPI::Text::Size::Huge);
        BWAPI::Broodwar->drawTextScreen(10, 5, "%c%s Config File Parse Error", red, Config::BotInfo::BotName.c_str());
        BWAPI::Broodwar->setTextSize(BWAPI::Text::Size::Default);
        BWAPI::Broodwar->drawTextScreen(10, 30, "%c%s will not run without a properly formatted configuration file", white, Config::BotInfo::BotName.c_str());
        BWAPI::Broodwar->drawTextScreen(10, 45, "%cThe configuration file was found, but could not be parsed. Check that it is valid JSON", white);
        BWAPI::Broodwar->drawTextScreen(10, 60, "%cFile Not Parsed: %c %s", white, green, Config::ConfigFile::ConfigFileLocation.c_str());
        return;
    }

	if (Config::Modules::UsingAutoObserver)
	{
		// UAlbertaBot Auto Observer
		//AutoObserver::Instance().onFrame();

		// krasi0 Auto Observer
		_autoObserver.onGameUpdate();
	}

	GameCommander::Instance().update();
}

void UAlbertaBotModule::onUnitDestroy(BWAPI::Unit unit)
{
	if (gameEnded) return;

	if (unit->getType().isMineralField())
		BWEMmap.OnMineralDestroyed(unit);
	else if (unit->getType().isSpecialBuilding())
		BWEMmap.OnStaticBuildingDestroyed(unit);

	BWEBmap.onUnitDestroy(unit);
	GameCommander::Instance().onUnitDestroy(unit);
}

void UAlbertaBotModule::onUnitMorph(BWAPI::Unit unit)
{
	if (gameEnded) return;

	BWEBmap.onUnitMorph(unit);
	GameCommander::Instance().onUnitMorph(unit);
}

void UAlbertaBotModule::onUnitCreate(BWAPI::Unit unit)
{ 
	if (gameEnded) return;

	BWEBmap.onUnitDiscover(unit);
	GameCommander::Instance().onUnitCreate(unit);
}

void UAlbertaBotModule::onUnitComplete(BWAPI::Unit unit)
{
	if (gameEnded) return;

	if (Config::Modules::UsingAutoObserver)
	{
		// krasi0 Auto Observer
		_autoObserver.onUnitComplete(unit);
	}

	GameCommander::Instance().onUnitComplete(unit);
}

void UAlbertaBotModule::onUnitShow(BWAPI::Unit unit)
{ 
	if (gameEnded) return;

	if (Config::Modules::UsingAutoObserver)
	{
		// krasi0 Auto Observer
		_autoObserver.onUnitShow(unit);
	}

	GameCommander::Instance().onUnitShow(unit);
}

void UAlbertaBotModule::onUnitHide(BWAPI::Unit unit)
{ 
	if (gameEnded) return;

	GameCommander::Instance().onUnitHide(unit);
}

void UAlbertaBotModule::onUnitRenegade(BWAPI::Unit unit)
{ 
	if (gameEnded) return;

	GameCommander::Instance().onUnitRenegade(unit);
}

void UAlbertaBotModule::onSendText(std::string text)
{
	if (gameEnded) return;

	// ParseTextCommand is disabled
	//ParseUtils::ParseTextCommand(text);
}