//
//  World.cpp
//  Game
//
//  Created by Darvydas on 24/01/2019.
//

#include "Config/Config.hpp"
#include "Game/GameScene/World/Player.hpp"
#include "Game/GameScene/HUD/HUD.hpp"
#include "Game/GameScene/HUD/StatisticBar.hpp"
#include "Game/GameScene/Scene.hpp"

using namespace cocos2d;

namespace Game
{
    CPlayer *CPlayer::create(Map::CHouse* pcHouse, cocos2d::Size sSize, CHUD* hud)
    {
        CPlayer* player = new CPlayer;
        
        player->m_pcHouse = pcHouse;
        
        if (player->init())
        {
			player->autorelease();
            
            player->setTextureRect(Rect(0, 0, sSize.width, sSize.height));
            player->setOpacity(0.0f);
            
			player->createVisualElements(hud);
            
            player->scheduleUpdate();
            
            player->m_eKeyW = EkeyState::None;
            player->m_eKeyA = EkeyState::None;
            player->m_eKeyS = EkeyState::None;
            player->m_eKeyD = EkeyState::None;
            
            player->setUp();
            
            player->createDragonBones();
            
            return player;
        }
        CC_SAFE_DELETE(player);
        return NULL;
    }
    
    cocos2d::Point CPlayer::getTilePositionPositionInWorld(cocos2d::Point pPoint)
    {
        return cocos2d::Point(pPoint.x / CConfig::m_fTileDimension, pPoint.y / CConfig::m_fTileDimension);
    }
    
    void CPlayer::update(const float dt)
    {
        const float kfSpeedMultiplier = 0.1f;
        
        Point lastSpeed = m_pCurrentSpeed;
        
        if (m_eKeyD != EkeyState::Pressed && m_eKeyA == EkeyState::Pressed && canMoveToDirection(Utils::EDirection::Left))
        {
            m_pCurrentSpeed.x = -m_fSpeed * kfSpeedMultiplier;
        }
        else if (m_eKeyA != EkeyState::Pressed && m_eKeyD == EkeyState::Pressed && canMoveToDirection(Utils::EDirection::Right))
        {
            m_pCurrentSpeed.x = m_fSpeed * kfSpeedMultiplier;
        }
        else
        {
            m_pCurrentSpeed.x = 0.0f;
        }
        
        if (m_eKeyS != EkeyState::Pressed && m_eKeyW == EkeyState::Pressed && canMoveToDirection(Utils::EDirection::Up))
        {
            m_pCurrentSpeed.y = m_fSpeed * kfSpeedMultiplier;
        }
        else if (m_eKeyW != EkeyState::Pressed && m_eKeyS == EkeyState::Pressed && canMoveToDirection(Utils::EDirection::Down))
        {
            m_pCurrentSpeed.y = -m_fSpeed * kfSpeedMultiplier;
        }
        else
        {
            m_pCurrentSpeed.y = 0.0f;
        }
        
        
        
        // animation changes
        
        if (m_pCurrentSpeed.x < lastSpeed.x)
        {
            if (m_pCurrentSpeed.x < 0)
            {
                armatureDisplay->setOpacity(0.0f);
                armatureDisplaySide->setOpacity(255.0f);
                armatureDisplaySide->getAnimation()->play("animtionSide");
                armatureDisplaySide->setScale(-1.0f, 1.0f);
            }
            else
            {
                armatureDisplay->setOpacity(0.0f);
                armatureDisplaySide->setOpacity(255.0f);
                armatureDisplaySide->getAnimation()->play("animtionSide_idle");
                armatureDisplaySide->setScale(1.0f, 1.0f);
            }
        }
        else if (m_pCurrentSpeed.x > lastSpeed.x)
        {
            if (m_pCurrentSpeed.x > 0)
            {
                armatureDisplay->setOpacity(0.0f);
                armatureDisplaySide->setOpacity(255.0f);
                armatureDisplaySide->getAnimation()->play("animtionSide");
                armatureDisplaySide->setScale(1.0f, 1.0f);
            }
            else
            {
                armatureDisplay->setOpacity(0.0f);
                armatureDisplaySide->setOpacity(255.0f);
                armatureDisplaySide->getAnimation()->play("animtionSide_idle");
                armatureDisplaySide->setScale(-1.0f, 1.0f);
            }
        }
        
        
        if (m_pCurrentSpeed.x == 0)
        {
            if (m_pCurrentSpeed.y < lastSpeed.y || (m_pCurrentSpeed.y < 0 && lastSpeed.x != 0))
            {
                if (m_pCurrentSpeed.y < 0)
                {
                    armatureDisplaySide->setOpacity(0.0f);
                    armatureDisplay->setOpacity(255.0f);
                    armatureDisplay->getAnimation()->play("animtion0");
                }
                else
                {
                    armatureDisplaySide->setOpacity(0.0f);
                    armatureDisplay->setOpacity(255.0f);
                    armatureDisplay->getAnimation()->play("animtion_idle_back");
                }
            }
            else if (m_pCurrentSpeed.y > lastSpeed.y || (m_pCurrentSpeed.y > 0 && lastSpeed.x != 0))
            {
                if (m_pCurrentSpeed.y > 0)
                {
                    armatureDisplaySide->setOpacity(0.0f);
                    armatureDisplay->setOpacity(255.0f);
                    armatureDisplay->getAnimation()->play("animtion0_back");
                    armatureDisplay->setScale(1.0f, 1.0f);
                }
                else
                {
                    armatureDisplaySide->setOpacity(0.0f);
                    armatureDisplay->setOpacity(255.0f);
                    armatureDisplay->getAnimation()->play("animtion_idle");
                    armatureDisplay->setScale(-1.0f, 1.0f);
                }
            }
        }
        // end animation changes
        
        
        
        this->setPosition(Point(this->getPosition().x + m_pCurrentSpeed.x, this->getPosition().y + m_pCurrentSpeed.y));
    }
    
