#include "app.h"
		
static STATES_T		state;
static UINT32		repaint_timer;
static WCHAR		file_cfg[256]; 			// ELF_NAME.cfg
						
static UINT16       status;
static char			msg[2048+1], 			// Буффер для редактора сообщений
					viewer_content[2048+1]; // Буффер для просмотощика	
					
static AHIROTATE_T		player_rotate;

static AHIPOINT_T		camera;	// Положение камеры (верхний левый угол (16*CAMERA_W)x(16*CAMERA_H) )
static AHIPOINT_T		player;	// Положение игрока
					
MME_GC_MEDIA_FILE 	mme_media_file = NULL; 	// id открытого mp3 файла
UIS_DIALOG_T        dialog; 				// Диалог
SETTING_T 			setting; // Настройки
ldrElf       	 	elf;					// Структура эльфа
ITEM 				item; 					// Пункты
DRAWING_BUFFER_T 	bufd = {NULL, 176, 220};// Буфер для рисования, Canvas.

/* Название приложения. Длина строки именно такая и никакая иначе */
const char app_name[APP_NAME_LEN] = ELF_NAME; 

/* Обработчики событий для каждого state-а */
/* Обработчики событий для APP_STATE_ANY (используется в любом state) */
static EVENT_HANDLER_ENTRY_T any_state_handlers[] =
{
	{ EV_TIMER_EXPIRED,       		   HandleTimer },
	{ EV_PM_API_EXIT,					destroyApp },	// PM API: cmd EXIT
	{ EV_MME_OPEN_SUCCESS,              HandlePlay },
    { EV_MME_PLAY_COMPLETE,     HandlePlayComplete },
    { STATE_HANDLERS_END,           		  NULL },
};

static EVENT_HANDLER_ENTRY_T main_state_handlers[] =
{
    { EV_INK_KEY_PRESS,             HandleKeypress },
    { STATE_HANDLERS_END,                     NULL },
};

/* Таблица соответствий обработчиков, состояний и функций входа-выхода из состояния.
   Порядок состояний такой же, как в enum-e */
static const STATE_HANDLERS_ENTRY_T state_handling_table[] =
{
    { APP_STATE_ANY,               // State
      NULL,                       // Обработчик входа в state
      NULL,                       // Обработчик выхода из state
      any_state_handlers          // Список обработчиков событий
    },
    { APP_STATE_MAIN,
      MainStateEnter,
      StateExit,
      main_state_handlers
    }

};

static const APP_STATE_NAME_TABLE_T state_name_table[] =
{
	{APP_STATE_ANY,			"ANY"},
	{APP_STATE_MAIN,		"MAIN"},
	{APP_STATE_MAX,			NULL}
};

/* Это entry для всех эльфов, должна быть объявлена именно так */
/* uri - путь к эльфу (аналогично argv[0]) */
/* params - параметры эльфа (аналогично остальным argv) */
ldrElf * _start( WCHAR * uri, WCHAR * params )
{
    ldrElf *	pelf;
	UINT32		reserve;
	int			i;
	
	dbg("\n_start: Enter");
	
		// ищем запущеный эльф по имени эльфа
	pelf = ldrFindElf(app_name);
	if ( pelf != NULL ) {
		// приложение уже запущено, вызвать запущеное
		ldrSendEvent( pelf->evbase );
		return NULL;
	}
	// база ивентов
	reserve = ldrRequestEventBase();
	// заполняем структуру эльфа
	elf.name = (char *)app_name;
	elf.app = NULL;
	
	// инитим таблицы ивентов
	for ( i=0; i<APP_STATE_MAX; i++ )
		reserve = ldrInitEventHandlersTbl((EVENT_HANDLER_ENTRY_T *)state_handling_table[i].htable, reserve);
	
	i = u_strlen( uri ) - 1;
	while ( i >= 0 && uri[i] != L'/' ) i--;
	i++;
	elf.dir = malloc( i * sizeof(WCHAR) );
	if ( elf.dir )
		u_strncpy( elf.dir, uri, i );

	
	u_mkpath(file_cfg, elf.dir, L"game.cfg", 0);
	

	elf.evbase = reserve ++;
	
	/* Регистрируем приложение */
	 status = APP_Register( &elf.evbase,            // На какое событие должно запускаться приложение
                           1,                       // Кол-во событий, на которое должно запускаться приложение
                           state_handling_table,    // Таблица состояний
                           APP_STATE_MAX,            // Количество состояний
                           (void*)startApp );   // Функция, вызываемая при запуске
	
	if ( status == RESULT_OK )
		ldrSendEvent( elf.evbase );
	 else {
		cprint(DEBUG_APP_NAME ":\x84 can't register app\n");
		return NULL;
	}

#ifdef DEBUG
	ReportPhoneInfo();
#endif

    return &elf; 
}

