#include "pixie/pixie.hpp"
using namespace pixie;

#include "dialog_playback.hpp"

tweener animate( sprite* spr, float speed )
    {
    return pixie::tween( 65536.0f / speed )
        .property( property_cel( spr ), 65536.0f )
        .ease( ease_linear )
		.repeat( true )
        ;
    }


template<typename F > tweener with_delay( float delay, F handler )
	{
	return pixie::tween( delay ).on_complete( handler );
	}


bool is_near( sprite* spr, float xpos )
	{
	return ( xpos > spr->position_x() - 25.0f ) && ( xpos < spr->position_x() + 25.0f );
	}

void set_interact( sprite* spr, string str, label* interact, float offset = 0.0f )
	{
	interact->text( str );
	interact->position_x( spr->position_x() + 160 + offset );
	}

void setup_speech( label& speech, string_id character )
	{
	speech.wrap( 220 );
	str_switch( character )
		{
		str_case( "player_sitting" )
			{
			speech
				.position( 50.0f, 85.0f )
				.color( 17 ); // green
			}
		str_case( "player" )
			{
			speech
				.position( 20.0f, 60.0f )
				.color( 17 ); // green
			}
		str_case( "player_hut" )
			{
			speech
				.position( 100.0f, 60.0f )
				.color( 17 );
			}
		str_case( "player_radio" )
			{
			speech
				.position( 50.0f, 20.0f )
				.color( 17 ); // green
			}
		str_case( "tv_guy" )
			{
			speech
				.position( 20.0f, 20.0f )
				.color( 30 ); // yellow
			}
		str_case( "book_guy" )
			{
			speech
				.position( 20.0f, 20.0f )
				.color( 51 ); // purple
			}
		str_case( "penguin" )
			{
			speech
				.wrap( 120 )
				.position( 185.0f, 75.0f )
				.color( 35 ); // brown
			}
		}
	}

void title_screen()
	{
	sprite background;
	background
		.position_x( -1050 )
        .bitmap( "data/background.pix" )
        ;

	sprite trees;
	trees
		.position_x( -1050 )
        .bitmap( "data/sprites/treeline.pix" )
        ;

	sprite face;
	face
		.bitmap( "data/sprites/face.pix" )
		.position_y( 200 )
        ;

	pixie::tween( 2.0f )
		.delay( 0.1f )
		.property( property_position_y( &face), 50.0f )
		.ease( ease_elastic_out )
		;

	sprite logo;
	logo
		.bitmap( "data/logo.pix" )
		.position_y( -200 )
        ;

	pixie::tween( 1.0f )
		.delay( 0.5f )
		.property( property_position_y( &logo ), 0.0f )
		.ease( ease_bounce_out )
		;

	label credits;
	credits
		.text( "Code, art, music and design by Mattias Gustavsson" )
		.font( "data/Volter__28Goldfish_29.fnt" )
		.position( -160, 185.0f )
		.align( TEXT_ALIGN_CENTER )
		.color( brightest_color() )
		.outline( darkest_color() )
		.shadow( darkest_color() )
		;

	pixie::tween( 1.0f )
		.delay( 0.5f )
		.property( property_position_x( &credits ), 160.0f )
		.ease( ease_quad_out )
		;

	while( is_running() )
		{
        execute_frame();
		if( key_was_pressed( KEY_ESCAPE ) ) end(); // exit with no error
        if( key_was_pressed( KEY_RETURN ) && key_is_down( KEY_MENU ) ) fullscreen( !fullscreen() );
        if( key_was_pressed( KEY_TAB ) ) crt_mode( !crt_mode() );
		if( key_was_pressed( KEY_SPACE ) ) return;
		}	
	}

