/*!
* @file GameSurfaceSDL.cpp
* @brief ゲームのメインインターフェイス(SDL2.0実装)
* @date 2014/02/19
* @author Deskull
* 2014 Sikabane Works.
*/

#include <vector>
#include <string>
#include "stdafx.h"
#include "GameSurfaceSDL.h"

namespace Deeangband
{

	std::string toUTF8(LPCSTR str)
	{
		const int cchWideChar = ::MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
		std::vector<WCHAR> lpw(cchWideChar);

		const int nUnicodeCount = ::MultiByteToWideChar(CP_ACP, 0, str, -1, &lpw[0], cchWideChar);
		if(nUnicodeCount <= 0)
		{
			return "";
		}

		const int cchMultiByte = ::WideCharToMultiByte(CP_UTF8, 0, &lpw[0], -1, NULL, 0, NULL, NULL);
		std::vector<CHAR> lpa(cchMultiByte);

		const int nMultiCount = ::WideCharToMultiByte(CP_UTF8, 0, &lpw[0], -1, &lpa[0], cchMultiByte, NULL, NULL);
		if(nMultiCount <= 0)
		{
			return "";
		}
		return std::string(&lpa[0]);
	}

	GameSurfaceSDL::GameSurfaceSDL(GameWorld *gameWorld) : GameSurface(gameWorld)
	{
		if(SDL_Init(SDL_INIT_VIDEO) < 0) return;
		window = SDL_CreateWindow(GAME_TITLE, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, WINDOW_WIDTH, WINDOW_HEIGHT, SDL_WINDOW_RESIZABLE);
		SDL_GetWindowSurface(window);
		if(!window) return;

		if(TTF_Init() == -1) return;
		if(IMG_Init(IMG_INIT_PNG) != IMG_INIT_PNG) return;

		initInterfaces();

		viewCreaturePtr = NULL;
		viewFieldPtr = NULL;

		windowSurface = SDL_GetWindowSurface(window);

		return;
	}

	GameSurfaceSDL::~GameSurfaceSDL(void)
	{
		IMG_Quit();
		TTF_Quit();
		SDL_Quit();
		return;
	}

	void GameSurfaceSDL::pushAnyKey(void)
	{
		SDL_Event event;
		do 
		{
			this->Redraw();
			SDL_PollEvent(&event);
		} while(event.type != SDL_KEYDOWN);
	}

