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

#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 PAR_TEXT_MAX_LEN  601

#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_F7         65*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_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];
} 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(const char *t);
char* copy_string(char *dest,char *src,int num);
char* to_string(char *str,int num);
int find_string(char *str,char *t);

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);
int get_before_paragraph(pParagraph pp,int id,pParagraph *res);
int get_next_paragraph(pParagraph pp,pParagraph *res);
int get_last_paragraph(pParagraph pp,pParagraph *res);
void recalc_paragraph(pParagraph pp);
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);
int Search(pParagraph pp,int *id,int *pos,char *txt);

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* Menu=" Fail  Tyrsene  Prozorec ";
const char* MenuFile[]={"Nov","Procheti","Zapomni","Krai",""};
const char* MenuSearch[]={"Tyrsene","Zamqna","Zamqna vsichki",""};
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 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(const 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 find_string(char *str,char *t)
{
 int i=0,j;
 if (t[0]==0) return 0;
 while (str[i]) {
  j=0;
  while (str[i+j] && t[j] && str[i+j]==t[j++]);
  if (t[j]==0 && str[i+j-1]==t[j-1]) return i;
  i++;
 }
 return -1;
}

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;
}

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

int get_next_paragraph(pParagraph pp,pParagraph *res)
{
 if (pp==NULL) return 0;
 if (*res==NULL) *res=pp;
 else *res=(*res)->next;
 if (*res==NULL) return 0;
 else return 1;
}

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

void recalc_paragraph(pParagraph pp)
{
 pParagraph tmp=pp;
 int i=1;
 while (tmp) {
  tmp->id=i++;
  tmp=tmp->next;
 }
}

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

void RemoveParagraph(pParagraph *pp,int id)
{
 pParagraph tmp,tmp2;
 if (!get_paragraph(*pp,id,&tmp2)) return;
 if (*pp==tmp2) {
  *pp=tmp2->next;
 } else {
  get_before_paragraph(*pp,id,&tmp);
  tmp->next=tmp2->next;
 }
 recalc_paragraph(*pp);
 free(tmp2);
 if (id==ID) {
  if (!get_last_paragraph(*pp,&tmp)) ID=0;
  else
   if (ID>tmp->id) ID=tmp->id;
  POS=0;
 }
}

int DeleteSymbol(pParagraph *pp,int id,int pos)
{
 pParagraph tmp;
 int len;
 get_paragraph(*pp,id,&tmp);
 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=NULL;
 char temp[PAR_TEXT_MAX_LEN]="";
 if (pp==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 (get_next_paragraph(pp,&tmp)) {
  if (tmp->text) fputs(tmp->text,f);
  if (tmp->next) fputs("\n",f);
 }
 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+1,temp);
 if (!ID) {
  ID++;
  POS=0;
 }
 return 1;
}

