
#include <nds.h>

#include "_const.h"
#include "maindef.h"
#include "_console.h"
#include "_consoleWriteLog.h"

#include "memtool.h"
#undef safemalloc
#define safemalloc safemalloc_chkmem
#include "lang.h"
#include "resume.h"
#include "procstate.h"
#include "shell.h"
#include "splash.h"
#include "strtool.h"
#include "inifile.h"
#include "internaldrivers.h"
#include "cwl.h"
#include "strpcm.h"
#include "__debug.h"

#include "arm9tcm.h"
#include "setarm9_reg_waitcr.h"

#include "fat2.h"
#include "io_dldi.h"
#include "zlibhelp.h"

#include "sndeff.h"
#include "PlaySE.h"
#include "datetime.h"

#include "OnSkin.h"

#include "TextEdit.h"

#include "OSK.h"

#include "unidef.h"

#include "_GlobalTool_DirectPenRead.h"

bool RequestRedrawMainFlag,RequestRedrawSubFlag;

// -------------------------------------------------------------------

static void CB_KeyPress_Enter(void);
static void CB_KeyPress_Space(void);
static void CB_KeyPress_BackSpace(bool BackSpaceSound);
static void CB_KeyPress_Cursor(u32 keys);

#include "skk_SysMsg.h"
#include "skk_DicTable.h"
#include "skk_DicSystem.h"
#include "skk_DicUser.h"
#include "skk_DicItem.h"
#include "skk_DicResultsDef.h"
#include "skk_DicFind.h"
#include "skk_DicResults.h"
#include "skk_ExitMenu.h"

static void CB_KeyPress_Enter(void)
{
  if(DicResults_Fix(false)==true){
    PlaySE_Long();
    RequestRedrawMainFlag=true;
    RequestRedrawSubFlag=true;
    return;
  }
  
  if(DicFind_Fix()==true){
    PlaySE_Long();
    RequestRedrawMainFlag=true;
    RequestRedrawSubFlag=true;
    return;
  }
  
  if(TextEdit_AddEnter()==true){
    PlaySE_Long();
    RequestRedrawSubFlag=true;
    return;
  }
  
  // Process ignored.
  PlaySE_Long();
}

static void CB_KeyPress_Space(void)
{
  if(DicResults_Space()==true){
    RequestRedrawMainFlag=true;
    RequestRedrawSubFlag=true;
    return;
  }
  
  if(DicFind_Space()==true){
    Sound_Start(WAVFN_MemoErase);
    RequestRedrawMainFlag=true;
    RequestRedrawSubFlag=true;
    return;
  }
  
  if(TextEdit_Space()==true){
    Sound_Start(WAVFN_MemoPenDown);
    RequestRedrawSubFlag=true;
    return;
  }
  
  // Process ignored.
  PlaySE_Long();
}

void CB_KeyPress_FromOSK(UnicodeChar wc,bool BackSpaceSound)
{
  switch(wc){
    case WC_Enter: CB_KeyPress_Enter(); break;
    case WC_Space: {
      if(DicResults_Fix(true)==true){
        RequestRedrawMainFlag=true;
        RequestRedrawSubFlag=true;
        }else{
        DicFind_Backup_Clear();
      }
      CB_KeyPress_Space();
    } break;
    case WC_BackSpace: CB_KeyPress_BackSpace(BackSpaceSound); break;
    case WC_Shift: case WC_CapsLock: case 0: {
      StopFatalError(0,"Internal error. Illigal char from OSK.");
    } break;
    default: {
      if(DicResults_Fix(true)==true){
        RequestRedrawMainFlag=true;
        RequestRedrawSubFlag=true;
        }else{
        DicFind_Backup_Clear();
      }
      if(isStrEqual(OSK_GlobalInfo.pIME,"SKK")==true){
        DicFind_Add(wc);
        }else{
        const UnicodeChar str[2]={wc,0};
        TextEdit_Add(str);
      }
    } break;
  }
}

static void CB_KeyPress_BackSpace(bool BackSpaceSound)
{
  if(DicFind_Del()==true){
    if(BackSpaceSound==true) Sound_Start(WAVFN_MemoErase);
    RequestRedrawMainFlag=true;
    RequestRedrawSubFlag=true;
    return;
  }
  
  if(TextEdit_Del()==true){
    if(BackSpaceSound==true) PlaySE_Short();
    RequestRedrawSubFlag=true;
    return;
  }
  
  // Process ignored.
  if(BackSpaceSound==true) PlaySE_Long();
}

