/******************************************************************************
 * program:     wp2latex                                                      *
 * function:    module for conversion Accent files into LaTeX 		      *
 * modul:       pass1acc.cc                                                   *
 * description: This module contains parser for Accent documents. It could be *
 *		optionally compiled with WP2LaTeX package.		      *
 * licency:     GPL		                                              *
 ******************************************************************************/
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#if defined(__unix__)||defined(__UNIX__)||defined(__DJGPP__)
#include <unistd.h>
#endif

#include"stringa.h"
#include"lists.h"
#include"dbllist.h"

#include"wp2latex.h"
#include"pass1xml.h"
#include"wmfsupp.h"
#include "cp_lib/cptran.h"


/*Register translators here*/
class TconvertedPass1_Accent: public TconvertedPass1_XML
     {
public:
     virtual int Convert_first_pass(void);

      void AccentImage(void);
      void AccentLanguage(void);
      void ProcessKeyAccent(void);
     };
TconvertedPass1 *Factory_Accent(void) {return new TconvertedPass1_Accent;}
FFormatTranslator FormatAccent("Accent",Factory_Accent);


typedef enum
{
    ACC_SOFT_RETURN = 128,
    ACC_ATTR_ON = 129,
    ACC_ATTR_OFF = 130,
    ACC_HRT = 131,
    ACC_SRT = 132,
    ACC_PAR_OFF = 133,
    ACC_JUSTIFICATION = 134,
    ACC_START_SECTIO =135,
    ACC_END_SECTION = 136,
    ACC_HLINE = 139,
    //	case 140:IndentHTML(this);	 break;
    ACC_END_INDENT = 141,
    ACC_TABLE = 143,

    ACC_IMAGE = 145,
    ACC_LANGUAGE = 146
} E_ACCENT_OPS;


#define AccentVersion "0.6"


bool Find4Bytes(FILE *F, const unsigned char *Bytes4)
{
  if(fgetc(F)==0x28)
  {
    if(fgetc(F)==0)
    {
      if(fgetc(F)==0)
      {
        if(fgetc(F)==0)
        {
	  return true;		// gobbled 4 bytes and true returned
        }
        fseek(F,-3,SEEK_CUR);
        return false;
      }
      fseek(F,-2,SEEK_CUR);
      return false;
    }
    fseek(F,-1,SEEK_CUR);
  }
  return false;			// false returned and seeked 1 byte.
}


