#include "app.h"

#include "base64.h"

static UINT32		state, item_select;							
static UINT16       status;
static WCHAR        file_cfg[256];			// Jabber.cfg

LIST 				pass;
UIS_DIALOG_T        dialog; 				// Диалог
ldrElf       	 	elf;					// Структура эльфа
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_PM_API_EXIT,				 HandleReqExit },	// PM API: cmd EXIT
    { 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,
      NULL
    },
	{ APP_STATE_EDIT,
      EditStateEnter,
      StateExit,
      NULL
	}
	
};

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

/* Это entry для всех эльфов, должна быть объявлена именно так */
/* uri - путь к эльфу (аналогично argv[0]) */
/* params - параметры эльфа (аналогично остальным argv) */
ldrElf * _start( WCHAR * uri, WCHAR * params )
{
    ldrElf *	pelf;
	UINT32		reserve;
	int			i;
	
	dbg("-----------------------------------");
	dbg("_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, ELF_NAME_W L".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(ELF_NAME ":\x84 can't register app\n");
		return NULL;
	}

#ifdef DEBUG
	ReportPhoneInfo();
#endif

    return &elf; 
}

void AppHandleEvent( EVENT_STACK_T *ev_st, APPLICATION_T *app, APP_ID_T app_id, REG_ID_T reg_id )
{

	UIX_HandleEvent( ev_st, app );
	APP_HandleEvent(ev_st, app, app_id, reg_id);
}

/* Функция вызываемая при старте приложения */
UINT32 startApp( EVENT_STACK_T *ev_st,  REG_ID_T reg_id,  UINT32 param2 )
{
	APP_ELF_T *			papp;
	
    papp = (APP_ELF_T*)APP_InitAppData((void*)AppHandleEvent, 
                                            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;
	}
	state = LOGIN;
	List_Init( &pass, PASSWORD_ITEM );
	ReadSetting();
    status = APP_Start( ev_st,
                        &papp->apt,
                        APP_STATE_EDIT, // Начальное состояние
                        state_handling_table,
                        destroyApp,
                        app_name,
                        state_name_table );
	
	// Теперь приложение может обрабатывать события
	if ( status == RESULT_OK ) {
		elf.app = &papp->apt;
		cprint(ELF_NAME ": Started\n");
	}
    return RESULT_OK;
}


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

    /* Завершаем работу приложения */
    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 )
{
	UIX_CALL_BACK_F 		*CallBackArr[2];
	UINT32					num;	// число пунктов в списке
	
	dbg("MainStateEnter: start");
	if(type != ENTER_STATE_ENTER) return UIX_Render( app->dialog );
	
	CallBackArr[0] = (void *)HandleSelect;
	CallBackArr[1] = (void *)HandleBack;
	CallBackArr[2] = (void *)HandleNavigate;
	
	switch (state)
	{
		case MAIN:
			num = List_GetNum(&pass);
			break;
			
		case EDIT_ITEM:
			num = 3;
			break;
		
	}
	
	app->dialog = UIX_CreateListDialog(app, num, MainEntryReq, CallBackArr);
	
	UIX_DialogAddAction(app->dialog, "New item", ( void *)HandleNew, 0 );
	UIX_DialogAddAction(app->dialog, "Delete item", ( void *)HandleDelete, 0 );
	UIX_DialogAddAction(app->dialog, "Exit", ( void *)HandleExit, 0 );
		
	UIX_DialogSetTitle(app->dialog, ELF_NAME " " ELF_VER " by R.U.S.H.A.N.", ElfGetIcon(0));
	
	UIX_Render(app->dialog);
	
	dbg("MainStateEnter: end");
	
    return RESULT_OK;
}

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
UINT32 EditStateEnter( EVENT_STACK_T *ev_st,  APPLICATION_T *app,  ENTER_STATE_TYPE_T type )
{
	dbgf("EditStateEnter: start, type = %d, substate = %d", type, state );
	if(type != ENTER_STATE_ENTER) return UIX_Render( app->dialog );
	
	char		buf[16];
	
	memclr(buf, 16);
	
	switch(state)
	{
		case LOGIN:
		app->dialog = UIX_CreateInputDialog(app, 16, "", INP_USE_DIGITAL | INP_USE_ENGLISH | INP_USE_OTHERS, ( void *)EditDone );
        UIX_DialogSetTitle(app->dialog, "Enter Password:", ElfGetIcon(0));
		break;
		
		case EDIT_ITEM_NAME:
		app->dialog = UIX_CreateInputDialog(app, 16, ElfGetDItem(item_select)->name, INP_USE_DIGITAL | INP_USE_ENGLISH | INP_USE_OTHERS, ( void *)EditDone );
        UIX_DialogSetTitle(app->dialog, "Enter item name:", ElfGetIcon(0));
		break;
		
		case EDIT_ITEM_LOGIN:
		app->dialog = UIX_CreateInputDialog(app, 16, ElfGetDItem(item_select)->login, INP_USE_DIGITAL | INP_USE_ENGLISH | INP_USE_OTHERS, ( void *)EditDone );
        UIX_DialogSetTitle(app->dialog, "Enter item login:", ElfGetIcon(0));
		break;
		
		case EDIT_ITEM_PASSWORD:
		base64_decode( ElfGetDItem(item_select)->password, (char*)buf );
		app->dialog = UIX_CreateInputDialog(app, 16, buf, INP_USE_DIGITAL | INP_USE_ENGLISH | INP_NO_ENDLINE, ( void *)EditDone );
		UIX_DialogSetTitle(app->dialog, "Enter item password:", ElfGetIcon(0));
        break;
	} 

	return UIX_Render(app->dialog);
}

