
#define HWM_FilenameAlias "HWMODELS.HWM"
static const u32 HWM_ID=0x314d5748;
static const char *HWM_pIDStr="Hand write models format Type.1";

static const u32 rbufsize=512;
static u8 rbuf[rbufsize];
static u32 rbufpos;

static void rbufinit(FAT_FILE *pf)
{
  FAT2_fread(rbuf,1,rbufsize,pf);
  rbufpos=0;
}

static void rbuffree(FAT_FILE *pf)
{
  rbufpos=0;
}

static u32 rrbuf(FAT_FILE *pf)
{
  if(rbufpos==rbufsize){
    FAT2_fread(rbuf,1,rbufsize,pf);
    rbufpos=0;
  }
  return(rbuf[rbufpos++]);
}

static u32 ru8(FAT_FILE *pf)
{
  u8 res=rrbuf(pf);
  return(res);
}

static s32 rs8(FAT_FILE *pf)
{
  s8 res=rrbuf(pf);
  return(res);
}

static u32 ru16(FAT_FILE *pf)
{
  u16 res=0;
  res|=rrbuf(pf);
  res|=rrbuf(pf)<<8;
  return(res);
}

static s32 rs16(FAT_FILE *pf)
{
  s16 res=0;
  res|=rrbuf(pf);
  res|=rrbuf(pf)<<8;
  return(res);
}

static UnicodeChar rwc(FAT_FILE *pf)
{
  UnicodeChar res=0;
  res|=rrbuf(pf);
  res|=rrbuf(pf)<<8;
  return(res);
}

static double rud(FAT_FILE *pf)
{
  u16 res=0;
  res|=rrbuf(pf);
  res|=rrbuf(pf)<<8;
  return(double(res)/0x100);
}

static double rsd(FAT_FILE *pf)
{
  s16 res=0;
  res|=rrbuf(pf);
  res|=rrbuf(pf)<<8;
  return(double(res)/0x100);
}

static u32 ru32(FAT_FILE *pf)
{
  u32 res=0;
  res|=rrbuf(pf);
  res|=rrbuf(pf)<<8;
  res|=rrbuf(pf)<<16;
  res|=rrbuf(pf)<<24;
  return(res);
}

static void rskipstr(FAT_FILE *pf)
{
  u32 len=ru8(pf);
  for(u32 idx=0;idx<len;idx++){
    ru8(pf);
  }
}

static void Models_LoadFromBin(void)
{
  FAT_FILE *pf=Shell_FAT_fopen_Root(HWM_FilenameAlias);
  rbufinit(pf);
  
  u32 ID=ru32(pf);
  if(ID!=HWM_ID) StopFatalError(0,"Illigal ID. (0x%08x!=0x%08x)",HWM_ID,ID);
  rskipstr(pf);

  ModelsCount=ru32(pf);
  _consolePrintf("Load: ModelsCount=%d.\n",ModelsCount);
  pModels=(TModel*)safemalloc(&MM_SKKOSKHW_Model,sizeof(TModel)*ModelsCount);
  for(u32 midx=0;midx<ModelsCount;midx++){
    TModel *pmdl=&pModels[midx];
    pmdl->wc=rwc(pf);
    pmdl->LinesCount=ru8(pf);
//    _consolePrintf("Load: midx=%d, LinesCount=%d.\n",midx,pmdl->LinesCount);
    pmdl->pLines=(TModelLine*)safemalloc(&MM_SKKOSKHW_Model,sizeof(TModelLine)*pmdl->LinesCount);
    for(u32 lidx=0;lidx<pmdl->LinesCount;lidx++){
      TModelLine *pline=&pmdl->pLines[lidx];
      pline->fx=rud(pf);
      pline->fy=rud(pf);
      pline->PointsCount=ru8(pf);
//      _consolePrintf("Load: midx=%d, lidx=%d, PointsCount=%d.\n",midx,lidx,pline->PointsCount);
      pline->pPoints=(TModelLinePoint*)safemalloc(&MM_SKKOSKHW_Model,sizeof(TModelLinePoint)*pline->PointsCount);
      for(u32 pidx=0;pidx<pline->PointsCount;pidx++){
        TModelLinePoint *ppoi=&pline->pPoints[pidx];
        ppoi->x=rsd(pf)*2;
        ppoi->y=rsd(pf)*2;
//        _consolePrintf("Load: midx=%d, lidx=%d, pidx=%d, %f,%f.\n",midx,lidx,pidx,ppoi->x,ppoi->y);
      }
      ModelLine_CreateLength(pline);
    }
  }
  
  rbuffree(pf);
  FAT2_fclose(pf); pf=NULL;
}

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

