﻿
#include "Start_Menu.h"

static UINT16          	ENTRIES_NUM;	// кол-во пунктов
static FILE_T 			file; // Файлы
static COLOR			Color; // Цветовая палитра
static LINE 			*item;

/*Skin */
static UINT32			prev_item;
static UINT32			sel_item;
static UINT32			ev_code;

static WCHAR           	cur_folder[256]=L"#/Start/";  // текущая папка
static char            	*BufR;
static BOOL				event_mode;
static ldrElf			elf;

UIS_DIALOG_T     dialog;
/* Название приложения. Длина строки именно такая и никакая иначе */
const char app_name[APP_NAME_LEN] = "Start_menu"; 

/* Обработчики событий для каждого state-а */

/* Обработчики событий для SM_STATE_ANY (используется в любом state) */
static EVENT_HANDLER_ENTRY_T any_state_handlers[] =
{
	{ EV_PM_API_EXIT,					destroyApp },	// PM API: cmd EXIT
    { STATE_HANDLERS_END,           		  NULL },
};

static EVENT_HANDLER_ENTRY_T main_state_handlers[] =
{
    { EV_INK_KEY_PRESS,             HandleKeypress },
    { STATE_HANDLERS_END,                     NULL },
};

/* Таблица соответствий обработчиков, состояний и функций входа-выхода из состояния.
   Порядок состояний такой же, как в enum-e */
static STATE_HANDLERS_ENTRY_T state_handling_table[] =
{
    { SM_STATE_ANY,               // State
      NULL,                       // Обработчик входа в state
      NULL,                       // Обработчик выхода из state
      any_state_handlers          // Список обработчиков событий
    },
    
    { SM_STATE_MAIN,
      MainStateEnter,
      NULL,
      main_state_handlers
    }
};

/* Это entry для всех эльфов, должна быть объявлена именно так */
/* file_uri - путь к эльфу (аналогично argv[0]) */
/* param - параметры эльфа (аналогично остальным argv) */
/* reserve - выделенная база eventcode-ов (зарезервировано 64 значения)*/
ldrElf* _start( WCHAR *uri, WCHAR *params )
{
    int    			i = 0, j = 0;
	char   			buf[128];
	UINT32			status, reserve, ev = 0;
	
	dbg( "======================================");
	dbg( ELF_NAME" "ELF_VER" "__DATE__" / " __TIME__ );
	dbg("_start: Enter");
	
	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_strcpy(file.ini, uri);
    file.ini[u_strlen(file.ini)-3] = 0;	
	u_strcat(file.ini, L"ini");	
	
	u_strcpy(file.menu, uri);
    file.menu[u_strlen(file.menu)-3] = 0;	
	u_strcat(file.menu, L"menu");	
	
	reserve = ldrRequestEventBase();
	
	// заполняем структуру эльфа
	elf.name = (char *)app_name;
	elf.app = NULL;
	
	// инитим таблицы ивентов
	for ( i=0; i<SM_STATE_MAX; i++ )
		reserve = ldrInitEventHandlersTbl((EVENT_HANDLER_ENTRY_T *)state_handling_table[i].htable, reserve);
	
	if ( params && u_strlen(params) )
	{
		u_utoa(params, buf);
		dbgf("params = '%s'", buf);
		
		ev = strtoul( buf, 0x00, 0 );
		dbgf("ev = 0x%x", ev);
	}
	// стартовый ивент
	if ( ev )
	{
		elf.evbase = ev;
		event_mode = TRUE;
	}
	else
	{
		elf.evbase = reserve++;
		event_mode = FALSE;
	}
	
	LoadSkin(file.ini);
	/* Регистрируем приложение */
    status = APP_Register( &elf.evbase,            // На какое событие должно запускаться приложение
                           1,                       // Кол-во событий, на которое должно запускаться приложение
                           state_handling_table,    // Таблица состояний
                           SM_STATE_MAX,            // Количество состояний
                           (void*)startApp );   // Функция, вызываемая при запуске
						   

	
	if ( !event_mode )
		ldrSendEvent( elf.evbase );	// Start now
    
 	return &elf;
}