    bool CPlayer::canMoveToDirection(Utils::EDirection eDirection)
    {
        Point pDistance;
        if (eDirection == Utils::EDirection::Left)
        {
            pDistance = Point(-1.0f, 0.0f);
        }
        else if (eDirection == Utils::EDirection::Right)
        {
            pDistance = Point(1.0f, 0.0f);
        }
        if (eDirection == Utils::EDirection::Up)
        {
            pDistance = Point(0.0f, 1.0f);
        }
        else if (eDirection == Utils::EDirection::Down)
        {
            pDistance = Point(0.0f, -1.0f);
        }
        
        pDistance *= 0.75f;
        Point pCurrentPosition = getTilePositionPositionInWorld(this->getPosition());
        Point pNextPosition = pCurrentPosition + pDistance;
        
        if (m_pcHouse->getTileValue(int(pNextPosition.x), int(pNextPosition.y)) != kTileAlive)
        {
            return false;
        }
        return true;
    }
    
    void CPlayer::keyPressed(EventKeyboard::KeyCode keyCode)
    {
        switch (keyCode) {
            case cocos2d::EventKeyboard::KeyCode::KEY_UP_ARROW:
            case cocos2d::EventKeyboard::KeyCode::KEY_W:
            {
                m_eKeyW = EkeyState::Pressed;
                break;
            }
            case cocos2d::EventKeyboard::KeyCode::KEY_LEFT_ARROW:
            case cocos2d::EventKeyboard::KeyCode::KEY_A:
            {
                m_eKeyA = EkeyState::Pressed;
                break;
            }
            case cocos2d::EventKeyboard::KeyCode::KEY_DOWN_ARROW:
            case cocos2d::EventKeyboard::KeyCode::KEY_S:
            {
                m_eKeyS = EkeyState::Pressed;
                break;
            }
            case cocos2d::EventKeyboard::KeyCode::KEY_RIGHT_ARROW:
            case cocos2d::EventKeyboard::KeyCode::KEY_D:
            {
                m_eKeyD = EkeyState::Pressed;
                break;
            }
            default:
                break;
        }
    }
    
    void CPlayer::keyReleased(EventKeyboard::KeyCode keyCode)
    {
        switch (keyCode) {
            case cocos2d::EventKeyboard::KeyCode::KEY_W:
            {
                m_eKeyW = EkeyState::Unpressed;
                break;
            }
            case cocos2d::EventKeyboard::KeyCode::KEY_A:
            {
                m_eKeyA = EkeyState::Unpressed;
                break;
            }
            case cocos2d::EventKeyboard::KeyCode::KEY_S:
            {
                m_eKeyS = EkeyState::Unpressed;
                break;
            }
            case cocos2d::EventKeyboard::KeyCode::KEY_D:
            {
                m_eKeyD = EkeyState::Unpressed;
                break;
            }
            default:
                break;
        }
    }

	LevelStatus CPlayer::AddVitality(int value)
	{
		if (value != 0)
		{
			m_CHUD->m_VitalityBar->addValue(value);
			m_CharacterData.vitality += value;
			if (m_CharacterData.vitality < 0)
			{
				m_CharacterData.vitality = 0;
			}
			if (m_CharacterData.vitality > 20)
			{
				m_CharacterData.vitality = 20;
			}
			return CheckStatsForLevelEnd();
		}
		return LEVEL_PLAYING;
	}

	LevelStatus CPlayer::AddIntelligence(int value)
	{
		if (value != 0)
		{
			m_CHUD->m_IntelligenceBar->addValue(value);
			m_CharacterData.intelligence += value;
			if (m_CharacterData.intelligence < 0)
			{
				m_CharacterData.intelligence = 0;
			}
			if (m_CharacterData.intelligence > 20)
			{
				m_CharacterData.intelligence = 20;
			}
			return CheckStatsForLevelEnd();
		}
		return LEVEL_PLAYING;
	}