#define wbufinit() { \
  wbufpos=0; \
}

#define wbuffree() { \
  if(wbufpos!=0) FAT2_fwrite(wbuf,1,wbufpos,pf); \
  wbufpos=0; \
}

#define wwbuf(data) { \
  if(wbufpos==wbufsize){ \
    FAT2_fwrite(wbuf,1,wbufsize,pf); \
    wbufpos=0; \
  } \
  wbuf[wbufpos++]=data; \
}

#define wu8(_data) { \
  s32 data=(_data); \
  if(data<0) data=0; \
  if(0xff<data) data=0xff; \
  wwbuf(data); \
}

#define ws8(_data) { \
  s32 data=(_data); \
  if(data<-0x80) data=-0x80; \
  if(0x7f<data) data=0x7f; \
  wwbuf(data); \
}

#define wu16(_data) { \
  s32 data=(_data); \
  if(data<0) data=0; \
  if(0xffff<data) data=0xffff; \
  wwbuf(data); \
  wwbuf(data>>8); \
}

#define ws16(_data) { \
  s32 data=(_data); \
  if(data<-0x8000) data=-0x8000; \
  if(0x7fff<data) data=0x7fff; \
  wwbuf(data); \
  wwbuf(data>>8); \
}

#define wwc(_data) { \
  UnicodeChar data=(_data); \
  wwbuf(data); \
  wwbuf(data>>8); \
}

#define wud(_data) { \
  double data=(_data); \
  u32 storedata=data*0x100; \
  wu16(storedata); \
}

#define wsd(_data) { \
  double data=(_data); \
  s32 storedata=data*0x100; \
  ws16(storedata); \
}

#define wu32(_data) { \
  u32 data=(_data); \
  wwbuf(data); \
  wwbuf(data>>8); \
  wwbuf(data>>16); \
  wwbuf(data>>24); \
}

#define wstr(_pstr) { \
  const char *pstr=(_pstr); \
  u32 len=strlen(pstr)+1; \
  wu8(len); \
  for(u32 idx=0;idx<len;idx++){ \
    wwbuf(pstr[idx]); \
  } \
}

static void Models_SaveToBin(void)
{
  FAT_FILE *pf=Shell_FAT_fopenwrite_Root(HWM_FilenameAlias);
  
  const u32 wbufsize=512;
  u8 wbuf[wbufsize];
  u32 wbufpos;
  
  wbufinit();
  
  wu32(HWM_ID);
  wstr(HWM_pIDStr);
  
  wu32(ModelsCount);
  _consolePrintf("Save: ModelsCount=%d.\n",ModelsCount);
  for(u32 midx=0;midx<ModelsCount;midx++){
    TModel *pmdl=&pModels[midx];
    wwc(pmdl->wc);
    wu8(pmdl->LinesCount);
//    _consolePrintf("Save: midx=%d, LinesCount=%d.\n",midx,pmdl->LinesCount);
    for(u32 lidx=0;lidx<pmdl->LinesCount;lidx++){
      TModelLine *pline=&pmdl->pLines[lidx];
      wud(pline->fx);
      wud(pline->fy);
      wu8(pline->PointsCount);
//      _consolePrintf("Save: midx=%d, lidx=%d, PointsCount=%d.\n",midx,lidx,pline->PointsCount);
      for(u32 pidx=0;pidx<pline->PointsCount;pidx++){
        TModelLinePoint *ppoi=&pline->pPoints[pidx];
        wsd(ppoi->x/2);
        wsd(ppoi->y/2);
      }
    }
  }
  
  wbuffree();
  
  FAT2_fclose(pf); pf=NULL;
  
  _consolePrintf("%s saved.\n",HWM_pIDStr);
}

