
#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 "strtool.h"
#include "unicode.h"
#include "cwl.h"

#include "TextEdit_CLine.h"

#define pTestFont pCglFontDefault

CTextEditLine::CTextEditLine(void)
{
  pBack=NULL;
  pNext=NULL;
  
  pstr=(UnicodeChar*)safemalloc(&MM_TextEdit,(1+1)*sizeof(UnicodeChar));
  pstr[0]=WC_Enter;
  pstr[1]=0;
  
  LineState_Init();
}

CTextEditLine::CTextEditLine(const UnicodeChar *psrcstr,const u32 srcstrlen)
{
  pBack=NULL;
  pNext=NULL;
  
  pstr=(UnicodeChar*)safemalloc(&MM_TextEdit,(srcstrlen+1+1)*sizeof(UnicodeChar));
  for(u32 idx=0;idx<srcstrlen;idx++){
    pstr[idx]=psrcstr[idx];
  }
  pstr[srcstrlen+0]=WC_Enter;
  pstr[srcstrlen+1]=0;
  
  LineState_Init();
}

CTextEditLine::~CTextEditLine(void)
{
  LineState_Free();
  
  if(pBack!=NULL) pBack->pNext=pNext;
  if(pNext!=NULL) pNext->pBack=pBack;
  
  if(pstr!=NULL){
    safefree(&MM_TextEdit,pstr); pstr=NULL;
  }
}

void CTextEditLine::ExpandBuffer(u32 addlen)
{
  u32 len=Unicode_GetLength(pstr);
  u32 explen=len+addlen;
  pstr=(UnicodeChar*)saferealloc(&MM_TextEdit,pstr,(explen+1)*sizeof(UnicodeChar));
  for(u32 idx=len;idx<explen+1;idx++){
    pstr[idx]=0;
  }
}

void CTextEditLine::LineState_Init(void)
{
  TLineState *pls=&LineState;
  
  pls->TotalLength=0;
  pls->LinesCount=0;
  pls->pLines=NULL;
}

void CTextEditLine::LineState_Free(void)
{
  TLineState *pls=&LineState;
  
  for(u32 idx=0;idx<pls->LinesCount;idx++){
    if(pls->pLines[idx].pstr!=NULL){
      safefree(&MM_TextEdit,pls->pLines[idx].pstr); pls->pLines[idx].pstr=NULL;
    }
  }
  if(pls->pLines!=NULL){
    safefree(&MM_TextEdit,pls->pLines); pls->pLines=NULL;
  }
  pls->LinesCount=0;
  
  pls->TotalLength=0;
}

void CTextEditLine::LineState_Clear(void)
{
  LineState_Free();
}

void CTextEditLine::LineState_Create(void)
{
  TLineState *pls=&LineState;
  
  if(pls->LinesCount!=0) return;
  
  const UnicodeChar *psrcstr=pstr;
  u32 srcidx=0;
  
  if(pls->TotalLength==0) pls->TotalLength=Unicode_GetLength(pstr);
  
  pls->LinesCount=1;
  pls->pLines=(TLineState_TLine*)safemalloc(&MM_TextEdit,pls->LinesCount*sizeof(TLineState_TLine));
  pls->pLines[pls->LinesCount-1].TopIndex=srcidx;
  pls->pLines[pls->LinesCount-1].Length=0;
  pls->pLines[pls->LinesCount-1].pstr=(UnicodeChar*)safemalloc(&MM_TextEdit,(256+1)*sizeof(UnicodeChar));
  
  UnicodeChar *pdststr=pls->pLines[pls->LinesCount-1].pstr;
  u32 dstlen=0;
  u32 dstx=0;
  
  while(1){
    UnicodeChar wc=psrcstr[srcidx++];
    if(wc==0) break;
    u32 w=0;
    if(wc!=WC_Enter) w=pTestFont->GetFontWidth(wc)+FontWidthMargin;
    if(WindowRectWidth<(dstx+w)){
      pdststr[dstlen]=0;
      pls->pLines[pls->LinesCount-1].Length=dstlen;
      pls->pLines[pls->LinesCount-1].pstr=(UnicodeChar*)saferealloc(&MM_TextEdit,pls->pLines[pls->LinesCount-1].pstr,(dstlen+1)*sizeof(UnicodeChar));
      pls->LinesCount++;
      pls->pLines=(TLineState_TLine*)saferealloc(&MM_TextEdit,pls->pLines,pls->LinesCount*sizeof(TLineState_TLine));
      pls->pLines[pls->LinesCount-1].TopIndex=srcidx-1;
      pls->pLines[pls->LinesCount-1].pstr=(UnicodeChar*)safemalloc(&MM_TextEdit,(256+1)*sizeof(UnicodeChar));
      pdststr=pls->pLines[pls->LinesCount-1].pstr;
      dstlen=0;
      dstx=0;
    }
    pdststr[dstlen++]=wc;
    dstx+=w;
  }
  
  pdststr[dstlen]=0;
  pls->pLines[pls->LinesCount-1].Length=dstlen;
  pls->pLines[pls->LinesCount-1].pstr=(UnicodeChar*)saferealloc(&MM_TextEdit,pls->pLines[pls->LinesCount-1].pstr,(dstlen+1)*sizeof(UnicodeChar));
}