/* Функция вызываемая при старте приложения */
UINT32 startApp( EVENT_STACK_T *ev_st,  REG_ID_T reg_id,  UINT32 param2 )
{
	APP_ELF_T *			papp;
	
	
	if( AFW_InquireRoutingStackByRegId( reg_id ) == RESULT_OK ) {
		return RESULT_FAIL;
	}
	
	cprint( ELF_NAME ":\x82 Started\n" );
	AHG_Init();
	
    papp = (APP_ELF_T*)APP_InitAppData((void*)APP_HandleEvent, 
                                            sizeof(APP_ELF_T), // Размер структуры приложения
                                            reg_id,
                                            0,
											0,			// history size
											1,			// priority
											AFW_APP_CENTRICITY_SECONDARY,
											AFW_FOCUS,
											AFW_POSITION_TOP );	
	
	if ( !papp )
	{
		dbg("can't init app data");
		ldrUnloadElf();
		return RESULT_FAIL;
	}
	
    status = APP_Start( ev_st,
                        &papp->apt,
                        APP_STATE_MAIN, // Начальное состояние
                        state_handling_table,
                        destroyApp,
                        app_name,
                        state_name_table );
	
	// Теперь приложение может обрабатывать события
	if ( status == RESULT_OK ) {
		elf.app = &papp->apt;
	}
	
    return RESULT_OK;
}


/* Функция выхода из приложения */
UINT32 destroyApp( EVENT_STACK_T *ev_st,  APPLICATION_T *app )
{
	cprint( ELF_NAME ":\x8E Exit\n" );
	
	AHG_Done();

    /* Завершаем работу приложения */
    status = APP_ExitStateAndApp( ev_st, app, 0 );
	
    ldrUnloadElf();
   
    return status;
}

/* Обработчик входа в main state */
UINT32 MainStateEnter( EVENT_STACK_T *ev_st,  APPLICATION_T *app,  ENTER_STATE_TYPE_T type )
{
	APP_ELF_T *		papp = (APP_ELF_T *)(app);
	dbg("MainStateEnter: start");
	if(type != ENTER_STATE_ENTER) return RESULT_OK;
	
	app->dialog = UIS_CreateColorCanvas( &app->port, &bufd, true ); // создаём канвас

	state = MENU_MAIN;
	
	repaint_timer = StartTimer(REPAINT_TIMER_ID, 100, ttCyclical, (APP_ELF_T*)app);
	DrawMain(app);

	dbg("MainStateEnter: end");
	
    return RESULT_OK;
}

UINT32 StateExit( EVENT_STACK_T *ev_st,  APPLICATION_T *app,  EXIT_STATE_TYPE_T type )
{
	dialog = app->dialog;
	status = APP_UtilUISDialogDelete( &app->dialog );

	if ( repaint_timer ) StopTimer( &repaint_timer, (APP_ELF_T*)app );
	
	return status;
}

UINT32 MainKeypress( EVENT_STACK_T * ev_st,  APPLICATION_T *app )
{
    APP_ELF_T        *papp = (APP_ELF_T*)app;
	EVENT_T 		 *event = AFW_GetEv(ev_st);
	APP_ConsumeEv( ev_st, app );
	
    switch (event->data.key_pressed)
    {
		 case KEY_2:
	     case KEY_UP:
                break;
					  
		 case KEY_8:	  
         case KEY_DOWN:
				break;

		//Выбрать
		case KEY_5:
        case KEY_JOY_OK:
				state = GAME;
				DrawGame( app );
				break;
				
		//Выход
		case KEY_RED:
		case KEY_GREEN:
				destroyApp(ev_st,app );
				break;	
				
					
	}	
	return RESULT_OK;
}

