/*******************************************************************/
//              "Меркурий"-"Правда" - open source переводчик
//          распространяется в соответсвии с лицензией GNU v 2.0
//
//                   Ввод новых слов и выражений
//      Анисимов Д.В.                               сегодня
/*******************************************************************/

# include <string.h>
# include "video.h"
# include "color.h"
# include "face.h"
# include <word.h>

extern t_NewWord NewWord ;
extern char      MercuryDir[] ;

e_WinMsg line_edit( short x, short y, char f, char *Str, short Length )
;

/************************************************************************/
t_NewWord :: t_NewWord( )
{  Mass=NULL ;
   j_Mass=n_Mass=z_Mass=0 ;

}
/************************************************************************/
t_NewWord :: ~t_NewWord( )
{  Free( Mass );
}
/************************************************************************/

void t_NewWord :: add( char *str )
{  long  L,N ;
   char *M ;

   L=strlen( str );
   if( n_Mass<j_Mass+L+2 )
   {   N=max(n_Mass/4,L+2);
       M=(char *)realloc( Mass,(n_Mass+N)*sizeof(char) );
       if( M==NULL ) return ;
       Mass=M ; n_Mass+=N ;
   }
   strcpy( Mass+j_Mass,str );
   strcpy( Mass+j_Mass+L,"\n" );
   j_Mass+=L+1 ;
}
/************************************************************************/
char 
* t_NewWord :: get_all( void )
{
   return Mass ;
}
/************************************************************************/
char 
* t_NewWord :: get_new( void )
{
   return Mass+z_Mass ;
}
/************************************************************************/

void t_NewWord :: remember( )
{
    z_Mass=j_Mass ;
}
/************************************************************************/
int tagsort1( const void *a, const void *b )
{  short i1,i2 ;
   char  s1[3],s2[3] ;
   t_Format1  *FF=&Grammar.format1()[0] ;

   i1=*(short *)a ;
   i2=*(short *)b ;
   strcpy( s1,FF->get_tag(0,i1) );
   strcpy( s2,FF->get_tag(0,i2) );
   return strcmp( s1,s2 );
}
/************************************************************************/
int tagsort2( const void *a, const void *b )
{  short i1,i2 ;
   char  s1[3],s2[3] ;
   t_Format1  *FF=&Grammar.format1()[0] ;

   i1=*(short *)a ;
   i2=*(short *)b ;
   strcpy( s1,FF->get_tag(1,i1) );
   strcpy( s2,FF->get_tag(1,i2) );
   return strcmp( s1,s2 );

}
/************************************************************************/
t_AddWord :: t_AddWord()
{
   sStr [0]=dStr [0]=0 ;
   sStr1[0]=dStr1[0]=0 ;
   sStr2[0]=dStr2[0]=0 ;
   j_Sou=j_Dst=0 ;
   s_i_struct=d_i_struct=-1 ;
}
/************************************************************************/
//   рассортировать структуры на головные и телесные
/************************************************************************/

void t_AddWord :: init( void )
{
   short  i,i_struct ;
   e_Type t ;
   
   FF=&Grammar.format1()[0] ;

   sWord.j=dWord.j=sStruct.j=dStruct.j=0 ;
   
   sWord.add( i_struct=-1 );
   for( i=0 ; i<FF->SouPart.j ; i++ )
   {  i_struct=FF->SouPart[i].i_part ;
      t=Grammar[i_struct].From.type ;
      if( t==TNULL || t==TCONST || t==TCONST1 || t==TWORD0 ) continue ;
      if( t==TWORD || t==TSTRUCT || t==TSELECT || t==TSELECT1 || t==TSELECT2 )
      {   sWord.add( i_struct );  }
      if( t==TWORD || t==TSTRUCT1 || t==TSTRUCT2 )
      {   sStruct.add( i_struct );  }
   }
   qsort( sWord.list  , sWord.j   ,sizeof(short),tagsort1 );
   qsort( sStruct.list, sStruct.j ,sizeof(short),tagsort1 );

   dWord.add( i_struct=-1 );
   for( i=0 ; i<FF->DstPart.j ; i++ )
   {  i_struct=FF->DstPart[i].i_part ;
      t=Grammar[i_struct].To.type ;
      if( t==TNULL || t==TCONST || t==TCONST1 || t==TWORD0 ) continue ;
      if( t==TWORD || t==TSTRUCT || t==TSELECT || t==TSELECT1 || t==TSELECT2 )
      {   dWord.add( i_struct );  }
      if( t==TWORD || t==TSTRUCT1 || t==TSTRUCT2 )
      {   dStruct.add( i_struct );  }
   }
   qsort( dWord.list  , dWord.j   ,sizeof(short),tagsort2 );
   qsort( dStruct.list, dStruct.j ,sizeof(short),tagsort2 );
}
/************************************************************************/

