//	LoadingScreen.cpp - Loading screen state.
//  ----------------------------------------------------------------------------
//	This file is part of 'NiallsAVLib', base code for any kind of audiovisual
//	apps.
//	Copyright (C) 2012  Niall Moody
//	
//	This program 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.
//
//	This program 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 this program.  If not, see <http://www.gnu.org/licenses/>.
//	----------------------------------------------------------------------------

#include "Font.h"
#include "Shader.h"
#include "SingleImage.h"
#include "LoadingScreen.h"
#include "sound/Sounder.h"
#include "drawing/Drawer.h"
#include "drawing/ImageLoader.h"

#include <cassert>

using namespace std;

//------------------------------------------------------------------------------
GameStateCreator<LoadingScreen> LoadingScreen::creator;

//------------------------------------------------------------------------------
LoadingScreen::LoadingScreen(Application *app, Sounder *sound):
GameState(app, sound),
totalResources(0),
resProgress(0),
resType(NumResourceTypes),
resIndex(0),
subIndex(0),
sounder(sound),
fadeOut(0.0f)
{
	int i, j;

	for(j=0;j<Height;++j)
	{
		for(i=0;i<Width;++i)
			grid[j][i] = 0.0f;
	}
}

//------------------------------------------------------------------------------
LoadingScreen::~LoadingScreen()
{

}

