/*
 * 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 "SoldierDiary.h"
#include <algorithm>
#include "../Mod/RuleCommendations.h"
#include "../Mod/Mod.h"
#include "BattleUnitStatistics.h"
#include "MissionStatistics.h"

namespace OpenXcom
{

/**
 * Initializes a new blank diary.
 */
SoldierDiary::SoldierDiary() : _daysWoundedTotal(0), _totalShotByFriendlyCounter(0), _totalShotFriendlyCounter(0), _loneSurvivorTotal(0),
	_monthsService(0), _unconciousTotal(0),	_shotAtCounterTotal(0), _hitCounterTotal(0), _ironManTotal(0), _longDistanceHitCounterTotal(0),
	_lowAccuracyHitCounterTotal(0), _shotsFiredCounterTotal(0), _shotsLandedCounterTotal(0), _shotAtCounter10in1Mission(0), _hitCounter5in1Mission(0),
	_timesWoundedTotal(0), _KIA(0), _allAliensKilledTotal(0), _allAliensStunnedTotal(0), _woundsHealedTotal(0), _allUFOs(0), _allMissionTypes(0),
	_statGainTotal(0), _revivedUnitTotal(0), _wholeMedikitTotal(0), _braveryGainTotal(0), _bestOfRank(0),
	_MIA(0), _martyrKillsTotal(0), _postMortemKills(0), _slaveKillsTotal(0), _bestSoldier(false),
	_revivedSoldierTotal(0), _revivedHostileTotal(0), _revivedNeutralTotal(0), _globeTrotter(false)
{
}

/**
 *
 */
SoldierDiary::~SoldierDiary()
{
	for (std::vector<SoldierCommendations*>::iterator i = _commendations.begin(); i != _commendations.end(); ++i)
	{
		delete *i;
	}
	for (std::vector<BattleUnitKills*>::iterator i = _killList.begin(); i != _killList.end(); ++i)
	{
		delete *i;
	}
}

/**
 * Loads the diary from a YAML file.
 * @param node YAML node.
 */
void SoldierDiary::load(const YAML::Node& node, const Mod *mod)
{
	if (const YAML::Node &commendations = node["commendations"])
	{
		for (YAML::const_iterator i = commendations.begin(); i != commendations.end(); ++i)
		{
			SoldierCommendations *sc = new SoldierCommendations(*i);
			RuleCommendations *commendation = mod->getCommendation(sc->getType());
			if (commendation)
			{
				_commendations.push_back(sc);
			}
			else
			{
				// obsolete commendation, ignore it... otherwise it would cause a crash later
				delete sc;
			}
		}
	}
	if (const YAML::Node &killList = node["killList"])
	{
		for (YAML::const_iterator i = killList.begin(); i != killList.end(); ++i)
			_killList.push_back(new BattleUnitKills(*i));
	}
	_missionIdList = node["missionIdList"].as<std::vector<int> >(_missionIdList);
	_daysWoundedTotal = node["daysWoundedTotal"].as<int>(_daysWoundedTotal);
	_totalShotByFriendlyCounter = node["totalShotByFriendlyCounter"].as<int>(_totalShotByFriendlyCounter);
	_totalShotFriendlyCounter = node["totalShotFriendlyCounter"].as<int>(_totalShotFriendlyCounter);
	_loneSurvivorTotal = node["loneSurvivorTotal"].as<int>(_loneSurvivorTotal);
	_monthsService = node["monthsService"].as<int>(_monthsService);
	_unconciousTotal = node["unconciousTotal"].as<int>(_unconciousTotal);
	_shotAtCounterTotal = node["shotAtCounterTotal"].as<int>(_shotAtCounterTotal);
	_hitCounterTotal = node["hitCounterTotal"].as<int>(_hitCounterTotal);
	_ironManTotal = node["ironManTotal"].as<int>(_ironManTotal);
	_longDistanceHitCounterTotal = node["longDistanceHitCounterTotal"].as<int>(_longDistanceHitCounterTotal);
	_lowAccuracyHitCounterTotal = node["lowAccuracyHitCounterTotal"].as<int>(_lowAccuracyHitCounterTotal);
	_shotsFiredCounterTotal = node["shotsFiredCounterTotal"].as<int>(_shotsFiredCounterTotal);
	_shotsLandedCounterTotal = node["shotsLandedCounterTotal"].as<int>(_shotsLandedCounterTotal);
	_shotAtCounter10in1Mission = node["shotAtCounter10in1Mission"].as<int>(_shotAtCounter10in1Mission);
	_hitCounter5in1Mission = node["hitCounter5in1Mission"].as<int>(_hitCounter5in1Mission);
	_timesWoundedTotal = node["timesWoundedTotal"].as<int>(_timesWoundedTotal);
	_allAliensKilledTotal = node["allAliensKilledTotal"].as<int>(_allAliensKilledTotal);
	_allAliensStunnedTotal = node["allAliensStunnedTotal"].as<int>(_allAliensStunnedTotal);
	_woundsHealedTotal = node["woundsHealedTotal"].as<int>(_woundsHealedTotal);
	_allUFOs = node["allUFOs"].as<int>(_allUFOs);
	_allMissionTypes = node["allMissionTypes"].as<int>(_allMissionTypes);
	_statGainTotal = node["statGainTotal"].as<int>(_statGainTotal);
	_revivedUnitTotal = node["revivedUnitTotal"].as<int>(_revivedUnitTotal);
	_revivedSoldierTotal = node["revivedSoldierTotal"].as<int>(_revivedSoldierTotal);
	_revivedHostileTotal = node["revivedHostileTotal"].as<int>(_revivedHostileTotal);
	_revivedNeutralTotal = node["revivedNeutralTotal"].as<int>(_revivedNeutralTotal);
	_wholeMedikitTotal = node["wholeMedikitTotal"].as<int>(_wholeMedikitTotal);
	_braveryGainTotal = node["braveryGainTotal"].as<int>(_braveryGainTotal);
	_bestOfRank = node["bestOfRank"].as<int>(_bestOfRank);
	_bestSoldier = node["bestSoldier"].as<bool>(_bestSoldier);
	_martyrKillsTotal = node["martyrKillsTotal"].as<int>(_martyrKillsTotal);
	_postMortemKills = node["postMortemKills"].as<int>(_postMortemKills);
	_globeTrotter = node["globeTrotter"].as<bool>(_globeTrotter);
	_slaveKillsTotal = node["slaveKillsTotal"].as<int>(_slaveKillsTotal);
}

/**
 * Saves the diary to a YAML file.
 * @return YAML node.
 */
