#include <stdio.h>
#include <conio.h>
#include <process.h>
#include <malloc.h>
#include <mem.h>

#define PAR_ALIGN_RIGHT     1
#define PAR_ALIGN_CENTER    2

#define PAR_TEXT_MAX_LEN  601

#define WIN_UL         'É'
#define WIN_UU         'Í'
#define WIN_UR         '»'
#define WIN_DL         'È'
#define WIN_DD         'º'
#define WIN_DR         '¼'

#define WIN_CLR_TXT    0xF
#define WIN_CLR_BCK    0x1
#define WIN_CLR_CUR    0x0
#define WIN_CLR_MRK    0x2
#define WIN_CLR_BRD    0xA
#define WIN_CLR_BRDM   0xB

#define WIN_MIN_WIDTH   10
#define WIN_MIN_HEIGHT   3

#define WIN_MAX_WIDTH   79
#define WIN_MAX_HEIGHT  24
#define WIN_MAX_LEN     81

#define WIN_BUFFER    4097

#define KEY_BS                  8
#define KEY_ENTER              13
#define KEY_ESC                27
#define KEY_SPACE              32
#define KEY_LAST              255

#define KEY_SPC_DEL        83*256
#define KEY_SPC_UP         72*256
#define KEY_SPC_LEFT       75*256
#define KEY_SPC_RIGHT      77*256
#define KEY_SPC_DOWN       80*256
#define KEY_SPC_F2         60*256
#define KEY_SPC_F11       133*256
#define KEY_SPC_PG_UP      73*256
#define KEY_SPC_PG_DN      81*256

#define KEY_SPC_C_HOME    119*256
#define KEY_SPC_C_END     117*256
#define KEY_SPC_C_DEL     147*256
#define KEY_SPC_C_F1       94*256
#define KEY_SPC_C_UP      141*256
#define KEY_SPC_C_LEFT    115*256
#define KEY_SPC_C_RIGHT   116*256
#define KEY_SPC_C_DOWN    145*256
#define KEY_SPC_C_A_UP    152*256
#define KEY_SPC_C_A_LEFT  155*256
#define KEY_SPC_C_A_RIGHT 157*256
#define KEY_SPC_C_A_DOWN  160*256

typedef struct _Paragraph
{
 struct _Paragraph *next;
 int id;
 char text[PAR_TEXT_MAX_LEN];
 unsigned char align;
} Paragraph, *pParagraph;

typedef struct
{
 char x,y,w,h;
 char name[WIN_MAX_LEN];
 char back[WIN_BUFFER];
 int pos;
} Window, *pWindow;

unsigned int toScreen(unsigned char c,unsigned char a);
void fillscreen(char x,char y,char w,char h,unsigned char c,unsigned char a);
int is_key_pressed(void);
unsigned int readkey(void);
int get_length(char *t);
char* copy_string(char *dest,char *src,int num);
char* to_string(char *str,int num);

int CheckWord(char *t);//razdeliteli: " .,?!:;/\t\r\n"
int CheckSentence(char *t);//razdeliteli: ".?!\r\n"
int CheckParagraph(char *t);//razdeliteli: "\r\n"
int get_paragraph(pParagraph pp,int id,pParagraph *res);
void AddParagraph(pParagraph *pp,int id,char *t);
void RemoveParagraph(pParagraph *pp,int id);
int DeleteSymbol(pParagraph *pp,int id,int pos);
void New(pParagraph *pp);
int Load(pParagraph *pp);
int Save(pParagraph pp);
int Add(pParagraph *pp);
void SaveStatistic(pParagraph pp);

pWindow CreateWindow(char x,char y,char w,char h,char *n);
pWindow OpenWindow(char x,char y,char w,char h,char *n);
int InputTextWindow(char x,char y,char w,char h,char *n,char *t);
void CloseWindow(pWindow *pw);
void ShowWindow(pWindow pw);
void HideWindow(pWindow pw);
void GetWindowPos(pWindow pw,char *x,char *y);
void GotoWindow(pWindow pw,char x,char y);
int DrawTextWindow(pWindow pw,const char *s);
int DrawLineWindow(pWindow pw,char x,char *y,pParagraph pp,int from);
void DrawParagraphsWindow(pWindow pw,pParagraph pp,int *id,int *pos);
void ShowCursor(pWindow pw);
void HideCursor(pWindow pw);
int ChooseMenu(char x,char y,char w,char h,char *n,const char *t[]);

