/*********************************************************************
*	SystemConfig
*	SOURCE FILE
*	Autor:	Michal Jirouš
*	Datum: 7.7.2008
*	Soubor: systemconf.cpp
*	Popis: Modul spravujici zakladni informace o systemu jako jsou
* 			rozliseni, bitova hloubka, jazyk. Nacita config ze souboru
* 			a kontroluje dostupnost nastavenych vlastnosti
**********************************************************************/

#include "systemconf.h"
#include <fstream>
#include <iostream>

//Nastaveni zakladnich informaci
systemconf::SystemInfo::SystemInfo()
{
	m_iResolutionWidth = systemconf::DEFAULT_RESOLUTION_WIDTH;
	m_iResolutionHeight = systemconf::DEFAULT_RESOLUTION_HEIGHT;
	m_iBpp = systemconf::DEFAULT_BPP;
	m_sLanguage = systemconf::DEFAULT_LANGUAGE;
}

systemconf::SystemInfo g_SystemInfo;
map<int,int> g_VideoModes;

//Ziska dostupne video mody a ulozi je do mapy
bool determineVideoModes()
{
	g_VideoModes.clear();
	
	SDL_Rect **modes;
	modes = SDL_ListModes(NULL, REQUIRED_FLAGS);

	// Jsou vubec nejake mody dostupne?
	if(modes == (SDL_Rect **)0)
	{
		cerr << "No video modes available" << endl;
		return false;
	}

	// Jsou nejaka omezeni na rozliseni?
	if(modes == (SDL_Rect **)-1)
	{
		cout << "All video modes available" << endl;
	}
	else
	{	
		//zjisteni dostupnych modu
		cout << "Available video modes:" << endl;
		for(int i = 0; modes[i]; i++)
		{
			cout << modes[i]->w << "x" << modes[i]->h << endl;	//vypis
			g_VideoModes.insert( make_pair( modes[i]->w, modes[i]->h) );	//ulozeni
		}
	}
	return true;
}

//Nacteni nastaveni z konfiguracniho souboru
bool systemconf::loadConfig( const char* filename )
{
	ifstream fin( filename, ios::in);
	if( fin.is_open() )
	{
		string parameter;
		string data;
		while( 1 )
		{
			fin >> parameter;
			if( fin.eof() )
				break;
			
			fin >> data;	//nacteni znaku "="
			fin >> data;
			
			setParameter( parameter, data );
		}
		
		fin.close();
	}
	return init();
}

//inicializace a kontrola aktualni konfigurace ( v pripade inicializace
//se kontroluji pocatecni parametry )
bool systemconf::init()
{
	if( !determineVideoModes() || !checkAndCorrectParameters() )
			return false;
	return true;
}

//nastavi parametr konfigurace
void systemconf::setParameter( string &parameter, string &data)
{
	if( parameter == COMMAND_RESOLUTION_WIDTH )
		g_SystemInfo.m_iResolutionWidth = atoi( data.c_str() );
	else if( parameter == COMMAND_RESOLUTION_HEIGHT )
		g_SystemInfo.m_iResolutionHeight = atoi( data.c_str() );
	else if( parameter == COMMAND_BPP )
		g_SystemInfo.m_iBpp = atoi( data.c_str() );
	else if( parameter == COMMAND_LANGUAGE )
		g_SystemInfo.m_sLanguage = data;

}

//vraci aktualni systemovou konfiguraci
systemconf::SystemInfo &systemconf::getSystemInfo()
{
	return g_SystemInfo;
}

//ulozi konfiguraci do souboru
void systemconf::saveConfig( const char* filename )
{
	ofstream fout(filename, ios::out | ios::trunc);
	if( !fout.is_open() )
		return;
	
	fout << COMMAND_RESOLUTION_WIDTH << " = " << g_SystemInfo.m_iResolutionWidth << endl;
	fout << COMMAND_RESOLUTION_HEIGHT << " = " << g_SystemInfo.m_iResolutionHeight << endl;
	fout << COMMAND_BPP << " = " << g_SystemInfo.m_iBpp << endl;
	fout << COMMAND_LANGUAGE << " = " << g_SystemInfo.m_sLanguage << endl;
	
	fout.close();
}