YAML::Node SoldierDiary::save() const
{
	YAML::Node node;
	for (std::vector<SoldierCommendations*>::const_iterator i = _commendations.begin(); i != _commendations.end(); ++i)
			node["commendations"].push_back((*i)->save());
	for (std::vector<BattleUnitKills*>::const_iterator i = _killList.begin(); i != _killList.end(); ++i)
			node["killList"].push_back((*i)->save());
	if (!_missionIdList.empty()) node["missionIdList"] = _missionIdList;
	if (_daysWoundedTotal) node["daysWoundedTotal"] = _daysWoundedTotal;
	if (_totalShotByFriendlyCounter) node["totalShotByFriendlyCounter"] = _totalShotByFriendlyCounter;
	if (_totalShotFriendlyCounter) node["totalShotFriendlyCounter"] = _totalShotFriendlyCounter;
	if (_loneSurvivorTotal) node["loneSurvivorTotal"] = _loneSurvivorTotal;
	if (_monthsService) node["monthsService"] = _monthsService;
	if (_unconciousTotal) node["unconciousTotal"] = _unconciousTotal;
	if (_shotAtCounterTotal) node["shotAtCounterTotal"] = _shotAtCounterTotal;
	if (_hitCounterTotal) node["hitCounterTotal"] = _hitCounterTotal;
	if (_ironManTotal) node["ironManTotal"] = _ironManTotal;
	if (_longDistanceHitCounterTotal) node["longDistanceHitCounterTotal"] = _longDistanceHitCounterTotal;
	if (_lowAccuracyHitCounterTotal) node["lowAccuracyHitCounterTotal"] = _lowAccuracyHitCounterTotal;
	if (_shotsFiredCounterTotal) node["shotsFiredCounterTotal"] = _shotsFiredCounterTotal;
	if (_shotsLandedCounterTotal) node["shotsLandedCounterTotal"] = _shotsLandedCounterTotal;
	if (_shotAtCounter10in1Mission) node["shotAtCounter10in1Mission"] = _shotAtCounter10in1Mission;
	if (_hitCounter5in1Mission) node["hitCounter5in1Mission"] = _hitCounter5in1Mission;
	if (_timesWoundedTotal) node["timesWoundedTotal"] = _timesWoundedTotal;
	if (_allAliensKilledTotal) node["allAliensKilledTotal"] = _allAliensKilledTotal;
	if (_allAliensStunnedTotal) node["allAliensStunnedTotal"] = _allAliensStunnedTotal;
	if (_woundsHealedTotal) node["woundsHealedTotal"] = _woundsHealedTotal;
	if (_allUFOs) node["allUFOs"] = _allUFOs;
	if (_allMissionTypes) node["allMissionTypes"] = _allMissionTypes;
	if (_statGainTotal) node["statGainTotal"] =_statGainTotal;
	if (_revivedUnitTotal) node["revivedUnitTotal"] = _revivedUnitTotal;
	if (_revivedSoldierTotal) node["revivedSoldierTotal"] = _revivedSoldierTotal;
	if (_revivedHostileTotal) node["revivedHostileTotal"] = _revivedHostileTotal;
	if (_revivedNeutralTotal) node["revivedNeutralTotal"] = _revivedNeutralTotal;
	if (_wholeMedikitTotal) node["wholeMedikitTotal"] = _wholeMedikitTotal;
	if (_braveryGainTotal) node["braveryGainTotal"] = _braveryGainTotal;
	if (_bestOfRank) node["bestOfRank"] = _bestOfRank;
	if (_bestSoldier) node["bestSoldier"] = _bestSoldier;
	if (_martyrKillsTotal) node["martyrKillsTotal"] = _martyrKillsTotal;
	if (_postMortemKills) node["postMortemKills"] = _postMortemKills;
	if (_globeTrotter) node["globeTrotter"] = _globeTrotter;
	if (_slaveKillsTotal) node["slaveKillsTotal"] = _slaveKillsTotal;
	return node;
}

/**
 * Update soldier diary statistics.
 * @param unitStatistics BattleUnitStatistics to get stats from.
 * @param missionStatistics MissionStatistics to get stats from.
 */
void SoldierDiary::updateDiary(BattleUnitStatistics *unitStatistics, std::vector<MissionStatistics*> *allMissionStatistics, Mod *rules)
{
	if (allMissionStatistics->empty()) return;
	MissionStatistics* missionStatistics = allMissionStatistics->back();
	std::vector<BattleUnitKills*> &unitKills = unitStatistics->kills;
	for (std::vector<BattleUnitKills*>::const_iterator kill = unitKills.begin() ; kill != unitKills.end() ; ++kill)
	{
		(*kill)->makeTurnUnique();
		_killList.push_back(*kill);
	}
	unitKills.clear();
	if (missionStatistics->success)
	{
		if (unitStatistics->loneSurvivor)
			_loneSurvivorTotal++;
		if (unitStatistics->ironMan)
			_ironManTotal++;
		if (unitStatistics->nikeCross)
			_allAliensKilledTotal++;
		if (unitStatistics->mercyCross)
			_allAliensStunnedTotal++;
	}
	_daysWoundedTotal += unitStatistics->daysWounded;
	if (unitStatistics->daysWounded)
		_timesWoundedTotal++;

	if (unitStatistics->wasUnconcious)
		_unconciousTotal++;
	_shotAtCounterTotal += unitStatistics->shotAtCounter;
	_shotAtCounter10in1Mission += (unitStatistics->shotAtCounter)/10;
	_hitCounterTotal += unitStatistics->hitCounter;
	_hitCounter5in1Mission += (unitStatistics->hitCounter)/5;
	_totalShotByFriendlyCounter += unitStatistics->shotByFriendlyCounter;
	_totalShotFriendlyCounter += unitStatistics->shotFriendlyCounter;
	_longDistanceHitCounterTotal += unitStatistics->longDistanceHitCounter;
	_lowAccuracyHitCounterTotal += unitStatistics->lowAccuracyHitCounter;
	_shotsFiredCounterTotal += unitStatistics->shotsFiredCounter;
	_shotsLandedCounterTotal += unitStatistics->shotsLandedCounter;
	if (unitStatistics->KIA)
		_KIA++;
	if (unitStatistics->MIA)
		_MIA++;
	_woundsHealedTotal += unitStatistics->woundsHealed;
	if (getUFOTotal(allMissionStatistics).size() >= rules->getUfosList().size())
		_allUFOs = 1;
	if ((getUFOTotal(allMissionStatistics).size() + getTypeTotal(allMissionStatistics).size()) == (rules->getUfosList().size() + rules->getDeploymentsList().size() - 2))
		_allMissionTypes = 1;
	if (getCountryTotal(allMissionStatistics).size() == rules->getCountriesList().size())
		_globeTrotter = true;
	_martyrKillsTotal += unitStatistics->martyr;
	_slaveKillsTotal += unitStatistics->slaveKills;

	// Stat change long hand calculation
	_statGainTotal = 0; // Reset.
	_statGainTotal += unitStatistics->delta.tu;
	_statGainTotal += unitStatistics->delta.stamina;
	_statGainTotal += unitStatistics->delta.health;
	_statGainTotal += unitStatistics->delta.bravery / 10; // Normalize
	_statGainTotal += unitStatistics->delta.reactions;
	_statGainTotal += unitStatistics->delta.firing;
	_statGainTotal += unitStatistics->delta.throwing;
	_statGainTotal += unitStatistics->delta.strength;
	_statGainTotal += unitStatistics->delta.psiStrength;
	_statGainTotal += unitStatistics->delta.melee;
	_statGainTotal += unitStatistics->delta.psiSkill;

	_braveryGainTotal = unitStatistics->delta.bravery;
	_revivedUnitTotal += (unitStatistics->revivedSoldier + unitStatistics->revivedHostile + unitStatistics->revivedNeutral);
	_revivedSoldierTotal += unitStatistics->revivedSoldier;
	_revivedNeutralTotal += unitStatistics->revivedNeutral;
	_revivedHostileTotal += unitStatistics->revivedHostile;
	_wholeMedikitTotal += std::min( std::min(unitStatistics->woundsHealed, unitStatistics->appliedStimulant), unitStatistics->appliedPainKill);
	_missionIdList.push_back(missionStatistics->id);
}

