#include "PlayerRenderer.h"
#include "EntityRenderDispatcher.h"
#include "../Textures.h"
#include "../../../world/entity/player/Player.h"
#include "../../../world/level/Level.h"
#include "../../../world/item/ArmorItem.h"

static const std::string armorFilenames[10] = {
	"armor/cloth_1.png",	"armor/cloth_2.png",
	"armor/chain_1.png",	"armor/chain_2.png",
	"armor/iron_1.png",		"armor/iron_2.png",
	"armor/diamond_1.png",	"armor/diamond_2.png",
	"armor/gold_1.png",		"armor/gold_2.png",
};

PlayerRenderer::PlayerRenderer( HumanoidModel* humanoidModel, float shadow )
:	super(humanoidModel, shadow),
	playerModel64(humanoidModel),
	playerModel32(new HumanoidModel(0, 0, 64, 32)),
	armorParts1(new HumanoidModel(1.0f, 0, 64, 64)),
	armorParts2(new HumanoidModel(0.5f, 0, 64, 64))
{
	// default to legacy skin path until we know the exact texture size
	model = playerModel32;
	humanoidModel = playerModel32;
}

PlayerRenderer::~PlayerRenderer() {
	// prevent MobRenderer destructor from deleting model pointers we manage manually
	model = nullptr;

	delete playerModel32;
	delete playerModel64;
	delete armorParts1;
	delete armorParts2;
}

void PlayerRenderer::setupPosition( Entity* mob, float x, float y, float z ) {
	Player* player = (Player*) mob;
	if(player->isAlive() && player->isSleeping()) {
		return super::setupPosition(mob, x + player->bedOffsetX, y + player->bedOffsetY, z + player->bedOffsetZ);
	}
	return super::setupPosition(mob, x, y, z);
}

void PlayerRenderer::setupRotations( Entity* mob, float bob, float bodyRot, float a ) {
	Player* player = (Player*) mob;
	if(player->isAlive() && player->isSleeping()) {
		glRotatef(player->getSleepRotation(), 0, 1, 0);
		glRotatef(getFlipDegrees(player), 0, 0, 1);
		glRotatef(270, 0, 1, 0);
		return;
	}
	super::setupRotations(mob, bob, bodyRot, a);
}

bool PlayerRenderer::isModernPlayerSkin(Mob* mob) {
	const std::string texName = mob->getTexture();
	TextureId texId = entityRenderDispatcher->textures->loadTexture(texName);
	if (!Textures::isTextureIdValid(texId))
		return false;
	const TextureData* texData = entityRenderDispatcher->textures->getTemporaryTextureData(texId);
	return texData && texData->w == 64 && texData->h == 64;
}

void PlayerRenderer::renderName( Mob* mob, float x, float y, float z ){
	//@todo: figure out how to handle HideGUI
	if (mob != entityRenderDispatcher->cameraEntity && mob->level->adventureSettings.showNameTags) {
		renderNameTag(mob, ((Player*)mob)->name, x, y, z, 32);
	}
}

void PlayerRenderer::render(Entity* mob_, float x, float y, float z, float rot, float a) {
	Mob* mob = (Mob*) mob_;
	HumanoidModel* desired = isModernPlayerSkin(mob) ? playerModel64 : playerModel32;
	if (model != desired || humanoidModel != desired) {
		model = desired;
		humanoidModel = desired;
	}
	// LOGI("[PlayerRenderer] %s: skin=%s, modelTex=%dx%d, desired=%s\n", 
	// 	((Player*)mob)->name.c_str(), mob->getTexture().c_str(), 
	// 	humanoidModel->texWidth, humanoidModel->texHeight,
	// 	(desired == playerModel64 ? "64" : "32"));
	HumanoidMobRenderer::render(mob_, x, y, z, rot, a);
}

int PlayerRenderer::prepareArmor(Mob* mob, int layer, float a) {
	Player* player = (Player*) mob;

	ItemInstance* itemInstance = player->getArmor(layer);
	if (!ItemInstance::isArmorItem(itemInstance))
		return -1;

	ArmorItem* armorItem = (ArmorItem*) itemInstance->getItem();
	int fnIndex = (armorItem->modelIndex + armorItem->modelIndex) + (layer == 2 ? 1 : 0);
	bindTexture(armorFilenames[fnIndex]);

	HumanoidModel* armor = layer == 2 ? armorParts2 : armorParts1;

	armor->head.visible = layer == 0;
	//armor.hair.visible = layer == 0;
	armor->body.visible = layer == 1 || layer == 2;
	armor->arm0.visible = layer == 1;
	armor->arm1.visible = layer == 1;
	armor->leg0.visible = layer == 2 || layer == 3;
	armor->leg1.visible = layer == 2 || layer == 3;

	setArmor(armor);

	/*if (itemInstance.isEnchanted())
		return 15; */

	return 1;
}

void PlayerRenderer::onGraphicsReset() {
	if (playerModel32) playerModel32->onGraphicsReset();
	if (playerModel64) playerModel64->onGraphicsReset();

	if (armorParts1) armorParts1->onGraphicsReset();
	if (armorParts2) armorParts2->onGraphicsReset();

	super::onGraphicsReset();
}