//otestuje nastaveni a pripadne ho opravi
bool systemconf::checkAndCorrectParameters()
{
	int bpp = SDL_VideoModeOK( g_SystemInfo.m_iResolutionWidth, g_SystemInfo.m_iResolutionHeight, g_SystemInfo.m_iBpp, REQUIRED_FLAGS);

	if( bpp == 0 )	//error
	{
		cerr << "Error while checking Video mode -> correcting BPP..." << endl;
		bpp = SDL_GetVideoInfo()->vfmt->BitsPerPixel;
		cout << "BPP set to " << bpp << endl;	
		g_SystemInfo.m_iBpp = bpp;	//nova hodnota BPP
		
		bpp = SDL_VideoModeOK( g_SystemInfo.m_iResolutionWidth, g_SystemInfo.m_iResolutionHeight, g_SystemInfo.m_iBpp, REQUIRED_FLAGS);
		
		if( bpp == 0 )	//error
		{
			cerr << "Error while checking Video mode -> correcting resolution..." << endl;
			
			bpp = SDL_GetVideoInfo()->vfmt->BitsPerPixel;

			// Zkusi ziskat dostupna rozliseni podle flagu
			SDL_Rect **modes;
			modes = SDL_ListModes(NULL, REQUIRED_FLAGS);
			
			if(modes == (SDL_Rect **)0)// Zadne dostupne mody
			{
				cerr << "No video mode available -> Quiting" << endl;
				return false;
			}
			else if(modes == (SDL_Rect **)-1)// Zadna omezeni
			{
				cout << "Setting video mode 640x480" << endl;
				g_SystemInfo.m_iResolutionWidth = 640;
				g_SystemInfo.m_iResolutionHeight = 480;
			}
			else// Pouzije maximalni dostupne rozmery
			{
				int i = 0;
				while( modes[i] && modes[i++]->w >= MINIMUM_WIDTH );
				
				if( i == 0 )
				{
					cerr << "No video mode available -> Quiting" << endl;
					return false;
				}
				g_SystemInfo.m_iResolutionWidth = modes[i-1]->w;
				g_SystemInfo.m_iResolutionHeight = modes[i-1]->h;
				
				cout << "Setting minimum video mode " << modes[i-1]->w << "x" << modes[i-1]->h << endl;
				
			}

			bpp = SDL_VideoModeOK( g_SystemInfo.m_iResolutionWidth, g_SystemInfo.m_iResolutionHeight, g_SystemInfo.m_iBpp, REQUIRED_FLAGS);
			if( bpp == 0 )
			{
				cerr << "Could not correct video mode -> quitting" << endl;
				return false;
			}
			
		}
		
	}
	
	
	//no a stejnak to muze byt spatne...takze..
	map<int,int>::iterator iter = g_VideoModes.find( g_SystemInfo.m_iResolutionWidth );
	if( iter == g_VideoModes.end() || iter->second != g_SystemInfo.m_iResolutionHeight )	//not available
	{
		if( g_VideoModes.empty() )
		{
			cerr << "No video modes available -> Quitting" << endl;
			return false;
			
		}
		
		cerr << "Error while checking Video mode -> correcting resolution..." << endl;
		g_SystemInfo.m_iResolutionWidth = g_VideoModes.begin()->first;
		g_SystemInfo.m_iResolutionHeight = g_VideoModes.begin()->second;
		for( map<int,int>::iterator i = g_VideoModes.begin(); i != g_VideoModes.end(); i++)
		{
			if( i->first >= MINIMUM_WIDTH &&  i->first < g_SystemInfo.m_iResolutionWidth )
			{
				g_SystemInfo.m_iResolutionWidth = i->first;
				g_SystemInfo.m_iResolutionHeight = i->second;
			}
		}
		
		cout << "Setting minimum video mode " << g_SystemInfo.m_iResolutionWidth << "x" << g_SystemInfo.m_iResolutionHeight << endl;
		
		bpp = SDL_VideoModeOK( g_SystemInfo.m_iResolutionWidth, g_SystemInfo.m_iResolutionHeight, g_SystemInfo.m_iBpp, REQUIRED_FLAGS);
		if( bpp == 0 )
		{
			cerr << "Could not correct video mode -> quitting" << endl;
			return false;
		}
		
		
	}
	return true;
}

//vraci seznam dostupnych video modu
map<int,int> &systemconf::getVideoModes()
{
	return g_VideoModes;
}