/**
 * Get soldier commendations.
 * @return SoldierCommendations list of soldier's commendations.
 */
std::vector<SoldierCommendations*> *SoldierDiary::getSoldierCommendations()
{
	return &_commendations;
}

/**
 * Manage the soldier's commendations.
 * Award new ones, if deserved.
 * @return bool Has a commendation been awarded?
 */
bool SoldierDiary::manageCommendations(Mod *mod, std::vector<MissionStatistics*> *missionStatistics)
{
	const int BATTLE_TYPES = 13;
	const int DAMAGE_TYPES = 11;
	const std::string battleTypeArray[BATTLE_TYPES] = { "BT_NONE", "BT_FIREARM", "BT_AMMO", "BT_MELEE", "BT_GRENADE",	"BT_PROXIMITYGRENADE", "BT_MEDIKIT", "BT_SCANNER", "BT_MINDPROBE", "BT_PSIAMP", "BT_FLARE", "BT_CORPSE", "BT_END" };
	const std::string damageTypeArray[DAMAGE_TYPES] = { "DT_NONE", "DT_AP", "DT_IN", "DT_HE", "DT_LASER", "DT_PLASMA", "DT_STUN", "DT_MELEE", "DT_ACID", "DT_SMOKE", "DT_END"};

	const std::map<std::string, RuleCommendations *> commendationsList = mod->getCommendationsList();
	bool awardedCommendation = false;                   // This value is returned if at least one commendation was given.
	std::map<std::string, int> nextCommendationLevel;   // Noun, threshold.
	std::vector<std::string> modularCommendations;      // Commendation name.
	bool awardCommendationBool = false;                 // This value determines if a commendation will be given.
	// Loop over all possible commendations
	for (std::map<std::string, RuleCommendations *>::const_iterator i = commendationsList.begin(); i != commendationsList.end(); )
	{
		awardCommendationBool = true;
		nextCommendationLevel.clear();
		nextCommendationLevel["noNoun"] = 0;
		modularCommendations.clear();
		// Loop over all the soldier's commendations, see if we already have the commendation.
		// If so, get the level and noun.
		for (std::vector<SoldierCommendations*>::const_iterator j = _commendations.begin(); j != _commendations.end(); ++j)
		{
			if ( (*i).first == (*j)->getType() )
			{
				nextCommendationLevel[(*j)->getNoun()] = (*j)->getDecorationLevelInt() + 1;
			}
		}
		// Go through each possible criteria. Assume the medal is awarded, set to false if not.
		// As soon as we find a medal criteria that we FAIL TO achieve, then we are not awarded a medal.
		for (std::map<std::string, std::vector<int> >::const_iterator j = (*i).second->getCriteria()->begin(); j != (*i).second->getCriteria()->end(); ++j)
		{
			// Skip this medal if we have reached its max award level.
			if ((unsigned int)nextCommendationLevel["noNoun"] >= (*j).second.size())
			{
				awardCommendationBool = false;
				break;
			}
			// These criteria have no nouns, so only the nextCommendationLevel["noNoun"] will ever be used.
			else if( nextCommendationLevel.count("noNoun") == 1 &&
				  ( ((*j).first == "totalKills" && (unsigned int)getKillTotal() < (unsigned int)(*j).second.at(nextCommendationLevel["noNoun"])) ||
					((*j).first == "totalMissions" && _missionIdList.size() < (unsigned int)(*j).second.at(nextCommendationLevel["noNoun"])) ||
					((*j).first == "totalWins" && getWinTotal(missionStatistics) < (*j).second.at(nextCommendationLevel["noNoun"])) ||
					((*j).first == "totalScore" && getScoreTotal(missionStatistics) < (*j).second.at(nextCommendationLevel["noNoun"])) ||
					((*j).first == "totalStuns" && getStunTotal() < (*j).second.at(nextCommendationLevel["noNoun"])) ||
					((*j).first == "totalDaysWounded" && _daysWoundedTotal < (*j).second.at(nextCommendationLevel["noNoun"])) ||
					((*j).first == "totalBaseDefenseMissions" && getBaseDefenseMissionTotal(missionStatistics) < (*j).second.at(nextCommendationLevel["noNoun"])) ||
					((*j).first == "totalTerrorMissions" && getTerrorMissionTotal(missionStatistics) < (*j).second.at(nextCommendationLevel["noNoun"])) ||
					((*j).first == "totalNightMissions" && getNightMissionTotal(missionStatistics) < (*j).second.at(nextCommendationLevel["noNoun"])) ||
					((*j).first == "totalNightTerrorMissions" && getNightTerrorMissionTotal(missionStatistics) < (*j).second.at(nextCommendationLevel["noNoun"])) ||
					((*j).first == "totalMonthlyService" && _monthsService < (*j).second.at(nextCommendationLevel["noNoun"])) ||
					((*j).first == "totalFellUnconcious" && _unconciousTotal < (*j).second.at(nextCommendationLevel["noNoun"])) ||
					((*j).first == "totalShotAt10Times" && _shotAtCounter10in1Mission < (*j).second.at(nextCommendationLevel["noNoun"])) ||
					((*j).first == "totalHit5Times" && _hitCounter5in1Mission < (*j).second.at(nextCommendationLevel["noNoun"])) ||
					((*j).first == "totalFriendlyFired" && (_totalShotByFriendlyCounter < (*j).second.at(nextCommendationLevel["noNoun"]) || _KIA || _MIA)) ||
					((*j).first == "total_lone_survivor" && _loneSurvivorTotal < (*j).second.at(nextCommendationLevel["noNoun"])) ||
					((*j).first == "totalIronMan" && _ironManTotal < (*j).second.at(nextCommendationLevel["noNoun"])) ||
					((*j).first == "totalImportantMissions" && getImportantMissionTotal(missionStatistics) < (*j).second.at(nextCommendationLevel["noNoun"])) ||
					((*j).first == "totalLongDistanceHits" && _longDistanceHitCounterTotal < (*j).second.at(nextCommendationLevel["noNoun"])) ||
					((*j).first == "totalLowAccuracyHits" && _lowAccuracyHitCounterTotal < (*j).second.at(nextCommendationLevel["noNoun"])) ||
					((*j).first == "totalReactionFire" && getReactionFireKillTotal(mod) < (*j).second.at(nextCommendationLevel["noNoun"])) ||
					((*j).first == "totalTimesWounded" && _timesWoundedTotal < (*j).second.at(nextCommendationLevel["noNoun"])) ||
					((*j).first == "totalDaysWounded" && _daysWoundedTotal < (*j).second.at(nextCommendationLevel["noNoun"])) ||
					((*j).first == "totalValientCrux" && getValiantCruxTotal(missionStatistics) < (*j).second.at(nextCommendationLevel["noNoun"])) ||
					((*j).first == "isDead" && _KIA < (*j).second.at(nextCommendationLevel["noNoun"])) ||
					((*j).first == "totalTrapKills" && getTrapKillTotal(mod) < (*j).second.at(nextCommendationLevel["noNoun"])) ||
					((*j).first == "totalAlienBaseAssaults" && getAlienBaseAssaultTotal(missionStatistics) < (*j).second.at(nextCommendationLevel["noNoun"])) ||
					((*j).first == "totalAllAliensKilled" && _allAliensKilledTotal < (*j).second.at(nextCommendationLevel["noNoun"])) ||
					((*j).first == "totalAllAliensStunned" && _allAliensStunnedTotal < (*j).second.at(nextCommendationLevel["noNoun"])) ||
					((*j).first == "totalWoundsHealed" && _woundsHealedTotal < (*j).second.at(nextCommendationLevel["noNoun"])) ||
					((*j).first == "totalAllUFOs" && _allUFOs < (*j).second.at(nextCommendationLevel["noNoun"])) ||
					((*j).first == "totalAllMissionTypes" && _allMissionTypes < (*j).second.at(nextCommendationLevel["noNoun"])) ||
					((*j).first == "totalStatGain" && _statGainTotal < (*j).second.at(nextCommendationLevel["noNoun"])) ||
					((*j).first == "totalRevives" && _revivedUnitTotal < (*j).second.at(nextCommendationLevel["noNoun"])) ||
					((*j).first == "totalSoldierRevives" && _revivedSoldierTotal < (*j).second.at(nextCommendationLevel["noNoun"])) ||
					((*j).first == "totalHostileRevives" && _revivedHostileTotal < (*j).second.at(nextCommendationLevel["noNoun"])) ||
					((*j).first == "totalNeutralRevives" && _revivedNeutralTotal < (*j).second.at(nextCommendationLevel["noNoun"])) ||
					((*j).first == "totalWholeMedikit" && _wholeMedikitTotal < (*j).second.at(nextCommendationLevel["noNoun"])) ||
					((*j).first == "totalBraveryGain" && _braveryGainTotal < (*j).second.at(nextCommendationLevel["noNoun"])) ||
					((*j).first == "bestOfRank" && _bestOfRank < (*j).second.at(nextCommendationLevel["noNoun"])) ||
					((*j).first == "bestSoldier" && (int)_bestSoldier < (*j).second.at(nextCommendationLevel["noNoun"])) ||
					((*j).first == "isMIA" && _MIA < (*j).second.at(nextCommendationLevel["noNoun"])) ||
					((*j).first == "totalMartyrKills" && _martyrKillsTotal < (*j).second.at(nextCommendationLevel["noNoun"])) ||
					((*j).first == "totalPostMortemKills" && _postMortemKills < (*j).second.at(nextCommendationLevel["noNoun"])) ||
					((*j).first == "globeTrotter" && (int)_globeTrotter < (*j).second.at(nextCommendationLevel["noNoun"])) ||
					((*j).first == "totalSlaveKills" && _slaveKillsTotal < (*j).second.at(nextCommendationLevel["noNoun"])) ) )

			{
				awardCommendationBool = false;
				break;
			}
			// Medals with the following criteria are unique because they need a noun.
			// And because they loop over a map<> (this allows for maximum moddability).
			else if ((*j).first == "totalKillsWithAWeapon" || (*j).first == "totalMissionsInARegion" || (*j).first == "totalKillsByRace" || (*j).first == "totalKillsByRank")
			{
				std::map<std::string, int> tempTotal;
				if ((*j).first == "totalKillsWithAWeapon")
					tempTotal = getWeaponTotal();
				else if ((*j).first == "totalMissionsInARegion")
					tempTotal = getRegionTotal(missionStatistics);
				else if ((*j).first == "totalKillsByRace")
					tempTotal = getAlienRaceTotal();
				else if ((*j).first == "totalKillsByRank")
					tempTotal = getAlienRankTotal();
				// Loop over the temporary map.
				// Match nouns and decoration levels.
				for(std::map<std::string, int>::const_iterator k = tempTotal.begin(); k != tempTotal.end(); ++k)
				{
					int criteria = -1;
					std::string noun = (*k).first;
					// If there is no matching noun, get the first award criteria.
					if (nextCommendationLevel.count(noun) == 0)
						criteria = (*j).second.front();
					// Otherwise, get the criteria that reflects the soldier's commendation level.
					else if ((unsigned int)nextCommendationLevel[noun] != (*j).second.size())
						criteria = (*j).second.at(nextCommendationLevel[noun]);

					// If a criteria was set AND the stat's count exceeds the criteria.
					if (criteria != -1 && (*k).second >= criteria)
					{
						modularCommendations.push_back(noun);
					}
				}
				// If it is still empty, we did not get a commendation.
				if (modularCommendations.empty())
				{
					awardCommendationBool = false;
					break;
				}
			}
			// Medals that are based on _how_ a kill was achieved are found here.
			else if ((*j).first == "killsWithCriteriaCareer" || (*j).first == "killsWithCriteriaMission" || (*j).first == "killsWithCriteriaTurn")
			{
				// Fetch the kill criteria list.
				if (!(*i).second->getKillCriteria())
					break;
				std::vector<std::vector<std::pair<int, std::vector<std::string> > > > *_killCriteriaList = (*i).second->getKillCriteria();

				int totalKillGroups = 0; // holds the total number of kill groups which satisfy one of the OR criteria blocks
				bool enoughForNextCommendation = false;

				// Loop over the OR vectors.
				// if OR criteria are not disjunctive (e.g. "kill 1 enemy" or "kill 1 enemy"), each one will be counted and added to totals - avoid that if you want good statistics
				for (std::vector<std::vector<std::pair<int, std::vector<std::string> > > >::const_iterator orCriteria = _killCriteriaList->begin(); orCriteria != _killCriteriaList->end(); ++orCriteria)
				{
					// prepare counters
					std::vector<int> referenceBlockCounters;
					referenceBlockCounters.assign((*orCriteria).size(), 0);
					int referenceTotalCounters = 0;
					for (std::vector<std::pair<int, std::vector<std::string> > >::const_iterator andCriteria = orCriteria->begin(); andCriteria != orCriteria->end(); ++andCriteria)
					{
						int index = andCriteria - orCriteria->begin();
						referenceBlockCounters[index] = (*andCriteria).first;
						referenceTotalCounters += (*andCriteria).first;
					}
					std::vector<int> currentBlockCounters;
					if ((*j).first == "killsWithCriteriaCareer") {
						currentBlockCounters = referenceBlockCounters;
					}
					int currentTotalCounters = referenceTotalCounters;
					int lastTimeSpan = -1;
					bool skipThisTimeSpan = false;
					// Loop over the KILLS, seeking to fulfill all criteria from entire AND block within the specified time span (career/mission/turn)
					for (std::vector<BattleUnitKills*>::const_iterator singleKill = _killList.begin(); singleKill != _killList.end(); ++singleKill)
					{
						int thisTimeSpan = -1;
						if ((*j).first == "killsWithCriteriaMission")
						{
							thisTimeSpan = (*singleKill)->mission;
						}
						else if ((*j).first == "killsWithCriteriaTurn")
						{
							thisTimeSpan = (*singleKill)->turn;
						}
						if (thisTimeSpan != lastTimeSpan)
						{
							// next time span, reset counters
							lastTimeSpan = thisTimeSpan;
							skipThisTimeSpan = false;
							currentBlockCounters = referenceBlockCounters;
							currentTotalCounters = referenceTotalCounters;
						}
						// same time span, we're skipping the rest of it if we already fulfilled criteria
						else if (skipThisTimeSpan)
						{
							continue;
						}

						bool andCriteriaMet = false;

						// Loop over the AND vectors.
						for (std::vector<std::pair<int, std::vector<std::string> > >::const_iterator andCriteria = orCriteria->begin(); andCriteria != orCriteria->end(); ++andCriteria)
						{
							bool foundMatch = true;

							// Loop over the DETAILs of one AND vector.
							for (std::vector<std::string>::const_iterator detail = andCriteria->second.begin(); detail != andCriteria->second.end(); ++detail)
							{
								int battleType = 0;
								for (; battleType != BATTLE_TYPES; ++battleType)
								{
									if ((*detail) == battleTypeArray[battleType])
									{
										break;
									}
								}

								int damageType = 0;
								for (; damageType != DAMAGE_TYPES; ++damageType)
								{
									if ((*detail) == damageTypeArray[damageType])
									{
										break;
									}
								}

								// See if we find _no_ matches with any criteria. If so, break and try the next kill.
								RuleItem *weapon = mod->getItem((*singleKill)->weapon);
								RuleItem *weaponAmmo = mod->getItem((*singleKill)->weaponAmmo);
								if (weapon == 0 || weaponAmmo == 0 ||
									((*singleKill)->rank != (*detail) && (*singleKill)->race != (*detail) &&
									 (*singleKill)->weapon != (*detail) && (*singleKill)->weaponAmmo != (*detail) &&
									 (*singleKill)->getUnitStatusString() != (*detail) && (*singleKill)->getUnitFactionString() != (*detail) &&
									 (*singleKill)->getUnitSideString() != (*detail) && (*singleKill)->getUnitBodyPartString() != (*detail) &&
									 weaponAmmo->getDamageType() != damageType && weapon->getBattleType() != battleType))
								{
									foundMatch = false;
									break;
								}
							} /// End of DETAIL loop.

							if (foundMatch)
							{
								int index = andCriteria - orCriteria->begin();
								// some current block counters might go into negatives, this is used to tally career kills correctly
								// currentTotalCounters will always ensure we're counting in proper batches
								if (currentBlockCounters[index]-- > 0 && --currentTotalCounters <= 0)
								{
									// we just counted all counters in a block to zero, this certainly means that the entire block criteria is fulfilled
									andCriteriaMet = true;
									break;
								}
							}
						} /// End of AND loop.

						if (andCriteriaMet)
						{
							// early exit if we got enough, no reason to continue iterations
							if (++totalKillGroups >= (*j).second.at(nextCommendationLevel["noNoun"]))
							{
								enoughForNextCommendation = true;
								break;
							}
							
							// "killsWithCriteriaTurn" and "killsWithCriteriaMission" are "peak achivements", they are counted once per their respective time span if criteria are fulfilled
							// so if we got them, we're skipping the rest of this time span to avoid counting more than once
							// e.g. 20 kills in a mission will not be counted as "10 kills in a mission" criteria twice
							// "killsWithCriteriaCareer" are totals, so they are never skipped this way
							if ((*j).first == "killsWithCriteriaTurn" || (*j).first == "killsWithCriteriaMission")
							{
								skipThisTimeSpan = true;
							}
							// for career kills we'll ADD reference counters to the current values and recalculate current total
							// this is used to count instances of full criteria blocks, e.g. if rules state that a career commendation must be awarded for 2 kills of alien leaders
							// and 1 kill of  alien commander, then we must ensure there's 2 leader kills + 1 commander kill for each instance of criteria fulfilled
							else if ((*j).first == "killsWithCriteriaCareer")
							{
								currentTotalCounters = 0;
								for (int i = 0; i < currentBlockCounters.size(); i++)
								{
									currentBlockCounters[i] += referenceBlockCounters[i];
									currentTotalCounters += std::max(currentBlockCounters[i], 0);
								}
							}
						}
					} /// End of KILLs loop.

					if (enoughForNextCommendation)
						break; // stop iterating here too, we've got enough

				} /// End of OR loop.

				if (!enoughForNextCommendation)
					awardCommendationBool = false;

			}
		}
		if (awardCommendationBool)
		{
			// If we do not have modular medals, but are awarded a different medal,
			// its noun will be "noNoun".
			if (modularCommendations.empty())
			{
				modularCommendations.push_back("noNoun");
			}
			for (std::vector<std::string>::const_iterator j = modularCommendations.begin(); j != modularCommendations.end(); ++j)
			{
				bool newCommendation = true;
				for (std::vector<SoldierCommendations*>::iterator k = _commendations.begin() ; k != _commendations.end() ; ++k)
				{
					if ( (*k)->getType() == (*i).first && (*k)->getNoun() == (*j))
					{
						(*k)->addDecoration();
						newCommendation = false;
						break;
					}
				}
				if (newCommendation)
				{
					_commendations.push_back(new SoldierCommendations((*i).first, (*j)));
				}
			}
			awardedCommendation = true;
		}
		else
		{
			++i;
		}
	}
	return awardedCommendation;
}