void Msg(const char *s);
void ErrorExit(const char *s);
void Begin(void);
void End(void);
void CheckArgs(int argc,char *argv[]);
int move(pWindow pw,pParagraph pp,int type,int *id,int *pos);

/*--------------------------------------------------------------------*/

const char* MenuFile[]={"Nov","Procheti","Zapomni","Krai",""};
const char* MenuWindow[]={"Promqna na razmer","Promqna na poziciq","Centriran","Golqm","Vyzstanovqvane",""};

unsigned int far *Screen=(unsigned int far *) 0xb8000000;
char Backup[WIN_BUFFER];
unsigned char win_clr_txt=WIN_CLR_TXT;
unsigned char win_clr_bck=WIN_CLR_BCK;
unsigned char win_clr_cur=WIN_CLR_CUR;
unsigned char win_clr_mrk=WIN_CLR_MRK;
unsigned char win_clr_brd=WIN_CLR_BRD;
unsigned char win_clr_brdm=WIN_CLR_BRDM;
unsigned char par_align=PAR_ALIGN_RIGHT;
unsigned char win_width=WIN_MAX_WIDTH;
unsigned char win_height=WIN_MAX_HEIGHT;
unsigned char win_maximize=0,win_x,win_y,win_w,win_h,win_clr;
int ID=0,POS=0;
unsigned char CURX=1,CURY=1;

/*--------------------------------------------------------------------*/

unsigned int toScreen(unsigned char c,unsigned char a)
{
 return (c+a*256);
}

void fillscreen(char x,char y,char w,char h,unsigned char c,unsigned char a)
{
 char xx,yy;
 for (yy=y;yy<=y+h;yy++)
  for (xx=x;xx<=x+w;xx++)
   Screen[xx+yy*80]=toScreen(c,a);
}

int is_keypressed(void)
{
 if (!kbhit()) return 0;
 return 1;
}

unsigned int readkey(void)
{
 unsigned int key;
 key=getch();
 if (!key) key=getch()*256;
 return key;
}

int get_length(char *t)
{
 int i=0;
 while (t[i]) i++;
 return i;
}

char* copy_string(char *dest,char *src,int num)
{
 unsigned int i=0;
 while ((!num || i<num) && src[i]) dest[i]=src[i++];
 dest[i]=0;
 return dest;
}

char* to_string(char *str, int num)
{
 int i=0,j;
 char temp[PAR_TEXT_MAX_LEN]="";
 do {
  temp[i++]='0'+num%10;
  num/=10;
 } while (num);
 temp[i]=0;
 for (j=0;j<i;j++) str[j]=temp[i-j-1];
 str[j]=0;
 return str;
}

int CheckWord(char *t)
{
 int i=0;
 while (t[i]!=0 && t[i]!=' ' && t[i]!='.' && t[i]!=',' &&
	t[i]!='?' && t[i]!='!' && t[i]!=':' && t[i]!=';' &&
	t[i]!='/' && t[i]!='\n' && t[i]!=EOF) i++;//t[i]!='\t' && t[i]!='\t' &&
 return i;
}

int CheckSentence(char *t)
{
 int i=0;
 while (t[i]!=0 && t[i]!='.' && t[i]!='?' && t[i]!='!' &&
	t[i]!='\n' && t[i]!=EOF) i++;//t[i]!='\r' &&
 return i;
}

int CheckParagraph(char *t)
{
 int i=0;
 while (t[i]!=0 && t[i]!='\n' && t[i]!=EOF) i++;//t[i]!='\r' &&
 return i;
}

int get_paragraph(pParagraph pp,int id,pParagraph *res)
{
 *res=pp;
 while (*res && (*res)->id!=id) *res=(*res)->next;
 if (*res) return 1;
 return 0;
}

void AddParagraph(pParagraph *pp,int id,char *t)
{
 pParagraph tmp=NULL,tmp2=*pp;
 int i;
 if ((tmp=(pParagraph)malloc(sizeof(Paragraph)))==NULL) ErrorExit("Nqma pamet!");
 tmp->next=NULL;
 copy_string(tmp->text,t,0);
 tmp->align=par_align;
 if (tmp2) {
  tmp->id=id;
  if (tmp2->id==id) {
   *pp=tmp;
   tmp->next=tmp2;
  } else {
   while (tmp2->next && tmp2->next->id!=id) tmp2=tmp2->next;
   if (tmp2->next) tmp->next=tmp2->next;
   else tmp->id=tmp2->id+1;
   tmp2->next=tmp;
  }
 } else {
  *pp=tmp;
  tmp->id=1;
 }
 i=id;
 while (tmp->next) {
  tmp->next->id=++i;
  tmp=tmp->next;
 }
}

