
static FAT_FILE *WriteBuf_pf;
static const u32 WriteBuf_BufSize=512;
static u8 WriteBuf_Buf[WriteBuf_BufSize];
static u32 WriteBuf_BufPos;

static void WriteBuf_Open(FAT_FILE *pf)
{
  WriteBuf_pf=pf;
  WriteBuf_BufPos=0;
}

static void WriteBuf_Close(void)
{
  if(WriteBuf_BufPos!=0) FAT2_fwrite(WriteBuf_Buf,1,WriteBuf_BufPos,WriteBuf_pf);
  
  WriteBuf_pf=NULL;
}

static void WriteBuf_Store8(u8 data)
{
  WriteBuf_Buf[WriteBuf_BufPos++]=data;
  if(WriteBuf_BufPos==WriteBuf_BufSize){
    FAT2_fwrite(WriteBuf_Buf,1,WriteBuf_BufPos,WriteBuf_pf);
    WriteBuf_BufPos=0;
  }
}

static void WriteBuf_Store16(u16 data)
{
  WriteBuf_Buf[WriteBuf_BufPos++]=data&0xff;
  WriteBuf_Buf[WriteBuf_BufPos++]=data>>8;
  if(WriteBuf_BufPos==WriteBuf_BufSize){
    FAT2_fwrite(WriteBuf_Buf,1,WriteBuf_BufPos,WriteBuf_pf);
    WriteBuf_BufPos=0;
  }
}

static void TextFile_SaveToFile_UTF8_WriteString_ins_Store(UnicodeChar wc)
{
  if((wc&(~0x7f))==0){
    WriteBuf_Store8(wc&0x7f);
    }else{
    if((wc&(~0x7ff))==0){
      WriteBuf_Store8(((wc>>6)&0x1f)|0xc0);
      WriteBuf_Store8((wc&0x3f)|0x80);
      }else{
      WriteBuf_Store8(((wc>>12)&0x0f)|0xe0);
      WriteBuf_Store8(((wc>>6)&0x3f)|0x80);
      WriteBuf_Store8((wc&0x3f)|0x80);
    }
  }
}

static void TextFile_SaveToFile_UTF8_WriteString(const UnicodeChar *pstr)
{
  while(1){
    UnicodeChar wc=*pstr++;
    if(wc==0) break;
    
    if(wc==WC_Enter){
      switch(ReturnCode){
        case ERC_CR: {
          TextFile_SaveToFile_UTF8_WriteString_ins_Store(WC_CR);
        } break;
        case ERC_LF: {
          TextFile_SaveToFile_UTF8_WriteString_ins_Store(WC_LF);
        } break;
        case ERC_CRLF: {
          TextFile_SaveToFile_UTF8_WriteString_ins_Store(WC_CR);
          TextFile_SaveToFile_UTF8_WriteString_ins_Store(WC_LF);
        } break;
        case ERC_LFCR: {
          TextFile_SaveToFile_UTF8_WriteString_ins_Store(WC_LF);
          TextFile_SaveToFile_UTF8_WriteString_ins_Store(WC_CR);
        } break;
      }
      }else{
      TextFile_SaveToFile_UTF8_WriteString_ins_Store(wc);
    }
  }
}

static void TextFile_SaveToFile_UTF16_WriteString_ins_Store(UnicodeChar wc)
{
  WriteBuf_Store16(wc);
}

static void TextFile_SaveToFile_UTF16_WriteString(const UnicodeChar *pstr)
{
  while(1){
    UnicodeChar wc=*pstr++;
    if(wc==0) break;
    
    if(wc==WC_Enter){
      switch(ReturnCode){
        case ERC_CR: {
          TextFile_SaveToFile_UTF16_WriteString_ins_Store(WC_CR);
        } break;
        case ERC_LF: {
          TextFile_SaveToFile_UTF16_WriteString_ins_Store(WC_LF);
        } break;
        case ERC_CRLF: {
          TextFile_SaveToFile_UTF16_WriteString_ins_Store(WC_CR);
          TextFile_SaveToFile_UTF16_WriteString_ins_Store(WC_LF);
        } break;
        case ERC_LFCR: {
          TextFile_SaveToFile_UTF16_WriteString_ins_Store(WC_LF);
          TextFile_SaveToFile_UTF16_WriteString_ins_Store(WC_CR);
        } break;
      }
      }else{
      TextFile_SaveToFile_UTF16_WriteString_ins_Store(wc);
    }
  }
}

static void TextFile_SaveToFile_SJIS_WriteString_ins_Store(UnicodeChar wc)
{
  if(wc==0){
    WriteBuf_Store8(0);
    return;
  }
  
  TEUC2Unicode *ps2u=&EUC2Unicode;
  
  u16 data=ps2u->pu2stbl[wc];
  if(data==0) data='?';
  
  if(data<0x100){
    WriteBuf_Store8(data);
    }else{
    WriteBuf_Store8(data>>8);
    WriteBuf_Store8(data&0xff);
  }
}