/**
 * Award commendations to the soldier.
 * @param type string
 * @param noun string
 */
void SoldierDiary::awardCommendation(const std::string& type, const std::string& noun)
{
	bool newCommendation = true;
	for (std::vector<SoldierCommendations*>::iterator i = _commendations.begin() ; i != _commendations.end() ; ++i)
	{
		if ( (*i)->getType() == type && (*i)->getNoun() == noun)
		{
			(*i)->addDecoration();
			newCommendation = false;
			break;
		}
	}
	if (newCommendation)
	{
		_commendations.push_back(new SoldierCommendations(type, noun));
	}
}

/**
 * Get vector of mission ids.
 * @return Vector of mission ids.
 */
std::vector<int> &SoldierDiary::getMissionIdList()
{
	return _missionIdList;
}

/**
 * Get vector of kills.
 * @return vector of BattleUnitKills
 */
std::vector<BattleUnitKills*> &SoldierDiary::getKills()
{
	return _killList;
}

/**
 * Get list of kills sorted by rank
 * @return
 */
std::map<std::string, int> SoldierDiary::getAlienRankTotal()
{
	std::map<std::string, int> list;
	for(std::vector<BattleUnitKills*>::const_iterator kill = _killList.begin(); kill != _killList.end(); ++kill)
	{
		list[(*kill)->rank]++;
	}
	return list;
}