UINT32 StateExit( EVENT_STACK_T *ev_st,  APPLICATION_T *app,  EXIT_STATE_TYPE_T type )
{
	if ( type != EXIT_STATE_EXIT )
		return RESULT_OK;
	
	status = APP_UtilUIXDialogDelete( &app->dialog );

	return status;
}
UINT32 HandleReqExit( EVENT_STACK_T *ev_st,  APPLICATION_T *app )
{
	dbg("HandleReqExit");
	APP_ConsumeEv( ev_st, app );
	app->exit_status = true;

	return RESULT_OK;
}
UINT32 HandleNavigate( EVENT_STACK_T * ev_st, APPLICATION_T * app, UINT32 idx )
{
	if ( state == MAIN ) 
		item_select = idx;	// индекс выбранного пункта
		
	return RESULT_OK;
}
// выбрать
UINT32 HandleSelect( EVENT_STACK_T * ev_st, APPLICATION_T * app, UINT32 idx )
{	
	
	dbg("HandleSelect");
	APP_ConsumeEv( ev_st, app );
	
	switch (state)
	{	
		case MAIN:
			state = EDIT_ITEM;
			item_select = idx;
			return APP_UtilChangeState( APP_STATE_MAIN, ev_st, app );
			
		case EDIT_ITEM:
				state = EDIT_ITEM_NAME + idx;
			return APP_UtilChangeState( APP_STATE_EDIT, ev_st, app );
	}
	
	return RESULT_OK;
}
// назад
UINT32 HandleBack( EVENT_STACK_T * ev_st, APPLICATION_T * app, UINT32 param )
{
	APP_ConsumeEv( ev_st, app );


	switch (state)
	{
		case MAIN:
			return HandleReqExit( ev_st, app );
			
		case EDIT_ITEM:
			state = MAIN;
			return APP_UtilChangeState( APP_STATE_MAIN, ev_st, app );
		
	}
	
	return RESULT_OK;
}
// Новый пункт
UINT32 HandleNew( EVENT_STACK_T * ev_st, APPLICATION_T * app, UINT32 idx )
{
	APP_ELF_T			*papp = (APP_ELF_T*)app;
	PASSWORD_ITEM 		p;
	
	memclr( &p, sizeof(PASSWORD_ITEM) );

	strcpy( p.name, "new" );
	
	List_AppendItem( &pass, &p );
	
	state = MAIN;
	return APP_UtilChangeState( APP_STATE_MAIN, ev_st, app );
}

UINT32 HandleDelete( EVENT_STACK_T * ev_st, APPLICATION_T * app, UINT32 idx )
{
	APP_ELF_T			*papp = (APP_ELF_T*)app;
	
	if( item_select )
		List_DeleteItem( &pass, item_select );
	
	state = MAIN;
	return APP_UtilChangeState( APP_STATE_MAIN, ev_st, app );
}
// Выход
UINT32 HandleExit( EVENT_STACK_T * ev_st, APPLICATION_T * app, UINT32 mode )
{
	if ( mode == ACTION_KEY_RELEASE || mode == ACTION_LIST )
		return HandleReqExit(ev_st, app);
	return RESULT_OK;
}