static void CB_KeyPress_Cursor(u32 keys)
{
  if(DicResults_MoveCursor(keys)==true){
    RequestRedrawMainFlag=true;
    RequestRedrawSubFlag=true;
    return;
  }
  
  if(DicFind_MoveCursor(keys)==true){
    RequestRedrawMainFlag=true;
    RequestRedrawSubFlag=true;
    return;
  }
  
  if(TextEdit_MoveCursor(keys)==true){
    RequestRedrawSubFlag=true;
    return;
  }
  
  // Process ignored.
  PlaySE_Long();
}

static void CB_KeyPress(u32 keys)
{
  SysMsg_Clear();
  
  if(OSK_KeyPress(keys)==true) return;
  
  if((keys&(KEY_B|KEY_L))!=0){
    if(DicFind_Backup_Restore()==true){
      Sound_Start(WAVFN_MemoUndo);
      RequestRedrawMainFlag=true;
      RequestRedrawSubFlag=true;
      keys&=~(KEY_B|KEY_L);
    }
  }
  
  DicFind_Backup_Clear();
  
  if((keys&KEY_A)!=0) CB_KeyPress_Enter();
  
  if((keys&(KEY_B|KEY_L))!=0) CB_KeyPress_BackSpace(true);
  
  if((keys&(KEY_UP|KEY_DOWN|KEY_LEFT|KEY_RIGHT|KEY_X|KEY_Y))!=0) CB_KeyPress_Cursor(keys);
}

static void CB_MouseDown(s32 mx,s32 my)
{
  SysMsg_Clear();
  
  if(OSK_MouseDown(mx,my)==true){
    return;
  }
}

static void CB_MouseUp(s32 mx,s32 my)
{
  OSK_MouseUp(mx,my);
}

static void CB_MouseMove(s32 mx,s32 my)
{
  OSK_MouseMove(mx,my);
}

static void CB_Init(void)
{
  RequestRedrawMainFlag=false;
  RequestRedrawSubFlag=false;
  
  OnSkin_Init();
  
  SysMsg_Init();
  
  {
    static char msg[64];
    snprintf(msg,64,"%s %s %s",ROMTITLE,ROMVERSION,ROMDATESHORT);
    SysMsg_Set(msg);
  }
  
  OSK_Init();
  
  DicSystem_Init();
  DicUser_Init();
  DicResults_Init();
  DicFind_Init();
  
  TextEdit_Init();
  TextEdit_Clipboard_Init();
  TextEdit_LoadFromFile();
  TextEdit_CheckLinkStructure();
  TextEdit_ChangedFlag=false;
  
  DirectPenStart();
  
  RequestRedrawMainFlag=true;
  RequestRedrawSubFlag=true;
}
  
static void CB_Free(void)
{
  DicSystem_DicState_Free();
  
  OSK_Free();
  
  DicSystem_Free();
  DicUser_Free();
  DicResults_Free();
  DicFind_Free();
  
  TextEdit_Clipboard_Free();
  TextEdit_Free();
  
  OnSkin_Free();
}

static void IME_Direct_DrawPreview(CglCanvas *pcan)
{
  u32 y=0;
  
  pcan->SetColor(RGB15(31,31,31)|BIT15);
  pcan->FillBox(0,y,ScreenWidth,glCanvasTextHeight+2);
  
  pcan->SetFontTextColor(RGB15(0,0,0)|BIT15);
  TextEdit_DrawCursorLine(pcan,1+y,true);
  y+=glCanvasTextHeight+2;
  
  pcan->SetColor(RGB15(0,0,0)|BIT15);
  pcan->DrawLine(0,y,ScreenWidth,y);
  y++;
}

