/*
 * Copyright 2010-2016 OpenXcom Developers.
 *
 * This file is part of OpenXcom.
 *
 * OpenXcom 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 3 of the License, or
 * (at your option) any later version.
 *
 * OpenXcom 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 OpenXcom.  If not, see <http://www.gnu.org/licenses/>.
 */
#include "MedikitState.h"
#include "MedikitView.h"
#include "../Engine/InteractiveSurface.h"
#include "../Engine/Game.h"
#include "../Engine/LocalizedText.h"
#include "../Engine/Action.h"
#include "../Engine/Palette.h"
#include "../Interface/Text.h"
#include "../Engine/Screen.h"
#include "../Savegame/BattleItem.h"
#include "../Savegame/BattleUnit.h"
#include "../Mod/RuleItem.h"
#include "../Mod/Mod.h"
#include <sstream>
#include "../Engine/Options.h"
#include "../Savegame/SavedGame.h"
#include "../Savegame/SavedBattleGame.h"
#include "../Savegame/BattleUnitStatistics.h"
 
namespace OpenXcom
{
 
/**
 * Helper function that returns a string representation of a type (mainly used for numbers).
 * @param t The value to stringify.
 * @return A string representation of the value.
 */
template<typename type>
std::string toString (type t)
{
	std::ostringstream ss;
	ss << t;
	return ss.str();
}
 
/**
 * Helper class for the medikit title.
 */
class MedikitTitle : public Text
{
public:
	/// Creates a medikit title.
	MedikitTitle(int y, const std::string & title);
};
 
/**
 * Initializes a Medikit title.
 * @param y The title's y origin.
 * @param title The title.
 */
MedikitTitle::MedikitTitle (int y, const std::string & title) : Text (73, 9, 186, y)
{
	this->setText(title);
	this->setHighContrast(true);
	this->setAlign(ALIGN_CENTER);
}
 
/**
 * Helper class for the medikit value.
 */
class MedikitTxt : public Text
{
public:
	/// Creates a medikit text.
	MedikitTxt(int y);
};
 
/**
 * Initializes a Medikit text.
 * @param y The text's y origin.
 */
MedikitTxt::MedikitTxt(int y) : Text(33, 17, 220, y)
{
	// Note: we can't set setBig here. The needed font is only set when added to State
	this->setColor(Palette::blockOffset(1));
	this->setHighContrast(true);
	this->setAlign(ALIGN_CENTER);
}
 
/**
 * Helper class for the medikit button.
 */
class MedikitButton : public InteractiveSurface
{
public:
	/// Creates a medikit button.
	MedikitButton(int y);
};
 
/**
 * Initializes a Medikit button.
 * @param y The button's y origin.
 */
MedikitButton::MedikitButton(int y) : InteractiveSurface(30, 20, 190, y)
{
}
 
/**
 * Initializes the Medikit State.
 * @param game Pointer to the core game.
 * @param targetUnit The wounded unit.
 * @param action The healing action.
 */
MedikitState::MedikitState (BattleUnit *targetUnit, BattleAction *action) : _targetUnit(targetUnit), _action(action), _revivedTarget(false)
{
	if (Options::maximizeInfoScreens)
	{
		Options::baseXResolution = Screen::ORIGINAL_WIDTH;
		Options::baseYResolution = Screen::ORIGINAL_HEIGHT;
		_game->getScreen()->resetDisplay(false);
	}
 
	_tu = action->TU;
	_unit = action->actor;
	_item = action->weapon;
	_bg = new Surface(320, 200);
 
	// Set palette
	_game->getSavedGame()->getSavedBattle()->setPaletteByDepth(this);
 
	if (_game->getScreen()->getDY() > 50)
	{
		_screen = false;
		_bg->drawRect(67, 44, 190, 100, Palette::blockOffset(15)+15);
	}
	_partTxt = new Text(62, 9, 82, 120);
	_woundTxt = new Text(14, 9, 145, 120);
	_medikitView = new MedikitView(52, 58, 95, 60, _game, _targetUnit, _partTxt, _woundTxt);
	_endButton = new InteractiveSurface(20, 20, 220, 140);
	_stimulantButton = new MedikitButton(84);
	_pkButton = new MedikitButton(48);
	_healButton = new MedikitButton(120);
	_pkText = new MedikitTxt (52);
	_stimulantTxt = new MedikitTxt (88);
	_healTxt = new MedikitTxt (124);
	add(_bg);
	add(_medikitView, "body", "medikit", _bg);
	add(_endButton, "buttonEnd", "medikit", _bg);
	add(new MedikitTitle (37, tr("STR_PAIN_KILLER")), "textPK", "medikit", _bg);
	add(new MedikitTitle (73, tr("STR_STIMULANT")), "textStim", "medikit", _bg);
	add(new MedikitTitle (109, tr("STR_HEAL")), "textHeal", "medikit", _bg);
	add(_healButton, "buttonHeal", "medikit", _bg);
	add(_stimulantButton, "buttonStim", "medikit", _bg);
	add(_pkButton, "buttonPK", "medikit", _bg);
	add(_pkText, "numPK", "medikit", _bg);
	add(_stimulantTxt, "numStim", "medikit", _bg);
	add(_healTxt, "numHeal", "medikit", _bg);
	add(_partTxt, "textPart", "medikit", _bg);
	add(_woundTxt, "numWounds", "medikit", _bg);
 
	centerAllSurfaces();
 
	_game->getMod()->getSurface("MEDIBORD.PCK")->blit(_bg);
	_pkText->setBig();
	_stimulantTxt->setBig();
	_healTxt->setBig();
	_partTxt->setHighContrast(true);
	_woundTxt->setHighContrast(true);
	_endButton->onMouseClick((ActionHandler)&MedikitState::onEndClick);
	_endButton->onKeyboardPress((ActionHandler)&MedikitState::onEndClick, Options::keyCancel);
	_healButton->onMouseClick((ActionHandler)&MedikitState::onHealClick);
	_stimulantButton->onMouseClick((ActionHandler)&MedikitState::onStimulantClick);
	_pkButton->onMouseClick((ActionHandler)&MedikitState::onPainKillerClick);
	update();
}
 
/**
 * Closes the window on right-click.
 * @param action Pointer to an action.
 */
void MedikitState::handle(Action *action)
{
	State::handle(action);
	if (action->getDetails()->type == SDL_MOUSEBUTTONDOWN && action->getDetails()->button.button == SDL_BUTTON_RIGHT)
	{
		onEndClick(0);
	}
}
 
/**
 * Returns to the previous screen.
 * @param action Pointer to an action.
 */
void MedikitState::onEndClick(Action *)
{
	if (Options::maximizeInfoScreens)
	{
		Screen::updateScale(Options::battlescapeScale, Options::baseXBattlescape, Options::baseYBattlescape, true);
		_game->getScreen()->resetDisplay(false);
	}
	_game->popState();
}
 
/**
 * Handler for clicking on the heal button.
 * @param action Pointer to an action.
 */
void MedikitState::onHealClick(Action *)
{
	int heal = _item->getHealQuantity();
	RuleItem *rule = _item->getRules();
	if (heal == 0)
	{
		return;
	}
	if (_unit->spendTimeUnits(_tu))
	{
		_targetUnit->heal(_medikitView->getSelectedPart(), rule->getWoundRecovery(), rule->getHealthRecovery());
		_item->setHealQuantity(--heal);
		_medikitView->updateSelectedPart();
		_medikitView->invalidate();
		update();
 
		if (_targetUnit->getStatus() == STATUS_UNCONSCIOUS && _targetUnit->getStunlevel() < _targetUnit->getHealth() && _targetUnit->getHealth() > 0)
		{
			if (!_revivedTarget)
			{
				_targetUnit->setTimeUnits(0);
				if(_targetUnit->getOriginalFaction() == FACTION_PLAYER)
				{
					_action->actor->getStatistics()->revivedSoldier++;
				}
				else if(_targetUnit->getOriginalFaction() == FACTION_HOSTILE)
				{
					_action->actor->getStatistics()->revivedHostile++;
				}
				else
				{
					_action->actor->getStatistics()->revivedNeutral++;
				}
				_revivedTarget = true;
			}
			// if the unit has revived and has no more wounds, we quit this screen automatically
			if (_targetUnit->getFatalWounds() == 0)
			{
				onEndClick(0);
			}
		}
		_unit->getStatistics()->woundsHealed++;
	}
	else
	{
		_action->result = "STR_NOT_ENOUGH_TIME_UNITS";
		onEndClick(0);
	}
}
 
/**
 * Handler for clicking on the stimulant button.
 * @param action Pointer to an action.
 */
void MedikitState::onStimulantClick(Action *)
{
	int stimulant = _item->getStimulantQuantity();
	RuleItem *rule = _item->getRules();
	if (stimulant == 0)
	{
		return;
	}
	if (_unit->spendTimeUnits (_tu))
	{
		_targetUnit->stimulant(rule->getEnergyRecovery(), rule->getStunRecovery());
		_item->setStimulantQuantity(--stimulant);
		_action->actor->getStatistics()->appliedStimulant++;
		update();
 
		// if the unit has revived we quit this screen automatically
		if (_targetUnit->getStatus() == STATUS_UNCONSCIOUS && _targetUnit->getStunlevel() < _targetUnit->getHealth() && _targetUnit->getHealth() > 0)
		{
			_targetUnit->setTimeUnits(0);
			if(_targetUnit->getOriginalFaction() == FACTION_PLAYER)
			{
				_action->actor->getStatistics()->revivedSoldier++;
			}
			else if(_targetUnit->getOriginalFaction() == FACTION_HOSTILE)
			{
				_action->actor->getStatistics()->revivedHostile++;
			}
			else
			{
				_action->actor->getStatistics()->revivedNeutral++;
			}
			onEndClick(0);
		}
	}
	else
	{
		_action->result = "STR_NOT_ENOUGH_TIME_UNITS";
		onEndClick(0);
	}
}
 
/**
 * Handler for clicking on the pain killer button.
 * @param action Pointer to an action.
 */
void MedikitState::onPainKillerClick(Action *)
{
	int pk = _item->getPainKillerQuantity();
	if (pk == 0)
	{
		return;
	}
	if (_unit->spendTimeUnits (_tu))
	{
		_targetUnit->painKillers();
		_item->setPainKillerQuantity(--pk);
		_action->actor->getStatistics()->appliedPainKill++;
		update();
	}
	else
	{
		_action->result = "STR_NOT_ENOUGH_TIME_UNITS";
		onEndClick(0);
	}
}
 
/**
 * Updates the medikit state.
 */
void MedikitState::update()
{
	_pkText->setText(toString(_item->getPainKillerQuantity()));
	_stimulantTxt->setText(toString(_item->getStimulantQuantity()));
	_healTxt->setText(toString(_item->getHealQuantity()));
	_medikitView->invalidate();
}
 
}

V1053 Calling the 'setHighContrast' virtual function in the constructor may lead to unexpected result at runtime.

V1053 Calling the 'setColor' virtual function in the constructor may lead to unexpected result at runtime.

V1053 Calling the 'setHighContrast' virtual function in the constructor may lead to unexpected result at runtime.