void RemoveParagraph(pParagraph *pp,int id)
{
 pParagraph tmp,tmp2=*pp;
 int i;
 if (tmp2==NULL) return;
 if (tmp2->id==id) {
  tmp=tmp2;
  tmp2=tmp2->next;
  *pp=tmp2;
  if (tmp2) tmp2->id=1;
 } else {
  while (tmp2->next && tmp2->next->id!=id) tmp2=tmp2->next;
  if (tmp2->next) {
   tmp=tmp2->next;
   tmp2->next=tmp2->next->next;
  } else return;
 }
 free(tmp);
 if (tmp2) i=tmp2->id;
 while (tmp2 && tmp2->next) {
  tmp2->next->id=++i;
  tmp2=tmp2->next;
 }
 if (id==ID) {
  tmp=*pp;
  while (tmp && tmp->next) tmp=tmp->next;
  if (tmp==NULL) ID=0;
  else
   if (ID>tmp->id) ID=tmp->id;
  POS=0;
 }
}

int DeleteSymbol(pParagraph *pp,int id,int pos)
{
 pParagraph tmp=*pp;
 int len;
 while (tmp && tmp->id!=id) tmp=tmp->next;
 if (tmp) {
  len=get_length(tmp->text);
  if (len>1) {
   copy_string(tmp->text+pos,tmp->text+pos+1,len-pos-1);
   if (id==ID && POS>get_length(tmp->text)-1) {
    POS--;
    return 1;
   }
  } else RemoveParagraph(pp,id);
 }
 return 0;
}

void New(pParagraph *pp)
{
 while (*pp) RemoveParagraph(pp,(*pp)->id);
 ID=0;
 POS=0;
 CURX=1;
 CURY=1;
}

int Load(pParagraph *pp)
{
 FILE *f;
 char temp[PAR_TEXT_MAX_LEN]="";
 int i;
 if (InputTextWindow(10,10,60,5,"Vyvedete fail za chetene",temp)<=0) return 0;
 if ((f=fopen(temp,"rt"))==NULL) {
  Msg("Faila ne moje da byde otvoren!");
  return 0;
 }
 New(pp);
 while (!feof(f)) {
  temp[0]=0;
  fgets(temp,PAR_TEXT_MAX_LEN,f);
  i=get_length(temp);
  if (i && temp[--i]==10) temp[i]=0;
  i=0;
  while (temp[i]) if (temp[i++]<KEY_SPACE) temp[i-1]=KEY_SPACE;
  AddParagraph(pp,0,temp);
 }
 fclose(f);
 if (*pp) ID=1;
 else ID=0;
 POS=0;
 CURX=1;
 CURY=1;
 return 1;
}

int Save(pParagraph pp)
{
 FILE *f;
 pParagraph tmp=pp;
 char temp[PAR_TEXT_MAX_LEN]="";
 if (tmp==NULL) return 0;
 if (InputTextWindow(10,10,60,5,"Vyvedete fail za zapis",temp)<=0) return 0;
 if ((f=fopen(temp,"wt"))==NULL) {
  Msg("Faila ne moje da byde syzdaden!");
  return 0;
 }
 while (tmp) {
  if (tmp->text) fputs(tmp->text,f);
  if (tmp->next) fputs("\n",f);
  tmp=tmp->next;
 }
 fclose(f);
 return 1;
}

int Add(pParagraph *pp)
{
 char temp[PAR_TEXT_MAX_LEN]="";
 if (InputTextWindow(10,10,60,5,"Vyvedete paragraf",temp)<0) return 0;
 AddParagraph(pp,ID,temp);
 if (!ID) {
  ID++;
  POS=0;
 }
 return 1;
}