	LevelStatus CPlayer::AddSanity(int value)
	{
		if (value != 0)
		{
			m_CHUD->m_SanityBar->addValue(value);
			m_CharacterData.sanity += value;
			if (m_CharacterData.sanity < 0)
			{
				m_CharacterData.sanity = 0;
			}
			if (m_CharacterData.sanity > 20)
			{
				m_CharacterData.sanity = 20;
			}
			return CheckStatsForLevelEnd();
		}
		return LEVEL_PLAYING;
	}

	LevelStatus CPlayer::AddEndurance(int value)
	{
		if (value != 0)
		{
			m_CHUD->m_EnduranceBar->addValue(value);
			m_CharacterData.endurance += value;
			if (m_CharacterData.endurance < 0)
			{
				m_CharacterData.endurance = 0;
			}
			if (m_CharacterData.endurance > 20)
			{
				m_CharacterData.endurance = 20;
			}
			return CheckStatsForLevelEnd();
		}
		return LEVEL_PLAYING;
	}

	LevelStatus CPlayer::AddCharisma(int value)
	{
		if (value != 0)
		{
			m_CHUD->m_CharismaBar->addValue(value);
			m_CharacterData.charisma += value;
			if (m_CharacterData.charisma < 0)
			{
				m_CharacterData.charisma = 0;
			}
			if (m_CharacterData.charisma > 20)
			{
				m_CharacterData.charisma = 20;
			}
			return CheckStatsForLevelEnd();
		}
		return LEVEL_PLAYING;
	}

	Game::LevelStatus CPlayer::CheckStatsForLevelEnd()
	{
		bool gameSuccesEnd = true;
		int average = 10;

		for (auto& objStat : m_ObjectiveStats)
		{
			if (objStat.m_StatType == VITALITY)
			{
				if (objStat.m_Target > average && m_CharacterData.vitality < objStat.m_Target)
				{
					gameSuccesEnd = false;
				}
				if (objStat.m_Target < average && m_CharacterData.vitality > objStat.m_Target)
				{
					gameSuccesEnd = false;
				}
			}
			else if (objStat.m_StatType == INTELLIGENCE)
			{
				if (objStat.m_Target > average && m_CharacterData.intelligence < objStat.m_Target)
				{
					gameSuccesEnd = false;
				}
				if (objStat.m_Target < average && m_CharacterData.intelligence > objStat.m_Target)
				{
					gameSuccesEnd = false;
				}
			}
			else if (objStat.m_StatType == SANITY)
			{
				if (objStat.m_Target > average && m_CharacterData.sanity < objStat.m_Target)
				{
					gameSuccesEnd = false;
				}
			}
			else if (objStat.m_StatType == ENDURANCE)
			{
				if (objStat.m_Target > average && m_CharacterData.endurance < objStat.m_Target)
				{
					gameSuccesEnd = false;
				}
				if (objStat.m_Target < average && m_CharacterData.endurance > objStat.m_Target)
				{
					gameSuccesEnd = false;
				}
			}
			else if (objStat.m_StatType == CHARISMA)
			{
				if (objStat.m_Target > average && m_CharacterData.charisma < objStat.m_Target)
				{
					gameSuccesEnd = false;
				}
				if (objStat.m_Target < average && m_CharacterData.charisma > objStat.m_Target)
				{
					gameSuccesEnd = false;
				}
			}
		}

		if (!gameSuccesEnd) // check for lose
		{
			if (m_CharacterData.vitality == 0 || m_CharacterData.vitality == 20 ||
				m_CharacterData.intelligence == 0 || m_CharacterData.intelligence == 20 ||
				m_CharacterData.sanity == 0 || m_CharacterData.sanity == 20 ||
				m_CharacterData.endurance == 0 || m_CharacterData.endurance == 20 ||
				m_CharacterData.charisma == 0 || m_CharacterData.charisma == 20)
			{
				if (CScene::m_SceneDisposed == 0)
				{
					CScene::m_SceneDisposed = 1;

					armatureDisplay->dispose();
					armatureDisplaySide->dispose();

					CScene::m_StartingLevel = 1;
					CScene::m_StartingCharacter = 1;

					auto scene = CScene::createScene(CScene::m_StartingLevel, CScene::m_StartingCharacter);
					Director::getInstance()->replaceScene(cocos2d::TransitionFade::create(1.0f, scene, Color3B::BLACK));
				}

				return LEVEL_LOST;
			}
			else
			{
				return LEVEL_PLAYING;
			}
		}
		else
		{
			if (CScene::m_SceneDisposed == 0)
			{
				CScene::m_SceneDisposed = 1;
				armatureDisplay->dispose();
				armatureDisplaySide->dispose();
				auto scene = CScene::createScene(++CScene::m_StartingLevel, ++CScene::m_StartingCharacter);
				Director::getInstance()->replaceScene(cocos2d::TransitionFade::create(1.0f, scene, Color3B::BLACK));
			}

			return LEVEL_WON;
		}
	}