UINT32 GameKeypress( EVENT_STACK_T * ev_st,  APPLICATION_T *app )
{
    APP_ELF_T        *papp = (APP_ELF_T*)app;
	EVENT_T 		 *event = AFW_GetEv(ev_st);
	APP_ConsumeEv( ev_st, app );
	
    switch (event->data.key_pressed)
    {
		 case KEY_2:
	     case KEY_UP:
				PlayerMove( 0, -1 );
				DrawGame( app );
                break;
					  
		 case KEY_8:	  
         case KEY_DOWN:
				PlayerMove( 0, 1 );
				DrawGame( app );
				break;
				
		case KEY_4:
		case KEY_LEFT:
				PlayerMove( -1, 0 );
				DrawGame( app );
				break;
			   
		case KEY_6:					
        case KEY_RIGHT:
				PlayerMove( 1, 0 );
				DrawGame( app );
				break; 
		
		
		case KEY_SOFT_LEFT:
				break;
	
		case KEY_SOFT_RIGHT:
				break;

		//Назад
		case KEY_RED:
		case KEY_GREEN:
				state = MENU_MAIN;
				DrawMain( app );
				break;	
				

		//Выбрать
		case KEY_5:
        case KEY_JOY_OK:
				break;
					
	}	
	return RESULT_OK;
}

UINT32 HandleKeypress( EVENT_STACK_T * ev_st,  APPLICATION_T *app )
{
	
    switch ( state )
    {
		 case MENU_MAIN:
		 case MENU_WIN:
			MainKeypress( ev_st, app );
			break;
		
		case GAME:
			GameKeypress( ev_st, app );
			break;
					
	}
	
	return RESULT_OK;
}
//#####################################MAIN#####################################//


void DrawMain( APPLICATION_T *app )
{
	AHIRECT_T		rect;
	int 			x, y, cur_pix;
	
	// Фон
	SetBrushColor( 0x000000 );
	FillRect( 0, 0, 176, 220 );
	
	switch( state ) {
	
		case MENU_MAIN:
			break;
		
	
	
		case MENU_WIN:
		
			break;
	}

	AHG_Flush();
}

void DrawGame( APPLICATION_T *app )
{
	AHIRECT_T		rect;
	int 			x, y, cur_pix;
	
	// Фон
	SetBrushColor( 0x000000 );
	FillRect( 0, 0, 176, 220 );
	
	SetBrushColor( 0xFF0000 );
	FillRect( 0, 14, 176, 2 );
	FillRect( 0, 176, 176, 2 );
	
	SetFgColor( 0xFF0000 );
	DrawText( ELF_NAME" "ELF_VER" by R.U.S.H.A.N.", 5, 2, 0);
	
	// Рисуем карту
	for ( y = camera.y; y < camera.y + CAMERA_H; y++ )
	{
		for ( x = camera.x; x < camera.x + CAMERA_W; x++ )
		{
		
			cur_pix = (bmp_level1.width*y)+x;
			
			if( !bmp_level1_data[cur_pix] ) { // если этот байт равен 0x00, то это стена.
			
				rect.x1 =  (x - camera.x) * 16; 
				rect.y1 = 16 + (y - camera.y) * 16;  
				rect.x2 = rect.x1 + 16; 
				rect.y2 = rect.y1 + 16;
				DrawBmpImage( &bmp_res, &rect, 4*16, 0 );
			
			} else {
				SetBrushColor( 0x000000 );
				FillRect( (x - camera.x)*16, 16 + (y - camera.y)*16, 16, 16 );
			}
		}
	}
	// Рисуем игрока

	x = player.x - camera.x;
	y = player.y - camera.y;

	rect.x1 =  x*16; 
	rect.y1 = 16 + y*16;  
	rect.x2 = rect.x1 + 16; 
	rect.y2 = rect.y1 + 16;
	
	DrawBmpImage( &bmp_res, &rect, player_rotate*16, 0 );
	
	char	buf[64];
	
	SetFgColor( 0xFF0000 );
	sprintf(buf, "player, x=%d,y=%d\n", player.x, player.y );
	DrawText( buf, 5, 180, 0);
	sprintf(buf, "camera, x=%d,y=%d\n", camera.x, camera.y );
	DrawText( buf, 5, 190, 0);
	
	AHG_Flush();
	
}