void SaveStatistic(pParagraph pp)
{
 FILE *f;
 pParagraph tmp=pp;
 int i,res,len,len_all=0,num_paragraph=0,num_word_all=0,num_sentence_all=0,num_word,num_sentence;
 char temp[PAR_TEXT_MAX_LEN]="";
 if (tmp==NULL) return;
 if (InputTextWindow(5,10,70,5,"Vyvedete fail za zapis na statistikata",temp)<=0) return;
 if ((f=fopen(temp,"wt"))==NULL) {
  Msg("Faila ne moje da byde syzdaden!");
  return;
 }
 while (tmp) {
  num_paragraph++;
  num_sentence=num_word=0;
  len=get_length(tmp->text);
  i=0;
  while (i<len) {
   res=CheckWord(tmp->text+i);
   if (!res) res++;
   else num_word++;
   i+=res;
  }
  i=0;
  while (i<len) {
   res=CheckSentence(tmp->text+i);
   if (!res) res++;
   else num_sentence++;
   i+=res;
  }
  fprintf(f,"Paragraf %3d: Simvoli=%5d, Dumi=%5d, Izrecheniq=%5d\n",num_paragraph,len,num_word,num_sentence);
  len_all+=len;
  num_word_all+=num_word;
  num_sentence_all+=num_sentence;
  tmp=tmp->next;
 }
 fprintf(f,"\nObshto Paragrafi=%3d: Simvoli=%5d, Dumi=%5d, Izrecheniq=%5d",num_paragraph,len_all,num_word_all,num_sentence_all);
 fclose(f);
 Msg("Faila e zapisan uspeshno!");
}

pWindow CreateWindow(char x,char y,char w,char h,char *n)
{
 pWindow tmp;
 int i;
 if ((tmp=(pWindow)malloc(sizeof(Window)))==NULL) ErrorExit("Nqma pamet!");
 tmp->x=x;
 tmp->y=y;
 if (w>WIN_MAX_WIDTH) tmp->w=WIN_MAX_WIDTH;
 else tmp->w=w;
 if (h>WIN_MAX_HEIGHT) tmp->h=WIN_MAX_HEIGHT;
 else tmp->h=h;
 tmp->name[0]=0;
 if (tmp->w<get_length(n)) i=tmp->w;
 else i=get_length(n);
 copy_string(tmp->name,n,i);
 _fmemcpy(tmp->back,Screen,WIN_BUFFER);
 tmp->pos=-1;
 return tmp;
}

pWindow OpenWindow(char x,char y,char w,char h,char *n)
{
 pWindow tmp;
 tmp=CreateWindow(x,y,w,h,n);
 ShowWindow(tmp);
 return tmp;
}

int InputTextWindow(char x0,char y0,char w,char h,char *n,char *t)
{
 pWindow pw;
 unsigned int key;
 int i=0,k,pos=0;
 char x,y;
 pw=OpenWindow(x0,y0,w,h,n);
 GotoWindow(pw,1,1);
 if (get_length(t)) {
  pos=DrawTextWindow(pw,t);
  i=get_length(t);
  if (pos>0) {
   pos=i-pos;
   ShowWindow(pw);
   GotoWindow(pw,1,1);
   DrawTextWindow(pw,t+pos);
  }
 }
 while (1) {
  ShowCursor(pw);
  while (!is_keypressed());
  HideCursor(pw);
  key=readkey();
  k=i-1;
  switch (key) {
   case KEY_SPC_DEL:
    k=0;
   case KEY_BS:
    if (i)
     for (;i>k;) {
      t[--i]=0;
      if (pos) {
       GotoWindow(pw,1,1);
       DrawTextWindow(pw,t+(--pos));
      } else {
       GetWindowPos(pw,&x,&y);
       if (--x<1) {x=pw->w-1;y--;}
       if (y<1) y=1;
       GotoWindow(pw,x,y);
       DrawTextWindow(pw," ");
       GotoWindow(pw,x,y);
      }
     }
    break;
   case KEY_ESC:
    CloseWindow(&pw);
    return -1;
   case KEY_ENTER:
    t[i]=0;
    CloseWindow(&pw);
    return i;
   default:
    if (i<PAR_TEXT_MAX_LEN-1 && key>=KEY_SPACE && key<=KEY_LAST) {
     t[i++]=(char)key;
     t[i]=0;
     GotoWindow(pw,1,1);
     if (DrawTextWindow(pw,t)>0) {
      pos++;
      ShowWindow(pw);
      GotoWindow(pw,1,1);
      DrawTextWindow(pw,t+pos);
     }
    }
  }
 }
}

void CloseWindow(pWindow *pw)
{
 HideWindow(*pw);
 free(*pw);
 *pw=NULL;
}