	void CPlayer::OnNextLevel()
	{
		++m_CharacterCurrID;
		if (m_CharacterCurrID == m_CharacterSkins.size())
		{
			m_CharacterCurrID = 0; // start again from neutral
		}

		// Get new data from character skin
		SCharacter* characterSkin = m_CharacterSkins[m_CharacterCurrID];
		m_CharacterData.characterName = characterSkin->characterName;
		m_CharacterData.vitality = characterSkin->vitality;
		m_CharacterData.intelligence = characterSkin->intelligence;
		m_CharacterData.sanity = characterSkin->sanity;
		m_CharacterData.endurance = characterSkin->endurance;
		m_CharacterData.charisma = characterSkin->charisma;
		
		//std::unordered_map<StatType, int> m_StatsMoreThenCopy = m_StatsMoreThen;
		//std::unordered_map<StatType, int> m_StatsLessThenCopy = m_StatsLessThen;
		std::vector<ObjectiveStat> m_ObjectiveStatsCopy = m_ObjectiveStats;

		// overwrite with previous super stats of that character
        /*
		for (auto& stat : m_StatsMoreThen)
		m_ObjectiveStats.clear();

		int average = 10;

		if (m_CharacterData.vitality != average)
		{
			m_ObjectiveStats.push_back({ VITALITY,  m_CharacterData.vitality });
			m_CHUD->m_VitalityBar->setInitialValue(m_CharacterData.vitality);
		}

		if (m_CharacterData.intelligence != average)
		{
			m_ObjectiveStats.push_back({ INTELLIGENCE,  m_CharacterData.intelligence });
			m_CHUD->m_IntelligenceBar->setInitialValue(m_CharacterData.intelligence);
		}

		if (m_CharacterData.sanity != average)
		{
			m_ObjectiveStats.push_back({ SANITY,  m_CharacterData.sanity });
			m_CHUD->m_SanityBar->setInitialValue(m_CharacterData.sanity);
		}

		if (m_CharacterData.endurance != average)
		{
			m_ObjectiveStats.push_back({ ENDURANCE,  m_CharacterData.endurance });
			m_CHUD->m_EnduranceBar->setInitialValue(m_CharacterData.endurance);
		}

		if (m_CharacterData.charisma != average)
		{
			m_ObjectiveStats.push_back({ CHARISMA,  m_CharacterData.charisma });
			m_CHUD->m_CharismaBar->setInitialValue(m_CharacterData.charisma);
		}

		// apply with previous objective stats of that character
		for (auto& stat : m_ObjectiveStatsCopy)
		{
			if (stat.m_StatType == VITALITY)
			{
				m_CharacterData.vitality = stat.m_Target;
			}
			else if (stat.m_StatType == INTELLIGENCE)
			{
				m_CharacterData.intelligence = stat.m_Target;
			}
			else if (stat.m_StatType == SANITY)
			{
				m_CharacterData.sanity = stat.m_Target;
			}
			else if (stat.m_StatType == ENDURANCE)
			{
				m_CharacterData.endurance = stat.m_Target;
			}
			else if (stat.m_StatType == CHARISMA)
			{
				m_CharacterData.charisma = stat.m_Target;
			}
		}
*/
		// save last values

		
		// update skins
	}

	void CPlayer::OnLevelFail()
	{
		m_CharacterCurrID = 0; // start again from neutral

		// Get new data from character skin
		SCharacter* characterSkin = m_CharacterSkins[m_CharacterCurrID];
		m_CharacterData.characterName = characterSkin->characterName;
		m_CharacterData.vitality = characterSkin->vitality;
		m_CharacterData.intelligence = characterSkin->intelligence;
		m_CharacterData.sanity = characterSkin->sanity;
		m_CharacterData.endurance = characterSkin->endurance;
		m_CharacterData.charisma = characterSkin->charisma;

		m_ObjectiveStats.clear();

		int average = 10;

		if (m_CharacterData.vitality != average)
		{
			m_ObjectiveStats.push_back({ VITALITY,  m_CharacterData.vitality });
			m_CHUD->m_VitalityBar->setInitialValue(m_CharacterData.vitality);
		}

		if (m_CharacterData.intelligence != average)
		{
			m_ObjectiveStats.push_back({ INTELLIGENCE,  m_CharacterData.intelligence });
			m_CHUD->m_IntelligenceBar->setInitialValue(m_CharacterData.intelligence);
		}

		if (m_CharacterData.sanity != average)
		{
			m_ObjectiveStats.push_back({ SANITY,  m_CharacterData.sanity });
			m_CHUD->m_SanityBar->setInitialValue(m_CharacterData.sanity);
		}

		if (m_CharacterData.endurance != average)
		{
			m_ObjectiveStats.push_back({ ENDURANCE,  m_CharacterData.endurance });
			m_CHUD->m_EnduranceBar->setInitialValue(m_CharacterData.endurance);
		}

		if (m_CharacterData.charisma != average)
		{
			m_ObjectiveStats.push_back({ CHARISMA,  m_CharacterData.charisma });
			m_CHUD->m_CharismaBar->setInitialValue(m_CharacterData.charisma);
		}
	}