/**
 *
 */
std::map<std::string, int> SoldierDiary::getAlienRaceTotal()
{
	std::map<std::string, int> list;
	for(std::vector<BattleUnitKills*>::const_iterator kill = _killList.begin(); kill != _killList.end(); ++kill)
	{
		list[(*kill)->race]++;
	}
	return list;
}

/**
 *
 */
std::map<std::string, int> SoldierDiary::getWeaponTotal()
{
	std::map<std::string, int> list;
	for(std::vector<BattleUnitKills*>::const_iterator kill = _killList.begin(); kill != _killList.end(); ++kill)
	{
		if ((*kill)->faction == FACTION_HOSTILE)
			list[(*kill)->weapon]++;
	}
	return list;
}

/**
 *
 */
std::map<std::string, int> SoldierDiary::getWeaponAmmoTotal()
{
	std::map<std::string, int> list;
	for(std::vector<BattleUnitKills*>::const_iterator kill = _killList.begin(); kill != _killList.end(); ++kill)
	{
		if ((*kill)->faction == FACTION_HOSTILE)
			list[(*kill)->weaponAmmo]++;
	}
	return list;
}

/**
 *  Get a map of the amount of missions done in each region.
 *  @param MissionStatistics
 */
std::map<std::string, int> SoldierDiary::getRegionTotal(std::vector<MissionStatistics*> *missionStatistics) const
{
	std::map<std::string, int> regionTotal;

	for (std::vector<MissionStatistics*>::const_iterator i = missionStatistics->begin(); i != missionStatistics->end(); ++i)
	{
		for (std::vector<int>::const_iterator j = _missionIdList.begin(); j != _missionIdList.end(); ++j)
		{
			if ((*j) == (*i)->id)
			{
				regionTotal[(*i)->region]++;
			}
		}
	}

	return regionTotal;
}