static void TextFile_SaveToFile_SJIS_WriteString(const UnicodeChar *pstr)
{
  while(1){
    UnicodeChar wc=*pstr++;
    if(wc==0) break;
    
    if(wc==WC_Enter){
      switch(ReturnCode){
        case ERC_CR: {
          TextFile_SaveToFile_SJIS_WriteString_ins_Store(WC_CR);
        } break;
        case ERC_LF: {
          TextFile_SaveToFile_SJIS_WriteString_ins_Store(WC_LF);
        } break;
        case ERC_CRLF: {
          TextFile_SaveToFile_SJIS_WriteString_ins_Store(WC_CR);
          TextFile_SaveToFile_SJIS_WriteString_ins_Store(WC_LF);
        } break;
        case ERC_LFCR: {
          TextFile_SaveToFile_SJIS_WriteString_ins_Store(WC_LF);
          TextFile_SaveToFile_SJIS_WriteString_ins_Store(WC_CR);
        } break;
      }
      }else{
      TextFile_SaveToFile_SJIS_WriteString_ins_Store(wc);
    }
  }
}

static void TextEdit_SaveToFile_CopyToBackupFile(void)
{
  const TExtLinkBody *pelb=GetFileBody_From_MoonShell2_ExtLink();
  
  FAT_FILE *prf=NULL,*pwf=NULL;
  
  {
    const char *pafn=ConvertFull_Unicode2Alias(pelb->DataPathUnicode,pelb->DataFilenameUnicode);
    prf=FAT2_fopen_AliasForRead(pafn);
    if(prf==NULL) StopFatalError(0,"File open error for read.\n");
  }
  
  {
    UnicodeChar *pufn=(UnicodeChar*)pelb->DataFilenameUnicode; // 面倒なので書き換えちゃう。
    u32 idx=0,dotidx=(u32)-1;
    while(1){
      UnicodeChar wc=pufn[idx];
      if(wc==0) break;
      if(wc==UnicodeChar('.')) dotidx=idx;
      idx++;
    }
    if(dotidx==(u32)-1) StopFatalError(0,"Can not found extention name.");
    pufn[dotidx+0]=UnicodeChar('.');
    pufn[dotidx+1]=UnicodeChar('b');
    pufn[dotidx+2]=UnicodeChar('a');
    pufn[dotidx+3]=UnicodeChar('k');
    pufn[dotidx+4]=0;
    const char *pafn;
    if(FileExistsUnicode(pelb->DataPathUnicode,pelb->DataFilenameUnicode)==true){
      pafn=ConvertFull_Unicode2Alias(pelb->DataPathUnicode,pelb->DataFilenameUnicode);
      }else{
      pafn=Shell_CreateNewFileUnicode(pelb->DataPathUnicode,pelb->DataFilenameUnicode);
    }
    _consolePrintf("Save to [%s]\n",pafn);
    pwf=FAT2_fopen_AliasForWrite(pafn);
    if(pwf==NULL) StopFatalError(0,"File open error for read.\n");
  }
  
  while(1){
    const u32 bufmax=512;
    u8 buf[bufmax];
    u32 bufsize=FAT2_fread(buf,1,bufmax,prf);
    if(bufsize==0) break;
    FAT2_fwrite(buf,1,bufsize,pwf);
    if(bufsize!=bufmax) break;
  }
  
  FAT2_fclose(prf); prf=NULL;
  FAT2_fclose(pwf); pwf=NULL;
  
  _consolePrintf("Backup file created.\n");
}

static FAT_FILE* TextEdit_SaveToFile_OpenFileForWrite_Overwrite(void)
{
  const TExtLinkBody *pelb=GetFileBody_From_MoonShell2_ExtLink();
  
  const char *pafn=ConvertFull_Unicode2Alias(pelb->DataPathUnicode,pelb->DataFilenameUnicode);
  FAT_FILE *pf=FAT2_fopen_AliasForWrite(pafn);
  if(pf==NULL) StopFatalError(0,"File open error for overwrite.\n");
  
  return(pf);
}

