////////////////////////////////////////////////////////////////////////////////
// FighterPlayer.cpp
// Class used by the player to control a conventional or aerospace fighter
// Written by Björn Ganster since 2021
////////////////////////////////////////////////////////////////////////////////

#include "Config.h"
#include "FighterPlayer.h"
#include "MechSim.h"
#include "MechVM.h"

#define FILE_NUMBER FILE_NO_FIGHTER_PLAYER_CPP	

// Construct fighter AI
FighterPlayer::FighterPlayer(AeroTech* aeroTech)
: PlayerVehicleAI("FighterPlayer", FighterPlayer_ID, aeroTech),
  mAeroTech(aeroTech),
  mJoystick(nullptr)
{
	mJoystick = registerJoystickListener(this);
}

// Destructor
FighterPlayer::~FighterPlayer()
{
	unregisterJoystickListener(this);
}

// Keyboard event handlers
void FighterPlayer::keypressed(BGKey key, bool shiftHeld, bool controlHeld, bool down, bool repeat)
{
	MechSim* mechSim = getMechSim();
	if (mVehicle == nullptr
	||  mechSim == nullptr) {
		return;
	}
	int env = mechSim->getEnvironment();

	SET_SCOPE;
	switch(key) {
		case '0':
			mAeroTech->setThrust(1.0, env);
			break;
		case '1':
			mAeroTech->setThrust(0.0, env);
			break;
		case '2':
			mAeroTech->setThrust(1.0/9.0, env);
			break;
		case '3':
			mAeroTech->setThrust(2.0/9.0, env);
			break;
		case '4':
			mAeroTech->setThrust(3.0/9.0, env);
			break;
		case '5':
			mAeroTech->setThrust(4.0/9.0, env);
			break;
		case '6':
			mAeroTech->setThrust(5.0/9.0, env);
			break;
		case '7':
			mAeroTech->setThrust(6.0/9.0, env);
			break;
		case '8':
			mAeroTech->setThrust(7.0/9.0, env);
			break;
		case '9':
			mAeroTech->setThrust(8.0/9.0, env);
			break;
		case 'c':
			if (down && !repeat) 
				mPerspective = (mPerspective + 1) % 2;
			break;
		case 'n':
			if (!shiftHeld && down) {
				if (mTarget != nullptr) {
					mTarget = nullptr;
				} else {
					mechSim->selectNextNavPoint();
				}
			}
			break;
		case 'q':
			mTarget = mechSim->findTarget();
			break;
		case 'x':
			if (!shiftHeld && down) {
				mechSim->adjustSatelliteDist(0.5);
			}
			if (shiftHeld && down) {
				mechSim->adjustSatelliteDist(2.0);
			}
			break;
		case '#':
			if (down && !repeat) {
				groupFire = !groupFire;
			}
			break;
		case SDLK_DOWN:
			if (down) {
				mAeroTech->mCurrPitch = -1.0;
			} else {
				mAeroTech->mCurrPitch = 0.0;
			}
			break;
		case SDLK_UP:
			if (down) {
				mAeroTech->mCurrPitch = 1.0;
			} else {
				mAeroTech->mCurrPitch = 0.0;
			}
			break;
		case SDLK_LEFT:
			if (down) {
				mAeroTech->mCurrRoll = 1.0;
			} else {
				mAeroTech->mCurrRoll = 0.0;
			}
			break;
		case SDLK_RIGHT:
			if (down) {
				mAeroTech->mCurrRoll = -1.0;
			} else {
				mAeroTech->mCurrRoll = 0.0;
			}
			break;
	}

	RETURN;
}

// Button state changed over a window: returns child that was clicked
void FighterPlayer::buttonStateChanged(int button, bool down, int /*x*/, int /*y*/)
{
	const MechSim* mechSim = getMechSim();
	DWORD now = mechSim->missionTime();
	if (mVehicle != nullptr && down) {
		if (button == SDL_BUTTON_LEFT && mVehicle->canFireWeapon(mVehicle->mActiveWeapon, now)) {
			mVehicle->fireWeapons(groupFire, now);
		} else {
			mVehicle->cycleWeapon(groupFire);
		}
	}
}

void FighterPlayer::mouseMoved(int /*x*/, int /*y*/)
{
}

// todo: does all AI do it the same way?
void FighterPlayer::setPosition(const Point3D& newPos, double heading)
{
	if (mVehicle != nullptr) {
		mVehicle->setPosition(newPos.x, newPos.y, newPos.z);
	}
}

void FighterPlayer::setAim(double dx, double dy)
{
}

// Stolen code from PlayerGroundVehicle
bool FighterPlayer::weaponActive(int i, bool groupFire) const 
{
	if (mVehicle != nullptr) {
		if (groupFire) {
			int group = mVehicle->getGroup(i);
			return (group == mVehicle->mActiveWeapon);
		} else {
			return (i == mVehicle->mActiveWeapon);
		}
	} else {
		return false;
	}
}


void FighterPlayer::planMovement(DWORD now)
{
}

// Notify AI of an event, like a destroyed object
void FighterPlayer::updateObjectStatus(const BGCPString& id, SubObjectiveType newStatus)
{
}

// Set various data (ignored here because player AI doesn't need it)
void FighterPlayer::setTriggerRange(double newVal)
{
}
void FighterPlayer::addAttackGoal(const BGCPString& target)
{
}
void FighterPlayer::addGoals(const std::vector<AIGoal>& goals, bool clearExisting)
{
}

// Process SDL joystick events
void FighterPlayer::joystickEvent(SDL_Event* event)
{
	MechSim* sim = getMechSim();
	if (sim == nullptr) {
		return;
	}
	int env = sim->getEnvironment();

	Config* config = getConfig();

	switch(event->type) {
		case SDL_JOYAXISMOTION:
			if (event->jaxis.axis == config->getRollAxis()) {
				mAeroTech->mCurrRoll = - event->jaxis.value / 32768.0;
			} else if (event->jaxis.axis == config->getPitchAxis()) {
				mAeroTech->mCurrPitch = - event->jaxis.value / 32768.0;
			} else if (event->jaxis.axis == config->getThrottleAxis()) {
				mAeroTech->setThrust(0.5 - 0.5 * event->jaxis.value / 32768.0, env);
			} 
			break;
		case SDL_JOYBUTTONDOWN:
			{
				int button = event->jbutton.button;
				const MechSim* mechSim = getMechSim();
				DWORD now = mechSim->missionTime();
				if (button == 0 && mVehicle->canFireWeapon(mVehicle->mActiveWeapon, now)) {
					mVehicle->fireWeapons(groupFire, now);
				} else {
					mVehicle->cycleWeapon(groupFire);
				}
			}
			break;
		case SDL_JOYBUTTONUP:
			{
				int button = event->jbutton.button;
				//std::cout << "Joystick button " << button << " up" << std::endl;
			}
			break;
	}
}