//------------------------------------------------------------------------------
void LoadingScreen::draw(DrawerPtr d)
{
	float progress;
	ImageData data;
	TwoFloats barSize;
	TwoFloats barStart;
	ImageLoader imLoad;
	const TwoFloats origin;
	const ThreeFloats black;
	const ThreeFloats white(1.0f);
	const TwoFloats& drawingSize = d->getDrawingAreaSize();
	const ResourceManager& manager = getResourceManager();

	//If progressInc is 0, we need to calculate how many total resources we
	//have to load to work out what progressInc should be.
	//We also figure out what our first resType is.
	//if(progressInc <= 0.0f)
	if(resProgress <= 0)
	{
		int i;

		totalResources = manager.getNumTextureAtlases();
		if(totalResources > 0)
			resType = TextureAtlasRes;

		totalResources += manager.getNumSingleImages();
		if((totalResources > 0) && (resType == NumResourceTypes))
			resType = SingleImageRes;

		for(i=0;i<manager.getNumFolders();++i)
			totalResources += manager.getFolder(i).getNumChildren();
		if((totalResources > 0) && (resType == NumResourceTypes))
			resType = ImageFolderRes;

		totalResources += manager.getNumShaders();
		if((totalResources > 0) && (resType == NumResourceTypes))
			resType = ShaderRes;

		totalResources += manager.getNumFonts();
		if((totalResources > 0) && (resType == NumResourceTypes))
			resType = FontRes;

		totalResources += manager.getNumSounds();
		if((totalResources > 0) && (resType == NumResourceTypes))
			resType = SoundRes;

		if(resType == NumResourceTypes)
		{
			resProgress = 1;
			totalResources = 1;
			fadeOut += 0.02f;
		}
	}

	//Draw progress.
	{
		//(this is a placeholder).
		//(fill background black)
		d->fillRect(origin, drawingSize, black);

		//(white border)
		barStart.x = 64.0f;
		barStart.y = (drawingSize.y * 0.5f) - 64.0f;
		barSize.x = drawingSize.x - 128.0f;
		barSize.y = 128.0f;
		d->fillRect(barStart, barSize, white);

		//(inside black border)
		barStart += 8.0f;
		barSize -= 16.0f;
		d->fillRect(barStart, barSize, black);

		//(white progress bar)
		progress = (float)resProgress/(float)totalResources;
		barStart += 8.0f;
		barSize -= 16.0f;
		barSize.x *= progress;
		d->fillRect(barStart, barSize, white);
	}

	if(fadeOut <= 0.0f)
	{
		//Load current resource.
		switch(resType)
		{
			case TextureAtlasRes:
				{
					TextureAtlasPtr atlas = manager.getTextureAtlas(resIndex);

					data = imLoad.loadImage(atlas->getImageData(), atlas->getImageDataSize());
					d->loadTextureAtlas(data.data, data.width, data.height, *atlas);

					++resIndex;
					if(resIndex >= manager.getNumTextureAtlases())
					{
						if(manager.getNumSingleImages() > 0)
							resType = SingleImageRes;
						else if(manager.getNumFolders() > 0)
							resType = ImageFolderRes;
						else if(manager.getNumShaders() > 0)
							resType = ShaderRes;
						else if(manager.getNumFonts() > 0)
							resType = FontRes;
						else if(manager.getNumSounds() > 0)
							resType = SoundRes;
						resIndex = 0;
					}
				}
				break;
			case SingleImageRes:
				{
					SingleImagePtr image = manager.getSingleImage(resIndex);

					data = imLoad.loadImage(image->getImageData(), image->getImageDataSize());
					d->loadSingleImage(data.data, data.width, data.height, image->getName());

					++resIndex;
					if(resIndex >= manager.getNumSingleImages())
					{
						if(manager.getNumFolders() > 0)
							resType = ImageFolderRes;
						else if(manager.getNumShaders() > 0)
							resType = ShaderRes;
						else if(manager.getNumFonts() > 0)
							resType = FontRes;
						else if(manager.getNumSounds() > 0)
							resType = SoundRes;
						resIndex = 0;
					}
				}
				break;
			case ImageFolderRes:
				{
					const FilePath& folder = manager.getFolder(resIndex);
					FilePath imageFile = folder.getChild(subIndex);

					data = imLoad.loadImage(imageFile);
					d->loadSingleImage(data.data, data.width, data.height, imageFile.getName());

					++subIndex;
					if(subIndex >= folder.getNumChildren())
					{
						++resIndex;
						if(resIndex >= manager.getNumFolders())
						{
							if(manager.getNumShaders() > 0)
								resType = ShaderRes;
							else if(manager.getNumFonts() > 0)
								resType = FontRes;
						else if(manager.getNumSounds() > 0)
							resType = SoundRes;
							resIndex = 0;
						}
						subIndex = 0;
					}
				}
				break;
			case ShaderRes:
				{
					ShaderPtr shader = manager.getShaders(resIndex);

					d->loadShader(shader->getVertexShader(),
								  shader->getFragmentShader(),
								  shader->getName());

					++resIndex;
					if(resIndex >= manager.getNumShaders())
					{
						if(manager.getNumFonts() > 0)
							resType = FontRes;
						else if(manager.getNumSounds() > 0)
							resType = SoundRes;
						resIndex = 0;
					}
				}
				break;
			case FontRes:
				{
					FontPtr font = manager.getFont(resIndex);

					d->loadFont(font->getPath().getName(),
								font->getSize(), 
								font->getId());

					++resIndex;
					if(resIndex >= manager.getNumFonts())
					{
						if(manager.getNumSounds() > 0)
							resType = SoundRes;
						resIndex = 0;
					}
				}
				break;
			case SoundRes:
				{
					sounder->loadSoundFileResource(manager.getSound(resIndex));

					++resIndex;
					if(resIndex >= manager.getNumSounds())
					{
						resType = NumResourceTypes;
						resIndex = 0;
					}
				}
				break;
			default:
				//You shouldn't ever get here. It means you've tried to load a
				//resource type that doesn't exist.
				assert(0);
		}

		//Update progress.
		++resProgress;
		if(resProgress >= totalResources)
			fadeOut += 0.02f;
	}

	if(fadeOut > 0.0f)
	{
		d->fillRect(origin, drawingSize, black, fadeOut);

		fadeOut += 0.02f;
	}

	if(fadeOut >= 1.0f)
		nextState(L"-start state-");
}

//------------------------------------------------------------------------------
void LoadingScreen::keyDown(const wstring& action,
							const wstring& keyPressed,
							int keyModifier)
{

}
