/* edit - editing functions
 */

#include "pico.h"
#include <string.h>

void pico_justify(Picovars *vars) {
 static int i;
 static short row,o_row,oldtoprow;
 static long pos,o_pos;
 static char finished;
 o_row=vars->row; o_pos=vars->position;
 row=o_row; pos=o_pos; finished=0;
 pico_readline(vars);
 if (strlen(vars->linebuf)<(vars->screendata->width-4)) return;
 i=(vars->screendata->width)-5;
 while ((i>0) & ((vars->linebuf[i])>32)) {i--;}
 if (i<1) return;
 pico_readline(vars);
 do {
  if (strlen(vars->linebuf)<1) finished=1;
  if (row>=vars->numrows) finished=1;
  i=(vars->screendata->width)-5;
  while ((i>0) & ((vars->linebuf[i])>32)) {i--;}
  if (i<1) finished=1;
  if (!finished) {
   row++; pos=pos+strlen(vars->linebuf)+1;
   vars->row=row; vars->position=pos;
   pico_readline(vars);
   if (strlen(vars->linebuf)>0) {
    pico_writechar(vars,pos-1,32);
   } else {finished=1;}
  }
 } while (!finished);
 finished=0;
 vars->row=o_row; vars->position=o_pos;
 row=o_row; pos=o_pos;
 do {
  pico_readline(vars);
  if (strlen(vars->linebuf)<(vars->screendata->width-4)) finished=1;
  if (!finished) {
   i=(vars->screendata->width)-5;
   while ((i>0) & ((vars->linebuf[i])>32)) {i--;}
   if (i<1) finished=1;
  }
  if (!finished) {
   pos=pos+i+1;
   pico_writechar(vars,pos-1,10);
   if (pos>=vars->filesize) {
    pico_insert(vars,pos-1,1);
    pico_writechar(vars,pos-1,10);
    pico_writechar(vars,pos,0);
   }
   (vars->numrows)++;
   if ((row==o_row) && (vars->column>=i)) {
    vars->column-=i; vars->column--;
    if (vars->column<0) vars->column=0;
    if (vars->column<=vars->leftcol)
     vars->leftcol=vars->column - (vars->screendata->width/2);
    if (vars->leftcol<0) vars->leftcol=0;
    oldtoprow=vars->toprow;
    o_row=row+1; o_pos=pos;
    if ((o_row-vars->toprow)>(vars->screendata->height-4)) {
     vars->toppos=o_pos;
     vars->toprow=o_row;
    }
    move(vars->screendata,vars->column-vars->leftcol,1+o_row-vars->toprow);
   }
   row++; vars->row=row; vars->position=pos;
  }
 } while (!finished);
 vars->row=o_row; vars->position=o_pos;
 vars->modified=1; vars->moved=1;
 pico_readline(vars); pico_countlines(vars);
 pico_position(vars); pico_screen(vars); refresh(vars->screendata);
}

void pico_character(Picovars *vars,int c) {
 static int a,b,i,l;
 if ((c<32) || (c==127)) return;
 l=strlen(vars->linebuf); a=c; l++;
 if (l>=(PICO_LINE_SIZE-1)) return;
 for(i=vars->column; i<=l; i++) {
  b=vars->linebuf[i]; vars->linebuf[i]=a; a=b;
 }
 if ((vars->mark!=-1) && (vars->markrow==vars->row) &&
     (vars->markcol>=vars->column)) (vars->markcol)++;
 vars->modified=1; pico_right(vars);
 vars->moved=1;
 if (strlen(vars->linebuf)<(vars->screendata->width-4)) return;
 i=(vars->screendata->width)-5;
 while ((i>0) & ((vars->linebuf[i])>32)) {i--;}
 if (i<1) return;
 pico_storeline(vars);
 pico_justify(vars);
}