/* Функция вызываемая при старте приложения */
UINT32 startApp( EVENT_STACK_T *ev_st,  REG_ID_T reg_id,  UINT32 param2 )//void *reg_hdl )
{
    APP_START_MENU_T	*papp = NULL;
	UINT32				status;
	dbg( "startApp" );

	AHG_Init();	
	ReadMenu("#/Start/", "#/Start/" );
	
    /* Инициализация для фоновых приложений */
    papp = (APP_START_MENU_T*)APP_InitAppData( (void *)APP_HandleEvent, // Обработчик для приложений с GUI
                                              sizeof(APP_START_MENU_T), // Размер структуры приложения
                                              reg_id,
                                              0, 1,
                                              1,
                                              1, 1, 0 );								  
    status = APP_Start( ev_st,
                        &papp->apt,
                        SM_STATE_MAIN, // Начальное состояние
                        state_handling_table,
                        destroyApp,
                        app_name,
                        0 );	

    return RESULT_OK;
}


/* Функция выхода из приложения */
UINT32 destroyApp( EVENT_STACK_T *ev_st,  APPLICATION_T *app )
{
	UINT32				status;
	
	dbg( "destroyApp" );

	if( &app->dialog !=0 )  APP_UtilUISDialogDelete(  &app->dialog ); // удалем диалог

	AHG_Done();
	mfree(BufR);
	mfree(item);
	
	u_strcpy(cur_folder, L"#/Start/");
	
    /* Завершаем работу приложения */
    status = APP_Exit( ev_st, app, 0 );
	
	if ( !event_mode ) ldrUnloadElf();

    return status;
}

/* Обработчик входа в main state */
UINT32 MainStateEnter( EVENT_STACK_T *ev_st,  APPLICATION_T *app,  ENTER_STATE_TYPE_T type )
{
	DRAWING_BUFFER_T bufd = {NULL, 176, 220}; // Буфер для рисования
   
	if(type!=ENTER_STATE_ENTER) return RESULT_OK;
	  

	app->dialog = UIS_CreateColorCanvas( &app->port, &bufd, TRUE ); // создаём канвас
	if( app->dialog == 0 ) return RESULT_FAIL;
	
    DrawMenu();

    return RESULT_OK;
}

UINT32 HandleKeypress( EVENT_STACK_T * ev_st,  APPLICATION_T * app )
{
	EVENT_T *		event = AFW_GetEv(ev_st);

	APP_ConsumeEv( ev_st, app );
	
     switch( event->data.key_pressed )
     {
	     case KEY_UP:
		 case KEY_2:
			 		if (sel_item == 0)
					     sel_item = ENTRIES_NUM;
					if (sel_item > 0) 
                         sel_item--;
                      DrawMenu();
                      break;
					  
         case KEY_DOWN:
		 case KEY_8:
                      if (sel_item < ENTRIES_NUM) 
                           sel_item ++;
					  if (sel_item == ENTRIES_NUM)
						   sel_item = 0;
                      DrawMenu();
					break;
				
		case KEY_RED:
				destroyApp(ev_st, app );
				break;
		
		case KEY_4:
		case KEY_LEFT:
		case KEY_SOFT_LEFT:
                Back(ev_st, app );
                break;	
						
		case KEY_5:
		case KEY_6:
		case KEY_RIGHT:
		case KEY_SOFT_RIGHT:
		case KEY_JOY_OK:
                Select( ev_st, app );
                break;		
				
		case KEY_MENU:
				APP_UtilChangeState( SM_STATE_MAIN, ev_st, app );
				break;
	}	
	return RESULT_OK;
}

UINT32 LoadSkin(WCHAR *file)
{
	char		buf[32];
	
	OpenINI(file);
	
	ReadParamINI("BackgroundColor", buf, 10, "0xFFFFFF");	
	Color.Background = strtoul(buf, 0, 16);
	
	ReadParamINI("TextColor", buf, 10, "0x000000");
	Color.Text = strtoul(buf, 0, 16);
	
	ReadParamINI("Line1Color", buf, 10, "0x524D52");	
	Color.Line1 = strtoul(buf, 0, 16);
	
	ReadParamINI("Line2Color", buf, 10, "0x292829");
	Color.Line2 = strtoul(buf, 0, 16);
	
	ReadParamINI("Line3Color", buf, 10, "0x636163");
	Color.Line3 = strtoul(buf, 0, 16);
	
	ReadParamINI("Line4Color", buf, 10, "0x313431");
	Color.Line4 = strtoul(buf, 0, 16);
	
	ReadParamINI("CusorColor", buf, 10, "0xC6E7F7");
	Color.Cursor = strtoul(buf, 0, 16);
	
	CloseINI();


    return RESULT_OK;
}