void t_AddWord :: init1( void )
{
// sStr [0]=0 ;
   dStr [0]=0 ;
   sStr1[0]=dStr1[0]=0 ;
   sStr2[0]=dStr2[0]=0 ;
   j_Sou=j_Dst=0 ;
   s_i_struct=d_i_struct=-1 ;
}
/************************************************************************/

void t_AddWord :: make_str( char *S )
{
   strcpy( sStr,S );
}
/************************************************************************/
//  разбить фразу на слова, сделать Sou
/************************************************************************/

void t_AddWord :: make_str1( char to )
{  short    i,j,j1,j_Str ;
   char    *sdStr,*sdStr1 ;
   t_sWord *WW ;
   char     Str[100] ;

   if( to==0 ){  sdStr =sStr ; sdStr1=sStr1 ;  WW=&Sou[0] ;  }
       else   {  sdStr =dStr ; sdStr1=dStr1 ;  WW=&Dst[0] ;  }

   for( i=j=j1=j_Str=0 ; i<200 ; i++ )
   {  
      if( (sdStr[i]==' ' || sdStr[i]==0) && 0<j )
      {  Str[j]=0 ;
         WW[j1].i_struct=-1 ;
	 WW[j1++].str   =sdStr1+j_Str ;
	 strcpy( sdStr1+j_Str,Str );
	 sdStr1[j_Str+j]=0 ;
	 j_Str+=j+1 ;
         j=0 ;
	 if( sdStr[i]==0 ) break ;
	 continue ;
      }    
      Str[j++]=sdStr[i] ;   
   }
   if( to==0 ) j_Sou=j1 ;
       else    j_Dst=j1 ;
}
/************************************************************************/
//   сделать строку с тегами
/************************************************************************/

void t_AddWord :: make_str2( void )
{
   long  i ;
   t_Format1  FFF=Grammar.format1()[0] ;
   char  Str1[100] ;
   
   sStr2[0]=0 ;
   for( i=0 ; i<j_Sou ; i++ )
   {
      sprintf( Str1,"%s[%s]", FFF.get_tag( 0,Sou[i].i_struct ),Sou[i].str );
      strcat( sStr2,Str1 ); strcat( sStr2," " );
   }
}
/************************************************************************/
//  нарисовать теги и структуры
/************************************************************************/

void t_AddWord :: paint_struct( t_shortList &List, char to, short current )
{  short i,i1,begin,size_y1,i_struct ;
   char  f,*s ;
   t_Struct *SS ;
   char  Str[100] ;

   size_y1=y2-y1-11 ;
   begin=0 ;
   if( begin+size_y1<=current ) begin=current-size_y1 ;
   for( i=0 ; begin+i<List.j && i<=size_y1 ; i++ )
   {  if( begin+i==current ) f=0xf0 ; else f=0x0f ;
      i_struct=List[begin+i] ;
      if( 0<=i_struct )
      {	  if( to==0 ) SS=&Grammar[i_struct].From ;
              else    SS=&Grammar[i_struct].To ;
      }
      if( i_struct<0 ) s="константа" ; else s=SS->Name ;
      sprintf( Str," %2s  %s",FF->get_tag(to,i_struct),s );
      if( SS->type==TSTRUCT1 )
      {   strcat( Str, " =" );
	  for( i1=0 ; i1<SS->Word.j ; i1++ )
	  {  strcat( Str, " " );
             strcat( Str, FF->get_tag(to,SS->Word[i1].i_struct) );
	  }
      }
      s_text_yxf( y1+10+i,3,f,Str );
   }
}
/************************************************************************/

void t_AddWord :: paint( void )
{
   t_Win::paint();
   s_rame2_F( y1-1, x1-1, y2+1, x2+1, 0x0f );
   s_text_yxf( y1-1,x1+3 ,name_Color, Name );

   s_rame2_F ( y1  ,x1   ,y1+2, x2, 0x0f );
   s_text_yxf( y1  ,x1+3 ,0x0f, "Выражение источника" );
   if( Reg<=2 ) s_text_yxf( y1+1,x1+3 ,0x0f, sStr );
       else     s_text_yxf( y1+1,x1+3 ,0x0f, sStr2 );
   s_rame2_F ( y1+3,x1   ,y1+5, x2, 0x0f );
   s_text_yxf( y1+3,x1+3 ,0x0f, "Выражение приемника" );
   s_text_yxf( y1+4,x1+3 ,0x0f, dStr );
   s_rame2_F ( y1+6,x1   ,y1+8, x2, 0x0f );
   s_text_yxf( y1+6,x1+3 ,0x0f, "Предполагаемый тег" );
   s_rame2_F ( y1+9,x1   ,y2, x2, 0x0f );
   s_text_yxf( y1+9,x1+3 ,0x0f, "Часть речи" );
   
}
/************************************************************************/