void TconvertedPass1_Accent::AccentImage(void)
{
#ifdef DEBUG
  fprintf(log,"\n#AccentImage() ");fflush(log);
#endif
int i;
long len;
const char *TAG;
string NewFilename;

  if(length(TAG_Args)<1) return;
  TAG = TAG_Args[0];
  if(TAG==NULL) return;
  if(!strncmp(TAG,"GRAPHIC",7)) TAG+=7;
  while(isspace(*TAG)) TAG++;
  NewFilename = '.';
  while(isalnum(*TAG))
  {
    NewFilename += *TAG;
    TAG++;
  }
  while(isspace(*TAG)) TAG++;
  i = sscanf(TAG,"%ld",&len);
  if(len<0 || i<1)
  {
    if(err != NULL)
	fprintf(err,_("\nError: Length of embedded image is not specified!"));
    return;
  }  

  i = fgetc(wpd);
  if(i=='\n' || i=='\r')
      i=fgetc(wpd);
  
  fseek(wpd, 4, SEEK_CUR);		// 00 00 00 00
  fseek(wpd, 30, SEEK_CUR);		// Custom image header? Contents unknown.

  long ImagePos = ftell(wpd);

  NewFilename = GetSomeImgName(".wmf");		//NewFilename());
  NewFilename = MergePaths(OutputDir,RelativeFigDir) + NewFilename;

  i = 0;
  FILE *F = fopen(NewFilename(),"wb");
  if(F)
  {
    _WindowsMetaHeader Hdr;
    uint32_t WmfRecordSize=0;   
    long WmfLen = len - 34;

    Hdr.FileType = 1;
    Hdr.HeaderSize = 9;
    Hdr.Version = 0x300;
    Hdr.FileSize = 0;       ///< Total size of the metafile in WORDs.
    Hdr.NumOfObjects = 0;   ///< Number of objects in the file.
    Hdr.MaxRecordSize = 0;  ///< The size of largest record in WORDs.
    Hdr.NumOfParams = 0;    ///< Not Used (always 0).
	// A new WMF header must be created.
    if(SaveWMFHeader(F, Hdr)==18)
      while(WmfLen > 4)
      {      
        if(RdDWORD_LoEnd(&WmfRecordSize,wpd) != 4) break;	// Input file read error.
        if(2*WmfRecordSize > WmfLen) break;		// WMF record too big.
        if(WrDWORD_LoEnd(WmfRecordSize,F) != 4) break;
        if(WmfRecordSize<2) break;			// Invalid WMF record.
        if(WmfRecordSize>2)
        {
          if(CopyFile(F,wpd,2*WmfRecordSize-4,false) != 0) break;
        }
        WmfLen -= 2*WmfRecordSize;
        Hdr.NumOfObjects++;
        if(Hdr.MaxRecordSize<WmfRecordSize) Hdr.MaxRecordSize=WmfRecordSize;
      }
      if(WmfRecordSize!=3)
      {      
        WrDWORD_LoEnd(3,F);	// WMF stop
        WrWORD_LoEnd(0,F);
      }

    Hdr.FileSize = ftell(F) / 2;
    fseek(F,0,SEEK_SET);
    SaveWMFHeader(F, Hdr);
    fclose(F);

    if(Hdr.NumOfObjects>2 && Hdr.FileSize>9+3+3) i=1;
  }

	// When WMF extraction fails, try to do brutal search for DIB section.
  if(i == 0)
  {
    fseek(wpd,ImagePos,SEEK_SET);
    NewFilename = copy(NewFilename,0,NewFilename.length()-3) + "dib";  
	// I do not understand what is inside this 100 byte blob. It looks like it is
	// followed by classic DIB section.

	// Brutal search for DIB block
    for(i=0; i<=200; i++)
    {
      static const unsigned char DIB_SZ[4] = {0x28,0,0,0};
      if(Find4Bytes(wpd,DIB_SZ))
      {
        fseek(wpd,-4,SEEK_CUR);
        break;
      }
    }

    if(i>=200)
    {
      len -= 200 + 2;
      i = -10;
    }
    else
    {
    len -= i  + 2;
      i = CopyFile(NewFilename(), wpd, len);
    }
    if(i < 0)  
    {
      fseek(wpd,len,SEEK_CUR);  //Skip image - this might be improved
      if(i < -1)				// -1 file already exists
      {					// <= -2 error
        //if(err != NULL)
        //	fprintf(err,_("\nError: cannot open file \"%s\"!"),NewFilename());
        NewFilename = "dummy";
      }
    }
  }

  TBox Box;
  initBox(Box);
  Box.Width = -1; 		// Undefined, use default 100mm
  Box.Image_type=0;		// Image on disk
  Box.AnchorType = 0; 	// 0-Paragraph, 1-Page, 2-Character
  Box.HorizontalPos=2;	// 0-Left, 1-Right, 2-Center, 3-Full
  Box.Image_size=0;

  ImageWP(this, NewFilename(), Box);

  if(!NewFilename.isEmpty() && SaveWPG<0)
  {
    unlink(NewFilename());
  }
}


void TconvertedPass1_Accent::AccentLanguage(void)
{
#ifdef DEBUG
  fprintf(log,"\n#TconvertedPass1_Accent::AccentLanguage() ");fflush(log);
#endif
const char *TAG;
unsigned LangCode;

  if(length(TAG_Args)<1) return;
  TAG = TAG_Args[0];
  if(TAG==NULL) return;
  while(isspace(*TAG)) TAG++;

  if(TAG[0]=='0' && TAG[1]=='x')
    LangCode = strtoul(TAG+2, NULL, 16);
  else
    LangCode = strtoul(TAG+2, NULL, 10);

  if(LangCode==0x2d171800)	// Czech
  {
    SelectTranslator("cp1250");
  }
  else if(LangCode==0x4f1b4a00) // Hebrew
  {
    SelectTranslator("cp1255");
  }
  else
  {
    ConvertCpg = NULL;
  }
}