	void CPlayer::LoadCharacterNeutral()
	{
		factory.loadTextureAtlasData(StringUtils::format("Character_Neutral_tex.json"));

		std::string fileName = StringUtils::format("Character_Neutral");

		const auto dragonBonesData = factory.loadDragonBonesData(StringUtils::format("%s_ske.json", fileName.c_str()));
		factory.loadTextureAtlasData(StringUtils::format("%s_tex.json", fileName.c_str()));

		const auto& armatureNames = dragonBonesData->getArmatureNames();
		const auto& armatureName = armatureNames[0];

		armatureDisplay = factory.buildArmatureDisplay(armatureName);

		armatureDisplay->setPosition(Point(this->getContentSize().width * 0.45, this->getContentSize().height * 0.6));
		armatureDisplay->setScale(1.0f);

		armatureDisplay->getAnimation()->play("animtion_idle");

		armatureDisplay->getEventDispatcher()->setEnabled(true);

		this->addChild(armatureDisplay, 100);

		/* - */

		factorySide.loadTextureAtlasData(StringUtils::format("Character_Neutral_Side_tex.json"));

		fileName = StringUtils::format("Character_Neutral_Side");

		const auto  dragonBonesDataSide = factorySide.loadDragonBonesData(StringUtils::format("%s_ske.json", fileName.c_str()));
		factorySide.loadTextureAtlasData(StringUtils::format("%s_tex.json", fileName.c_str()));

		const auto& armatureNamesSide = dragonBonesDataSide->getArmatureNames();
		const auto& armatureNameSide = armatureNamesSide[0];

		armatureDisplaySide = factorySide.buildArmatureDisplay(armatureNameSide);

		armatureDisplaySide->setPosition(Point(this->getContentSize().width * 0.45, this->getContentSize().height * 0.6));
		armatureDisplaySide->setScale(1.0f);
		armatureDisplaySide->setOpacity(0.0f);

		armatureDisplaySide->getAnimation()->play("animtionSide");

		armatureDisplaySide->getEventDispatcher()->setEnabled(true);

		this->addChild(armatureDisplaySide, 100);
	}

	void CPlayer::LoadCharacterDetective()
	{
		factory.loadTextureAtlasData(StringUtils::format("Character_Detective_tex.json"));

		std::string fileName = StringUtils::format("Character_Detective");

		const auto dragonBonesData = factory.loadDragonBonesData(StringUtils::format("%s_ske.json", fileName.c_str()));
		factory.loadTextureAtlasData(StringUtils::format("%s_tex.json", fileName.c_str()));

		const auto& armatureNames = dragonBonesData->getArmatureNames();
		const auto& armatureName = armatureNames[0];

		armatureDisplay = factory.buildArmatureDisplay(armatureName);

		armatureDisplay->setPosition(Point(this->getContentSize().width * 0.45, this->getContentSize().height * 0.6));
		armatureDisplay->setScale(1.0f);

		armatureDisplay->getAnimation()->play("animtion_idle");

		armatureDisplay->getEventDispatcher()->setEnabled(true);

		this->addChild(armatureDisplay, 100);

		/* - */

		factorySide.loadTextureAtlasData(StringUtils::format("Character_Detective_Side_tex.json"));

		fileName = StringUtils::format("Character_Detective_Side");

		const auto  dragonBonesDataSide = factorySide.loadDragonBonesData(StringUtils::format("%s_ske.json", fileName.c_str()));
		factorySide.loadTextureAtlasData(StringUtils::format("%s_tex.json", fileName.c_str()));

		const auto& armatureNamesSide = dragonBonesDataSide->getArmatureNames();
		const auto& armatureNameSide = armatureNamesSide[0];

		armatureDisplaySide = factorySide.buildArmatureDisplay(armatureNameSide);

		armatureDisplaySide->setPosition(Point(this->getContentSize().width * 0.45, this->getContentSize().height * 0.6));
		armatureDisplaySide->setScale(1.0f);
		armatureDisplaySide->setOpacity(0.0f);

		armatureDisplaySide->getAnimation()->play("animtionSide");

		armatureDisplaySide->getEventDispatcher()->setEnabled(true);

		this->addChild(armatureDisplaySide, 100);
	}