void pico_readline(Picovars *vars) {
 static short i;
 static long position;
 static int c;
 position=vars->position;
 i=0; vars->linelength=0;
 memset(vars->linebuf,0,PICO_LINE_SIZE);
 while (i<PICO_LINE_SIZE) {
  c=pico_readchar(vars,position); position++;
  vars->linebuf[i]=c;
  if ((c<=0) || (c==10)) {
   vars->linebuf[i]=0; i=PICO_LINE_SIZE;
  } else {
   i++; (vars->linelength)++;
  }
 }
}

long pico_findline(Picovars *vars,short row) {
 short crow;
 long position;
 short direction;
 int c;
 if (row<=0) return(0);
 if (row==vars->row) return(vars->position);
 crow=vars->toprow; position=vars->toppos;
 if (abs(crow-row)>row) {crow=0; position=0;}
 if (abs(crow-row)>abs(vars->row-row)) {
  crow=vars->row; position=vars->position;}
 if (crow>row) {position-=2; direction=-1;} else {direction=1;}
 if (crow==row) return(position);
 while (crow!=row) {
  if (position<0) return(0);
  if (position>=vars->filesize) return(-1);
  c=pico_readchar(vars,position);
  if ((c<=0) || (c==10)) crow+=direction;
  position+=direction;
 }
 if (direction<0) return(position+2);
 return(position);
}

void pico_whereis(Picovars *vars) {
 static int a,b,i,c,x,y,row,frow,fpos;
 static long position;
 static char search[128]={0};
 static char *s;
 static char found;
 pico_storeline(vars);
 b=standout(vars->screendata,1);
 x=vars->screendata->x; y=vars->screendata->y;
 move(vars->screendata,0,(vars->screendata->height)-1);
 for(a=0; a<vars->screendata->width; a++) {addch(vars->screendata,' ');}
 move(vars->screendata,0,(vars->screendata->height)-1);
 addstr(vars->screendata,"Enter whereis query: ");
 a=pico_input(vars,search);
 if (((a==10) || (a==13)) && (search[0]<32)) a=-1;
 switch(a) {
  case 10:
  case 13:
   pico_status(vars,"Searching..."); refresh(vars->screendata);
   found=0;
   position=vars->position;
   for (row=vars->row; row<=vars->numrows; row++) {
    i=0; vars->temp[0]=0;
    while ((c=pico_readchar(vars,position+i))>31) {
     vars->temp[i]=c; i++; vars->temp[i]=0;
    }
    if (row==vars->row) {i=vars->column+1;} else {i=0;}
    if (i<strlen(vars->temp)) {
     s=strstr((vars->temp)+i,search);
     if (s!=NULL) {found=1; frow=row; fpos=position; row=vars->numrows+1;}
    }
    position++; position+=strlen(vars->temp);
   }
   if (!found) {
    a=-1; pico_status(vars,"Search Wrapped");
    position=0;
    for (row=0; row<vars->row; row++) {
     i=0; vars->temp[0]=0;
     while ((c=pico_readchar(vars,position+i))>31) {
      vars->temp[i]=c; i++; vars->temp[i]=0;
     }
     s=strstr(vars->temp,search);
     if (s!=NULL) {found=1; frow=row; fpos=position; row=vars->row;}
     position++; position+=strlen(vars->temp);
    }
   }
   if (!found) {
    a=-1; pico_status(vars,"Not Found");
   } else {
    vars->moved=1;
    vars->row=frow; vars->position=fpos;
    s-=(vars->temp);
    vars->column=(short)s;
    if (vars->column>(vars->screendata->width-2))
     vars->leftcol=vars->column-4;
    row=vars->row-(vars->screendata->height/2); if (row<0) row=0;
    vars->toppos=pico_findline(vars,row); vars->toprow=row;
    x=vars->column-vars->leftcol; y=1+vars->row-vars->toprow;
    pico_readline(vars); pico_screen(vars);
   }
   break;
  case 22:                                                            /* ^V */
   vars->column=0; vars->leftcol=0; x=0;
   row=vars->numrows-1; if (row<0) row=0;
   vars->position=pico_findline(vars,row); vars->row=row;
   row-=(vars->screendata->height-4); if (row<0) row=0;
   vars->toppos=pico_findline(vars,row); vars->toprow=row;
   pico_readline(vars);
   y=1+vars->row-vars->toprow;
   vars->moved=1;
   pico_screen(vars);
   break;
  case 25:                                                            /* ^Y */
   vars->row=0; vars->toprow=0; vars->position=0; vars->toppos=0;
   vars->column=0; vars->leftcol=0; x=0; vars->moved=1;
   pico_readline(vars); pico_screen(vars); y=1;
   break;
  default:
   a=-1; pico_status(vars,"Cancelled!"); break;
 }
 standout(vars->screendata,b); move(vars->screendata,x,y);
 if (a>=0) {pico_position(vars);} else {refresh(vars->screendata);}
}