void ShowWindow(pWindow pw)
{
 char x,y;
 unsigned char color=win_clr_txt+win_clr_bck*16,color_brd=win_clr_brd+win_clr_bck*16;

 Screen[pw->x+pw->y*80]=toScreen(WIN_UL,color_brd);
 Screen[pw->x+pw->w+pw->y*80]=toScreen(WIN_UR,color_brd);
 Screen[pw->x+(pw->y+pw->h)*80]=toScreen(WIN_DL,color_brd);
 Screen[pw->x+pw->w+(pw->y+pw->h)*80]=toScreen(WIN_DR,color_brd);
 for(x=pw->x+1;x<pw->x+pw->w;x++)
 {
  Screen[x+pw->y*80]=toScreen(WIN_UU,color_brd);
  Screen[x+(pw->y+pw->h)*80]=toScreen(WIN_UU,color_brd);
 }
 for(y=pw->y+1;y<pw->y+pw->h;y++)
 {
  Screen[pw->x+y*80]=toScreen(WIN_DD,color_brd);
  Screen[pw->x+pw->w+y*80]=toScreen(WIN_DD,color_brd);
 }
 fillscreen(pw->x+1,pw->y+1,pw->w-2,pw->h-2,' ',color);

 GotoWindow(pw,(pw->w-get_length(pw->name))/2+1,0);
 DrawTextWindow(pw,pw->name);
}

void HideWindow(pWindow pw)
{
 _fmemcpy(Screen,pw->back,WIN_BUFFER);
}

void GetWindowPos(pWindow pw,char *x,char *y)
{
 *x=pw->pos%80-pw->x;
 *y=pw->pos/80-pw->y;
}

void GotoWindow(pWindow pw,char x,char y)
{
 if (x>pw->w) x=pw->w;
 if (y>pw->h) y=pw->h;
 x+=pw->x;
 y+=pw->y;
 pw->pos=x+y*80;
}

int DrawTextWindow(pWindow pw,const char *s)
{
 unsigned char color=win_clr_txt+win_clr_bck*16;
 int i=0;
 char curx,x,y,maxx,maxy;
 if (s==NULL) return 0;
 curx=x=pw->pos%80;
 maxx=pw->x+pw->w-1;
 y=pw->pos/80;
 maxy=pw->y+pw->h-1;
 if (x>maxx || y>maxy) return -1;
 while(s[i]!=0) {
  Screen[pw->pos++]=toScreen(s[i++],color);
  if (++x>maxx) {
   if (++y>maxy) return i;
   x=curx;
   pw->pos=x+y*80;
  }
 }
 return 0;
}

int DrawLineWindow(pWindow pw,char x,char *y,pParagraph pp,int from)
{
 int len,num,k,pos,i=0,maxx=pw->w-1,maxy=pw->h-1;
 char s[WIN_MAX_LEN];
 char *t;
 if (pp==NULL) return -1;
 t=pp->text+from;
 len=get_length(t);
 while (i<=len) {
  if (*y>maxy) return i;
  if (i+maxx>=len) pos=len-i;
  else pos=maxx;
  num=maxx-pos;//broi dopylnitelni intervali za podravnqvane
  k=0;
  switch (pp->align) {
   case PAR_ALIGN_RIGHT:
    for (;k<num;k++) s[k]=' ';
   case PAR_ALIGN_CENTER:
    for (;k<num/2;k++) s[k]=' ';
    s[k]=0;
    if (ID==pp->id && POS>=from+i && POS<=from+i+pos) {
     CURX=x+k+POS-from-i;
     CURY=*y;
    }
    copy_string(s+k,t+i,pos);
    for (;k<num;k++) s[pos+k]=' ';
    s[pos+k]=0;
    break;
  }
  i+=pos;
  GotoWindow(pw,x,(*y)++);
  DrawTextWindow(pw,s);
  if (i==len) break;
 }
 return 0;
}

void DrawParagraphsWindow(pWindow pw,pParagraph pp,int *id,int *pos)
{
 pParagraph tmp=pp;
 char y=1;
 while (tmp && tmp->id!=*id) tmp=tmp->next;
 while (tmp) {
  *pos=DrawLineWindow(pw,1,&y,tmp,*pos);
  *id=tmp->id;
  if (*pos>0 || (*pos==0 && y>pw->h-1)) break;
  tmp=tmp->next;
 }
}

void ShowCursor(pWindow pw)
{
 Screen[pw->pos]&=0x8FFF;
 Screen[pw->pos]|=(unsigned int)win_clr_cur<<12;
}

void HideCursor(pWindow pw)
{
 Screen[pw->pos]&=0x8FFF;
 Screen[pw->pos]|=(unsigned int)win_clr_bck<<12;
}