u32 CTextEditLine::GetLength(void)
{
  TLineState *pls=&LineState;
  if(pls->TotalLength==0) pls->TotalLength=Unicode_GetLength(pstr);
  return(pls->TotalLength);
}

const UnicodeChar* CTextEditLine::GetPlaneStringBuffer(void) const
{
  return(pstr);
}

void CTextEditLine::AddNewLine(void)
{
  CTextEditLine *pnew=new CTextEditLine();
  if(pNext!=NULL) pNext->pBack=pnew;
  pnew->pNext=pNext;
  pNext=pnew;
  pNext->pBack=this;
}

void CTextEditLine::AddNewLineWithSet(const UnicodeChar *psrcstr,const u32 srcstrlen)
{
  CTextEditLine *pnew=new CTextEditLine(psrcstr,srcstrlen);
  if(pNext!=NULL) pNext->pBack=pnew;
  pnew->pNext=pNext;
  pNext=pnew;
  pNext->pBack=this;
}

void CTextEditLine::AddStr(u32 Index,const UnicodeChar *psrcstr)
{
  if(psrcstr==NULL) return;
  if(psrcstr[0]==0) return;
  
  LineState_Free();
  
  u32 len=Unicode_GetLength(pstr);
  
  if(Index==(u32)-1) Index=len-1;
  if(len==Index) StopFatalError(0,"Store position error. This position is WC_Enter. (%d/%d)",Index,len);
  if(len<Index) StopFatalError(0,"Store position overflow (%d/%d)",Index,len);
  
  u32 srclen=Unicode_GetLength(psrcstr);
  
  if((Index==0)&&(len==1)){
    pstr=(UnicodeChar*)saferealloc(&MM_TextEdit,pstr,(srclen+1+1)*sizeof(UnicodeChar));
    for(u32 idx=0;idx<srclen;idx++){
      pstr[idx]=psrcstr[idx];
    }
    pstr[srclen+0]=WC_Enter;
    pstr[srclen+1]=0;
    return;
  }
  
  UnicodeChar *ptmp_Store=(UnicodeChar*)safemalloc(&MM_TextEdit,(len+srclen+1)*sizeof(UnicodeChar));
  UnicodeChar *ptmp=ptmp_Store;
  *ptmp=0;
  
  for(u32 idx=0;idx<Index;idx++){
    *ptmp++=pstr[idx];
  }
  *ptmp=0;
  
  Unicode_Copy(ptmp,psrcstr);
  ptmp+=Unicode_GetLength(ptmp);
  
  Unicode_Copy(ptmp,&pstr[Index]);
  
  if(pstr!=NULL){
    safefree(&MM_TextEdit,pstr); pstr=NULL;
  }
  
  pstr=ptmp_Store;
}

void CTextEditLine::Split(u32 Index)
{
  LineState_Free();
  
  AddNewLine();
  
  u32 len=Unicode_GetLength(pstr);
  pstr[len-1]=0; // Delete WC_Enter.
  pNext->AddStr((u32)-1,&pstr[Index]);
  
  pstr[Index]=0;
  ExpandBuffer(1);
  pstr[Index]=WC_Enter;
  pstr[Index+1]=0;
}

void CTextEditLine::ApplyReduce(void)
{
  u32 len=Unicode_GetLength(pstr);
  pstr=(UnicodeChar*)saferealloc(&MM_TextEdit,pstr,(len+1)*sizeof(UnicodeChar));
}

const TLineState* CTextEditLine::GetLineState(void)
{
  LineState_Create();
  return(&LineState);
}

void CTextEditLine::DeleteOne(u32 pos)
{
  if(pos==0) StopFatalError(0,"Can not delete top char. Please marge to back line.");
  pos--;
  
  LineState_Free();
  
  UnicodeChar *_ptmp=(UnicodeChar*)safemalloc(&MM_Temp,(Unicode_GetLength(pstr)+1)*sizeof(UnicodeChar));
  UnicodeChar *ptmp=_ptmp;
  Unicode_Copy(ptmp,pstr);
  
  UnicodeChar *pdst=pstr;
  *pdst=0;
  
  for(u32 idx=0;idx<pos;idx++){
    *pdst++=*ptmp++;
  }
  
  ptmp++;
  
  while(*ptmp!=0){
    *pdst++=*ptmp++;
  }
  *pdst=0;
  
  if(_ptmp!=NULL){
    safefree(&MM_Temp,_ptmp); _ptmp=NULL;
  }
}