/**
 *  Get a map of the amount of missions done in each country.
 *  @param MissionStatistics
 */
std::map<std::string, int> SoldierDiary::getCountryTotal(std::vector<MissionStatistics*> *missionStatistics) const
{
	std::map<std::string, int> countryTotal;

	for (std::vector<MissionStatistics*>::const_iterator i = missionStatistics->begin(); i != missionStatistics->end(); ++i)
	{
		for (std::vector<int>::const_iterator j = _missionIdList.begin(); j != _missionIdList.end(); ++j)
		{
			if ((*j) == (*i)->id)
			{
				countryTotal[(*i)->country]++;
			}
		}
	}

	return countryTotal;
}

/**
 *  Get a map of the amount of missions done in each type.
 *  @param MissionStatistics
 */
std::map<std::string, int> SoldierDiary::getTypeTotal(std::vector<MissionStatistics*> *missionStatistics) const
{
	std::map<std::string, int> typeTotal;

	for (std::vector<MissionStatistics*>::const_iterator i = missionStatistics->begin(); i != missionStatistics->end(); ++i)
	{
		for (std::vector<int>::const_iterator j = _missionIdList.begin(); j != _missionIdList.end(); ++j)
		{
			if ((*j) == (*i)->id)
			{
				typeTotal[(*i)->type]++;
			}
		}
	}

	return typeTotal;
}

/**
 *  Get a map of the amount of missions done in each UFO.
 *  @param MissionStatistics
 */
std::map<std::string, int> SoldierDiary::getUFOTotal(std::vector<MissionStatistics*> *missionStatistics) const
{
	std::map<std::string, int> ufoTotal;

	for (std::vector<MissionStatistics*>::const_iterator i = missionStatistics->begin(); i != missionStatistics->end(); ++i)
	{
		for (std::vector<int>::const_iterator j = _missionIdList.begin(); j != _missionIdList.end(); ++j)
		{
			if ((*j) == (*i)->id)
			{
				ufoTotal[(*i)->ufo]++;
			}
		}
	}

	return ufoTotal;
}

/**
 *
 */
int SoldierDiary::getKillTotal() const
{
	int killTotal = 0;

	for (std::vector<BattleUnitKills*>::const_iterator i = _killList.begin(); i != _killList.end(); ++i)
	{
		if ((*i)->status == STATUS_DEAD && (*i)->faction == FACTION_HOSTILE)
		{
			killTotal++;
		}
	}

	return killTotal;
}

/**
 *
 */
int SoldierDiary::getMissionTotal() const
{
	return _missionIdList.size();
}

/**
 *  Get the total if wins.
 *  @param Mission Statistics
 */
int SoldierDiary::getWinTotal(std::vector<MissionStatistics*> *missionStatistics) const
{
	int winTotal = 0;

	for (std::vector<MissionStatistics*>::const_iterator i = missionStatistics->begin(); i != missionStatistics->end(); ++i)
	{
		for (std::vector<int>::const_iterator j = _missionIdList.begin(); j != _missionIdList.end(); ++j)
		{
			if ((*j) == (*i)->id)
			{
				if ((*i)->success)
				{
					winTotal++;
				}
			}
		}
	}

	return winTotal;
}