void pico_mark(Picovars *vars) {
 if (vars->mark!=-1) {
  vars->mark=-1;
  pico_status(vars,"Mark Unset");
 } else {
  vars->mark=vars->position;
  vars->markrow=vars->row;
  vars->markcol=vars->column;
  pico_status(vars,"Mark Set");
 }
 pico_screen(vars); refresh(vars->screendata);
 vars->moved=1;
}

void pico_storeline(Picovars *vars) {
 static short i;
 if (vars->row==vars->numrows) {
  vars->position--;
  if (vars->position<0) {
   vars->position=0; if (vars->filesize<1) {
    pico_allocate(vars,strlen(vars->linebuf)+1);
    vars->filesize=strlen(vars->linebuf)+1;
   } else {
    pico_insert(vars,0,1+strlen(vars->linebuf)-(vars->linelength));
   }
   vars->numrows=1;
   for(i=0; i<strlen(vars->linebuf); i++) {
    pico_writechar(vars,i,vars->linebuf[i]);
   }
   pico_writechar(vars,strlen(vars->linebuf),10);
  } else {
   pico_insert(vars,vars->position,
               1+strlen(vars->linebuf)-(vars->linelength));
   pico_writechar(vars,vars->position,10);
   vars->position++;
   for(i=0; i<strlen(vars->linebuf); i++) {
    pico_writechar(vars,(vars->position)+i,vars->linebuf[i]);
   }
   vars->numrows++;
  }
 } else {
  pico_insert(vars,vars->position,strlen(vars->linebuf)-(vars->linelength));
  for(i=0; i<strlen(vars->linebuf); i++) {
   pico_writechar(vars,(vars->position)+i,vars->linebuf[i]);
  }
 }
}

void pico_delete(Picovars *vars) {
 static int i,l;
 static long rmpos,row;
 if (vars->column>0) {
  l=strlen(vars->linebuf); l++;
  for(i=vars->column; i<=l; i++) {vars->linebuf[i-1]=vars->linebuf[i];}
  if ((vars->mark!=-1) && (vars->markrow==vars->row) &&
      (vars->markcol>=vars->column)) (vars->markcol)--;
  vars->modified=1; pico_left(vars); return;
 }
 if (vars->row<=0) return;
 vars->modified=1; vars->moved=1;
 pico_storeline(vars);
 rmpos=vars->position-1;
 vars->position=pico_findline(vars,vars->row-1);
 (vars->row)--;
 if (vars->row<=vars->toprow) {
  row=vars->toprow-(vars->screendata->height-5);
  if (row<0) row=0;
  vars->toppos=pico_findline(vars,row);
  vars->toprow=row;
 }
 pico_readline(vars);
 vars->column=strlen(vars->linebuf);
 vars->leftcol=0;
 if (vars->column>=vars->screendata->width)
  vars->leftcol=5+vars->column-(vars->screendata->width);
 move(vars->screendata,vars->column-vars->leftcol,1+vars->row-vars->toprow);
 pico_remove(vars,rmpos,1);
 pico_readline(vars);
 pico_countlines(vars);
 pico_screen(vars);
 if (vars->mark!=-1) {vars->mark=-1; pico_status(vars,"Mark Unset");}
 pico_position(vars);
}

