/****************************************************************************/
//              "Меркурий"-"Правда" - open source переводчик
//          распространяется в соответсвии с лицензией GNU v 2.0
//
//                         Грамматический словарь
//       Анисимов Д.В.                                    сегодня
/****************************************************************************/
# include <stdio.h>
# include <string.h>
# include <stdlib.h>
# include <mylib.h>
# include <slowo2.h>


struct t_Sort
{   long  i ;
    char *s ;
};

t_Form Form0 
;
//uchar *SC ;

/****************************************************************************/
//                     инициировать нулями
/****************************************************************************/
t_Slowo2 :: t_Slowo2( void )
{
   Lang   =NULL ;
   Format =NULL ;

   n_Word=0 ;
   n_Form=0 ;
   Mass=NULL ;
   Word=NULL ;
   reverce=NULL ;
   Form0.init();
}
/***************************************************************************/
//                     установить Lang и формат
/***************************************************************************/

void t_Slowo2 :: set_lf( t_Lang *_Lang, t_Format *_Format )
{
   Lang  = _Lang ;
   Format= _Format ;
}
/***************************************************************************/
//              сравнить два слова из словаря (для сортировки)
/***************************************************************************/
int wordcmp( const void *s1, const void *s2 )
{
   return Strcmp( ((t_Sort *)s1)->s,((t_Sort *)s2)->s );
}
/***************************************************************************/
//             прочесть словарь из файла в соответствии с форматом
//   File    - имя файла
//   Lang    - язык (источник или приемник), которому принадлежит словарь
//   _Format - формат, которому соответствует этот язык
/***************************************************************************/

void t_Slowo2 :: read( char *File, t_Lang *_Lang, t_Format *_Format )
{
   FILE *fr ;
   long  i,i1,j,z,L ;
   char *Str ;
   t_Lexer Lexer ;
   t_Sort *ss ;
try
{
   //SC = SortChar();
   Lang  = _Lang ;
   Format= _Format ;

   n_Form=Format->Record.j ;

   fr=Fopen( File,"r" );
   L=FileLength( fr );

   Mass=(char   *)Calloc( L,sizeof(char) );
   Fread( Mass,L,sizeof(char),fr );

   Lexer.clr_breaker(  );
   Lexer.init( Mass,L );
   Lexer.remark();
   Lexer.make_words();

   for( i=0,n_Word=0 ; i<Lexer.n_Word ; i++ )
      if( ';'==Lexer.Word[i][0] ) n_Word++ ;

   Word=(long   *)Calloc( n_Word*n_Form,sizeof(long) );

   // ---- отсортировать строки по алфавиту -----
   ss=(t_Sort *)Malloc( n_Word,sizeof(t_Sort) );
   for( i=0 ; i<n_Word ; i++ )
   {  ss[i].i=i*(n_Form+1) ;
      ss[i].s=Lexer.Word[i*(n_Form+1)] ;
   }
   qsort( ss,n_Word,sizeof(t_Sort),wordcmp );

   for( i=z=0 ; i<n_Word ; i++ )
   {  for( i1=j=0 ; i1<n_Form+2 ; i1++ )
      {
         Str=Lexer.Word[ ss[i].i+i1 ] ;
	 if( 0==strcmp(Str,";") )
	 {   if( n_Form!=j )
	     {   fprintf( File_Error,"\n Че-то странное с форматом %s",File );
	         fprintf( File_Error,"\n Строка \"%s\" дурит",Mass+Word[i*n_Form] ); 
		 throw(-1);
             }
	     break ;
	 }
	 // --------------- чтение слова ---------------
	 Word[i*n_Form+j] = z ;
	 strcpy( Mass+z,Str );
	 z+=strlen( Str )+1 ;
	 j++ ;
      }
   }
   Free( ss );
}
catch( int E )
{  
   fprintf( File_Error,"\n Ребята, че-то я словарь %s не могу прочесть.",File );
   if( E==Err_Fopen ) fprintf( File_Error,"\n А он вообще-то есть?" );
   throw( E );
}
}
/***************************************************************************/
//    построить таблицы для поиска слов, заданных не в начальной форме
/***************************************************************************/