	void CPlayer::LoadCharacterHulk()
	{
		factory.loadTextureAtlasData(StringUtils::format("Character_Hulk_tex.json"));

		std::string fileName = StringUtils::format("Character_Hulk");

		const auto dragonBonesData = factory.loadDragonBonesData(StringUtils::format("%s_ske.json", fileName.c_str()));
		factory.loadTextureAtlasData(StringUtils::format("%s_tex.json", fileName.c_str()));

		const auto& armatureNames = dragonBonesData->getArmatureNames();
		const auto& armatureName = armatureNames[0];

		armatureDisplay = factory.buildArmatureDisplay(armatureName);

		armatureDisplay->setPosition(Point(this->getContentSize().width * 0.45, this->getContentSize().height * 0.6));
		armatureDisplay->setScale(1.0f);

		armatureDisplay->getAnimation()->play("animtion_idle");

		armatureDisplay->getEventDispatcher()->setEnabled(true);

		this->addChild(armatureDisplay, 100);

		/* - */

		factorySide.loadTextureAtlasData(StringUtils::format("Character_Hulk_Side_tex.json"));

		fileName = StringUtils::format("Character_Hulk_Side");

		const auto  dragonBonesDataSide = factorySide.loadDragonBonesData(StringUtils::format("%s_ske.json", fileName.c_str()));
		factorySide.loadTextureAtlasData(StringUtils::format("%s_tex.json", fileName.c_str()));

		const auto& armatureNamesSide = dragonBonesDataSide->getArmatureNames();
		const auto& armatureNameSide = armatureNamesSide[0];

		armatureDisplaySide = factorySide.buildArmatureDisplay(armatureNameSide);

		armatureDisplaySide->setPosition(Point(this->getContentSize().width * 0.45, this->getContentSize().height * 0.6));
		armatureDisplaySide->setScale(1.0f);
		armatureDisplaySide->setOpacity(0.0f);

		armatureDisplaySide->getAnimation()->play("animtionSide");

		armatureDisplaySide->getEventDispatcher()->setEnabled(true);

		this->addChild(armatureDisplaySide, 100);
	}

	void CPlayer::LoadCharacterRockstar()
	{
		factory.loadTextureAtlasData(StringUtils::format("Character_Rockstar_tex.json"));

		std::string fileName = StringUtils::format("Character_Rockstar");

		const auto dragonBonesData = factory.loadDragonBonesData(StringUtils::format("%s_ske.json", fileName.c_str()));
		factory.loadTextureAtlasData(StringUtils::format("%s_tex.json", fileName.c_str()));

		const auto& armatureNames = dragonBonesData->getArmatureNames();
		const auto& armatureName = armatureNames[0];

		armatureDisplay = factory.buildArmatureDisplay(armatureName);

		armatureDisplay->setPosition(Point(this->getContentSize().width * 0.45, this->getContentSize().height * 0.6));
		armatureDisplay->setScale(1.0f);

		armatureDisplay->getAnimation()->play("animtion_idle");

		armatureDisplay->getEventDispatcher()->setEnabled(true);

		this->addChild(armatureDisplay, 100);

		/* - */

		factorySide.loadTextureAtlasData(StringUtils::format("Character_Rockstar_Side_tex.json"));

		fileName = StringUtils::format("Character_Rockstar_Side");

		const auto  dragonBonesDataSide = factorySide.loadDragonBonesData(StringUtils::format("%s_ske.json", fileName.c_str()));
		factorySide.loadTextureAtlasData(StringUtils::format("%s_tex.json", fileName.c_str()));

		const auto& armatureNamesSide = dragonBonesDataSide->getArmatureNames();
		const auto& armatureNameSide = armatureNamesSide[0];

		armatureDisplaySide = factorySide.buildArmatureDisplay(armatureNameSide);

		armatureDisplaySide->setPosition(Point(this->getContentSize().width * 0.45, this->getContentSize().height * 0.6));
		armatureDisplaySide->setScale(1.0f);
		armatureDisplaySide->setOpacity(0.0f);

		armatureDisplaySide->getAnimation()->play("animtionSide");

		armatureDisplaySide->getEventDispatcher()->setEnabled(true);

		this->addChild(armatureDisplaySide, 100);
	}