int ChooseMenu(char x0,char y0,char w,char h,char *n,const char *t[])
{
 pWindow pw;
 unsigned int key;
 int i,y,pos=1;
 pw=OpenWindow(x0,y0,w,h,n);
 while (1) {
  i=0;
  y=1;
  ShowWindow(pw);
  GotoWindow(pw,1,pos);
  DrawTextWindow(pw,">");
  while (t[i][0]) {
   GotoWindow(pw,2,y++);
   DrawTextWindow(pw,t[i++]);
  }
  GotoWindow(pw,1,pos);
  ShowCursor(pw);
  while (!is_keypressed());
  HideCursor(pw);
  key=readkey();
  switch (key) {
   case KEY_SPC_UP:
    if (pos==1) pos=i;
    else pos--;
    break;
   case KEY_SPC_DOWN:
    if (pos==i) pos=1;
    else pos++;
    break;
   case KEY_ESC:
    pos=0;
   case KEY_ENTER:
    CloseWindow(&pw);
    return pos;
  }
 }
}

void Msg(const char *s)
{
 pWindow pw;
 pw=OpenWindow(8,12,60,8,"Saobshtenie");
 GotoWindow(pw,2,2);
 DrawTextWindow(pw,s);
 readkey();
 CloseWindow(&pw);
}

void ErrorExit(const char *s)
{
 End();
 printf("\n%s",s);
 exit(1);
}

void Begin(void)
{
 _setcursortype(_NOCURSOR);
 _fmemcpy(Backup, Screen, WIN_BUFFER);
}

void End(void)
{
 _setcursortype(_NORMALCURSOR);
 _fmemcpy(Screen, Backup, WIN_BUFFER);
}

