/* ScummVM - Graphic Adventure Engine
 *
 * ScummVM is the legal property of its developers, whose names
 * are too numerous to list here. Please refer to the COPYRIGHT
 * file distributed with this source distribution.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 *
 */

#include "bladerunner/script/ai_script.h"

namespace BladeRunner {

AIScriptKlein::AIScriptKlein(BladeRunnerEngine *vm) : AIScriptBase(vm) {
}

void AIScriptKlein::Initialize() {
	_animationState = 0;
	_animationFrame = 0;
	_animationStateNext = 0;
	Actor_Put_In_Set(kActorKlein, kSetPS07);
	Actor_Set_At_XYZ(kActorKlein, 338.0f, 0.22f, -612.0f, 768);
	Actor_Set_Goal_Number(kActorKlein, kGoalKleinDefault);
}

bool AIScriptKlein::Update() {
	if (_vm->_cutContent) {
		if (Global_Variable_Query(kVariableChapter) > 3 && Actor_Query_Goal_Number(kActorKlein) < kGoalKleinAwayAtEndOfActThree) {
			Actor_Set_Goal_Number(kActorKlein, kGoalKleinAwayAtEndOfActThree);
			return true;
		}
	} else {
		// original behavior - Klein disappears after Act 1
		if (Global_Variable_Query(kVariableChapter) > 1 && Actor_Query_Goal_Number(kActorKlein) < kGoalKleinAwayAtEndOfActOne) {
			Actor_Set_Goal_Number(kActorKlein, kGoalKleinAwayAtEndOfActOne);
			return true;
		}
	}

	if (Actor_Query_Goal_Number(kActorKlein) < kGoalKleinIsAnnoyedByMcCoyInit
	    && Actor_Query_Friendliness_To_Other(kActorKlein, kActorMcCoy) < 40
	) {
		Actor_Set_Goal_Number(kActorKlein, kGoalKleinIsAnnoyedByMcCoyInit);
	}

	if (Player_Query_Current_Scene() == kScenePS07 && Actor_Query_Goal_Number(kActorKlein) == kGoalKleinDefault) {
		Actor_Set_Goal_Number(kActorKlein, kGoalKleinMovingInLab01);
		return true;
	}

	if (!_vm->_cutContent) {
		// Original behavior:
		// The following if-clauses and flags circumvent the manual's explicit instruction
		// that McCoy should upload his clues on the Mainframe, so that Dino Klein can acquire them.
		if (Actor_Clue_Query(kActorMcCoy, kClueOfficersStatement)
		    && !Game_Flag_Query(kFlagMcCoyHasOfficersStatement)
		) {
			Game_Flag_Set(kFlagMcCoyHasOfficersStatement);
		}
		if (Actor_Clue_Query(kActorMcCoy, kCluePaintTransfer)
		    && !Game_Flag_Query(kFlagMcCoyHasPaintTransfer)
		) {
			Game_Flag_Set(kFlagMcCoyHasPaintTransfer);
		}
		if (Actor_Clue_Query(kActorMcCoy, kClueShellCasings)
		    && !Game_Flag_Query(kFlagMcCoyHasShellCasings)
		) {
			Game_Flag_Set(kFlagMcCoyHasShellCasings);
		}
		if (Actor_Clue_Query(kActorMcCoy, kClueChromeDebris)
		    && !Game_Flag_Query(kFlagMcCoyHasChromeDebris)
		) {
			Game_Flag_Set(kFlagMcCoyHasChromeDebris);
		}
	}

	// The following deals with the case that Klein gets annoyed by McCoy
	if (Player_Query_Current_Scene() == kScenePS07
	    && ((_vm->_cutContent && Actor_Query_Friendliness_To_Other(kActorKlein, kActorMcCoy) < 40)
	        || (!_vm->_cutContent && Actor_Query_Friendliness_To_Other(kActorKlein, kActorMcCoy) < 35) )
	    && !Game_Flag_Query(kFlagPS07KleinInsulted)
	) {
		// kActorTimerAIScriptCustomTask2 causes the "Klein is annoyed dialogue" to occur after a few seconds
		AI_Countdown_Timer_Reset(kActorKlein, kActorTimerAIScriptCustomTask2);
		if (_vm->_cutContent) {
			// original's 5 seconds is too slow. Reduce it to 2 seconds
			Actor_Set_Goal_Number(kActorKlein, kGoalKleinIsAnnoyedByMcCoyPreInit);
			AI_Countdown_Timer_Start(kActorKlein, kActorTimerAIScriptCustomTask2, 2);
		} else {
			AI_Countdown_Timer_Start(kActorKlein, kActorTimerAIScriptCustomTask2, 5);
		}
		Game_Flag_Set(kFlagPS07KleinInsulted);
		return true;
	}

	// The following deals with how Klein recovers from being annoyed at McCoy
	if (Actor_Query_Goal_Number(kActorKlein) == kGoalKleinIsAnnoyedByMcCoyFinal) {
		if (Actor_Query_Friendliness_To_Other(kActorKlein, kActorMcCoy) > 20
		    && Actor_Query_Friendliness_To_Other(kActorKlein, kActorMcCoy) < 40
		) {
			// when insulted, slowly increase friendliness again, until it's at 40 or greater
			Actor_Modify_Friendliness_To_Other(kActorKlein, kActorMcCoy, 2);
#if !BLADERUNNER_ORIGINAL_BUGS
			if (Actor_Query_Friendliness_To_Other(kActorKlein, kActorMcCoy) < 40) {
				// if after the increase (+2) it is still lower than 40 then keep being annoyed
				Actor_Set_Goal_Number(kActorKlein, kGoalKleinIsAnnoyedByMcCoyInit);
				return true;
			}
#endif // BLADERUNNER_ORIGINAL_BUGS
		}

#if BLADERUNNER_ORIGINAL_BUGS
		AI_Movement_Track_Flush(kActorKlein);
		Actor_Set_Goal_Number(kActorKlein, kGoalKleinDefault);
#else
		// don't go to Default if Actor_Query_Friendliness_To_Other(kActorKlein, kActorMcCoy) <= 20
		// and also reset kFlagPS07KleinInsulted if the friendliness is now above 40
		if (Actor_Query_Friendliness_To_Other(kActorKlein, kActorMcCoy) >= 40)
		{
			if (Game_Flag_Query(kFlagPS07KleinInsulted)) {
				Game_Flag_Reset(kFlagPS07KleinInsulted);
				// don't reset the kFlagPS07KleinInsultedTalk
			}
			AI_Movement_Track_Flush(kActorKlein);
			Actor_Set_Goal_Number(kActorKlein, kGoalKleinDefault);
		}
#endif // BLADERUNNER_ORIGINAL_BUGS
		return true;
	}
	return false;
}

void AIScriptKlein::TimerExpired(int timer) {
	if (timer == kActorTimerAIScriptCustomTask2) {
#if !BLADERUNNER_ORIGINAL_BUGS
		// This timer expiration was buggy; it would play the short dialogue version
		// even when the timer expires even if McCoy has left the room and is somewhere else
		// The fix is to return when the player is somewhere else
		if (Player_Query_Current_Set() != kSetPS07
		    || !Actor_Query_Is_In_Current_Set(kActorKlein)
		    || !Game_Flag_Query(kFlagPS07KleinInsulted)
		) {
			if (Actor_Query_Goal_Number(kActorKlein) == kGoalKleinIsAnnoyedByMcCoyPreInit) {
				Actor_Set_Goal_Number(kActorKlein, kGoalKleinDefault);
			}
			return;
		}
		AI_Movement_Track_Flush(kActorKlein);
#endif
		if (!Game_Flag_Query(kFlagPS07KleinInsultedTalk)
#if BLADERUNNER_ORIGINAL_BUGS
			// this is redundant now because we return in the added code above if Klein is not insulted
			// (and the flag now gets reset when Klein calms down)
		    && Game_Flag_Query(kFlagPS07KleinInsulted)
			// this is redundant now because we return in the added code above if Klein is not in the current set
		    && Actor_Query_Is_In_Current_Set(kActorKlein)
#endif
		) {
			// Klein is annoyed - full dialogue
			Actor_Face_Actor(kActorKlein, kActorMcCoy, true);
			Actor_Says(kActorKlein, 10, kAnimationModeTalk);
			Actor_Says(kActorMcCoy, 4120, kAnimationModeTalk);
			Actor_Says(kActorKlein, 20, kAnimationModeTalk);
			Actor_Says(kActorMcCoy, 4125, kAnimationModeTalk);
			Game_Flag_Set(kFlagPS07KleinInsultedTalk);
#if BLADERUNNER_ORIGINAL_BUGS
			Actor_Set_Goal_Number(kActorKlein, kGoalKleinIsAnnoyedByMcCoyInit);
#else
			if (Actor_Query_Goal_Number(kActorKlein) != kGoalKleinIsAnnoyedByMcCoyInit) {
				Actor_Set_Goal_Number(kActorKlein, kGoalKleinIsAnnoyedByMcCoyInit);
			}
#endif // BLADERUNNER_ORIGINAL_BUGS
		} else {
			// Klein is annoyed - short dialogue
			Actor_Says(kActorKlein, 10, kAnimationModeTalk);
#if BLADERUNNER_ORIGINAL_BUGS
			Actor_Set_Goal_Number(kActorKlein, kGoalKleinIsAnnoyedByMcCoyInit);
#else
			if (Actor_Query_Goal_Number(kActorKlein) != kGoalKleinIsAnnoyedByMcCoyInit) {
				Actor_Set_Goal_Number(kActorKlein, kGoalKleinIsAnnoyedByMcCoyInit);
			}
#endif // BLADERUNNER_ORIGINAL_BUGS
		}
		// return true;
	}
	//return false;
}

void AIScriptKlein::CompletedMovementTrack() {
	// Normal behavior
	if (Actor_Query_Goal_Number(kActorKlein) == kGoalKleinMovingInLab01) {
		Actor_Set_Goal_Number(kActorKlein, kGoalKleinMovingInLab02);
		return; // true;
	}
	if (Actor_Query_Goal_Number(kActorKlein) == kGoalKleinMovingInLab02) {
		Actor_Set_Goal_Number(kActorKlein, kGoalKleinMovingInLab01);
		return; // true;
	}

	// Annoyed behavior
	if (Actor_Query_Goal_Number(kActorKlein) == kGoalKleinIsAnnoyedByMcCoyInit) {
		Actor_Set_Goal_Number(kActorKlein, kGoalKleinIsAnnoyedByMcCoy01);
		if (_vm->_cutContent) {
			return;
		}
		// NOTE: original was missing return here
	}
	if (Actor_Query_Goal_Number(kActorKlein) == kGoalKleinIsAnnoyedByMcCoy01) {
		Actor_Set_Goal_Number(kActorKlein, kGoalKleinIsAnnoyedByMcCoy02);
		if (_vm->_cutContent) {
			return;
		}
		// NOTE: original was missing return here
	}
	if (Actor_Query_Goal_Number(kActorKlein) == kGoalKleinIsAnnoyedByMcCoy02) {
		Actor_Set_Goal_Number(kActorKlein, kGoalKleinIsAnnoyedByMcCoyFinal);
		return; // true;
	}
	if (Actor_Query_Goal_Number(kActorKlein) == kGoalKleinIsAnnoyedByMcCoyFinal) {
#if BLADERUNNER_ORIGINAL_BUGS
		Actor_Set_Goal_Number(kActorKlein, kGoalKleinDefault);
#else
		if (Actor_Query_Friendliness_To_Other(kActorKlein, kActorMcCoy) < 40) {
			Actor_Set_Goal_Number(kActorKlein, kGoalKleinIsAnnoyedByMcCoyInit);
		} else {
			if (Game_Flag_Query(kFlagPS07KleinInsulted)) {
				Game_Flag_Reset(kFlagPS07KleinInsulted);
				// don't reset the kFlagPS07KleinInsultedTalk
			}
			Actor_Set_Goal_Number(kActorKlein, kGoalKleinDefault);
		}
#endif // BLADERUNNER_ORIGINAL_BUGS
		return; // true;
	}
	// return false;
}

void AIScriptKlein::ReceivedClue(int clueId, int fromActorId) {
	//return false;
}

void AIScriptKlein::ClickedByPlayer() {
	//return false;
}

void AIScriptKlein::EnteredScene(int sceneId) {
	// return false;
}

void AIScriptKlein::OtherAgentEnteredThisScene(int otherActorId) {
	// return false;
}

void AIScriptKlein::OtherAgentExitedThisScene(int otherActorId) {
	// return false;
}

void AIScriptKlein::OtherAgentEnteredCombatMode(int otherActorId, int combatMode) {
	// return false;
}

void AIScriptKlein::ShotAtAndMissed() {
	// return false;
}

bool AIScriptKlein::ShotAtAndHit() {
	return false;
}

void AIScriptKlein::Retired(int byActorId) {
	// return false;
}

int AIScriptKlein::GetFriendlinessModifierIfGetsClue(int otherActorId, int clueId) {
	return 0;
}

bool AIScriptKlein::GoalChanged(int currentGoalNumber, int newGoalNumber) {
	switch (newGoalNumber) {
	case kGoalKleinMovingInLab01:
		AI_Movement_Track_Flush(kActorKlein);
		AI_Movement_Track_Append(kActorKlein, 73, Random_Query(3, 20));  // kSetPS07
		AI_Movement_Track_Repeat(kActorKlein);
		break;
	case kGoalKleinMovingInLab02:
		AI_Movement_Track_Flush(kActorKlein);
		AI_Movement_Track_Append(kActorKlein, 74, Random_Query(10, 20)); // kSetPS07
		AI_Movement_Track_Repeat(kActorKlein);
		break;
	case kGoalKleinGotoLabSpeaker:
		AI_Movement_Track_Flush(kActorKlein);
		AI_Movement_Track_Append(kActorKlein, 31, 3);  // kSetPS07
		AI_Movement_Track_Repeat(kActorKlein);
		break;
	case kGoalKleinIsAnnoyedByMcCoyPreInit:
		// aux goal (added)
		break;
	case kGoalKleinIsAnnoyedByMcCoyInit:
		AI_Movement_Track_Flush(kActorKlein);
		AI_Movement_Track_Append(kActorKlein, 32, 5);  // kSetPS07 (hidden spot)
		AI_Movement_Track_Repeat(kActorKlein);
		break;
	case kGoalKleinIsAnnoyedByMcCoy01:
		AI_Movement_Track_Flush(kActorKlein);
		if (_vm->_cutContent) {
			AI_Movement_Track_Append(kActorKlein, 35, Random_Query(8, 24)); // kSetFreeSlotC
		} else {
			// this never really gets triggered in the original game
			AI_Movement_Track_Append(kActorKlein, 35, 60); // kSetFreeSlotC
		}
		AI_Movement_Track_Repeat(kActorKlein);
		break;
	case kGoalKleinIsAnnoyedByMcCoy02:
		AI_Movement_Track_Flush(kActorKlein);
		AI_Movement_Track_Append(kActorKlein, 32, 5);  // kSetPS07 (hidden spot)
		AI_Movement_Track_Repeat(kActorKlein);
		break;
	case kGoalKleinIsAnnoyedByMcCoyFinal:
		// Note: Original was missing the kGoalKleinIsAnnoyedByMcCoyFinal case
		//       so we just "break" for the original behavior
		if (_vm->_cutContent) {
			AI_Movement_Track_Flush(kActorKlein);
			AI_Movement_Track_Append(kActorKlein, 74, Random_Query(10, 20)); // kSetPS07
			AI_Movement_Track_Repeat(kActorKlein);
		}
		break;
	case kGoalKleinAwayAtEndOfActThree:
		// fall-through
	case kGoalKleinAwayAtEndOfActOne:
		AI_Movement_Track_Flush(kActorKlein);
		Actor_Put_In_Set(kActorKlein, kSetFreeSlotC);
		Actor_Set_At_Waypoint(kActorKlein, 35, 0);    //  kSetFreeSlotC
		break;
	}
	return false;
}

bool AIScriptKlein::UpdateAnimation(int *animation, int *frame) {
	switch (_animationState) {
	case 0:
		if (Actor_Query_Goal_Number(kActorKlein) == kGoalKleinMovingInLab01
		    || Actor_Query_Goal_Number(kActorKlein) == kGoalKleinMovingInLab02
		) {
			*animation = kModelAnimationKleinWorkingOnInstruments;
			_animationFrame++;
			if (_animationFrame >= Slice_Animation_Query_Number_Of_Frames(kModelAnimationKleinWorkingOnInstruments)) {
				_animationFrame = 0;
			}
		} else if (!Game_Flag_Query(kFlagKleinAnimation1)
		           && Actor_Query_Goal_Number(kActorKlein) == kGoalKleinGotoLabSpeaker
		) {
			*animation = kModelAnimationKleinStandingIdle;
			_animationFrame++;
			if (_animationFrame >= Slice_Animation_Query_Number_Of_Frames(kModelAnimationKleinStandingIdle)) {
				_animationFrame = 0;
				if (Random_Query(1, 10) == 1) {
					Game_Flag_Set(kFlagKleinAnimation1);
				}
			}
		} else {
			if (Game_Flag_Query(kFlagKleinAnimation3)
			    && Actor_Query_Goal_Number(kActorKlein) == kGoalKleinGotoLabSpeaker
			) {
				_animationFrame--;
				if (_animationFrame < 0) {
					_animationFrame = 0;
				}
			} else {
				++_animationFrame;
			}

			*animation = kModelAnimationKleinTalkScratchBackOfHead;
			if (_animationFrame <= 9) {
				if (Game_Flag_Query(kFlagKleinAnimation3)) {
					Game_Flag_Reset(kFlagKleinAnimation3);
				}
			}
			if (_animationFrame == 14) {
				if (Random_Query(1, 5) == 1) {
					Game_Flag_Set(kFlagKleinAnimation2);
				}
			}
			if (_animationFrame == 15) {
				if (Game_Flag_Query(kFlagKleinAnimation2)) {
					Game_Flag_Reset(kFlagKleinAnimation2);
					Game_Flag_Set(kFlagKleinAnimation3);
				}
			}
			if (_animationFrame >= Slice_Animation_Query_Number_Of_Frames(kModelAnimationKleinTalkScratchBackOfHead)) {
				_animationFrame = 0;
				Game_Flag_Reset(kFlagKleinAnimation1);
			}
		}
		break;
	case 1:
		*animation = kModelAnimationKleinWalking;
		_animationFrame++;
		if (_animationFrame >= Slice_Animation_Query_Number_Of_Frames(kModelAnimationKleinWalking)) {
			_animationFrame = 0;
		}
		break;
	case 2:
		*animation = kModelAnimationKleinTalkSmallLeftHandMove;
		_animationFrame++;
		if (_animationFrame >= Slice_Animation_Query_Number_Of_Frames(kModelAnimationKleinTalkSmallLeftHandMove)) {
			_animationFrame = 0;
		}
		break;
	case 3:
		*animation = kModelAnimationKleinTalkRightHandTouchFace;
		_animationFrame++;
		if (_animationFrame >= Slice_Animation_Query_Number_Of_Frames(kModelAnimationKleinTalkRightHandTouchFace)) {
			_animationState = 2;
			_animationFrame = 0;
			*animation = kModelAnimationKleinTalkSmallLeftHandMove;
		}
		break;
	case 4:
		*animation = kModelAnimationKleinTalkWideHandMotion;
		_animationFrame++;
		if (_animationFrame >= Slice_Animation_Query_Number_Of_Frames(kModelAnimationKleinTalkWideHandMotion)) {
			_animationState = 2;
			_animationFrame = 0;
			*animation = kModelAnimationKleinTalkSmallLeftHandMove;
		}
		break;
	case 5:
		*animation = kModelAnimationKleinTalkSuggestOrAsk;
		_animationFrame++;
		if (_animationFrame >= Slice_Animation_Query_Number_Of_Frames(kModelAnimationKleinTalkSuggestOrAsk)) {
			_animationState = 2;
			_animationFrame = 0;
			*animation = kModelAnimationKleinTalkSmallLeftHandMove;
		}
		break;
	case 6:
		*animation = kModelAnimationKleinTalkDismissive;
		_animationFrame++;
		if (_animationFrame >= Slice_Animation_Query_Number_Of_Frames(kModelAnimationKleinTalkDismissive)) {
			_animationState = 2;
			_animationFrame = 0;
			*animation = kModelAnimationKleinTalkSmallLeftHandMove;
		}
		break;
	case 7:
		*animation = kModelAnimationKleinTalkRaisingBothHands;
		_animationFrame++;
		if (_animationFrame>= Slice_Animation_Query_Number_Of_Frames(kModelAnimationKleinTalkRaisingBothHands)) {
			_animationState = 2;
			_animationFrame = 0;
			*animation = kModelAnimationKleinTalkSmallLeftHandMove;
		}
		break;
	case 8:
		_animationFrame = 0;
		*animation      = _animationNext;
		_animationState = _animationStateNext;
		break;
	default:
		*animation = 399; // TODO: A bug? This belongs to Zuben
		break;
	}
	*frame = _animationFrame;
	return true;
}

bool AIScriptKlein::ChangeAnimationMode(int mode) {
	switch (mode) {
	case kAnimationModeIdle:
		_animationState = 0;
		_animationFrame = 0;
		break;
	case kAnimationModeWalk:
		if (_animationState > 1) {
			_animationState = 1;
			_animationFrame = 0;
		} else if (_animationState == 0) {
			_animationState = 8;
			_animationStateNext = 1;
			_animationNext = kModelAnimationKleinWalking;
		}
		break;
	case kAnimationModeTalk:
		if (_animationState > 0) {
			_animationState = 2;
			_animationFrame = 0;
		} else {
			_animationState = 8;
			_animationStateNext = 2;
			_animationNext = kModelAnimationKleinTalkSmallLeftHandMove;
		}
		break;
	case 12:
		if (_animationState > 0) {
			_animationState = 2;
			_animationFrame = 0;
		} else {
			_animationState = 8;
			_animationStateNext = 3;
			_animationNext = kModelAnimationKleinTalkRightHandTouchFace;
		}
		break;
	case 13:
		if (_animationState > 0) {
			_animationState = 2;
			_animationFrame = 0;
		} else {
			_animationState = 8;
			_animationStateNext = 4;
			_animationNext = kModelAnimationKleinTalkWideHandMotion;
		}
		break;
	case 14:
		if (_animationState > 0) {
			_animationState = 2;
			_animationFrame = 0;
		} else {
			_animationState = 8;
			_animationStateNext = 5;
			_animationNext = kModelAnimationKleinTalkSuggestOrAsk;
		}
		break;
	case 15:
		if (_animationState > 0) {
			_animationState = 2;
			_animationFrame = 0;
		} else {
			_animationState = 8;
			_animationStateNext = 6;
			_animationNext = kModelAnimationKleinTalkDismissive;
		}
		break;
	case 16:
		if (_animationState > 0) {
			_animationState = 2;
			_animationFrame = 0;
		} else {
			_animationState = 8;
			_animationStateNext = 7;
			_animationNext = kModelAnimationKleinTalkRaisingBothHands;
		}
		break;
	}
	return true;
}

void AIScriptKlein::QueryAnimationState(int *animationState, int *animationFrame, int *animationStateNext, int *animationNext) {
	*animationState     = _animationState;
	*animationFrame     = _animationFrame;
	*animationStateNext = _animationStateNext;
	*animationNext      = _animationNext;
}

void AIScriptKlein::SetAnimationState(int animationState, int animationFrame, int animationStateNext, int animationNext) {
	_animationState     = animationState;
	_animationFrame     = animationFrame;
	_animationStateNext = animationStateNext;
	_animationNext      = animationNext;
}

bool AIScriptKlein::ReachedMovementTrackWaypoint(int waypointId) {
	if (waypointId == 73 || waypointId == 74) {
		Actor_Face_Heading(kActorKlein, 768, false);
	}
	if (waypointId == 31) {
		Actor_Face_Heading(kActorKlein, 216, false);
	}
	return true;
}

void AIScriptKlein::FledCombat() {
	// return false;
}

} // End of namespace BladeRunner