/**
 *
 */
int SoldierDiary::getStunTotal() const
{
	int stunTotal = 0;

	for (std::vector<BattleUnitKills*>::const_iterator i = _killList.begin(); i != _killList.end(); ++i)
	{
		if ((*i)->status == STATUS_UNCONSCIOUS && (*i)->faction == FACTION_HOSTILE)
		{
			stunTotal++;
		}
	}

	return stunTotal;
}

/**
 *
 */
int SoldierDiary::getPanickTotal() const
{
	int panickTotal = 0;

	for (std::vector<BattleUnitKills*>::const_iterator i = _killList.begin(); i != _killList.end(); ++i)
	{
		if ((*i)->status == STATUS_PANICKING && (*i)->faction == FACTION_HOSTILE)
		{
			panickTotal++;
		}
	}

	return panickTotal;
}

/**
 *
 */
int SoldierDiary::getControlTotal() const
{
	int controlTotal = 0;

	for (std::vector<BattleUnitKills*>::const_iterator i = _killList.begin(); i != _killList.end(); ++i)
	{
		if ((*i)->status == STATUS_TURNING && (*i)->faction == FACTION_HOSTILE)
		{
			controlTotal++;
		}
	}

	return controlTotal;
}

/**
 *
 */
int SoldierDiary::getDaysWoundedTotal() const
{
	return _daysWoundedTotal;
}

/**
 * Increment soldier's service time one month
 */
void SoldierDiary::addMonthlyService()
{
	_monthsService++;
}

/**
 * Returns the total months this soldier has been in service.
 */
int SoldierDiary::getMonthsService() const
{
	return _monthsService;
}

/**
 * Award special commendation to the original 8 soldiers.
 */
void SoldierDiary::awardOriginalEightCommendation()
{
	// TODO: Unhardcode this
	_commendations.push_back(new SoldierCommendations("STR_MEDAL_ORIGINAL8_NAME", "NoNoun"));
}

/**
 * Award post-humous best-of commendation.
 */
void SoldierDiary::awardBestOfRank(int score)
{
	_bestOfRank = score;
}

/**
 * Award post-humous best-of commendation.
 */
void SoldierDiary::awardBestOverall(int score)
{
	_bestSoldier = score;
}

/**
 * Award post-humous kills commendation.
 */
void SoldierDiary::awardPostMortemKill(int kills)
{
	_postMortemKills = kills;
}

/**
 *
 */
int SoldierDiary::getShotsFiredTotal() const
{
	return _shotsFiredCounterTotal;
}

/**
 *
 */
int SoldierDiary::getShotsLandedTotal() const
{
	return _shotsLandedCounterTotal;
}

/**
 *  Get the soldier's accuracy.
 */
int SoldierDiary::getAccuracy() const
{
	if (_shotsFiredCounterTotal != 0)
		return 100 * _shotsLandedCounterTotal / _shotsFiredCounterTotal;
	return 0;
}

/**
 *  Get trap kills total.
 */
int SoldierDiary::getTrapKillTotal(Mod *mod) const
{
	int trapKillTotal = 0;

	for (std::vector<BattleUnitKills*>::const_iterator i = _killList.begin(); i != _killList.end(); ++i)
	{
		RuleItem *item = mod->getItem((*i)->weapon);
		if ((*i)->hostileTurn() && (item == 0 || item->getBattleType() == BT_GRENADE || item->getBattleType() == BT_PROXIMITYGRENADE))
		{
			trapKillTotal++;
		}
	}

	return trapKillTotal;
}

/**
 *  Get reaction kill total.
 */
 int SoldierDiary::getReactionFireKillTotal(Mod *mod) const
 {
	int reactionFireKillTotal = 0;

	for (std::vector<BattleUnitKills*>::const_iterator i = _killList.begin(); i != _killList.end(); ++i)
	{
		RuleItem *item = mod->getItem((*i)->weapon);
		if ((*i)->hostileTurn() && item != 0 && item->getBattleType() != BT_GRENADE && item->getBattleType() != BT_PROXIMITYGRENADE)
		{
			reactionFireKillTotal++;
		}
	}

	return reactionFireKillTotal;
 }

/**
 *  Get the total of terror missions.
 *  @param Mission Statistics
 */
int SoldierDiary::getTerrorMissionTotal(std::vector<MissionStatistics*> *missionStatistics) const
{
	/// Not a UFO, not the base, not the alien base or colony
	int terrorMissionTotal = 0;

	for (std::vector<MissionStatistics*>::const_iterator i = missionStatistics->begin(); i != missionStatistics->end(); ++i)
	{
		for (std::vector<int>::const_iterator j = _missionIdList.begin(); j != _missionIdList.end(); ++j)
		{
			if ((*j) == (*i)->id)
			{
				if ((*i)->success && !(*i)->isBaseDefense() && !(*i)->isUfoMission() && !(*i)->isAlienBase())
				{
					terrorMissionTotal++;
				}
			}
		}
	}

	return terrorMissionTotal;
}

/**
 *  Get the total of night missions.
 *  @param Mission Statistics
 */
int SoldierDiary::getNightMissionTotal(std::vector<MissionStatistics*> *missionStatistics) const
{
	int nightMissionTotal = 0;

	for (std::vector<MissionStatistics*>::const_iterator i = missionStatistics->begin(); i != missionStatistics->end(); ++i)
	{
		for (std::vector<int>::const_iterator j = _missionIdList.begin(); j != _missionIdList.end(); ++j)
		{
			if ((*j) == (*i)->id)
			{
				if ((*i)->success && (*i)->isDarkness() && !(*i)->isBaseDefense() && !(*i)->isAlienBase())
				{
					nightMissionTotal++;
				}
			}
		}
	}

	return nightMissionTotal;
}

/**
 *  Get the total of night terror missions.
 *  @param Mission Statistics
 */
int SoldierDiary::getNightTerrorMissionTotal(std::vector<MissionStatistics*> *missionStatistics) const
{
	int nightTerrorMissionTotal = 0;

	for (std::vector<MissionStatistics*>::const_iterator i = missionStatistics->begin(); i != missionStatistics->end(); ++i)
	{
		for (std::vector<int>::const_iterator j = _missionIdList.begin(); j != _missionIdList.end(); ++j)
		{
			if ((*j) == (*i)->id)
			{
				if ((*i)->success && (*i)->isDarkness() && !(*i)->isBaseDefense() && !(*i)->isUfoMission() && !(*i)->isAlienBase())
				{
					nightTerrorMissionTotal++;
				}
			}
		}
	}

	return nightTerrorMissionTotal;
}

/**
 *  Get the total of base defense missions.
 *  @param Mission Statistics
 */