int Search(pParagraph pp,int *id,int *pos,char *txt)
{
 pParagraph tmp;
 int cur=*pos,res;
 char *t;
 if (pp==NULL) return 0;
 get_paragraph(pp,*id,&tmp);
 if (tmp)
  do {
   t=tmp->text+cur;
   res=find_string(t,txt);
   if (res>=0) {
    *id=tmp->id;
    *pos=cur+res;
    return 1;
   }
   cur=0;
  } while (get_next_paragraph(pp,&tmp));
 return 0;
}

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+1;
   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,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;
  if (ID==pp->id && POS>=from+i && POS<=from+i+pos) {
   CURX=x+POS-from-i;
   CURY=*y;
  }
  copy_string(s,t+i,pos);
  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;
 char y=1;
 get_paragraph(pp,*id,&tmp);
 if (tmp)
  do {
   *pos=DrawLineWindow(pw,1,&y,tmp,*pos);
   *id=tmp->id;
   if (*pos>0 || (*pos==0 && y>pw->h-1)) break;
  } while (get_next_paragraph(pp,&tmp));
}

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;
 unsigned char txt=win_clr_txt,bck=win_clr_bck,cur=win_clr_cur;
 if (!n[0]) {
  win_clr_txt=BLACK;
  win_clr_bck=LIGHTGRAY;
  win_clr_cur=GREEN;
  pw=OpenWindow(x0,y0+1,w,h,"");
  for (i=0,y=get_length(Menu);i<80;i++)
   if (i>=4 && i<4+y) Screen[i+y0*80]=toScreen(Menu[i-4],win_clr_txt+win_clr_bck*16);
   else Screen[i+y0*80]=toScreen(' ',win_clr_txt+win_clr_bck*16);
 } else pw=OpenWindow(x0,y0,w,h,n);
 while (1) {
  i=0;
  y=1;
  ShowWindow(pw);
  GotoWindow(pw,1,pos);
  if (n[0]) DrawTextWindow(pw,">");
  while (t[i][0]) {
   GotoWindow(pw,2,y++);
   DrawTextWindow(pw,t[i++]);
  }
  GotoWindow(pw,1,pos);
  if (!n[0]) for (y=0;y<w-1;y++) {ShowCursor(pw);pw->pos++;}
  else ShowCursor(pw);
  while (!is_keypressed());
  if (n[0]) 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);
    if (!n[0]) {
     win_clr_txt=txt;
     win_clr_bck=bck;
     win_clr_cur=cur;
    }
    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) ErrorExit("Ussage: [Filename]\n   Filename - text initialisation file\n");
 else
  if (argc==2 && (f=fopen(argv[1],"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;
 int l,p,i=0,np1=*pos,np2=-1;
 char *t;
 if (!get_paragraph(pp,*id,&tmp)) 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 (get_next_paragraph(pp,&tmp)) {
       (*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;
   char text1[PAR_TEXT_MAX_LEN]="";
   char text2[PAR_TEXT_MAX_LEN]="";
 char search_txt[PAR_TEXT_MAX_LEN]="";
 char temp_txt[PAR_TEXT_MAX_LEN]="";
 char temp_txt2[PAR_TEXT_MAX_LEN]="";
 char temp_txt3[PAR_TEXT_MAX_LEN]="";
 unsigned int key;
 int choice,i,j,n,l,c,index;
 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(4,0,20,5,"",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
   if (ID && POS)
	{
		for (index=0;index<POS;index++)
			text1[index]=tmp->text[index];
		strcpy(text2,(tmp->text)+POS);
		RemoveParagraph(&pp,ID);
		AddParagraph(&pp,ID+1,text1);
		AddParagraph(&pp,ID+1,text2);strcpy(text2,"");
		strcpy(text1,"");
        POS=0;

	} else
	{Add(&pp);                                           //enter za paragraf
	POS=0;}
    break;
   case KEY_SPC_F7://Search
    choice=ChooseMenu(10,0,20,4,"",MenuSearch);
    switch (choice) {
     case 1://Search
      cur_id=ID;
      cur_pos=POS;
      search_txt[0]=0;
      if (InputTextWindow(10,10,60,5,"Vyvedete tekst",search_txt)>0)
       if (Search(pp,&cur_id,&cur_pos,search_txt)) {
	ID=cur_id;
	POS=cur_pos;
	cur_page_id=ID;
       } else Msg("Teksta ne e nameren!");
      break;
     case 2://Replace
      cur_id=ID;
      cur_pos=POS;
      temp_txt[0]=0;
      if (InputTextWindow(10,10,60,5,"Vyvedete tekst za tyrsene",temp_txt)>0)
       if (Search(pp,&cur_id,&cur_pos,temp_txt) && get_paragraph(pp,cur_id,&tmp)) {
	l=get_length(tmp->text);
	i=get_length(temp_txt);
	temp_txt[0]=0;
	if (InputTextWindow(10,10,60,5,"Vyvedete tekst za zamqna",temp_txt)>0) {
	 n=get_length(temp_txt);
	 if (l-i+n>PAR_TEXT_MAX_LEN) Msg("Niza za zamqna e prekaleno golqm!");
	 else {
	  copy_string(temp_txt2,tmp->text,cur_pos);
	  copy_string(temp_txt2+cur_pos,temp_txt,n);
	  copy_string(temp_txt2+cur_pos+n,tmp->text+cur_pos+i,l-cur_pos-i);
	  copy_string(tmp->text,temp_txt2,0);
	  temp_txt2[0]=0;
	 }
	}
       } else Msg("Teksta ne e nameren!");
      temp_txt[0]=0;
      break;
     case 3://Replace All
      cur_id=1;
      cur_pos=0;
      temp_txt[0]=0;
      if (InputTextWindow(10,10,60,5,"Vyvedete tekst za tyrsene",temp_txt)>0) {
       j=c=0;
       temp_txt3[0]=0;
       if (InputTextWindow(10,10,60,5,"Vyvedete tekst za zamqna",temp_txt3)>0)
	while (Search(pp,&cur_id,&cur_pos,temp_txt) && get_paragraph(pp,cur_id,&tmp)) {
	 l=get_length(tmp->text);
	 i=get_length(temp_txt);
	 n=get_length(temp_txt3);
	 if (l-i+n<=PAR_TEXT_MAX_LEN) {
	  copy_string(temp_txt2,tmp->text,cur_pos);
	  copy_string(temp_txt2+cur_pos,temp_txt3,n);
	  copy_string(temp_txt2+cur_pos+n,tmp->text+cur_pos+i,l-cur_pos-i);
	  copy_string(tmp->text,temp_txt2,0);
	  temp_txt2[0]=0;
	  cur_pos+=n;
	 } else {
	  j++;
	  cur_pos++;
	 }
	 c++;
	}
       temp_txt[0]=0;
       if (c) {
	if (c-j) {
	 copy_string(temp_txt," Teksta e zamenen na ",0);
	 to_string(temp_txt+get_length(temp_txt),c-j);
	 copy_string(temp_txt+get_length(temp_txt)," mesta!",0);
	}
	if (j) {
	 copy_string(temp_txt+get_length(temp_txt)," Niza za zamqna e prekaleno golqm na ",0);
	 to_string(temp_txt+get_length(temp_txt),j);
	 copy_string(temp_txt+get_length(temp_txt)," mesta!",0);
	}
	Msg(temp_txt);
       } else Msg("Teksta ne e nameren!");
       temp_txt3[0]=0;
      }
      temp_txt[0]=0;
      break;
    }
    break;
   case KEY_SPC_F11://Window
    choice=ChooseMenu(19,0,20,6,"",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 && get_paragraph(pp,ID,&tmp)) {
     if (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;
  }
 }
}