#include "GameMode.h"
#include "../Minecraft.h"
#include "../../network/packet/UseItemPacket.h"
#include "../../network/packet/PlayerActionPacket.h"
#include "../../world/level/Level.h"
#include "../../world/item/ItemInstance.h"
#include "../player/LocalPlayer.h"
#include "client/Options.h"
#ifndef STANDALONE_SERVER
#include "../sound/SoundEngine.h"
#include "../particle/ParticleEngine.h"
#endif
#include "../../network/RakNetInstance.h"
#include "../../network/packet/RemoveBlockPacket.h"
#ifndef STANDALONE_SERVER
#include "../renderer/LevelRenderer.h"
#endif
#include "../../world/level/material/Material.h"

GameMode::GameMode( Minecraft* minecraft)
:	minecraft(minecraft),
	destroyProgress(0),
	oDestroyProgress(0),
	destroyTicks(0),
	destroyDelay(0)
{
}

/*virtual*/
Player* GameMode::createPlayer(Level* level) {
    return new LocalPlayer(minecraft, level, minecraft->options.getStringValue(OPTIONS_USERNAME), level->dimension->id, isCreativeType());
}

/*virtual*/
void GameMode::interact(Player* player, Entity* entity) {
    player->interact(entity);
}

/*virtual*/
void GameMode::attack(Player* player, Entity* entity) {
	if (minecraft->level->adventureSettings.noPvP && entity->isPlayer())
		return;
	if (minecraft->level->adventureSettings.noPvM && entity->isMob())
		return;
    player->attack(entity);
}

/* virtual */
void GameMode::startDestroyBlock( int x, int y, int z, int face ) {
	if(minecraft->player->getCarriedItem() != NULL && minecraft->player->getCarriedItem()->id == Item::bow->id)
		return;
	destroyBlock(x, y, z, face);
}

/*virtual*/
bool GameMode::destroyBlock(int x, int y, int z, int face) {
    Level* level = minecraft->level;
    Tile* oldTile = Tile::tiles[level->getTile(x, y, z)];
	if (!oldTile)
		return false;

    if (level->adventureSettings.immutableWorld) {
        if (oldTile != (Tile*)Tile::leaves
         && oldTile->material != Material::plant) {
             return false;
        }
    }
#ifndef STANDALONE_SERVER
	minecraft->particleEngine->destroy(x, y, z);
#endif
	int data = level->getData(x, y, z);
    bool changed = level->setTile(x, y, z, 0);
    if (changed) {
#ifndef STANDALONE_SERVER
        minecraft->soundEngine->play(oldTile->soundType->getBreakSound(), x + 0.5f, y + 0.5f, z + 0.5f, (oldTile->soundType->getVolume() + 1) / 2, oldTile->soundType->getPitch() * 0.8f);
#endif
        oldTile->destroy(level, x, y, z, data);
		if (minecraft->options.getBooleanValue(OPTIONS_DESTROY_VIBRATION)) minecraft->platform()->vibrate(24);

		if (minecraft->isOnline()) {
			RemoveBlockPacket packet(minecraft->player, x, y, z);
			minecraft->raknetInstance->send(packet);
		}
	}
    return changed;
}
/*virtual*/
bool GameMode::useItemOn(Player* player, Level* level, ItemInstance* item, int x, int y, int z, int face, const Vec3& hit) {
	float clickX = hit.x - x;
	float clickY = hit.y - y;
	float clickZ = hit.z - z;
	item = player->inventory->getSelected();
	if(level->isClientSide) {
		UseItemPacket packet(x, y, z, face, item, player->entityId, clickX, clickY, clickZ);
		minecraft->raknetInstance->send(packet);
	}
    int t = level->getTile(x, y, z);
	if (t == Tile::invisible_bedrock->id) return false;
    if (t > 0 && Tile::tiles[t]->use(level, x, y, z, player))
		return true;

	if (item == NULL) return false;
	if(isCreativeType()) {
		int aux = item->getAuxValue();
		int count = item->count;
		bool success = item->useOn(player, level, x, y, z, face, clickX, clickY, clickZ);
		item->setAuxValue(aux);
		item->count = count;
		return success;
	} else {
		return item->useOn(player, level, x, y, z, face, clickX, clickY, clickZ);
	}
}

bool GameMode::useItem( Player* player, Level* level, ItemInstance* item ) {
	int oldCount = item->count;

	ItemInstance* itemInstance = item->use(level, player);
	if(level->isClientSide) {
		UseItemPacket packet(item, player->entityId, player->aimDirection);
		minecraft->raknetInstance->send(packet);
	}
	if (itemInstance != item || (itemInstance != NULL && itemInstance->count != oldCount)) {
	    //player.inventory.items[player.inventory.selected] = itemInstance;
	    //if (itemInstance.count == 0) {
	    //    player.inventory.items[player.inventory.selected] = NULL;
	    //}
	    return true;
	}
	return false;
}

ItemInstance* GameMode::handleInventoryMouseClick( int containerId, int slotNum, int buttonNum, Player* player ) {
	//return player.containerMenu.clicked(slotNum, buttonNum, player);
	return NULL;
}

void GameMode::handleCloseInventory( int containerId, Player* player ) {
	//player.containerMenu.removed(player);
	//player.containerMenu = player.inventoryMenu;
}

float GameMode::getPickRange() {
	return 5.0f;
}

void GameMode::initPlayer( Player* player ) {
	initAbilities(player->abilities);
}

void GameMode::releaseUsingItem(Player* player){
	if(minecraft->level->isClientSide) {
		PlayerActionPacket packet(PlayerActionPacket::RELEASE_USE_ITEM,  0, 0, 0, 0, player->entityId);
		minecraft->raknetInstance->send(packet);
	}
	player->releaseUsingItem();
}

void GameMode::tick() {
	oDestroyProgress = destroyProgress;
}

void GameMode::render( float a ) {
#ifndef STANDALONE_SERVER
	if (destroyProgress <= 0) {
		minecraft->gui.progress = 0;
		minecraft->levelRenderer->destroyProgress = 0;
	} else {
		float dp = oDestroyProgress + (destroyProgress - oDestroyProgress) * a;
		minecraft->gui.progress = dp;
		minecraft->levelRenderer->destroyProgress = dp;
	}
#endif
}