void t_AddWord :: paint_from( long i_Word )
{  short i,z ;
   char  Str[100] ;
   uchar  f[16]={ 0xf0 };

   z=0 ;
   sprintf( sStr2,"%2s:",FF->get_tag( 0,s_i_struct ) );
   for( i=0 ; i<j_Sou ; i++ )
   {  if( i_Word==i+1 ) z=strlen(sStr2)+1 ;
      sprintf(Str," %2s[%s]",FF->get_tag( 0, Sou[i].i_struct ),Sou[i].str );
      strcat( sStr2,Str );
   }
   s_text_yxf( y1+1, x1+3 ,0x0f, sStr2 );
   s_color_yxt( y1+1, x1+3+z, f , "00" );
}
/************************************************************************/

void t_AddWord :: paint_to( long i_Word )
{  short i,z ;
   char  Str[100] ;
   uchar  f[16]={ 0xf0 };

   z=0 ;
   sprintf( dStr2,"%2s:",FF->get_tag( 1,d_i_struct ) );
   for( i=0 ; i<j_Dst ; i++ )
   {  if( i_Word==i+1 ) z=strlen(sStr2)+1 ;
      sprintf(Str," %2s[%s]",FF->get_tag( 1, Dst[i].i_struct ),Dst[i].str );
      strcat( dStr2,Str );
   }
   s_text_yxf( y1+4, x1+3 ,0x0f, dStr2 );
   s_color_yxt( y1+1, x1+3+z, f , "00" );
}
/************************************************************************/

e_WinMsg t_AddWord :: loop( void )
{
   e_WinMsg r ;
   
   Reg=1 ;
   init(  );
   init1(  );

   while( 1 )
   {
      paint( );
      switch( Reg )
      {
         case 1 : r=line_edit( x1+1,y1+1,0x1f,sStr,x2-x1-1 ); 
	          make_str1( 0 ); break ;
	 case 2 : r=tag_edit1( 0 ); break ;
	 case 3 : paint_from( -1 );
	          r=line_edit( x1+1,y1+4,0x1f,dStr,x2-x1-1 ); 
	          make_str1( 1 ); break ;
	 case 4 : r=tag_edit1( 1 ); break ;
      }
      switch( r )
      {
	 case WM_NEXT : case WM_OK :
            if( Reg==4 ) goto M_End ;
	        else  Reg++ ;
            break ;
         case WM_PREV : case WM_ESC :
            if( Reg==1 ) return WM_ESC ;
	        else  Reg-- ;
            break ;
      }
   }
M_End:

   NewWord.add( antwort() );
   message("Идет обновление словаря.\n        Ждите...");

   Perevod.add_new( filename( MercuryDir,"dicts") ,NewWord.get_all() );
   return WM_OK ;
}
/************************************************************************/
e_WinMsg line_edit( short x, short y, char f, char *Str, short Length )
{  e_WinMsg r ;


M1:r=kommand_yxf( y, x, f, Str, Length, 0x01, NULL, 0 );

   switch( r )
   {  case WM_HELP : Window_help( (void *)"newwords.html") ; goto M1;
      case WM_PREV : case WM_NEXT : case WM_ESC : case WM_OK :
                     return r ;
   }
   return WM_ESC ;
}
/************************************************************************/