	void CPlayer::LoadCharacterStickMan()
	{
		factory.loadTextureAtlasData(StringUtils::format("Character_Stickman_tex.json"));

		std::string fileName = StringUtils::format("Character_Stickman");

		const auto dragonBonesData = factory.loadDragonBonesData(StringUtils::format("%s_ske.json", fileName.c_str()));
		factory.loadTextureAtlasData(StringUtils::format("%s_tex.json", fileName.c_str()));

		const auto& armatureNames = dragonBonesData->getArmatureNames();
		const auto& armatureName = armatureNames[0];

		armatureDisplay = factory.buildArmatureDisplay(armatureName);

		armatureDisplay->setPosition(Point(this->getContentSize().width * 0.45, this->getContentSize().height * 0.6));
		armatureDisplay->setScale(1.0f);

		armatureDisplay->getAnimation()->play("animtion_idle");

		armatureDisplay->getEventDispatcher()->setEnabled(true);

		this->addChild(armatureDisplay, 100);

		/* - */

		factorySide.loadTextureAtlasData(StringUtils::format("Character_Stickman_Side_tex.json"));

		fileName = StringUtils::format("Character_Stickman_Side");

		const auto  dragonBonesDataSide = factorySide.loadDragonBonesData(StringUtils::format("%s_ske.json", fileName.c_str()));
		factorySide.loadTextureAtlasData(StringUtils::format("%s_tex.json", fileName.c_str()));

		const auto& armatureNamesSide = dragonBonesDataSide->getArmatureNames();
		const auto& armatureNameSide = armatureNamesSide[0];

		armatureDisplaySide = factorySide.buildArmatureDisplay(armatureNameSide);

		armatureDisplaySide->setPosition(Point(this->getContentSize().width * 0.45, this->getContentSize().height * 0.6));
		armatureDisplaySide->setScale(1.0f);
		armatureDisplaySide->setOpacity(0.0f);

		armatureDisplaySide->getAnimation()->play("animtionSide");

		armatureDisplaySide->getEventDispatcher()->setEnabled(true);

		this->addChild(armatureDisplaySide, 100);
	}

	void CPlayer::LoadCharacterMadScientist()
	{
		factory.loadTextureAtlasData(StringUtils::format("Character_Scientist_tex.json"));

		std::string fileName = StringUtils::format("Character_Scientist");

		const auto dragonBonesData = factory.loadDragonBonesData(StringUtils::format("%s_ske.json", fileName.c_str()));
		factory.loadTextureAtlasData(StringUtils::format("%s_tex.json", fileName.c_str()));

		const auto& armatureNames = dragonBonesData->getArmatureNames();
		const auto& armatureName = armatureNames[0];

		armatureDisplay = factory.buildArmatureDisplay(armatureName);

		armatureDisplay->setPosition(Point(this->getContentSize().width * 0.45, this->getContentSize().height * 0.6));
		armatureDisplay->setScale(1.0f);

		armatureDisplay->getAnimation()->play("animtion_idle");

		armatureDisplay->getEventDispatcher()->setEnabled(true);

		this->addChild(armatureDisplay, 100);

		/* - */

		factorySide.loadTextureAtlasData(StringUtils::format("Character_Scientist_Side_tex.json"));

		fileName = StringUtils::format("Character_Scientist_Side");

		const auto  dragonBonesDataSide = factorySide.loadDragonBonesData(StringUtils::format("%s_ske.json", fileName.c_str()));
		factorySide.loadTextureAtlasData(StringUtils::format("%s_tex.json", fileName.c_str()));

		const auto& armatureNamesSide = dragonBonesDataSide->getArmatureNames();
		const auto& armatureNameSide = armatureNamesSide[0];

		armatureDisplaySide = factorySide.buildArmatureDisplay(armatureNameSide);

		armatureDisplaySide->setPosition(Point(this->getContentSize().width * 0.45, this->getContentSize().height * 0.6));
		armatureDisplaySide->setScale(1.0f);
		armatureDisplaySide->setOpacity(0.0f);

		armatureDisplaySide->getAnimation()->play("animtionSide");

		armatureDisplaySide->getEventDispatcher()->setEnabled(true);

		this->addChild(armatureDisplaySide, 100);
	}
    