UINT32 DrawMenu()
{
	UINT8	item_num = 8;
	UINT8	item_width = 120;
	UINT8	item_height = 20;
	UINT8	x = 3;
	UINT8	y = 196 - item_num * item_height;
	
	SetBrushColor(Color.Background);
	FillRect(x, y, x+item_width, item_height*item_num+2);

	SetBrushColor(Color.Line1);
	DrawRect(x, y, item_width, item_height*item_num);

	SetBrushColor(Color.Line2);
	DrawRect(x-1, y-1, item_width+2, item_height*item_num+2);

	SetBrushColor(Color.Line3);
	DrawRect(x-2, y-2, item_width+4, item_height*item_num+4);
	
	SetBrushColor(Color.Line4);
	DrawRect(x-3, y-3, item_width+6, item_height*item_num+6);

	// Курсор
	SetBrushColor(Color.Cursor);
	FillRect(x+2, y+(sel_item*item_height)+2, item_width-4, item_height-3);
	
	UINT8 				i=0, Y=0;
	WCHAR				ico[256];
	AHIRECT_T			rect;


	SetFgColor(Color.Text);
	
	for( i=0; i < ENTRIES_NUM; i++ ){
	
	    u_strcpy( ico, elf.dir );
	    u_strcat( ico, L"icons/" );
	    u_strcat( ico, item[i].icon_name );

		Y = y + i*item_height+2;
		
		rect.x1 = x + 3; 
		rect.y1 = Y; 
		rect.x2 = rect.x1 + 16; 
		rect.y2 = rect.y1 + 16;
	
		DrawBmpImageFS(ico, &rect, 0, 0);
		DrawTextW(item[i].name, x+20, Y, false);
	}
	
	AHG_Flush();
	
	return RESULT_OK;
}



UINT32 Select( EVENT_STACK_T *ev_st,  APPLICATION_T *app )
{
	char  			buf[256]; 
	WCHAR 			elf_path[256]; 
	
	dbgf("SelectItem %d", sel_item);
	
	if( !u_strcmp(item[sel_item].isfolder, L"1" ) ) 
	{
		dbg( "Open folder" );
		//  открыть папку
		u_strcat(cur_folder, item[sel_item].name);
		u_strcat(cur_folder, L"/");
		UCS2toCP1251(cur_folder, buf);
		ReadMenu( buf, "#/Start/" );
		prev_item = sel_item;
		sel_item = 0;
		DrawMenu();
	} else {
	
		//  запустить команду
		dbg( "Open command" );
		////////////////////////////////////////////////
		if (item[sel_item].path[0]== '!') {
		
			u_strcpy(elf_path, elf.dir);
			u_strcat(elf_path, item[sel_item].path);
			
			if ( DL_FsFFileExist(elf_path) ) {
				ldrLoadElf(elf_path, NULL);
				destroyApp(ev_st, app);
			}
			
		} else if ( DL_FsFFileExist(item[sel_item].path) ) {							
			ldrLoadElf(item[sel_item].path, NULL);
			destroyApp(ev_st, app);
		} else {
		
			dbgf("ldrSendEvent: %s", item[sel_item].path );
			u_utoa(item[sel_item].path, buf);
			ldrSendEvent( strtoul(buf, 0x00, 0) );
			destroyApp(ev_st, app);
		}
     }	   
    return RESULT_OK;
}

UINT32 Back( EVENT_STACK_T *ev_st,  APPLICATION_T *app )
{
	UINT32          i;
	char 			buf[256]; 
	
	APP_ConsumeEv( ev_st, app );
	// назад	
	if ( !u_strcmp(cur_folder, L"#/Start/") )
		destroyApp(ev_st, app);
	else {
		if (cur_folder[u_strlen(cur_folder)-1] == '/') cur_folder[u_strlen(cur_folder)-1] = 0;
			for (i=u_strlen(cur_folder)-1; i > 0 ; i--)
			{
				if (cur_folder[i] == '/')
				{
					//destroyApp(ev_st, app);
					break;
				}
				else
				{
					cur_folder[i] = 0;
				}
			}
	}	
	sel_item = prev_item;
	ReadMenu( u_utoa(cur_folder, buf), "#/Start/");
	DrawMenu();
			
    return RESULT_OK;
}