static FAT_FILE* TextEdit_SaveToFile_OpenFileForWrite_SaveAs(void)
{
  const TExtLinkBody *pelb=GetFileBody_From_MoonShell2_ExtLink();
  
  UnicodeChar fnu[MaxFilenameLength];
  Unicode_Copy(fnu,pelb->DataFilenameUnicode);
  
  const UnicodeChar *pext=NULL;
  
  {
    const UnicodeChar *psrc=pelb->DataFilenameUnicode;
    u32 idx=0,dotidx=(u32)-1;
    while(1){
      UnicodeChar wc=psrc[idx];
      if(wc==0) break;
      if(wc==UnicodeChar('.')) dotidx=idx;
      idx++;
    }
    if(dotidx==(u32)-1) StopFatalError(0,"Can not found extention name.");
    pext=&psrc[dotidx];
    fnu[dotidx]=0;
  }
  
  {
    TDateTime dt=DateTime_GetNow();
    
    char dtstr[128];
    UnicodeChar dtstrw[128];
    snprintf(dtstr,128,".%04d%02d%02d-%02d%02d%02d",dt.Date.Year,dt.Date.Month,dt.Date.Day,dt.Time.Hour,dt.Time.Min,dt.Time.Sec);
    StrConvert_Ank2Unicode(dtstr,dtstrw);
    Unicode_Add(fnu,dtstrw);
  }
  
  Unicode_Add(fnu,pext);
  
  const char *pafn;
  if(FileExistsUnicode(pelb->DataPathUnicode,fnu)==true){
    pafn=ConvertFull_Unicode2Alias(pelb->DataPathUnicode,fnu);
    }else{
    pafn=Shell_CreateNewFileUnicode(pelb->DataPathUnicode,fnu);
  }
  _consolePrintf("Save to [%s]\n",pafn);
  
  FAT_FILE *pf=FAT2_fopen_AliasForWrite(ConvertFull_Unicode2Alias(pelb->DataPathUnicode,fnu));
  if(pf==NULL) StopFatalError(0,"File open error for save as.\n");
  
  return(pf);
}

static FAT_FILE* TextEdit_SaveToFile_OpenFileForWrite_NewFilename(const UnicodeChar *fnu)
{
  const TExtLinkBody *pelb=GetFileBody_From_MoonShell2_ExtLink();
  
  const char *pafn;
  if(FileExistsUnicode(pelb->DataPathUnicode,fnu)==true){
    pafn=ConvertFull_Unicode2Alias(pelb->DataPathUnicode,fnu);
    }else{
    pafn=Shell_CreateNewFileUnicode(pelb->DataPathUnicode,fnu);
  }
  _consolePrintf("Save to [%s]\n",pafn);
  
  FAT_FILE *pf=FAT2_fopen_AliasForWrite(ConvertFull_Unicode2Alias(pelb->DataPathUnicode,fnu));
  if(pf==NULL) StopFatalError(0,"File open error for new filename.\n");
  
  return(pf);
}

void TextEdit_SaveToFile(EFilenameType FilenameType,const UnicodeChar *pNewFilename)
{
  TextEdit_ClearAllLineState();
  
  DateTime_ResetNow();
  
  {
    TFAT2_TIME fattime;
    TDateTime dt=DateTime_GetNow();
    fattime.Year=dt.Date.Year;
    fattime.Month=dt.Date.Month;
    fattime.Day=dt.Date.Day;
    fattime.Hour=dt.Time.Hour;
    fattime.Minuts=dt.Time.Min;
    fattime.Second=dt.Time.Sec;
    FAT2_SetSystemDateTime(fattime);
  }
  
  switch(FilenameType){
    case EFT_Overwrite: TextEdit_SaveToFile_CopyToBackupFile(); break;
    case EFT_SaveAs: break;
    case EFT_NewFilename: break;
  }
  
  FAT_FILE *pf=NULL;
  switch(FilenameType){
    case EFT_Overwrite: pf=TextEdit_SaveToFile_OpenFileForWrite_Overwrite(); break;
    case EFT_SaveAs: pf=TextEdit_SaveToFile_OpenFileForWrite_SaveAs(); break;
    case EFT_NewFilename: pf=TextEdit_SaveToFile_OpenFileForWrite_NewFilename(pNewFilename); break;
  }
  if(pf==NULL) StopFatalError(0,"Internal error or open file failed.");
  
  _consolePrintf("Saving...\n");
  
  WriteBuf_Open(pf);
  
  switch(TextEncode){
    case ETE_UTF8: {
      if(UTF8Header[0]!=0){
        WriteBuf_Store8(UTF8Header[0]);
        WriteBuf_Store8(UTF8Header[1]);
        WriteBuf_Store8(UTF8Header[2]);
      }
    } break;
    case ETE_UTF16: {
      if(UTF16Header!=0) WriteBuf_Store16(UTF16Header);
    } break;
    case ETE_SJIS: {
      EUC2Unicode_Init();
      EUC2Unicode_Load(true);
    } break;
  }
  
  {
    CTextEditLine *pCurLine=pTextEdit->pTopLine;
    while(1){
      const UnicodeChar *pstr=pCurLine->GetPlaneStringBuffer();
      switch(TextEncode){
        case ETE_UTF8: TextFile_SaveToFile_UTF8_WriteString(pstr); break;
        case ETE_UTF16: TextFile_SaveToFile_UTF16_WriteString(pstr); break;
        case ETE_SJIS: TextFile_SaveToFile_SJIS_WriteString(pstr); break;
      }
      pCurLine=pCurLine->pNext;
      if(pCurLine==NULL) break;
    }
  }
  
  switch(TextEncode){
    case ETE_UTF8: break;
    case ETE_UTF16: break;
    case ETE_SJIS: {
      EUC2Unicode_Free();
    } break;
  }
  
  WriteBuf_Close();
  
  FAT2_fclose(pf); pf=NULL;
  
  _consolePrintf("Saved.\n");
}