void t_Slowo2 :: freverce( void )
{  long i,n_All ;
   t_Sort *ss ;

   // ---- отсортировать строки по алфавиту -----
   n_All=n_Word*n_Form ;
   ss=(t_Sort *)Malloc( n_All,sizeof(t_Sort) );
   for( i=0 ; i<n_All ; i++ )
   {  ss[i].i=i ;
      ss[i].s=Mass+Word[i] ;
   }
   qsort( ss,n_All,sizeof(t_Sort),wordcmp );
   reverce=(long *)Malloc( n_All,sizeof(long) );
   for( i=0 ; i<n_All ; i++ )
      reverce[i]=ss[i].i ;
   Free( ss );
}
/***************************************************************************/
//                  вернуть слово в начальной форме
//    index - индекс слова (строки)
/***************************************************************************/
char 
* t_Slowo2 :: normal( long index )
{
   return Mass + Word[index*n_Form] ;
}
/***************************************************************************/
//                  вернуть слово в заданной форме
//    index - индекс слова (строки)
//    Form  - форма слова
/***************************************************************************/
char 
* t_Slowo2 :: form( long index, t_Form *Form )
{  long i,i1,i_Form ;
   t_Form       *R ;
   t_Param1List *Param ;

   Param=&Lang->Part[Format->i_part].Param ; // параметры этой части речи

   i_Form=0 ;
   for( i=0 ; i<Format->Record.j ; i++ )
   {  R=&Format->Record[i] ;
      for( i1=0 ; i1<Param->j ; i1++ )
         if( Param->list[i1].Dir==0 &&  // переменный параметр слова
	     Form->value[i1]>=0 &&      // параметр задан в конструкции
	     R->value[i1]>=0 &&         // параметр задан в словаре 
	     Form->value[i1]!=R->value[i1] ) // параметр не соответствует 
	     goto M_No;
      i_Form=i ; break ;
      M_No:;
   }
   return Mass + Word[index*n_Form+i_Form] ;
}
/***************************************************************************/
//            вернуть слово в заданной форме (другой интерфейс)
//    Str   - слово в начальной форме
//    Form1 - форма слова
/***************************************************************************/
char 
* t_Slowo2 :: form( char *Str, t_Form *Form1 )
{  long i,S1,S2,SS ;

   S1=0 ; S2=n_Word-1 ;

   while( 1 )
   {  if( S2-S1<=4 ) break ;
      SS=(S1+S2)/2 ;
      if( 0<Strcmp( Str,Mass+Word[SS*n_Form] ) ) S1=SS ; else S2=SS ;
   }
   for( i=S1 ; i<=S2 ; i++ )
      if( 0==Strcmp( Str,Mass+Word[i*n_Form] ) ) goto M_Found ;
   return Str ;
M_Found:
   return form( i, Form1 );
}
/**************************************************************************/
//             найти слово и определить в какой оно форме
//             Str  - искомое слово
//             Ant  - индексы подходящих слов
//            _Form - их формы
/**************************************************************************/

short t_Slowo2 :: quest( char *Str, long *Ant, t_Form *_Form )
{  long i,i1,j,S1,S2,S21,SS ;
   char f ;

   S1=0 ; S2=S21=n_Word*n_Form ;

   // ---- установить i на первое слово в массиве reverce, равное Str ----
   while( 1 )
   {  if( S2-S1<=4 )
      {   for( i=S1 ; i<=S2 && i<S21 ; i++ )
             if( 0==Strcmp( Str,Mass+Word[reverce[i]] ) ) break ;
          S1=i ;
          break ;
      }
      SS=(S1+S2)/2 ;
      f=Strcmp( Str,Mass+Word[reverce[SS]] );
      if( 0<f ) S1=SS ; 
      if( 0>f ) S2=SS ;
      if( f==0 )
      {   for( i=SS ; S1<=i ; i--)
             if( 0!=Strcmp( Str,Mass+Word[reverce[i]] ) ) { S1=i+1 ; break ; }
          break ;
      }
   }

   // -------------- заполнить масивы ответов ---------------------------
   for( j=0,i=S1 ; i<n_Word*n_Form ; i++ )
   {  i1=reverce[i] ;      
      if( 0!=Strcmp( Str,Mass+Word[i1] ) ) break ;
      Ant[j] = i1/n_Form ; 
      // -------- прописать переменные параметры слова ----------
      _Form[j] = Format->Record[ i1%n_Form ] ;
      j++ ;
      if( 20<=j ) break ;
   }
   return j ;
}
/***************************************************************************/
//                   найти номер слова в словаре
/***************************************************************************/

long t_Slowo2 :: find( char *str )
{  long a,b,c,i ;

   a=0 ; b=n_Word-1 ;
   while( 1 )
   {  if( b-a<10 )
      {  for( i=a ; i<=b ; i++ )
	 {  if( 0==Strncmp( str,Mass+Word[i*n_Form],40 ) )
		return i ;
	 }
	 return -1 ;
      }
      c=(a+b)>>1 ;
      if( 0<Strncmp( str,Mass+Word[c*n_Form],40 ) ) a=c ; else b=c ;
   }
}
/***************************************************************************/
//                 есть ли в словаре такое слово
/***************************************************************************/

char t_Slowo2 :: word_exist( char *str )
{
    if( 0>find( str ) ) return -1 ;
        else return 0 ;
}
/***************************************************************************/
//                напечатать все формы слова в заданный файл 
/***************************************************************************/

void t_Slowo2 :: print_word( FILE *fw, long index )
{  long i,N ;

   N=Format->Record.j ;
   for( i=0 ; i<N ; i++ )
      fprintf( fw,"%s ",Mass + Word[index*n_Form+i] );

   fprintf( fw,";\n");
}