int SoldierDiary::getBaseDefenseMissionTotal(std::vector<MissionStatistics*> *missionStatistics) const
{
	int baseDefenseMissionTotal = 0;

	for (std::vector<MissionStatistics*>::const_iterator i = missionStatistics->begin(); i != missionStatistics->end(); ++i)
	{
		for (std::vector<int>::const_iterator j = _missionIdList.begin(); j != _missionIdList.end(); ++j)
		{
			if ((*j) == (*i)->id)
			{
				if ((*i)->success && (*i)->isBaseDefense())
				{
					baseDefenseMissionTotal++;
				}
			}
		}
	}

	return baseDefenseMissionTotal;
}

/**
 *  Get the total of alien base assaults.
 *  @param Mission Statistics
 */
int SoldierDiary::getAlienBaseAssaultTotal(std::vector<MissionStatistics*> *missionStatistics) const
{
	int alienBaseAssaultTotal = 0;

	for (std::vector<MissionStatistics*>::const_iterator i = missionStatistics->begin(); i != missionStatistics->end(); ++i)
	{
		for (std::vector<int>::const_iterator j = _missionIdList.begin(); j != _missionIdList.end(); ++j)
		{
			if ((*j) == (*i)->id)
			{
				if ((*i)->success && (*i)->isAlienBase())
				{
					alienBaseAssaultTotal++;
				}
			}
		}
	}

	return alienBaseAssaultTotal;
}

/**
 *  Get the total of important missions.
 *  @param Mission Statistics
 */
int SoldierDiary::getImportantMissionTotal(std::vector<MissionStatistics*> *missionStatistics) const
{
	int importantMissionTotal = 0;

	for (std::vector<MissionStatistics*>::const_iterator i = missionStatistics->begin(); i != missionStatistics->end(); ++i)
	{
		for (std::vector<int>::const_iterator j = _missionIdList.begin(); j != _missionIdList.end(); ++j)
		{
			if ((*j) == (*i)->id)
			{
				if ((*i)->success && (*i)->type != "STR_UFO_CRASH_RECOVERY")
				{
					importantMissionTotal++;
				}
			}
		}
	}

	return importantMissionTotal;
}

/**
 *  Get the total score.
 *  @param Mission Statistics
 */
int SoldierDiary::getScoreTotal(std::vector<MissionStatistics*> *missionStatistics) const
{
	int scoreTotal = 0;

	for (std::vector<MissionStatistics*>::const_iterator i = missionStatistics->begin(); i != missionStatistics->end(); ++i)
	{
		for (std::vector<int>::const_iterator j = _missionIdList.begin(); j != _missionIdList.end(); ++j)
		{
			if ((*j) == (*i)->id)
			{
				scoreTotal += (*i)->score;
			}
		}
	}

	return scoreTotal;
}

/**
 *  Get the Valient Crux total.
 *  @param Mission Statistics
 */
int SoldierDiary::getValiantCruxTotal(std::vector<MissionStatistics*> *missionStatistics) const
{
	int valiantCruxTotal = 0;

	for (std::vector<MissionStatistics*>::const_iterator i = missionStatistics->begin(); i != missionStatistics->end(); ++i)
	{
		for (std::vector<int>::const_iterator j = _missionIdList.begin(); j != _missionIdList.end(); ++j)
		{
			if ((*j) == (*i)->id && (*i)->valiantCrux)
			{
				valiantCruxTotal++;
			}
		}
	}

	return valiantCruxTotal;
}

/**
 *  Get the loot value total.
 *  @param Mission Statistics
 */
int SoldierDiary::getLootValueTotal(std::vector<MissionStatistics*> *missionStatistics) const
{
	int lootValueTotal = 0;

	for (std::vector<MissionStatistics*>::const_iterator i = missionStatistics->begin(); i != missionStatistics->end(); ++i)
	{
		for (std::vector<int>::const_iterator j = _missionIdList.begin(); j != _missionIdList.end(); ++j)
		{
			if ((*j) == (*i)->id)
			{
				lootValueTotal += (*i)->lootValue;
			}
		}
	}

	return lootValueTotal;
}

/**
 * Initializes a new commendation entry from YAML.
 * @param node YAML node.
 */
SoldierCommendations::SoldierCommendations(const YAML::Node &node)
{
	load(node);
}

/**
 * Initializes a soldier commendation.
 */
SoldierCommendations::SoldierCommendations(std::string commendationName, std::string noun) : _type(commendationName), _noun(noun), _decorationLevel(0), _isNew(true)
{
}

/**
 *
 */
SoldierCommendations::~SoldierCommendations()
{
}

/**
 * Loads the commendation from a YAML file.
 * @param node YAML node.
 */
void SoldierCommendations::load(const YAML::Node &node)
{
	_type = node["commendationName"].as<std::string>(_type);
	_noun = node["noun"].as<std::string>("noNoun");
	_decorationLevel = node["decorationLevel"].as<int>(_decorationLevel);
	_isNew = node["isNew"].as<bool>(false);
}

/**
 * Saves the commendation to a YAML file.
 * @return YAML node.
 */
YAML::Node SoldierCommendations::save() const
{
	YAML::Node node;
	node["commendationName"] = _type;
	if (_noun != "noNoun") node["noun"] = _noun;
	node["decorationLevel"] = _decorationLevel;
	return node;
}

/**
 * Get the soldier's commendation's name.
 * @return string Commendation name.
 */
std::string SoldierCommendations::getType() const
{
	return _type;
}

/**
 * Get the soldier's commendation's noun.
 * @return string Commendation noun
 */
std::string SoldierCommendations::getNoun() const
{
	return _noun;
}

/**
 * Get the soldier commendation level's name.
 * @return string Commendation level.
 */
std::string SoldierCommendations::getDecorationLevelName(int skipCounter) const
{
	std::ostringstream ss;
	ss << "STR_AWARD_" << _decorationLevel - skipCounter;
	return ss.str();
}

/**
 * Get the soldier commendation level's description.
 * @return string Commendation level description.
 */
std::string SoldierCommendations::getDecorationDescription() const
{
	std::ostringstream ss;
	ss << "STR_AWARD_DECOR_" << _decorationLevel;
	return ss.str();
}

/**
 * Get the soldier commendation level's int.
 * @return int Commendation level.
 */
int SoldierCommendations::getDecorationLevelInt() const
{
	return _decorationLevel;
}

/**
 * Get newness of commendation.
 * @return bool Is the commendation new?
 */
bool SoldierCommendations::isNew() const
{
	return _isNew;
}

/**
 * Set the newness of the commendation to old.
 */
void SoldierCommendations::makeOld()
{
	_isNew = false;
}

/**
 * Add a level of decoration to the commendation.
 * Sets isNew to true.
 */
void SoldierCommendations::addDecoration()
{
	_decorationLevel++;
	_isNew = true;
}

}