int stranded_main()
	{
	title( "Stranded" );
	screen_size( 320, 200 );
	border_size( 32, 44 );
	fullscreen( true );
	crt_mode( true );
	
	u8 zero = 0;
	mouse_pointer( &zero, &zero, 1, 1 );

	load_palette( "data/palette.pal" );
	play_music( "data/music.ogg" );

	title_screen();

	array<sprite*> objects;

	sprite background;
	background
		.origin_x( 0 )
        .bitmap( "data/background.pix" )
        ;

	sprite treeline;
	treeline
		.origin_x( 0 )
        .bitmap( "data/sprites/treeline.pix" )
        ;

	sprite radio;
	objects.add( &radio);
	radio
		.bitmap( "data/sprites/radio_spr.pix" )
		.position( 240, 0 )
		;


	sprite hut1;
	objects.add( &hut1);
	hut1
		.bitmap( "data/sprites/hut1.pix" )
		.position( 540, 0 )
		;

	sprite hut2;
	objects.add( &hut2);
	hut2
		.bitmap( "data/sprites/hut2.pix" )
		.position( 850, 20 )
		;
	sprite tree2;
	objects.add( &tree2 );
	tree2
        .bitmap( "data/sprites/tree2.pix" )
		.position( 180, -30 )
        ;

	sprite tree;
	objects.add( &tree );
	tree
        .bitmap( "data/sprites/palmtree.pix" )
		.position( 120, -10 )
        ;

	sprite chair;
	objects.add( &chair );
	chair
        .bitmap( "data/sprites/chair.pix" )
		.position( 65, 25 )
        ;

	sprite penguin_battery;
	objects.add( &penguin_battery );
	penguin_battery
        .bitmap( "data/sprites/penguin_battery.pix" )
		.position( 970 + 62, -10 )
        ;

	sprite penguin;
	objects.add( &penguin );
	penguin
        .bitmap( "data/sprites/penguin.pix" )
		.position( 970, -10 )
        ;


	sprite guy;
	guy 
        .bitmap( "data/sprites/guychair.pix" )
		.position( 0, 25 )
		.zorder( 10.0f )
        ;
	animate( &guy, 25.0f );

	sprite guy_inside;
	guy_inside
        .bitmap( "data/sprites/guy_idle.pix" )
		.visible( false )
		.zorder( 101.0f )
        ;

	sprite radio_pic;
	radio_pic
		.bitmap( "data/sprites/radio_full.pix" )
		.zorder( 100.0f )
		.visible( false )
		;
	sprite radio_back;
	radio_back
		.bitmap( "data/background.pix" )
		.position_x( -250.0f )
		.zorder( 99.0f )
		.visible( false )
		;

	sprite hut_tv_pic;
	hut_tv_pic
		.bitmap( "data/sprites/hut_tv.pix" )
		.zorder( 100.0f )
		.visible( false )
		;


	sprite hut_bulb;
	hut_bulb
		.bitmap( "data/sprites/hut_book.pix" )
		.zorder( 100.0f )
		.visible( false )
		;

	label interact;
	interact
		.font( "data/Volter__28Goldfish_29.fnt" )
		.position( 160.0f, 70.0f )
		.align( TEXT_ALIGN_CENTER )
		.color( brightest_color() )
		.outline( darkest_color() )
		.shadow( darkest_color() )
		;

	sprite boat;
	boat
		.position( -320.0f, 30.0f )
		.bitmap( "data/sprites/boat.pix" )
		;

	label speech;
	speech
		.font( "data/Volter__28Goldfish_29.fnt" )
		.zorder( 200 )
		.wrap( 220)
		.align( TEXT_ALIGN_CENTER )
		.position( 50.0f, 70.0f )
		.color( 18 ) // green
		.outline( darkest_color() )
		.shadow( darkest_color() )
		;

	dialog_playback dlg;
	dlg.load_dialog( "data/dialog.dlg" );

	with_delay( 1.0f, [&dlg]() { dlg.start_conversation( "lets_go_home" ); dlg.execute(); } );

	bool fadeout = false;
	bool rescued = false;
	bool may_stand = false;
	bool looked_at_radio = false;
	bool sitting = true;
	bool penguin_gone = false;
	bool at_radio = false;
	bool at_hut_tv = false;
	bool at_hut_bulb = false;
	bool has_dish = false;
	bool has_bulb = false;
	bool has_battery = false;
	  
	float xpos = 65.0f;

	while( is_running() )
		{
        execute_frame();
		if( fadeout )
			{
			bool all_black = true;
			for( int i = 0; i < 64; ++i )
				{
				rgb c = palette_color( i );
				if( c.r > 0 || c.g > 0 || c.b > 0 ) all_black = false;
				if( c.r > 0 ) c.r = (u8)( c.r - min( c.r, 3 ) ); 
				if( c.r < 80 && c.g > 0 ) c.g = (u8)( c.g - min( c.g, 3 ) ); 
				if( c.g < 80 && c.b > 0 ) c.b = (u8)( c.b - min( c.b, 3 ) ); 
				palette_color( i, c );
				}
			if( all_black ) end();
			}
		
		if( exit_requested() ) end(); // exit immediately if user closes window
		if( key_was_pressed( KEY_ESCAPE ) ) end(); // exit with no error
        if( key_was_pressed( KEY_RETURN ) && key_is_down( KEY_MENU ) ) fullscreen( !fullscreen() );
        if( key_was_pressed( KEY_TAB ) ) crt_mode( !crt_mode() );

		if( dlg.state() != dialog_playback::STATE_READY )
			{
			if( dlg.state() == dialog_playback::STATE_SENDING_EVENT )
				{
   				string_id event = dlg.current_conversation_event()->event;
				if( starts_with( event, "SetFlag:" ) )
					{
					string_id flag = trim( mid( event, 8 ) );
					str_switch( flag )
						{
						str_case( "may_stand" )
							{
							may_stand = true;
							}
						str_case( "looked_at_radio" )
							{
							looked_at_radio = true;
							}
						str_case( "penguin_running" )
							{
							penguin.bitmap( "data/sprites/penguin_walk.pix" );
							penguin.position_x( 970.0f + 62.0f );
							animate( &penguin, 25.0f ).delay( 0.5f );
							pixie::tween( 1.0f )
								.delay( 0.5f )
								.property( property_position_x( &penguin ), 970.0f + 62.0f + 160.0f )
								.ease( ease_linear )
								.on_complete( [&penguin]() { penguin.visible( false ); } )
								;
							}
						str_case( "penguin_gone" )
							{
							penguin_gone = true;
							dlg.execute();
							}
						str_case( "rescued" )
							{
							rescued = true;
							}
						}
					}
				if( starts_with( event, "ClearFlag:" ) )
					{
					string_id flag = trim( mid( event, 10 ) );
					str_switch( flag )
						{
						str_case( "at_hut_tv" )
							{
							hut_tv_pic.visible( false );
							guy_inside.visible( false );
							hut_tv_pic.bitmap( "data/sprites/hut_tv_nodish.pix" );
							has_dish = true;
							at_hut_tv = false;
							}
						str_case( "at_hut_bulb" )
							{
							hut_bulb.visible( false );
							guy_inside.visible( false );
							hut_bulb.bitmap( "data/sprites/hut_book_nobulb.pix" );
							has_bulb = true;
							at_hut_bulb = false;
							}
						}
					}
 				dlg.execute();
				}
			else if( dlg.state() == dialog_playback::STATE_DISPLAYING_SPEECH )
				{
				setup_speech( speech, dlg.current_conversation_line()->actor );
				speech.text( dlg.current_conversation_line()->line );
				if( speech.visible() && key_was_pressed( KEY_SPACE ) ) 
					{					
					speech.visible( false );
					with_delay( 0.5f, [&dlg, &speech]() { dlg.execute(); speech.text( "" ); speech.visible( true ); } );
					}
				}
			else
				{
				dlg.execute();
				}
			continue;
			}
		else
			{
			speech.text( "" );
			}

		interact.text( "" );
		if( !sitting && !at_radio && !at_hut_tv && !at_hut_bulb && !rescued )
			{
			if( is_near( &radio, xpos ) ) set_interact( &radio, "Radio", &interact );
			if( is_near( &hut1, xpos ) ) set_interact( &hut1, "Hut", &interact );
			if( is_near( &hut2, xpos ) ) set_interact( &hut2, "Hut", &interact );
			if( !penguin_gone && is_near( &penguin, xpos ) ) set_interact( &penguin, "Penguin", &interact, + 60.0f );
			if( !has_battery && penguin_gone && is_near( &penguin_battery, xpos ) ) set_interact( &penguin_battery, "Battery", &interact );
				
			if( key_is_down( KEY_LEFT ) ) 
				{
				xpos -= 2.0f;
				if( xpos < 10 ) xpos = 10.0f;
				guy.bitmap( "data/sprites/guy_walk_left.pix" );
				}
			else if( key_is_down( KEY_RIGHT ) )
				{
				xpos += 2.0f;
				if( xpos > 1120 ) xpos = 1120.0f;
				guy.bitmap( "data/sprites/guy_walk_right.pix" );
				}
			else
				{
				guy.bitmap( "data/sprites/guy_idle.pix" );
				}
			if( key_was_pressed( KEY_SPACE ) )
				{
				if( is_near( &radio, xpos ) )
					{
					radio_pic.visible( true );
					if( has_dish && has_bulb && has_battery )
						{
						radio_pic.bitmap( "data/sprites/radio_full.pix" );
						dlg.start_conversation( "radio_all" );
						}
					else if( has_dish && has_bulb )
						{
						radio_pic.bitmap( "data/sprites/radio_bulb_dish.pix" );
						dlg.start_conversation( "radio_bulb_dish" );
						}
					else if( has_battery && has_bulb )
						{
						radio_pic.bitmap( "data/sprites/radio_bulb_battery.pix" );
						dlg.start_conversation( "radio_bulb_battery" );
						}
					else if( has_dish && has_battery )
						{
						radio_pic.bitmap( "data/sprites/radio_battery_dish.pix" );
						dlg.start_conversation( "radio_battery_dish" );
						}
					else if( has_dish )
						{
						radio_pic.bitmap( "data/sprites/radio_dish.pix" );
						dlg.start_conversation( "radio_dish" );
						}
					else if( has_battery )
						{
						radio_pic.bitmap( "data/sprites/radio_battery.pix" );
						dlg.start_conversation( "radio_battery" );
						}
					else if( has_bulb )
						{
						radio_pic.bitmap( "data/sprites/radio_bulb.pix" );
						dlg.start_conversation( "radio_bulb" );
						}
					else
						{
						radio_pic.bitmap( "data/sprites/radio_none.pix" );
						if( !looked_at_radio )
							dlg.start_conversation( "radio_first" );
						else
							dlg.start_conversation( "radio_none" );
						}

					radio_back.visible( true );
					at_radio = true;
					}
				if( is_near( &hut1, xpos ) )
					{
					hut_tv_pic.visible( true );
					guy_inside.visible( true ).position( 100, 40 );
					if( !has_dish )
						dlg.start_conversation( "hut_tv" );
					else
						dlg.start_conversation( "hut_tv_sleep" );
					at_hut_tv = true;
					}
				if( is_near( &hut2, xpos ) )
					{
					hut_bulb.visible( true );
					guy_inside.visible( true ).position( 100, 40 );
					if( !has_bulb )
						dlg.start_conversation( "hut_book" );
					else
						dlg.start_conversation( "hut_book_sleep" );
					at_hut_bulb = true;
					}
				if( !penguin_gone && is_near( &penguin, xpos ) )
					{
					penguin.bitmap( "data/sprites/penguin.pix" );
					dlg.start_conversation( "penguin" );
					interact.text( "" );
					guy.bitmap( "data/sprites/guy_idle.pix" );
					}
				if( !has_battery && penguin_gone && is_near( &penguin_battery, xpos ) )
					{
					interact.text( "" );
					penguin.visible( false );
					dlg.start_conversation( "grab_battery" );
					penguin_battery.visible( false );
					has_battery = true;
					}
				if( is_near( &chair, xpos ) )
					{
					sitting = true;
					xpos = 65;
					guy 
						.bitmap( "data/sprites/guychair.pix" )
						.position( 0, 25 )
						;
					}
				}
			}
		else if( sitting && may_stand )
			{
			if( key_was_pressed( KEY_SPACE ) )
				{
				sitting = false;
				guy 
					.bitmap( "data/sprites/guy_idle.pix" )
					.position( 0, 30 )
					;
				}
			}
		else if( at_radio )
			{
			if( key_was_pressed( KEY_SPACE ) )
				{
				radio_pic.visible( false );
				radio_back.visible( false );
				at_radio = false;
				if( rescued )
					{
					guy.bitmap( "data/sprites/guy_jump.pix" );
					xpos = 20;
					pixie::tween( 2.0f )
						.delay( 1.5f )
						.property( property_position_x( &boat ), -190.0f )
						.ease( ease_quad_out );
					with_delay( 3.0f, [&fadeout]() { fadeout = true; } );
					}
				}
			}
		else if( at_hut_tv )
			{
			if( key_was_pressed( KEY_SPACE ) )
				{
				hut_tv_pic.visible( false );
				guy_inside.visible( false );
				hut_tv_pic.bitmap( "data/sprites/hut_tv_nodish.pix" );
				has_dish = true;
				at_hut_tv = false;
				}
			}
		else if( at_hut_bulb )
			{
			if( key_was_pressed( KEY_SPACE ) )
				{
				hut_bulb.visible( false );
				guy_inside.visible( false );
				hut_bulb.bitmap( "data/sprites/hut_book.pix" );
				has_bulb = true;
				at_hut_bulb = false;
				}
			}

		for( int i = 0; i < objects.count(); ++i )
			objects[i]->origin_x( xpos );

		interact.origin_x( xpos );

		guy.origin_x( xpos );
		guy.position_x( xpos );
		background.position_x( -xpos );
		treeline.position_x( -xpos );			

		dlg.execute();
		}

    return 0;
	}