static void CB_VSyncUpdate(void)
{
  if(DicFind_Execute()==false) return;
  
  SysMsg_VSyncUpdate();
  
  if(RequestRedrawMainFlag==true){
    RequestRedrawMainFlag=false;
    CglCanvas *pcan=pScreenMain->pBackCanvas;
    pSkinOSKBG->BitBltFullBeta(pcan);
    OSK_Draw(pcan);
    if(SysMsg_Draw(pcan)==false){
      if(isStrEqual(OSK_GlobalInfo.pIME,"SKK")==true) DicFind_DrawInputStr(pcan,NULL);
      if(isStrEqual(OSK_GlobalInfo.pIME,"Direct")==true) IME_Direct_DrawPreview(pcan);
    }
    pScreenMain->Flip(true);
  }
  
  static u32 LastCursorPosition=(u32)-1;
  static bool DrawCursorFlag=false;
  static u32 DrawCursorTimeout=0;
  
  if(LastCursorPosition!=TextEdit_GetCursorPosition()){
    LastCursorPosition=TextEdit_GetCursorPosition();
    DrawCursorFlag=true;
    DrawCursorTimeout=60;
    RequestRedrawSubFlag=true;
    }else{
    if(DrawCursorTimeout!=0){
      DrawCursorTimeout--;
      }else{
      DrawCursorFlag=!DrawCursorFlag;
      if(DrawCursorFlag==false){
        DrawCursorTimeout=30;
        }else{
        DrawCursorTimeout=60;
      }
      RequestRedrawSubFlag=true;
    }
  }
    
  if(RequestRedrawSubFlag==true){
    RequestRedrawSubFlag=false;
    CglCanvas *pcan=new CglCanvas(&MM_Temp,NULL,ScreenWidth,ScreenHeight,pf15bit);
    pcan->SetCglFont(pCglFontDefault);
    pSkinTextBG->BitBltFullBeta(pcan);
    TextEdit_Draw(pcan,DrawCursorFlag);
    DicResults_Draw(pcan);
    pcan->BitBltFullBeta(pScreenSub->pCanvas);
    if(pcan!=NULL){
      delete pcan; pcan=NULL;
    }
  }
}

static bool CB_UserInput(void)
{
  const TDirectPenInfo pen=DirectPenRead();
  if(pen.CanRead==true){
    static bool lastmf=false;
    static s32 lastmx=0,lastmy=0;
    if(pen.PenDown==true){
      if(TextEdit_SelectCancel()==true) RequestRedrawSubFlag=true;
    }
    if(lastmf==pen.PenDown){
      if((lastmx!=pen.x)||(lastmy!=pen.y)) CB_MouseMove(pen.x,pen.y);
      }else{
      if(pen.PenDown==true){
        CB_MouseDown(pen.x,pen.y);
        }else{
        CB_MouseUp(lastmx,lastmy);
      }
    }
    lastmf=pen.PenDown;
    lastmx=pen.x;
    lastmy=pen.y;
  }
  
  u32 keys=GetKeyInputWithXY();
  
  {
    if((keys&(KEY_START|KEY_SELECT))!=0){
      if(TextEdit_ChangedFlag==false) return(false);
      if(ExitMenu_Execute()==true) return(false);
      RequestRedrawMainFlag=true;
      RequestRedrawSubFlag=true;
    }
  }
  
  {
    static bool PressR=false;
    
    if(PressR==false){
      if((keys&KEY_R)!=0){
        PressR=true;
        TextEdit_SelectStart();
      }
      }else{
      if((keys&KEY_R)==0){
        PressR=false;
        TextEdit_SelectEnd();
        RequestRedrawSubFlag=true;
      }
    }
    
    if(PressR==true){
      TextEdit_SelectVSyncUpdate();
      u16 KeyMask=~(KEY_UP|KEY_DOWN|KEY_LEFT|KEY_RIGHT|KEY_R|KEY_X|KEY_Y);
      if((keys&KeyMask)!=0){
        TextEdit_SelectCancel();
        RequestRedrawSubFlag=true;
      }
    }
    
  }
  
  keys&=~(KEY_START|KEY_SELECT|KEY_R);
  
  if(keys!=0){
    CB_KeyPress(keys);
    u32 Timeout=15;
    while(keys!=0){
      swiWaitForVBlank();
      CB_VSyncUpdate();
      const TDirectPenInfo pen=DirectPenRead();
      keys=GetKeyInputWithXY();
      keys&=~(KEY_START|KEY_SELECT|KEY_R);
      Timeout--;
      if(Timeout==0){
        Timeout=3;
        CB_KeyPress(keys);
      }
    }
  }
  
  return(true);
}

extern void skk_Main(void);
void skk_Main(void)
{
  CB_Init();
  
  Sound_Start(WAVFN_Opening);
  
  while(1){
    if(DirectPenRead_isExclusive()==false){
      if(VBlankPassedFlag==false){
        while(VBlankPassedFlag==false){
          swiWaitForIRQ();
        }
      }
      VBlankPassedFlag=false;
    }
    
    if(CB_UserInput()==false) break;
    CB_VSyncUpdate();
    
#ifdef InternalDebugMode
    MM_CheckOverRange();
    MM_CheckMemoryLeak(&MM_Temp);
#endif
    
    if(false){
      PrintFreeMem_Accuracy_Already();
      MM_ShowAllocated(&MM_TextEdit);
      while(1);
    }
  }
  
  CB_Free();
}
