module vs.main;



import gedo.system.gameloop;
import gedo.system.scene;
import gedo.input.joystick;
import gedo.audio.music;
import vs.scene.title;
import vs.scene.action;
import vs.scene.interval;
import vs.scene.characterselect;
import vs.scene.gameover;
import vs.scene.gameclear;
import vs.action.field;
import vs.action.character;



int main(string[] args)
{
	auto m = new SceneManager();

	return m.run(args);
}



private class SceneManager
{
public:
	int run(string[] args)
	{
		auto loop = GameLoop.create("vs", args);

		auto result = loop.run({return cast(Scene)(new Title(&onTitleQuit));});

		loop.saveConfig();

		return result;
	}


private:
	CharacterID[4] _characters;
	Joystick[2]    _joysticks;
	Player2is      _player2is;
	uint[2]        _scores;
	uint[2]        _times;
	Music          _bgm;
	uint           _cplevel;
	uint           _arrowSize;
	bool           _isHitCameraEnable;
	int            _stage;


	Scene onTitleQuit(Title title)
	{
		bool isVSMode = true;

		_cplevel = title.cplevel;
		_arrowSize = title.arrowSize;
		_isHitCameraEnable = title.isHitCameraEnable;

		switch(title.result)
		{
		case Title.Result.TOURNAMENT_SOLO:
			_player2is = Player2is.NONE;
			isVSMode = false;
			break;

		case Title.Result.TOURNAMENT_FRIEND_2P:
			_player2is = Player2is.FRIEND;
			isVSMode = false;
			break;

		case Title.Result.VS_FRIEND_2P:
			_player2is = Player2is.FRIEND;
			break;

		case Title.Result.VS_ENEMY_2P:
			_player2is = Player2is.ENEMY;
			break;

		case Title.Result.VS_SOLO:
			_player2is = Player2is.NONE;
			break;

		case Title.Result.TIMEOUT:
			_joysticks[] = null;
			return demoAction();
		}

		_scores[] = 0;
		_times[]  = 0;

		_joysticks[0] = title.joystick1;
		_joysticks[1] = title.joystick2;

		if(isVSMode)
		{
			return new CharacterSelect(&onVSCharacterSelectQuit, _joysticks, _player2is);
		}
		else
		{
			return new CharacterSelect(&onTournamentCharacterSelectQuit, _joysticks, _player2is, false);
		}
	}


	Scene onVSCharacterSelectQuit(CharacterSelect scene)
	{
		if(!scene)
		{
			return new Title(&onTitleQuit);
		}
		else
		{
			static int count = 0;

			CharacterFactory[CharacterID.max+1] factories;

			CharacterID bgmid;

			CharacterFactory[][] teams;
			teams.length    = 2;
			teams[0].length = 2;
			teams[1].length = 2;
			foreach(t, inout team; teams)
			{
				foreach(p, inout member; team)
				{
					auto id = scene.id(t, p);
					if(!factories[id])
					{
						factories[id] = createFactory(id);
					}

					member = factories[id];

					if(t == ((count>>1)&1) && p == (count&1))
					{
						bgmid = id;
					}
				}
			}

			++count;

			_bgm = createBGM(bgmid);
			_bgm.play();

			auto field = createField(bgmid);

			auto action = new Action(&onVSActionQuit, field, teams, _joysticks, _player2is, _cplevel, _arrowSize, _isHitCameraEnable);

			action.scores = _scores;
			action.times  = _times;

			return action;
		}
	}


	Scene onTournamentCharacterSelectQuit(CharacterSelect scene)
	{
		if(!scene)
		{
			return new Title(&onTitleQuit);
		}
		else
		{
			_characters[0] = scene.id(0, 0);
			if(_player2is != Player2is.NONE)
			{
				_characters[1] = scene.id(0, 1);
			}
			else
			{
				_characters[1] = autoSelect();
			}
			_characters[2] = autoSelect();
			_characters[3] = autoSelect();

			_stage = 0;
			_scores[] = 0;
			_times[]  = 0;

			_bgm = createBGM(_characters[2]);
			_bgm.play();
			return new Interval(&onIntervalQuit, _stage, _characters, _player2is);
		}
	}


	Scene onIntervalQuit()
	{
		CharacterFactory[][] teams;
		teams.length    = 2;
		teams[0].length = 2;
		teams[1].length = 2;

		CharacterFactory[CharacterID.max+1] factories;
		foreach(t, inout team; teams)
		{
			foreach(p, inout member; team)
			{
				auto id = _characters[t*2+p];
				if(!factories[id])
				{
					factories[id] = createFactory(id);
				}

				member = factories[id];
			}
		}

		auto field = createField(_characters[2]);

		auto action = new Action(
				&onTournamentActionQuit,
				field,
				teams,
				_joysticks,
				_player2is,
				_cplevel,
				_arrowSize,
				_isHitCameraEnable,
				0.5,
				_stage + 2
			);

		action.scores = _scores;
		action.times  = _times;

		return action;
	}


	Scene onVSActionQuit(Action scene)
	{
		_scores[0] = scene.score(0);
		_scores[1] = scene.score(1);
		_times[0]  = scene.time(0);
		_times[1]  = scene.time(1);
		return new CharacterSelect(&onVSCharacterSelectQuit, _joysticks, _player2is);
	}


	Scene onTournamentActionQuit(Action scene)
	{
		const int STAGE_COUNT = 6;

		_stage += 1;
		_scores[0] = scene.score(0);
		_scores[1] = scene.score(1);
		_times[0]  = scene.time(0);
		_times[1]  = scene.time(1);
		if(scene.playerWin)
		{
			if(_stage < STAGE_COUNT)
			{
				if(_player2is == Player2is.NONE)
				{
					_characters[1] = _characters[2];
				}
				_characters[2] = autoSelect();
				_characters[3] = autoSelect();

				_bgm = createBGM(_characters[2]);
				_bgm.play();
				return new Interval(&onIntervalQuit, (_stage==STAGE_COUNT-1)?2:1, _characters, _player2is);
			}
			else
			{
				return new GameClear(&backToTitle);
			}
		}
		else
		{
			return new GameOver(&backToTitle);
		}
	}


	Scene demoAction()
	{
		_bgm = null;
		Field field = null;

		CharacterFactory[][] teams;

		CharacterFactory[CharacterID.max+1] factories;

		teams.length = 2;
		teams[0].length = 2;
		teams[1].length = 2;
		foreach(inout team; teams)
		{
			foreach(inout member; team)
			{
				auto id = autoSelect();
				if(!factories[id])
				{
					factories[id] = createFactory(id);
				}

				member = factories[id];

				if(!_bgm)
				{
					_bgm = createBGM(id);
				}
				if(!field)
				{
					field = createField(id);
				}
			}
		}

		_bgm.play();
		return new Action(&onDemoActionQuit, field, teams, _joysticks, Player2is.NONE, 2, _arrowSize, _isHitCameraEnable);
	}


	Scene onDemoActionQuit(Action scene)
	{
		return new Title(&onTitleQuit);
	}


	Scene backToTitle()
	{
		return new Title(&onTitleQuit);
	}
}