	void GameSurfaceSDL::initInterfaces(void)
	{
		font = TTF_OpenFont("ttf\\ipam.ttf", 18);
		src.x = 0;
		src.y = 0;
		src.w = 300;
		src.h = 200;
		title.x = 0;
		title.y = 0;
		title.w = 512;
		title.h = 512;
		color.r = 255;
		color.g = 223;
		color.b = 200;
		color.a = 255;

		if(!font)
		{	
			OutputDebugString(L"Failed: loading .ttf files.\n");
			exit(1);
		}

		rwop = SDL_RWFromFile("img\\Title.png", "rb");
		error = IMG_GetError();
		titleSurface = IMG_LoadPNG_RW(rwop);

		renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_PRESENTVSYNC);
	}

	void GameSurfaceSDL::Redraw()
	{
		SDL_Rect rect = {0, 0, 0, 0};

		SDL_GetWindowSurface(this->window);
		this->windowSurface = SDL_GetWindowSurface(this->window);
		SDL_GetWindowSize(window, &rect.w, &rect.h);
		SDL_SetRenderDrawColor(renderer, 100, 80, 0, 255);
		SDL_FillRect(windowSurface, &rect, SDL_MapRGBA(windowSurface->format, 50, 20, 10, 255));
		SDL_BlitSurface(titleSurface, &title, windowSurface, &title); 

		if(this->viewFieldPtr) this->drawField(gameWorld, viewFieldPtr, 0, 0, 20, 20);
		if(this->sideStatusCreatutePtr) this->drawSideCreatureStatus();
		if(this->viewCreaturePtr) this->drawCreatureStatus(viewCreaturePtr);
		if(this->currentMessage.size() > 0) this->drawSystemMessage();
		this->drawGameMessage();

		SDL_UpdateWindowSurfaceRects(window, &rect, 1);
		SDL_UpdateWindowSurface(window);

		return;
	}

	void GameSurfaceSDL::ViewCreatureStatus(Creature *creaturePtr)
	{
		this->viewCreaturePtr = creaturePtr;
		pushAnyKey();
		this->viewCreaturePtr = NULL;
	}

	void GameSurfaceSDL::SetSideStatusCreature(Creature *creaturePtr)
	{
		this->sideStatusCreatutePtr = creaturePtr;
		if(creaturePtr) this->updateSideCreatureStatus(creaturePtr);
	}

	void GameSurfaceSDL::SetField(Field *fieldPtr)
	{
		this->viewFieldPtr = fieldPtr;
	}

	void GameSurfaceSDL::drawCreatureStatus(Creature *creaturePtr)
	{
		int id;

		enum CREATURE_STATUS_VIEW_POSITION
		{
			POS_NAME,
			POS_LEVEL,
			POS_HP,
			POS_MP,
			POS_AC,
			POS_EV,
			POS_VO,
			POS_STR,
			POS_INT,
			POS_WIS,
			POS_DEX,
			POS_CON,
			POS_CHA,
			POS_SOUL,
			POS_GOOD,
			POS_EVIL,
			POS_ORDER,
			POS_CHAOS,
			POS_BALANCE,
			POS_HEIGHT,
			POS_WEIGHT,
			POS_BODY_SIZE,
			POS_MAX
		};

		SDL_Rect CreatureStatusViewPosition[POS_MAX] =
		{
			{10, 10, 0, 0},
			{10, 30, 0, 0},
			{10, 50, 0, 0},
			{10, 70, 0, 0},
			{10, 90, 0, 0},
			{10, 110, 0, 0},
			{10, 130, 0, 0},
			{200, 30, 0, 0},
			{200, 50, 0, 0},
			{200, 70, 0, 0},
			{200, 90, 0, 0},
			{200, 110, 0, 0},
			{200, 130, 0, 0},
			{200, 150, 0, 0},
			{200, 170, 0, 0},
			{200, 190, 0, 0},
			{200, 210, 0, 0},
			{200, 230, 0, 0},
			{200, 250, 0, 0},
			{10, 150, 0, 0},
			{10, 170, 0, 0},
			{10, 190, 0, 0},
		};

		SDL_Rect CreatureStatusViewRect[POS_MAX];

		const int STATUS_BUFSIZE = 100;
		char statusBuf[POS_MAX][STATUS_BUFSIZE];
		SDL_Surface *statusSurface[POS_MAX];

		SDL_Rect masterRect = {10, 10, 490, 450};

		sprintf_s(statusBuf[POS_NAME], STATUS_BUFSIZE, "名前:%s", creaturePtr->GetName().c_str()); 
		sprintf_s(statusBuf[POS_LEVEL], STATUS_BUFSIZE, "LV:%3d", creaturePtr->GetLevel()); 
		sprintf_s(statusBuf[POS_HP], STATUS_BUFSIZE, "HP:%5d/%5d", creaturePtr->GetCurHP(), creaturePtr->GetMaxHP()); 
		sprintf_s(statusBuf[POS_MP], STATUS_BUFSIZE, "MP:%5d/%5d", creaturePtr->GetCurMP(), creaturePtr->GetMaxMP()); 
		sprintf_s(statusBuf[POS_AC], STATUS_BUFSIZE, "AC:%4d", creaturePtr->GetArmorSaving()); 
		sprintf_s(statusBuf[POS_EV], STATUS_BUFSIZE, "EV:%4d", creaturePtr->GetEvasionSaving()); 
		sprintf_s(statusBuf[POS_VO], STATUS_BUFSIZE, "VO:%4d", creaturePtr->GetVolitionSaving()); 
		sprintf_s(statusBuf[POS_GOOD], STATUS_BUFSIZE, " 善 :%4d", creaturePtr->GetDiscipilneRank(DISCIPLINE_TYPE_GOOD)); 
		sprintf_s(statusBuf[POS_EVIL], STATUS_BUFSIZE, " 悪 :%4d", creaturePtr->GetDiscipilneRank(DISCIPLINE_TYPE_EVIL)); 
		sprintf_s(statusBuf[POS_ORDER], STATUS_BUFSIZE, "秩序:%4d", creaturePtr->GetDiscipilneRank(DISCIPLINE_TYPE_ORDER)); 
		sprintf_s(statusBuf[POS_CHAOS], STATUS_BUFSIZE, "混沌:%4d", creaturePtr->GetDiscipilneRank(DISCIPLINE_TYPE_CHAOS)); 
		sprintf_s(statusBuf[POS_BALANCE], STATUS_BUFSIZE, "天秤:%4d", creaturePtr->GetDiscipilneRank(DISCIPLINE_TYPE_BALANCE)); 
		sprintf_s(statusBuf[POS_STR], STATUS_BUFSIZE, "腕力:%4d", creaturePtr->GetCurrentStatus(CS_STR)); 
		sprintf_s(statusBuf[POS_INT], STATUS_BUFSIZE, "知力:%4d", creaturePtr->GetCurrentStatus(CS_INT)); 
		sprintf_s(statusBuf[POS_WIS], STATUS_BUFSIZE, "賢さ:%4d", creaturePtr->GetCurrentStatus(CS_WIS)); 
		sprintf_s(statusBuf[POS_DEX], STATUS_BUFSIZE, "器用:%4d", creaturePtr->GetCurrentStatus(CS_DEX)); 
		sprintf_s(statusBuf[POS_CON], STATUS_BUFSIZE, "耐久:%4d", creaturePtr->GetCurrentStatus(CS_CON)); 
		sprintf_s(statusBuf[POS_CHA], STATUS_BUFSIZE, "魅力:%4d", creaturePtr->GetCurrentStatus(CS_CHA)); 
		sprintf_s(statusBuf[POS_SOUL], STATUS_BUFSIZE, "ソウル:%4d", creaturePtr->GetCurrentSoul()); 
		sprintf_s(statusBuf[POS_HEIGHT], STATUS_BUFSIZE, "身長:%13s", GameElement::HeightFormat(creaturePtr->GetHeight()).c_str()); 
		sprintf_s(statusBuf[POS_WEIGHT], STATUS_BUFSIZE, "体重:%13s", GameElement::WeightFormat(creaturePtr->GetWeight()).c_str()); 
		sprintf_s(statusBuf[POS_BODY_SIZE], STATUS_BUFSIZE, "体格:%3d", creaturePtr->GetSize()); 

		for(id = 0; id < POS_MAX; id++)
		{
			statusSurface[id] = TTF_RenderUTF8_Blended(font, toUTF8(statusBuf[id]).c_str(), color);
			CreatureStatusViewRect[id].x = 0;
			CreatureStatusViewRect[id].y = 0;
			CreatureStatusViewRect[id].w = statusSurface[id]->w;
			CreatureStatusViewRect[id].h = statusSurface[id]->h;
			CreatureStatusViewPosition[id].x += masterRect.x;
			CreatureStatusViewPosition[id].y += masterRect.y;
		}

		SDL_FillRect(windowSurface, &masterRect, SDL_MapRGBA(windowSurface->format, 0, 0, 0, 120));

		for(id = 0; id < POS_MAX; id++)
		{
			SDL_BlitSurface(statusSurface[id], &CreatureStatusViewRect[id], windowSurface, &CreatureStatusViewPosition[id]); 
		}

		for(id = 0; id < POS_MAX; id++)
		{
			SDL_FreeSurface(statusSurface[id]);
		}
		return;
	}

	void GameSurfaceSDL::updateSideCreatureStatus(Creature *creaturePtr)
	{
		int id;

		enum CREATURE_SIDE_STATUS_VIEW_POSITION
		{
			POS_NAME,
			POS_LEVEL,
			POS_HP,
			POS_MP,
			POS_AC,
			POS_EV,
			POS_VO,
			POS_STR,
			POS_INT,
			POS_WIS,
			POS_DEX,
			POS_CON,
			POS_CHA,
			POS_SOUL,
			POS_MAX
		};

		SDL_Rect CreatureStatusViewPosition[POS_MAX] =
		{
			{10, 10, 0, 0},
			{10, 30, 0, 0},
			{10, 50, 0, 0},
			{10, 70, 0, 0},
			{10, 90, 0, 0},
			{10, 110, 0, 0},
			{10, 130, 0, 0},
			{200, 30, 0, 0},
			{200, 50, 0, 0},
			{200, 70, 0, 0},
			{200, 90, 0, 0},
			{200, 110, 0, 0},
			{200, 130, 0, 0},
			{200, 150, 0, 0},
		};

		SDL_Rect CreatureStatusViewRect[POS_MAX];

		const int STATUS_BUFSIZE = 100;
		char statusBuf[POS_MAX][STATUS_BUFSIZE];
		SDL_Surface *statusSurface[POS_MAX];

		SDL_Rect masterRect = {0, 0, 180, 350};

		creatureStatusSurface = SDL_CreateRGBSurface(0, 490, 450, 32, 0, 0, 0, 0);

		sprintf_s(statusBuf[POS_NAME], STATUS_BUFSIZE, "名前:%s", creaturePtr->GetName().c_str()); 
		sprintf_s(statusBuf[POS_LEVEL], STATUS_BUFSIZE, "LV:%3d", creaturePtr->GetLevel()); 
		sprintf_s(statusBuf[POS_HP], STATUS_BUFSIZE, "HP:%5d/%5d", creaturePtr->GetCurHP(), creaturePtr->GetMaxHP()); 
		sprintf_s(statusBuf[POS_MP], STATUS_BUFSIZE, "MP:%5d/%5d", creaturePtr->GetCurMP(), creaturePtr->GetMaxMP()); 
		sprintf_s(statusBuf[POS_AC], STATUS_BUFSIZE, "AC:%4d", creaturePtr->GetArmorSaving()); 
		sprintf_s(statusBuf[POS_EV], STATUS_BUFSIZE, "EV:%4d", creaturePtr->GetEvasionSaving()); 
		sprintf_s(statusBuf[POS_VO], STATUS_BUFSIZE, "VO:%4d", creaturePtr->GetVolitionSaving()); 
		sprintf_s(statusBuf[POS_STR], STATUS_BUFSIZE, "腕力:%4d", creaturePtr->GetCurrentStatus(CS_STR)); 
		sprintf_s(statusBuf[POS_INT], STATUS_BUFSIZE, "知力:%4d", creaturePtr->GetCurrentStatus(CS_INT)); 
		sprintf_s(statusBuf[POS_WIS], STATUS_BUFSIZE, "賢さ:%4d", creaturePtr->GetCurrentStatus(CS_WIS)); 
		sprintf_s(statusBuf[POS_DEX], STATUS_BUFSIZE, "器用:%4d", creaturePtr->GetCurrentStatus(CS_DEX)); 
		sprintf_s(statusBuf[POS_CON], STATUS_BUFSIZE, "耐久:%4d", creaturePtr->GetCurrentStatus(CS_CON)); 
		sprintf_s(statusBuf[POS_CHA], STATUS_BUFSIZE, "魅力:%4d", creaturePtr->GetCurrentStatus(CS_CHA)); 
		sprintf_s(statusBuf[POS_SOUL], STATUS_BUFSIZE, "ソウル:%4d", creaturePtr->GetCurrentSoul()); 

		for(id = 0; id < POS_MAX; id++)
		{
			statusSurface[id] = TTF_RenderUTF8_Blended(font, toUTF8(statusBuf[id]).c_str(), color);
			CreatureStatusViewRect[id].x = 0;
			CreatureStatusViewRect[id].y = 0;
			CreatureStatusViewRect[id].w = statusSurface[id]->w;
			CreatureStatusViewRect[id].h = statusSurface[id]->h;
			CreatureStatusViewPosition[id].x += masterRect.x;
			CreatureStatusViewPosition[id].y += masterRect.y;
		}

		SDL_FillRect(creatureStatusSurface, &masterRect, SDL_MapRGBA(creatureStatusSurface->format, 0, 0, 0, 120));

		for(id = 0; id < POS_MAX; id++)
		{
			SDL_BlitSurface(statusSurface[id], &CreatureStatusViewRect[id], creatureStatusSurface, &CreatureStatusViewPosition[id]); 
		}

		for(id = 0; id < POS_MAX; id++)
		{
			SDL_FreeSurface(statusSurface[id]);
		}
		return;

	}

	void GameSurfaceSDL::drawSideCreatureStatus(void)
	{
		SDL_Rect masterRect = {0, 0, 180, 350};
		SDL_Rect posRect = {10, 120, 0, 0};
		SDL_BlitSurface(creatureStatusSurface, &masterRect, windowSurface, &posRect); 
	}

	GAME_COMMAND GameSurfaceSDL::GetCommand(void)
	{
		SDL_Event event;
		SDL_Keycode key;

		this->Redraw();
		while (SDL_PollEvent(&event))
		{

			switch(event.type)
			{

			case SDL_KEYDOWN:
				{
					key=event.key.keysym.sym;

					switch(key)
					{
					case SDLK_ESCAPE:
						return GAME_COMMAND_EXIT;
					case SDLK_c:
						return GAME_COMMAND_VIEW_PLAYER_STATUS;
					case SDLK_F11:
						return GAME_COMMAND_DEBUG_XML_SAVE;
					case SDLK_F12:
						return GAME_COMMAND_DEBUG_XML_LOAD;
					case SDLK_k:
						return GAME_COMMAND_NORTH;
					case SDLK_u:
						return GAME_COMMAND_NORTH_EAST;
					case SDLK_l:
						return GAME_COMMAND_EAST;
					case SDLK_n:
						return GAME_COMMAND_SOUTH_EAST;
					case SDLK_j:
						return GAME_COMMAND_SOUTH;
					case SDLK_b:
						return GAME_COMMAND_SOUTH_WEST;
					case SDLK_h:
						return GAME_COMMAND_WEST;
					case SDLK_y:
						return GAME_COMMAND_NORTH_WEST;
					case SDLK_s:
						return GAME_COMMAND_STAY;
					}

				}
				break;

			case SDL_WINDOWEVENT:
				switch (event.window.event) {
				case SDL_WINDOWEVENT_SHOWN:
					break;
				case SDL_WINDOWEVENT_HIDDEN:
					break;
				case SDL_WINDOWEVENT_EXPOSED:
					break;
				case SDL_WINDOWEVENT_MOVED:
					break;
				case SDL_WINDOWEVENT_RESIZED:
					break;
				case SDL_WINDOWEVENT_MINIMIZED:
					break;
				case SDL_WINDOWEVENT_MAXIMIZED:
					break;
				case SDL_WINDOWEVENT_RESTORED:
					break;
				case SDL_WINDOWEVENT_ENTER:
					break;
				case SDL_WINDOWEVENT_LEAVE:
					break;
				case SDL_WINDOWEVENT_FOCUS_GAINED:
					break;
				case SDL_WINDOWEVENT_FOCUS_LOST:
					break;
				case SDL_WINDOWEVENT_CLOSE:
					break;
				default:
					break;
				}
				this->Redraw();
				break;

			case SDL_QUIT:
				return GAME_COMMAND_EXIT;
				break;

		}
	}

	return GAME_COMMAND_REDRAW;
}