void TconvertedPass1_Accent::ProcessKeyAccent(void)
{
#ifdef DEBUG
  fprintf(log,"\n#TconvertedPass1_Accent::ProcessKeyAccent() ");fflush(log);
#endif
string TAG;
const char *tag;
uint8_t by, subby;

 *ObjType=0;
 if(this->TAG.isEmpty()) ReadXMLTag();
 by = this->by;
 subby = this->subby;

 switch(by)
	{
	case XML_char:
               switch(this->subby)                        //Normal character
		  {
		  case 10:
		  case 13:by=128;break; //CR
		  case  9:strcpy(ObjType, "!Tab");
		  case 32:by=32;break;  //Space
		  }
	       break;
	case XML_extchar:
               if(this->TAG.isEmpty()) break;			//Extended chatacter &xxx;
	       TAG = Ext_chr_str(this->TAG[0],this) + copy(this->TAG,1,length(this->TAG)-1);
	       tag = TAG();
	       by = 201;
	       break;
	case XML_tag:
        case XML_closedtag:
               TAG = copy(this->TAG,1,length(this->TAG)-2);	//Normal tag <xxx>
	       if((tag=TAG())==NULL) break;
	       if(TAG=="AC"){by=134;subby=0x82;break;}	//Justification Center
	       if(TAG=="AJ"){by=134;subby=0x81;break;}	//Justification Full
	       if(TAG=="AL"){by=134;subby=0x80;break;}	//Justification Left
	       if(TAG=="AR"){by=134;subby=0x83;break;}	//Justification Right
	       if(TAG=="B")
			{
			if(StrStr(TAG_Args.Member(0,0),"/B"))
			     by=ACC_ATTR_OFF;
			else by=ACC_ATTR_ON;
			subby=12;break;
			}   //ATTR on bold
	       if(TAG=="BIG")  {by=ACC_ATTR_ON;subby=2;break;}    //ATTR on large
	       if(TAG=="BR")   {by=131;break;} 	   	  //HRt
	       if(TAG=="DD")   {by=140;break;} 	   	  //Indented definition
	       if(TAG=="FLD")  {by=ACC_IMAGE;break;} 	   	  //Image
	       if(TAG=="H1")   {by=135;subby=1;break;}    //section level 1
	       if(TAG=="H2")   {by=135;subby=2;break;}    //section level 2
	       if(TAG=="H3")   {by=135;subby=3;break;}    //section level 3
	       if(TAG=="H4")   {by=135;subby=4;break;}    //section level 4
	       if(TAG=="H5")   {by=135;subby=1;break;}    //section level 5
	       if(TAG=="H6")   {by=135;subby=2;break;}    //section level 6
	       if(TAG=="HR")   {by=139;subby=0;break;}    //horizontal line
	       if(TAG=="I")				  //ATTR on italic
			{
			if(StrStr(TAG_Args.Member(0,0),"/I"))
			     by=ACC_ATTR_OFF;
			else by=ACC_ATTR_ON;
			subby=8;break;
			}
	       if(TAG=="IMG")  {by=142;break;}		  //Image
//	       if(TAG=="LI")   {by=144;subby=2;break;}    //Start of item
	       if(TAG=="LANG") {by=ACC_LANGUAGE;break;}
	       if(TAG=="META") {by=137;subby=0;break;}  //meta tag
	       if(TAG=="P")    {by=132;break;}		//new paragraph
	       if(TAG=="S")				//ATTR on strike out
			{
			if(StrStr(TAG_Args.Member(0,0),"/S"))
			     by=ACC_ATTR_OFF;
			else by=ACC_ATTR_ON;
			subby=13;break;
			}
	       if(TAG=="SMALL"){by=ACC_ATTR_ON;subby=3;break;}    //ATTR on small
	       if(TAG=="SCRIPT"){by=138;subby=0;break;}    //start SCRIPT
	       if(TAG=="SUB")  {by=ACC_ATTR_ON;subby=6;break;}    //ATTR on subscript
	       if(TAG=="SUP")  {by=ACC_ATTR_ON;subby=5;break;}    //ATTR on superscript
	       if(TAG=="T")    {by=ACC_TABLE;subby=0;break;}    //Start of the table
	       if(TAG=="TD")   {by=ACC_TABLE;subby=4;break;}    //Start of cell
	       if(TAG=="TH")   {by=ACC_TABLE;subby=6;break;}    //Start of head cell
	       if(TAG=="TR")   {by=ACC_TABLE;subby=2;break;}    //Start of row
	       if(TAG=="TT")   {by=ACC_ATTR_ON;subby=16;break;}	  //ATTR on typewriter
	       if(TAG=="U")				  //ATTR on underline
			{
			if(StrStr(TAG_Args.Member(0,0),"/U"))
			     by=ACC_ATTR_OFF;
			else by=ACC_ATTR_ON;
			subby=14;break;
			}
//	       if(TAG=="UL")   {by=144;subby=0;break;}    //Start of itemize
	       break;
	case XML_closetag:
        case XML_closedclosetag:
               TAG = copy(this->TAG,2,length(this->TAG)-3);	//Closing tag </xxx>
	       if( (tag=TAG())==NULL) break;
	       if(TAG=="B")    {by=ACC_ATTR_OFF;subby=12;break;}  //ATTR off bold
	       if(TAG=="BIG")  {by=ACC_ATTR_OFF;subby=2;break;}   //ATTR off large
	       if(TAG=="DD")   {by=141;break;} 	   	  //End of indented definition
	       if(TAG=="DL")   {by=141;break;} 	   	  //End of definition list
	       if(TAG=="H1")   {by=136;subby=1;break;}    //section off level 1
	       if(TAG=="H2")   {by=136;subby=2;break;}    //section off level 2
	       if(TAG=="H3")   {by=136;subby=3;break;}    //section off level 3
	       if(TAG=="H4")   {by=136;subby=4;break;}    //section off level 4
	       if(TAG=="H5")   {by=136;subby=1;break;}    //section off level 5
	       if(TAG=="H6")   {by=136;subby=2;break;}    //section off level 6
//	       if(TAG=="LI")   {by=144;subby=3;break;}    //End of item
	       if(TAG=="I")    {by=ACC_ATTR_OFF;subby=8;break;}    //ATTR off italic
	       if(TAG=="P")    {by=ACC_PAR_OFF;break;} 		  //end paragraph
	       if(TAG=="S")    {by=ACC_ATTR_OFF;subby=13;break;}	  //ATTR off strike out
	       if(TAG=="SMALL"){by=ACC_ATTR_OFF;subby=3;break;}    //ATTR off small
	       if(TAG=="SCRIPT"){by=138;subby=1;break;}   //end SCRIPT
	       if(TAG=="SUB")  {by=ACC_ATTR_OFF;subby=6;break;}    //ATTR off subscript
	       if(TAG=="SUP")  {by=ACC_ATTR_OFF;subby=5;break;}    //ATTR off superscript
	       if(TAG=="T")    {by=ACC_TABLE;subby=1;break;}    //End of Table
	       if(TAG=="TD")   {by=ACC_TABLE;subby=5;break;}	  //End of cell
	       if(TAG=="TH")   {by=ACC_TABLE;subby=7;break;}    //End of head cell
	       if(TAG=="TR")   {by=ACC_TABLE;subby=3;break;}    //End of row
	       if(TAG=="TT")   {by=ACC_ATTR_OFF;subby=16;break;}	  //ATTR off typewriter
	       if(TAG=="U")    {by=ACC_ATTR_OFF;subby=14;break;}   //ATTR off underline
//	       if(TAG=="UL")   {by=144;subby=1;break;}    //End of itemize
	       break;
        case XML_CDATA:
	case XML_comment:				//comment
	       break;
	case XML_badextchar:
               if(this->TAG.isEmpty()) break;		//Extended chatacter &xxx
	       this->TAG[length(this->TAG)-1]=' ';
	       TAG = Ext_chr_str(this->TAG[0],this) + copy(this->TAG,1,length(this->TAG)-1);
	       tag = TAG();
	       by = 201;
	       break;
	}

  this->by=by;
  this->subby=subby;
  if(this->flag<Nothing)
    switch(by)
	{
	case XML_char:                  //Normal character
                tag = Ext_chr_str(subby,this,this->ConvertCpg);
	        CharacterStr(this,tag);
	        break;
        case XML_CDATA:
	case XML_comment:		//comment
                this->CommentXML();
	        break;
	case XML_unicode:
                CharacterStr(this,this->TAG);
	        break;		//Already expanded unicode character

	case 32:putc(' ', this->strip);   /*soft space*/
		break;

	case 128:if(TablePos!=1 && TablePos!=3)
		   if(this->char_on_line)
			SoftReturn(this);
		 break;
	case ACC_ATTR_ON: attr.AttrOn(subby); break;
	case ACC_ATTR_OFF:AttrOff(subby); break;
	case 131:HardReturn(this); break;
	case 132:if(this->char_on_line) HardReturn(this);  //Paragraph on
		 SoftReturn(this);
		 break;
	case ACC_PAR_OFF:if(this->char_on_line) HardReturn(this);  //Paragraph off
		 break;
	case 134:Justification(this,subby);break;
	case 135:StartSection(this,-subby);break;
	case 136:EndSection(this,-subby);	 break;
//	case 137:MetaHTML(this);		 break;
//	case 138:ScriptXML(this);		 break;
	case 139:HLine(this,-16);		 break;
//	case 140:IndentHTML(this);	 break;
	case 141:End_of_indent(this);	 break;
//	case 142:ImageHTML(this);		 break;
	case ACC_TABLE:switch(subby)
		   {
//		   case 0:TableHTML(this);TablePos=1;break;
		   case 1:EndTable(this); TablePos=0; break;
		   case 2:RowTable(this); TablePos|=2;break;
		   case 3:TablePos&=~2;break;
		   case 4:
		   case 6:CellTable(this); TablePos|=4;break;
		   case 5:
		   case 7:TablePos&=~4;break;
		   }
		 break;
	case ACC_IMAGE: AccentImage();break;
	case ACC_LANGUAGE: AccentLanguage();break;

	case 200:fputc('~', strip);strcpy(ObjType, " ");
		 break;
	case 201:CharacterStr(this,tag);break; //
	}


 this->by=by;
 this->subby=subby;
 if (this->log != NULL)
    {   /**/
    if(by==128) fputc('\n',this->log);
    else if(by==' ' || by==200) fputc(' ',this->log);
    else if(by==0 || by==201)
	{
	fprintf(this->log,"%s",tag);
	}
    else
	{
	fprintf(this->log, "\n%*s [%s %s]   ",
		  this->recursion * 2, "", this->TAG(), this->ObjType);
//	if(*this->ObjType==0) UnknownObjects++;
	}
    }

 this->ActualPos = ftell(this->wpd);
}


int TconvertedPass1_Accent::Convert_first_pass(void)
{
#ifdef DEBUG
  fprintf(log,"\n#TconvertedPass1_Accent::Convert_first_pass() ");fflush(log);
#endif
uint32_t fsize;

  if(Verbosing >= 1)
     printf(_("\n>>>Accent2LaTeX<<< Conversion program: From Accent to LaTeX Version %s\n"
	      "      Made by J.Fojtik  (Hosted on WP2LaTeX :))))\n\n"),
			AccentVersion);
  ConvertHTML = GetTranslator("htmlTOinternal");
  CharReader = &ch_fgetc;

  TablePos=0;

  DocumentStart = ftell(wpd);
  fsize = FileSize(wpd);
  perc.Init(ftell(wpd), fsize,_("First pass Accent:") );

  ActualPos = ftell(wpd);
  while(ActualPos < fsize)
  {
    if(Verbosing >= 1)		//actualise a procentage counter
	perc.Actualise(ActualPos);

    TAG.erase();
    ProcessKeyAccent();
  }

  Finalise_Conversion();
  return(1);
}