e_WinMsg t_AddWord :: tag_edit1( char to )
{
   short       i,i_struct,*sd_i_struct,i_Word,n_Word ; 
   t_shortList *Struct ; 
   t_shortList *Word ; 
   t_sWord     *WW ;
   t_Struct    *SS ;
   e_WinMsg     r ;
   e_Type       t ;

   if( 0==to  ) 
   {  n_Word= j_Sou ;      
      Struct=&sStruct ;
      Word  =&sWord ; 
      WW    = Sou ;
      sd_i_struct=&s_i_struct ;

      sStruct1.j=0 ;
      for( i=0 ; i<sStruct.j ; i++ )
      {  t=Grammar[sStruct[i]].From.type ;
	 if( (t==TSTRUCT1 && Grammar[sStruct[i]].From.Word.j==n_Word) ||
             (t==TWORD    && n_Word==1 ) || t==TSTRUCT2 )
             sStruct1.add( sStruct[i] );
      }
      Struct=&sStruct1 ;
   }
   else
   {  n_Word= j_Dst ;
      Struct=&dStruct ;
      Word  =&dWord ;
      WW    = Dst ;
      sd_i_struct=&d_i_struct ;

      dStruct1.j=0 ;
      for( i=0 ; i<dStruct.j ; i++ )
      {  t=Grammar[dStruct[i]].To.type ;
	 if( (t==TSTRUCT1 && Grammar[dStruct[i]].To.Word.j==n_Word) ||
             (t==TWORD    && n_Word==1 ) || t==TSTRUCT2 )
             dStruct1.add( dStruct[i] );
      }
      Struct=&dStruct1 ;
      if( Grammar[s_i_struct].From.type==TWORD )
          WW[0].i_struct=d_i_struct=s_i_struct ;
   }
   i_Word=0 ;
   
   while( 1 )
   {
      if( 0==to ) paint_from( i_Word );
          else    paint_to  ( i_Word );

      if( i_Word==0 ) r=tag_edit( *Struct, to, i_Word, i_struct );
          else        r=tag_edit( *Word  , to, i_Word, i_struct );

      switch( r )
      {
	 case WM_NEXT : case WM_OK :
	    if( 0<i_Word ) 
	        WW[i_Word-1].i_struct=i_struct ;
	    else 
	    {  *sd_i_struct=i_struct ;
	       if( 0==to ) SS=&Grammar[i_struct].From ;
	           else    SS=&Grammar[i_struct].To ;
	       if( SS->type==TSTRUCT1 )
	       {   for( i=0 ; i<SS->Word.j ; i++ )
	              WW[i].i_struct=SS->Word[i].i_struct ;
	       }
	       if( SS->type==TWORD )
	       {   WW[0].i_struct=i_struct ;  }
	    }
            if( n_Word<=i_Word ) goto M_End ;
	    i_Word++ ;	    
            break ;
         case WM_PREV : case WM_ESC :
            if( i_Word<=0 ) return WM_ESC ;
	        else  i_Word-- ;
            break ;
      }
   }
M_End: ;
   return WM_OK ;
}
/************************************************************************/

e_WinMsg t_AddWord :: tag_edit( t_shortList &List, char to, short i_Word, 
                      short &i_struct )
{
   t_Format1  *FFF=&Grammar.format1()[0] ;
   char  Tag[10]="",*s ;
   short i,z,jTag=0,current ;
   short key1,key2 ;

   if( to==0 ){ if( i_Word==0 ) z=s_i_struct ; else z=Sou[i_Word-1].i_struct ; }
       else   { if( i_Word==0 ) z=d_i_struct ; else z=Dst[i_Word-1].i_struct ; }
   current=find( List,z ) ;
   if( current<0 ) current=0 ;

   while( 1 )
   {
      paint();
      if( 0==to ) paint_from( i_Word );
          else    paint_to  ( i_Word );
      s_text_yxf( y1+7,3,0x0b,Tag );
      paint_struct( List, to, current );

      s_getch( &key1,&key2 );

      if( key1==0 )
      {  switch(key2)
	 {
	    case S_key_F1   :  Window_help( (void *)"newwords.html") ; continue ;
	    case S_key_Left :  return WM_PREV ;
	    case S_key_Right:  goto M_End ;
	    case S_key_Up   :  if( 0<current        ) current-- ; break ;
	    case S_key_Down :  if( current<List.j-1 ) current++ ; break ;
	 }
      }
      else
      {  switch( key1 )
	 {  case  S_key_Back : if( 0<jTag ) Tag[--jTag]=0 ; break ;

	    case '\r'     : goto M_End ;
	    case S_key_Esc: return WM_ESC ;
	    default:  
	       Tag[jTag++]=key1 ; 
	       Tag[jTag]=0 ;
               for( i=0 ; i<List.j ; i++ )
	       {  s=FFF->get_tag( to,List[i] );
	          if( 0==strncmp(Tag,s,jTag ) )
		  {   current=i ; goto M_Ok ; }
	       }
               Tag[--jTag]=0 ;
	       M_Ok : ;
	       if( 2<=jTag ) goto M_End ;
         }
      }
   }
   M_End :
   i_struct=List[current] ;
   return WM_OK ;
}
/************************************************************************/

short  t_AddWord :: find( t_shortList &List, short z )
{  short i ;
   for( i=0 ; i<List.j ; i++ )
      if( List[i]==z ) return i ;
   return -1 ;
}
/************************************************************************/
char 
* t_AddWord :: antwort( void )
{  long i ;
   sprintf( Antwort,"%s=%s",sStr2,dStr2 );
   for( i=0 ; i<200 && Antwort[i]!=0 ; i++ )
      if( Antwort[i]=='@' && Antwort[i+1]=='1' )
          Antwort[i+1]='0' ;
   return Antwort;
}