    void CPlayer::setUp()
    {
        json::CManager::getInstance()->openFile("PlayerConfig.json");
        m_fSpeed = json::CManager::getInstance()->getIntForKey("Speed");
        m_fSpeedDecline = json::CManager::getInstance()->getIntForKey("SpeedDecline");

		json::Document& document = *json::CManager::getInstance()->getOpenedDocument();
		
		const rapidjson::Value& array = document["Characters"];  // you are missing this
		if (array.IsArray())
		{
			for (rapidjson::SizeType i = 0; i < array.Size(); i++)
			{
				const rapidjson::Value& character = array[i];

				int defaultvalue = 10;

				std::string characterName;
				int vitality = defaultvalue;
				int intelligence = defaultvalue;
				int sanity = defaultvalue;
				int endurance = defaultvalue;
				int charisma = defaultvalue;

				if (character.HasMember("Name"))
				{
					const rapidjson::Value& name = character["Name"];
					characterName = cocos2d::Value(name.GetString()).asString();
				}

				if (character.HasMember("Vitality"))
				{
					const rapidjson::Value& name = character["Vitality"];
					vitality = name.GetInt();
				}

				if (character.HasMember("Intelligence"))
				{
					const rapidjson::Value& name = character["Intelligence"];
					intelligence = name.GetInt();
				}

				if (character.HasMember("Sanity"))
				{
					const rapidjson::Value& name = character["Sanity"];
					sanity = name.GetInt();
				}

				if (character.HasMember("Endurance"))
				{
					const rapidjson::Value& name = character["Endurance"];
					endurance = name.GetInt();
				}

				if (character.HasMember("Charisma"))
				{
					const rapidjson::Value& name = character["Charisma"];
					charisma = name.GetInt();
				}

				SCharacter* charStruct = new SCharacter();
				charStruct->characterName = characterName;
				charStruct->vitality = vitality;
				charStruct->intelligence = intelligence;
				charStruct->sanity = sanity;
				charStruct->endurance = endurance;
				charStruct->charisma = charisma;


				m_CharacterSkins.push_back(charStruct);
			}
		}

		// Get last character id objective as additional parameter
		if (m_CharacterCurrID > 1)
		{
			SCharacter* characterSkinPrevious = m_CharacterSkins[m_CharacterCurrID - 1];
		}

		m_CharacterCurrID = CScene::m_StartingCharacter - 1; // first neutral skin
		SCharacter* characterSkin = m_CharacterSkins[m_CharacterCurrID];
		m_CharacterData.characterName = characterSkin->characterName;
		m_CharacterData.vitality = characterSkin->vitality;
		m_CharacterData.intelligence = characterSkin->intelligence;
		m_CharacterData.sanity = characterSkin->sanity;
		m_CharacterData.endurance = characterSkin->endurance;
		m_CharacterData.charisma = characterSkin->charisma;
		

		m_CHUD->m_VitalityBar->setInitialValue(m_CharacterData.vitality);
		m_CHUD->m_VitalityBar->calcInitialProgress(m_CharacterData.vitality, true);

		m_CHUD->m_IntelligenceBar->setInitialValue(m_CharacterData.intelligence);
		m_CHUD->m_IntelligenceBar->calcInitialProgress(m_CharacterData.intelligence, true);

		m_CHUD->m_SanityBar->setInitialValue(m_CharacterData.sanity);
		m_CHUD->m_SanityBar->calcInitialProgress(m_CharacterData.sanity, true);

		m_CHUD->m_EnduranceBar->setInitialValue(m_CharacterData.endurance);
		m_CHUD->m_EnduranceBar->calcInitialProgress(m_CharacterData.endurance, true);

		m_CHUD->m_CharismaBar->setInitialValue(m_CharacterData.charisma);
		m_CHUD->m_CharismaBar->calcInitialProgress(m_CharacterData.charisma, true);

		// Find next character objectives
		int average = 10;

		SCharacter* characterSkinNext = m_CharacterSkins[m_CharacterCurrID + 1];

		if (characterSkinNext->vitality != average)
		{
			m_ObjectiveStats.push_back({ VITALITY,  characterSkinNext->vitality });
			m_CHUD->m_VitalityBar->calcInitialProgress(characterSkinNext->vitality, false);
		}

		if (characterSkinNext->intelligence != average)
		{
			m_ObjectiveStats.push_back({ INTELLIGENCE,  characterSkinNext->intelligence });
			m_CHUD->m_IntelligenceBar->calcInitialProgress(characterSkinNext->intelligence, false);
		}

		if (characterSkinNext->sanity != average)
		{
			m_ObjectiveStats.push_back({ SANITY,  characterSkinNext->sanity });
			m_CHUD->m_SanityBar->calcInitialProgress(characterSkinNext->sanity, false);
		}

		if (characterSkinNext->endurance != average)
		{
			m_ObjectiveStats.push_back({ ENDURANCE,  characterSkinNext->endurance });
			m_CHUD->m_EnduranceBar->calcInitialProgress(characterSkinNext->endurance, false);
		}

		if (characterSkinNext->charisma != average)
		{
			m_ObjectiveStats.push_back({ CHARISMA,  characterSkinNext->charisma });
			m_CHUD->m_CharismaBar->calcInitialProgress(characterSkinNext->charisma, false);
		}
    }
    
    void CPlayer::createVisualElements(CHUD* hud)
    {
		m_CHUD = hud;
    }
    
    void CPlayer::createDragonBones()
    {
		if (CScene::m_StartingCharacter == 1)
		{
			//LoadCharacterMadScientist();
			LoadCharacterNeutral();
			//LoadCharacterHulk();
			//LoadCharacterDetective();
			//LoadCharacterRockstar();
			//LoadCharacterStickMan();
		}
		else if (CScene::m_StartingCharacter == 2)
		{
			//LoadCharacterNeutral();
			LoadCharacterDetective();
			//LoadCharacterNeutral();
		}
		else if (CScene::m_StartingCharacter == 3)
		{
			LoadCharacterHulk();
			//LoadCharacterNeutral();
		}
		else if (CScene::m_StartingCharacter == 4)
		{
			LoadCharacterRockstar();
			//LoadCharacterNeutral();
		}
		else if (CScene::m_StartingCharacter == 5)
		{
			LoadCharacterStickMan();
			//LoadCharacterNeutral();
		}
		else if (CScene::m_StartingCharacter == 6)
		{
			LoadCharacterMadScientist();
			//LoadCharacterNeutral();
		}
		else
		{
			LoadCharacterNeutral();
		}
    }
}