void GameSurfaceSDL::drawField(GameWorld *gameWorld, Field *fieldPtr, int x, int y, int w, int h)
{	
	SDL_Rect symbolRect = {0, 0, 30, 30};
	SDL_Surface *symbolSurface;
	char symBuf[5];
	std::map<ID, boost::shared_ptr<Creature>>::iterator creatureIt;

	int px, py;
	for(py = y; py < y + h; py++)
	{
		for(px = x; px < x + w; px++)
		{
			if(px < fieldPtr->GetWidth() && py < fieldPtr->GetHeight())
			{
				TAG tag = fieldPtr->GetSquare(px, py)->GetFloorTag();
				Color symColor = gameWorld->GetFloor(tag)->GetSymbolColor();
				Color backColor = gameWorld->GetFloor(tag)->GetBackColor();
				SDL_Color sdlSymCol = {(Uint8)symColor.GetRed(), (Uint8)symColor.GetGreen(), (Uint8)symColor.GetBlue(), (Uint8)symColor.GetAlpha()};
				SDL_Rect blitRect = {240 + px * 24, 30 + py * 24 , 24, 24};
				SDL_FillRect(windowSurface, &blitRect, SDL_MapRGBA(windowSurface->format, (Uint8)backColor.GetRed(), (Uint8)backColor.GetGreen(), (Uint8)backColor.GetBlue(), (Uint8)backColor.GetAlpha()));
				sprintf_s(symBuf, 5, "%s", gameWorld->GetFloor(tag)->GetSymbol().c_str()); 
				symbolSurface = TTF_RenderUTF8_Blended(font, toUTF8(symBuf).c_str(), sdlSymCol);
				blitRect.x += (24 - symbolSurface->w) / 2;
				blitRect.y += (24 - symbolSurface->h) / 2;
				SDL_BlitSurface(symbolSurface, &symbolRect, windowSurface, &blitRect); 
				SDL_FreeSurface(symbolSurface);
			}
		}
	}

	for(creatureIt = gameWorld->GetCreatureList()->begin(); creatureIt != gameWorld->GetCreatureList()->end(); creatureIt++)
	{
		Color symColor = creatureIt->second->GetSymbolColor();
		SDL_Color sdlSymCol = {(Uint8)symColor.GetRed(), (Uint8)symColor.GetGreen(), (Uint8)symColor.GetBlue(), (Uint8)symColor.GetAlpha()};
		sprintf_s(symBuf, 5, "%s", creatureIt->second->GetSymbol().c_str()); 
		SDL_Rect blitRect = {240 + creatureIt->second->GetPosition().GetX() * 24, 30 + creatureIt->second->GetPosition().GetY() * 24 , 24, 24};
		symbolSurface = TTF_RenderUTF8_Blended(font, toUTF8(symBuf).c_str(), sdlSymCol);
		blitRect.x += (24 - symbolSurface->w) / 2;
		blitRect.y += (24 - symbolSurface->h) / 2;
		SDL_BlitSurface(symbolSurface, &symbolRect, windowSurface, &blitRect); 
		SDL_FreeSurface(symbolSurface);
	}
}

void GameSurfaceSDL::FocusField(int x, int y)
{	
	this->focusPoint.Set(x, y);
}

void GameSurfaceSDL::FocusField(Coordinates coord)
{	
	this->focusPoint.Set(coord.GetX(), coord.GetY());
}

void GameSurfaceSDL::drawSystemMessage(void)
{
	SDL_Rect messageRect = {0, 0, 200, 200};
	SDL_Rect messagePositon = {220, 180, 0, 0}; 
	SDL_Rect windowRect = {210, 170, 420, 220};
	SDL_FillRect(windowSurface, &windowRect, SDL_MapRGBA(messageSurface->format, 0, 0, 0, 120));
	SDL_BlitSurface(messageSurface, &messageRect, windowSurface, &messagePositon); 
}

void GameSurfaceSDL::drawGameMessage(void)
{
}


void GameSurfaceSDL::SystemMessage(std::string message)
{
	this->currentMessage = message;
	messageSurface = TTF_RenderUTF8_Blended(font, toUTF8(this->currentMessage.c_str()).c_str(), color);
	pushAnyKey();
	this->currentMessage.erase();
	SDL_FreeSurface(messageSurface);
}

}