UINT32 EditDone( EVENT_STACK_T * ev_st, APPLICATION_T * app, UINT32 l  )
{
	char			*data;
	char			buf[64];
	
	if ( l == (UINT32)(-1) || l == 0 ) {
		// Cancel
		switch(state)
		{
			case LOGIN:
				return HandleReqExit(ev_st, app);
				
			case EDIT_ITEM_NAME:
			case EDIT_ITEM_LOGIN:
			case EDIT_ITEM_PASSWORD:
				state = EDIT_ITEM;
				return APP_UtilChangeState( APP_STATE_MAIN, ev_st, app );
		}
	}
	
	data = malloc( sizeof(char)*(l+1) );
	
	UIX_InputGetData(app->dialog, data, 0);
	
		switch(state)
		{	
			case LOGIN:
				base64_decode( ElfGetDItem( 0 )->password, (char*)buf);
				
				if ( !strcmp( data, buf ) ) {
					state = MAIN;
					return APP_UtilChangeState( APP_STATE_MAIN, ev_st, app );
				} else 
					return APP_UtilChangeState( APP_STATE_EDIT, ev_st, app );
				
			case EDIT_ITEM_NAME:
				state = EDIT_ITEM;
				strcpy(ElfGetDItem(item_select)->name, data);
				break;
				
			case EDIT_ITEM_LOGIN:
				state = EDIT_ITEM;
				strcpy(ElfGetDItem(item_select)->login, data);
				break;
				
			case EDIT_ITEM_PASSWORD:
				state = EDIT_ITEM;
				char	*pass = malloc( strlen(data) );
				memclr(pass, strlen(data));
				base64_encode(data, strlen(data), &pass );
				
				strcpy( ElfGetDItem(item_select)->password, pass );
				mfree( pass );
		
				break;			
		}
		
	mfree(data);
	SaveSetting();
	
    return APP_UtilChangeState( APP_STATE_MAIN, ev_st, app );		
}

static void * MainEntryReq( APPLICATION_T * app, UINT32 idx )
{
	UIX_LIST_ENTRY_T    *e;
	UIX_ICON_T			icon;
	char				buf[16];
	
	memclr(buf, 16);
	// динамически создаем
	e = suAllocMem(sizeof(UIX_LIST_ENTRY_T), NULL);
	memclr(e, sizeof(UIX_LIST_ENTRY_T));
	
	
	if ( state == MAIN ) {
	
		e->name = ElfGetDItem( idx )->name;
		
	} else {
	
		e->flags = LE_FLAG_HAS_DATA | LE_FLAG_FREE_MEM;
		e->dtype = LE_DATA_TYPE_STR;
		switch ( idx )
		{
			
			case 0:
				e->name = "Name:";
				e->d.s = ElfGetDItem(item_select)->name;
			break;
			
			case 1:
				e->name = "Login:";
				e->d.s = ElfGetDItem(item_select)->login;
			break;
			
			case 2:
				e->name = "Password:";
				base64_decode( ElfGetDItem(item_select)->password, buf );
				e->d.s = buf;
			break;
			
		}
	
	}
	return e;
}

UINT32 ReadSetting() 
{
	FILE_HANDLE_T 		f;
	
	// читаем данные из конфига
	if (DL_FsFFileExist(file_cfg)) { // проверяем есть ли файл
	
		f = DL_FsOpenFile(file_cfg, FILE_READ_MODE, 0);
		
		List_ReadFile( &pass, f );
		
        DL_FsCloseFile(f);
		
        dbg("ReadSetting: done");
    }  else {	// если нет его, то грузим конфиг по умолчанию
		
		PASSWORD_ITEM 		p;

		memclr(&p, sizeof(PASSWORD_ITEM) );
		
		strcpy( p.name, "PassManager" );	
		strcpy( p.login, "passmgr" );	
		
		char	*pass_ = malloc( 4 ); 
		base64_encode("1234", 4, &pass_ );	
		
		strcpy( p.password, pass_ );
		
		mfree( pass_ );
		
		List_AppendItem( &pass, &p );
		SaveSetting();
	}
	
	return RESULT_OK;
}

// записываем в конфиг
UINT32 SaveSetting()
{
	FILE_HANDLE_T 			f;

	
	// запись в файл
	f = DL_FsOpenFile(file_cfg, FILE_WRITE_MODE, 0);
	
	List_WriteFile( &pass, f );
		
	DL_FsCloseFile(f);
	
	dbg("Save Setting");
	return RESULT_OK;
}

PASSWORD_ITEM * ElfGetDItem( int i )
{

	return (PASSWORD_ITEM *)List_GetItem(&pass, i);
}

UIX_ICON_T ElfGetIcon( int i )
{
	UIX_ICON_T		icon;
	
		icon.bmp = NULL;
		icon.point.x = i * 16;
		icon.point.y = 0;
	
	return icon;
}

#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