void CheckArgs(int argc,char *argv[])
{
 FILE *f;
 unsigned int i;
 if (argc<2 || argc>3 || (argv[1][0]!='C' && argv[1][0]!='R'))
  ErrorExit("Ussage: [Align] [Filename]\n   Align - C (center) or R (right)\n   Filename - text initialisation file\n");
 else {
  if (argv[1][0]=='C') par_align=PAR_ALIGN_CENTER;
  else par_align=PAR_ALIGN_RIGHT;
  if (argc==3 && (f=fopen(argv[2],"rt"))!=NULL) {
   fscanf(f,"%u",&i);
   if (i<=WIN_MAX_WIDTH) win_width=(unsigned char)i;
   fscanf(f,"%u",&i);
   if (i<=WIN_MAX_HEIGHT) win_height=(unsigned char)i;
   fscanf(f,"%u",&i);
   if (i<=15) win_clr_txt=(unsigned char)i;
   fscanf(f,"%u",&i);
   if (i<=7) win_clr_bck=(unsigned char)i;
   fscanf(f,"%u",&i);
   if (i<=7) win_clr_cur=(unsigned char)i;
   fscanf(f,"%u",&i);
   if (i<=7) win_clr_mrk=(unsigned char)i;
   fscanf(f,"%u",&i);
   if (i<=15) win_clr_brd=(unsigned char)i;
   fscanf(f,"%u",&i);
   if (i<=15) win_clr_brdm=(unsigned char)i;
   fclose(f);
 }
}


int move(pWindow pw,pParagraph pp,int type,int *id,int *pos)
{
 pParagraph tmp=pp;
 int l,p,i=0,np1=*pos,np2=-1;
 char *t;
 while (tmp && tmp->id!=*id) tmp=tmp->next;
 if (tmp==NULL) return 0;
 t=tmp->text;
 l=get_length(t);
 while (i<=l) {
  if (i+pw->w-1>=l) p=l-i;
  else p=pw->w-1;
  switch (type) {
   case 1://move +1 y
    if (*pos>=i && ((i+p<l && *pos<i+p) || (i+p==l && *pos<=i+p)))
     if (i+p<l) {
      np1=*pos+p;
      type=2;
     } else
      if (tmp->next) {
       (*id)++;
       (*pos)-=i;
       move(pw,pp,2,id,pos);
       return 1;
      } else return 0;
    break;
   case -1://move -1 y
    if (*pos>=i && ((i+p<l && *pos<i+p) || (i+p==l && *pos<=i+p)))
     if (np2<0)
      if (*id>1) {
       (*id)--;
       (*pos)-=i;
       move(pw,pp,-2,id,pos);
       return 1;
      } else return 0;
     else {
      (*pos)=np2;
      return 1;
     }
    else
     if (*pos-p<i+p) np2=*pos-p;
     else np2=i+p-1;
    break;
   case 2://move +1 id
    if (!l) *pos=0;
    else
     if (np1>=i && ((i+p<l && np1<i+p) || (i+p==l && np1<=i+p))) *pos=np1;
     else *pos=i+p-1;
    return 1;
   case -2://move -1 id
    if (!l) *pos=0;
    else
     if (i+p==l) {
      if (*pos>p) *pos=i+p-1;
      else *pos+=i;
      return 1;
     }
    break;
  }
  i+=p;
  if (i==l) break;
 }
 return 1;
}

/*--------------------------------------------------------------------*/

void main(int argc,char *argv[])
{
 pWindow pw=NULL;
 pParagraph pp=NULL,tmp;
 unsigned int key;
 int choice,i;
 int cur_page_id=ID,cur_id,cur_pos;

 Begin();
 CheckArgs(argc,argv);
 pw=OpenWindow(0,0,win_width,win_height,"Redaktor");
 while (1) {
  if (!cur_page_id) cur_page_id=ID;
  cur_id=cur_page_id;
  cur_pos=0;
  ShowWindow(pw);
  DrawParagraphsWindow(pw,pp,&cur_id,&cur_pos);
  GotoWindow(pw,CURX,CURY);
  ShowCursor(pw);
  while (!is_keypressed());
  HideCursor(pw);
  key=readkey();
  switch (key) {
   case KEY_SPC_F2://File
    choice=ChooseMenu(30,12,20,5,"Fail",MenuFile);
    switch (choice) {
     case 1:
      New(&pp);
      break;
     case 2:
      Load(&pp);
      break;
     case 3:
      if (pp) Save(pp);
      else Msg("Nqma paragrafi!");
      break;
     case 4:
      CloseWindow(&pw);
      End();
      return;
    }
    break;
   case KEY_SPC_C_DEL://Remove Paragraph
    if (ID) {
     RemoveParagraph(&pp,ID);
     if (ID<cur_page_id) cur_page_id=ID;
    }
    break;
   case KEY_SPC_DEL://Delete Symbol current
    if (ID) {
     DeleteSymbol(&pp,ID,POS);
     if (ID<cur_page_id) cur_page_id=ID;
    }
    break;
   case KEY_ENTER://Add Paragraph
    Add(&pp);
    POS=0;
    break;
   case KEY_SPC_C_F1://Save Statistic
    if (pp) SaveStatistic(pp);
    else Msg("Nqma vyvedeni paragrafi!");
    break;
   case KEY_SPC_F11://Window
    choice=ChooseMenu(20,10,40,6,"Prozorec",MenuWindow);
    switch (choice) {
     case 1:
      if (!win_maximize) {
       win_clr=win_clr_brd;
       win_clr_brd=win_clr_brdm;
       win_x=pw->x;
       win_y=pw->y;
       win_w=pw->w;
       win_h=pw->h;
       do {
	ShowWindow(pw);
	while (!is_keypressed());
	HideWindow(pw);
	key=readkey();
	switch (key) {
	 case KEY_SPC_C_UP:
	  if (pw->y>0 && pw->h<WIN_MAX_HEIGHT) {pw->y--;pw->h++;}
	  break;
	 case KEY_SPC_C_DOWN:
	  if (pw->y+pw->h<=WIN_MAX_HEIGHT && pw->h>=WIN_MIN_HEIGHT) {pw->y++;pw->h--;}
	  break;
	 case KEY_SPC_C_LEFT:
	  if (pw->x>0 && pw->w<WIN_MAX_WIDTH) {pw->x--;pw->w++;}
	  break;
	 case KEY_SPC_C_RIGHT:
	  if (pw->x+pw->w<=WIN_MAX_WIDTH && pw->w>=WIN_MIN_WIDTH) {pw->x++;pw->w--;}
	  break;
	 case KEY_SPC_C_A_UP:
	  if (pw->h>=WIN_MIN_HEIGHT) pw->h--;
	  break;
	 case KEY_SPC_C_A_DOWN:
	  if (pw->y+pw->h<WIN_MAX_HEIGHT) pw->h++;
	  break;
	 case KEY_SPC_C_A_LEFT:
	  if (pw->w>=WIN_MIN_WIDTH) pw->w--;
	  break;
	 case KEY_SPC_C_A_RIGHT:
	  if (pw->x+pw->w<WIN_MAX_WIDTH) pw->w++;
	  break;
	}
       } while (key!=KEY_ENTER && key!=KEY_ESC);
       if (key==KEY_ESC) {
	pw->x=win_x;
	pw->y=win_y;
	pw->w=win_w;
	pw->h=win_h;
       } else if (ID) cur_page_id=ID;
       win_clr_brd=win_clr;
      }
      break;
     case 2:
      if (!win_maximize) {
       win_clr=win_clr_brd;
       win_clr_brd=win_clr_brdm;
       win_x=pw->x;
       win_y=pw->y;
       win_w=pw->w;
       win_h=pw->h;
       do {
	ShowWindow(pw);
	while (!is_keypressed());
	HideWindow(pw);
	key=readkey();
	switch (key) {
	 case KEY_SPC_C_UP:
	  if (pw->y>0) pw->y--;
	  break;
	 case KEY_SPC_C_DOWN:
	  if (pw->y+pw->h<WIN_MAX_HEIGHT) pw->y++;
	  break;
	 case KEY_SPC_C_LEFT:
	  if (pw->x>0) pw->x--;
	  break;
	 case KEY_SPC_C_RIGHT:
	  if (pw->x+pw->w<WIN_MAX_WIDTH) pw->x++;
	  break;
	}
       } while (key!=KEY_ENTER && key!=KEY_ESC);
       if (key==KEY_ESC) {
	pw->x=win_x;
	pw->y=win_y;
	pw->w=win_w;
	pw->h=win_h;
       }
       win_clr_brd=win_clr;
      }
      break;
     case 3:
      if (!win_maximize) {
       HideWindow(pw);
       pw->x=(WIN_MAX_WIDTH-pw->w)/2;
       pw->y=(WIN_MAX_HEIGHT-pw->h)/2;
      }
      break;
     case 4:
      if (!win_maximize && (pw->x>0 || pw->y>0 || pw->w<WIN_MAX_WIDTH || pw->h<WIN_MAX_HEIGHT)) {
       HideWindow(pw);
       win_x=pw->x;pw->x=0;
       win_y=pw->y;pw->y=0;
       win_w=pw->w;pw->w=WIN_MAX_WIDTH;
       win_h=pw->h;pw->h=WIN_MAX_HEIGHT;
       win_maximize=1;
      }
      break;
     case 5:
      if (win_maximize) {
       HideWindow(pw);
       pw->x=win_x;
       pw->y=win_y;
       pw->w=win_w;
       pw->h=win_h;
       win_maximize=0;
      }
      break;
    }
    break;
   case KEY_SPC_PG_UP://Previous Paragraph
    if (ID>1) ID--;
    POS=0;
    if (ID && ID<cur_page_id) cur_page_id=ID;
    break;
   case KEY_SPC_PG_DN://Next Paragraph
    if (pp) {
     tmp=pp;
     while (tmp->next) tmp=tmp->next;
     if (ID<tmp->id) ID++;
     POS=0;
     while (ID>cur_id) {
      cur_page_id++;
      cur_id=cur_page_id;
      cur_pos=0;
      DrawParagraphsWindow(pw,pp,&cur_id,&cur_pos);
     }
    }
    break;
   case KEY_SPC_C_HOME://Begin Paragraph
    if (ID) POS=0;
    break;
   case KEY_SPC_C_END://End Paragraph
    if (ID) {
     tmp=pp;
     while (tmp->id!=ID) tmp=tmp->next;
     if (tmp) POS=get_length(tmp->text)-1;
     if (POS<0) POS=0;
     if (ID==cur_id)
      while (cur_pos && POS>=cur_pos) {
       cur_page_id++;
       cur_id=cur_page_id;
       cur_pos=0;
       DrawParagraphsWindow(pw,pp,&cur_id,&cur_pos);
      }
    }
    break;
   case KEY_BS://Delete Symbol previous
    if (ID && POS) {
     if (DeleteSymbol(&pp,ID,POS-1)) break;
     if (!ID) cur_page_id=ID;
    } else break;
   case KEY_SPC_LEFT://Move Cursor left
    if (ID && POS) POS--;
    break;
   case KEY_SPC_RIGHT://Move Cursor right
    if (ID) {
     tmp=pp;
     while (tmp->id!=ID) tmp=tmp->next;
     if (tmp && POS<get_length(tmp->text)-1) POS++;
     if (ID==cur_id && cur_pos && POS>=cur_pos) cur_page_id++;
    }
    break;
   case KEY_SPC_DOWN://Move Cursor down
    if (ID && move(pw,pp,1,&ID,&POS))
     if (ID>cur_id || (ID==cur_id && cur_pos && POS>=cur_pos)) cur_page_id++;
    break;
   case KEY_SPC_UP://Move Cursor up
    if (ID && move(pw,pp,-1,&ID,&POS))
     if (ID<cur_page_id) cur_page_id=ID;
    break;
  }
 }
}