
#include "skk_DicSystem_dfs.h"

typedef struct {
  u32 Offset;
  u32 TopDicIndex;
  u32 DiskSize;
  u32 UnPackSize;
} TDicHeader_Pack;

typedef struct {
  char DicID[8];
  u32 DstStrDicOffset;
  TDicHeader_Pack Pack[WideToBinTableCount];
} TDicHeader;

static TDicHeader DicHeader;

typedef struct {
  u32 LoadedBinArea;
  u32 TopDicIndex;
  u8 *pBuf;
  u32 BufSize;
} TDicState;

static TDicState DicState;

typedef struct {
  u32 Offset;
  UnicodeChar *presstr;
} TDicDstStrBuf;

static u32 DicDstStrBufsIndex;
#define DicDstStrBufsCount (128)
static TDicDstStrBuf DicDstStrBufs[DicDstStrBufsCount];

static void DicSystem_Init(void)
{
  FAT_FILE *pf=Shell_FAT_fopen_Root(EstDicFilename);
  DicSystemDFS_Init(pf);
  FAT2_fclose(pf);
  
  TDicHeader *pdh=&DicHeader;
  DicSystemDFS_SetOffset(0);
  DicSystemDFS_Read16bit(pdh,sizeof(TDicHeader));
  
  u8 ID[8]={0x45,0x53,0x54,0x44,0x49,0x43,0x30,0x32};
  for(u32 idx=0;idx<8;idx++){
    if(ID[idx]!=pdh->DicID[idx]) StopFatalError(0,"EstDic file version error.");
  }
  
  TDicState *pds=&DicState;
  pds->LoadedBinArea=(u32)-1;
  pds->TopDicIndex=0;
  pds->pBuf=NULL;
  pds->BufSize=0;
  
  DicDstStrBufsIndex=0;
  for(u32 idx=0;idx<DicDstStrBufsCount;idx++){
    DicDstStrBufs[idx].Offset=0;
    DicDstStrBufs[idx].presstr=NULL;
  }
}

static void DicSystem_DicState_Free(void)
{
  TDicState *pds=&DicState;
  
  pds->LoadedBinArea=(u32)-1;
  pds->TopDicIndex=0;
  if(pds->pBuf!=NULL){
    safefree(&MM_SKKDic,pds->pBuf); pds->pBuf=NULL;
  }
  pds->BufSize=0;
}

static void DicSystem_Free(void)
{
  for(u32 idx=0;idx<DicDstStrBufsCount;idx++){
    if(DicDstStrBufs[idx].presstr!=NULL){
      safefree(&MM_SKKDic,DicDstStrBufs[idx].presstr); DicDstStrBufs[idx].presstr=NULL;
    }
  }
  
  DicSystem_DicState_Free();
  
  DicSystemDFS_Free();
  
  TDicHeader *pdh=&DicHeader;
  MemSet32CPU(0,pdh,sizeof(TDicHeader));
}

static void DicFind_DrawInputStr(CglCanvas *pcan,const char *pOverwriteMessage);

static bool DicSystem_Load(UnicodeChar ReqArea)
{
  u32 ReqBinArea=(u32)-1;
  for(u32 idx=0;idx<WideToBinTableCount;idx++){
    if(WideToBinTable[idx]==ReqArea){
      ReqBinArea=idx;
      break;
    }
  }
  if(ReqBinArea==(u32)-1) StopFatalError(0,"Not found DIC area. (ReqArea=0x%04x)",ReqArea);
  
  TDicState *pds=&DicState;
  
  if(pds->LoadedBinArea==ReqBinArea) return(true);
  
  DicFind_DrawInputStr(pScreenMainOverlay->pCanvas,"Preloading dictionary.");
  
  DicSystem_DicState_Free();
  
  TDicHeader_Pack *pdhp=&DicHeader.Pack[ReqBinArea];
  
  pds->LoadedBinArea=ReqBinArea;
  pds->TopDicIndex=pdhp->TopDicIndex;
  
  u32 ofs=pdhp->Offset;
  u32 DiskSize=pdhp->DiskSize;
  u32 UnPackSize=pdhp->UnPackSize;
  
  _consolePrintf("BinArea=%d, ofs=%d, DiskSize=%d, UnPackSize=%d.\n",ReqBinArea,ofs,DiskSize,UnPackSize);
  
  // あ ZLIB prf data=0 159512us
  // あ FLAT prf data=0 129847us
  
//  PrfStart();
  if(DiskSize==0){
    pds->pBuf=NULL;
    pds->BufSize=0;
    }else{
    if(DiskSize==UnPackSize){
      pds->pBuf=(u8*)safemalloc(&MM_SKKDic,DiskSize);
      pds->BufSize=DiskSize;
      DicSystemDFS_SetOffset(ofs);
      u8 *pBuf=pds->pBuf;
      u32 BufSize=pds->BufSize;
      while(BufSize!=0){
        if(GetPenDown()==true){
          _consolePrintf("DicSystem_Load: Canceled.\n");
          DicSystem_DicState_Free();
          return(false);
        }
        u32 readsize=BufSize;
        if((8*1024)<readsize) readsize=8*1024;
        DicSystemDFS_Read16bit(pBuf,readsize);
        pBuf+=readsize;
        BufSize-=readsize;
      }
      }else{
      TZLIBData z;
      
      // メモリフラグメントを防ぐために先にpDstBufを確保する。
      z.DstSize=UnPackSize;
      z.pDstBuf=(u8*)safemalloc(&MM_SKKDic,z.DstSize);
      
      z.SrcSize=DiskSize;
      z.pSrcBuf=(u8*)safemalloc(&MM_Temp,z.SrcSize);
      DicSystemDFS_SetOffset(ofs);
      DicSystemDFS_Read16bit(z.pSrcBuf,z.SrcSize);
      
      zlibdecompress(&z);
      
      if(z.pSrcBuf!=NULL){
        safefree(&MM_Temp,z.pSrcBuf); z.pSrcBuf=NULL;
      }
      
      pds->pBuf=z.pDstBuf;
      pds->BufSize=z.DstSize;
    }
  }
//  PrfEnd(0);
  
  {
    CglCanvas *pcan=pScreenMainOverlay->pCanvas;
    pcan->SetColor(0);
    pcan->FillBox(0,0,ScreenWidth,glCanvasTextHeight+2+1);
  }
  
  return(true);
}

static const UnicodeChar* DicSystem_GetDstStr(const u32 DstStrOffset,const u32 DstLen)
{
  TDicDstStrBuf *pres=NULL;
  
  for(u32 idx=0;idx<DicDstStrBufsCount;idx++){
    if(DicDstStrBufs[idx].Offset==DstStrOffset){
      pres=&DicDstStrBufs[idx];
      break;
    }
  }
  
  if(pres==NULL){
    pres=&DicDstStrBufs[DicDstStrBufsIndex++];
    if(DicDstStrBufsIndex==DicDstStrBufsCount) DicDstStrBufsIndex=0;
    
    if(pres->presstr!=NULL){
      safefree(&MM_SKKDic,pres->presstr); pres->presstr=NULL;
    }
    
    pres->Offset=DstStrOffset;
    u32 ofs=DicHeader.DstStrDicOffset+pres->Offset;
    DicSystemDFS_SetOffset(ofs);
    pres->presstr=(UnicodeChar*)safemalloc(&MM_SKKDic,(DstLen+1)*sizeof(UnicodeChar));
    DicSystemDFS_Read16bit(pres->presstr,DstLen*2);
    pres->presstr[DstLen]=0;
  }
  
  return(pres->presstr);
}