void pico_newline(Picovars *vars) {
 vars->modified=1; vars->moved=1;
 pico_storeline(vars);
 pico_insert(vars,vars->position+vars->column,1);
 pico_writechar(vars,vars->position+vars->column,10);
 vars->numrows++; vars->column=0; vars->leftcol=0;
 move(vars->screendata,0,vars->screendata->y);
 pico_readline(vars); pico_screen(vars); pico_down(vars);
}

void pico_paste(Picovars *vars) {
 static long i,pos;
 if (vars->clipboard==NULL) return;
 vars->mark=-1; vars->moved=1;
 pico_storeline(vars);
 pos=vars->position+vars->column;
 pico_status(vars,"Pasting block..."); refresh(vars->screendata);
 pico_insert(vars,pos,vars->clipsize);
 for(i=0; i<vars->clipsize; i++) {
  pico_writechar(vars,pos+i,vars->clipboard[i]);
 }
 vars->modified=1;
 pico_countlines(vars);
 pico_readline(vars);
 pico_status(vars,"Block pasted");
 pico_screen(vars); refresh(vars->screendata);
}

void pico_cut(Picovars *vars) {
 static long mposmin,mposmax,i,markpos,addpos,addsize;
 static short row;
 static char line,addbuffer;
 static char *oldclip;
 addbuffer=1;
 if (vars->moved!=0) addbuffer=0;
 if (vars->mark!=-1) addbuffer=0;
 if (vars->clipboard==NULL) addbuffer=0;
 pico_storeline(vars);
 if (vars->mark!=-1) {
  mposmin=vars->mark+vars->markcol; mposmax=vars->position+vars->column;
  if (mposmin>mposmax) {mposmin=mposmax; mposmax=vars->mark+vars->markcol;}
  markpos=vars->mark;
  line=0;
 } else {
  pico_readline(vars);
  mposmin=vars->position; mposmax=mposmin+1+vars->linelength;
  vars->mark=mposmin; vars->markcol=0; vars->markrow=vars->row;
  pico_storeline(vars);
  markpos=mposmin;
  line=1;
  if (addbuffer==0) vars->moved=0;
 }
 addsize=mposmax-mposmin;
 if (addbuffer==0) {
  if (vars->clipboard!=NULL) {free(vars->clipboard); vars->clipboard=NULL;}
  vars->clipsize=addsize; addpos=0;
  vars->clipboard=(char *)malloc(addsize);
 } else {
  addpos=vars->clipsize; oldclip=vars->clipboard;
  vars->clipboard=(char *)realloc(vars->clipboard,addpos+addsize);
/*
  if (vars->clipboard==oldclip) {
   vars->moved=1;
   pico_readline(vars);
   pico_status(vars,"Failed to add line to clipboard");
   refresh(vars->screendata);
   return;
  }
*/
  vars->clipsize=addpos+addsize;
 }
 if (vars->clipboard==NULL) {
  pico_readline(vars);
  pico_status(vars,"Failed to allocate clipboard memory");
  refresh(vars->screendata);
  return;
 }
 vars->mark=-1;
 pico_status(vars,"Cutting..."); refresh(vars->screendata);
 for(i=0; i<addsize; i++) {
  vars->clipboard[i+addpos]=pico_readchar(vars,mposmin+i);
 }
 pico_remove(vars,mposmin,addsize);
 vars->modified=1;
 if (vars->row>vars->markrow) {
  vars->row=vars->markrow;
  vars->position=markpos;
  row=vars->row-(vars->screendata->height/2); if (row<0) row=0;
  vars->toprow=0; vars->toppos=0;
  vars->toppos=pico_findline(vars,row); vars->toprow=row;
 }
 if (vars->column>vars->markcol) vars->column=vars->markcol;
 if (vars->column>(vars->screendata->width-2))
  vars->leftcol=vars->column-4;
 move(vars->screendata,vars->column-vars->leftcol,1+vars->row-vars->toprow);
 pico_countlines(vars);
 pico_readline(vars);
 if (line) {
  pico_status(vars,"Line cut");
 } else {
  pico_status(vars,"Block cut");
 }
 pico_screen(vars); refresh(vars->screendata);
}