UINT32 ReadMenu(char * begin, char * end)
{
	UINT32          readen;
	FILE_HANDLE_T   f;
	int 			i, j;
	char 			bufVal[256];
	char 			bufpath[256];
	char 			bufVal2[256];
    char 			bufName[32];
	UINT32          fSize = 0;
	UINT32 			parse_mode = 0, _begin__=0, _end__=0; 
	
	ENTRIES_NUM = 0;
	 
	if ( !DL_FsFFileExist(file.menu) ) return RESULT_FAIL;// проверяем есть ли файл

	f = DL_FsOpenFile(file.menu, FILE_READ_MODE, 0);
	fSize = DL_FsGetFileSize(f);
	BufR = (char*)malloc(fSize+2);
	if (!BufR) return RESULT_FAIL; // не может выделить память
	DL_FsReadFile( BufR,  1, fSize, f, &readen );
	DL_FsCloseFile(f);

	_begin__ = FindPattern(0, begin) + strlen(begin)+2;
	_end__   = FindPattern(FindPattern(0, begin)+strlen(begin), end);

	for (i=_begin__; i < _end__; i++)
		if (BufR[i] == 0x0D) j++;
	
	item = (LINE*)malloc(sizeof(LINE)*(j+1));
	j=0;

	for ( i=_begin__; i < _end__; i++ )
	{
		if (BufR[i] == 0x0A) // следующая строка
		{	 
			j=0;
			parse_mode = FALSE;
	//						udbg(" name: %s", item[ENTRIES_NUM].name);
	//						udbg(" isfolder: %s", item[ENTRIES_NUM].isfolder);
	//						udbg(" path: %s", item[ENTRIES_NUM].path);
	//						udbg(" icon_name: %s\n", item[ENTRIES_NUM].icon_name);
			ENTRIES_NUM++; // следующаястрока
		}
		if(BufR[i] != '\n') // пропускать
		{
			switch(parse_mode)
			{
				case PARSE_NAME:
					if ( BufR[i] == '=' ) {
						item[ENTRIES_NUM].name[j] = 0;
						parse_mode = PARSE_PARAM1;
						j=0;
						 continue;
					}
					bufName[j] = BufR[i];
					bufName[j+1] = 0;
					CP1251toUCS2(bufName, item[ENTRIES_NUM].name);
					break;
					
				case PARSE_PARAM1:
					if ( BufR[i] == ';' ) {
						item[ENTRIES_NUM].isfolder[j] = 0;
						parse_mode = PARSE_PARAM2;
						j=0;
						 continue;
					}
					bufVal[j] = BufR[i];
					bufVal[j+1] = 0; // строка должна заканчиваться нулём
					CP1251toUCS2(bufVal, item[ENTRIES_NUM].isfolder);
					break;
					
				case PARSE_PARAM2:
					if ( BufR[i] == ';' ) {
						item[ENTRIES_NUM].path[j] = 0;
						parse_mode = PARSE_PARAM3;
						j=0;
						continue;
					}
					bufpath[j] = BufR[i];
					bufpath[j+1] = 0; // строка должна заканчиваться нулём
					CP1251toUCS2(bufpath, item[ENTRIES_NUM].path);
					break;
					
				case PARSE_PARAM3:
					if ( BufR[i] == 0x0D ) {
						item[ENTRIES_NUM].icon_name[j] = 0;
						j=0;
						continue;
					}
					bufVal2[j] = BufR[i];
					bufVal2[j+1] = 0; // строка должна заканчиваться нулём
					CP1251toUCS2(bufVal2, item[ENTRIES_NUM].icon_name);
					break;
			}
			j++;
		}
	}
		
	return RESULT_OK;
}	

UINT32 FindPattern(UINT32 start_offset, char *pattern)
{
    UINT32 off_set = 0;  
    UINT32 offset_pattern = -1;
    UINT32 i=0, j=0;

    //dbg("Find pattern = %s", pattern);

        for (i=start_offset; i < DL_FsSGetFileSize(file.menu,0); i++) {
            if (BufR[i] == pattern[j]){
                if (j < strlen(pattern)-1) {
                    j++;
                    if (offset_pattern == -1) offset_pattern = off_set+i;
                } else {
                  //  dbg("Pattern is found", NULL); // паттерна найдена!
                    return offset_pattern;
                }
            } else {
                j=0;
                offset_pattern = -1;
            }
        }

        off_set += 32;

    return offset_pattern;
}