void PlayerMove( int x, int y )
{
	AHIPOINT_T			temp_player = player;
	
	if ( x > 0 && temp_player.x < bmp_level1.width ) {
		temp_player.x += x;
		player_rotate = AHIROT_90;
	} else if ( x < 0 && temp_player.x > 0 ) {
		temp_player.x -= abs_0(x);
		player_rotate = AHIROT_270;
	} else if ( y > 0 && temp_player.y < bmp_level1.height ) {
		temp_player.y += y;
		player_rotate = AHIROT_180;
	} else if ( y < 0 && temp_player.y > 0 ) {
		temp_player.y -= abs_0(y);
		player_rotate = AHIROT_0;
	}
	
	int 	cur_pix = (bmp_level1.width*temp_player.y)+temp_player.x;
	
	if( bmp_level1_data[cur_pix] )
		player = temp_player;
	
	
	if( (player.x >= camera.x + CAMERA_W-1) && camera.x < bmp_level1.width-1 )
		camera.x++;
	if( (player.x <= camera.x) && (camera.x > 0) )
		camera.x--;
		
	if( (player.y >= camera.y + CAMERA_H-1 ) && camera.y < bmp_level1.height-1  )
		camera.y++;
	if( (player.y <= camera.y) && (camera.y > 0 ) )
		camera.y--;	

	// если игрок дошел до финиша	
	if( player.x == bmp_level1.width-1 && player.y == bmp_level1.height-1 ) {
		state = MENU_WIN;
		DrawMain( elf.app );
	}
}

UINT32 HandleTimer( EVENT_STACK_T *ev_st,  APPLICATION_T *app )
{
	UINT32 				id = ((DL_TIMER_DATA_T*)(AFW_GetEv(ev_st)->attachment))->ID;
	
	switch(id) 
	{
		case REPAINT_TIMER_ID:
			if( state != GAME ) return RESULT_OK;
			
			
			DrawGame(app);
			break;
		
	} 

	return RESULT_OK;
}

UINT32 Create(WCHAR *name)
{       
    WCHAR 		 uri[256]; 
	IFACE_DATA_T if_data;
	
	if_data.port = elf.app->port;

	
    u_strcpy(uri, elf.dir);
	u_strcat(uri, L"sounds/");
	u_strcat(uri, name);
	
    if (mme_media_file == 0 && DL_FsFFileExist(uri))
    {
        mme_media_file = MME_GC_playback_create(&if_data, uri, 0, 0, 0, 0, 0, 0); // открываем файл
    } 

    return RESULT_OK;
}

UINT32 HandlePlay( EVENT_STACK_T *ev_st,  APPLICATION_T *app )
{
    UINT32 error;
	
    if (mme_media_file)
    {
        error = MME_GC_playback_start(mme_media_file, 0, 0);   // воспроизводим
    }

    return error;
}

UINT32 HandlePlayComplete( EVENT_STACK_T *ev_st,  APPLICATION_T *app )
{
    UINT32 error;

    if (mme_media_file)
    {
        error = MME_GC_playback_delete(mme_media_file); // удаляем, ранее созданный
        mme_media_file = (MME_GC_MEDIA_FILE *) NULL; // обнуляем id
    }

    return error;
}

#ifdef	DEBUG
void ReportPhoneInfo()
{
	dbg("");
	
	dbgf("PhoneInfo: PhoneName = %s", ldrGetPhoneName());
	dbgf("PhoneInfo: PlatformName = %s", ldrGetPlatformName());
	dbgf("PhoneInfo: FirmwareVersion = %s", ldrGetFirmwareVersion());
	
	dbg("");
	const AHIDRVINFO_T	*ahi = ldrGetAhiDrvInfo();
	dbgf("PhoneInfo: ahi.drvName = %s", ahi->drvName);
	dbgf("PhoneInfo: ahi.drvVer = %s", ahi->drvVer);
	dbgf("PhoneInfo: ahi.totalMemory = %d b", ahi->totalMemory);
	dbgf("PhoneInfo: ahi.internalMemSize = %d b", ahi->internalMemSize);
	dbgf("PhoneInfo: ahi.externalMemSize = %d b", ahi->externalMemSize);
	dbg("");
}
#endif

