/******************************************************************************
 * program:     wp2latex                                                      *
 * function:    module for conversion DocBook files into LaTeX		      *
 * modul:       pass1dcb.cc                                                   *
 * description: This module contains parser for DocBook documents. It could   *
 *		be optionally compiled with WP2LaTeX package.		      *
 * licency:     GPL		                                              *
 ******************************************************************************/
#include<stdio.h>
#include<string.h>
#include<stdlib.h>

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

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


extern list HTMLChars;


/*Register translators here*/
class TconvertedPass1_Docbook: public TconvertedPass1_XML
{
protected:
     void Emphasis(void);
     void Chapter(void);
     void Image(void);
     void Itemize(void);
     void ProcessKey(void);

public:
     virtual int Convert_first_pass(void);
};
TconvertedPass1 *Factory_Docbook(void) {return new TconvertedPass1_Docbook;}
FFormatTranslator FormatDocbook("docbook",Factory_Docbook);

#define DocbookVersion "0.5"


typedef enum
{
  TAG_DCB_SRT	 =	128,
  TAG_DCB_HRT,
  TAG_DCB_PAR,
  TAG_DCB_PAREND,
  TAG_DCB_CHAPTER,
  TAG_DCB_ORDERLIST,
  TAG_DCB_IMAGE,
  TAG_DCB_TITLE,
  TAG_DCB_EMPH,
  TAG_DCB_H_SPACE =	200,
  TAG_DCB_EXT_CHR
} DOCBOOK_TAGS;


void TconvertedPass1_Docbook::Emphasis(void)
{
//TODO: Text attributes:
//<literal> – Pro zdrojový kód nebo text psaný neproporcionálním písmem (monospace).
//<foreignphrase> – Pro cizojazyčné výrazy (automaticky kurzíva).
//<quote> – Pro citace v textu (automaticky doplní uvozovky podle jazyka dokumentu).
  switch(subby)
  {
    case 0:			// falls down to bold
    case 1: Attr_ON(12); return;		// "bold" or "strong"
    case 2: Attr_ON(14); return;		// "underline"
    case 3: Attr_ON(13); return;		// "strikethrough"
    case 128: break;
    default: return;		// Unsupported/unexpected attribute value.
  }
	// subby must be here 128

  unsigned pos = attr.Closed_Depth; 
  while(pos > 0)
  {
    pos--;
    const char a = attr.stack[pos];
    if(a==12 || a==13 || a== 14)	// Look for attributes handled by <emphasis>
    {
      Attr_OFF(a);
      return;
    }
  }
}


void TconvertedPass1_Docbook::Itemize(void)
{
#ifdef DEBUG
  fprintf(log,"\n#TconvertedPass1_Docbook::Itemize() ");fflush(log);
#endif
unsigned char OldFlag;
char OldEnvir;
long FilePos;

  FilePos = ftell(wpd);
  OldFlag = flag;
  OldEnvir = envir;
  flag = Nothing;
  recursion++;

  line_term = 's';   /* Soft return */
  if(char_on_line == LEAVE_ONE_EMPTY_LINE)  /* Left one enpty line for new enviroment */
  {
    fputc('%', table);fputc('%', strip);
    NewLine(this);
  }
  if(char_on_line>=CHAR_PRESENT) //  if(char_on_line>=-1)
  {
    NewLine(this);
  }
  envir='!';
  fputc('%', table);fputc('%', strip);
  NewLine(this);

  envir = ' ';

  if(OldEnvir=='B') fprintf(strip, "\\vbox{"); //protect itemize inside table
  fprintf(strip, "\\begin{itemize}");

  char_on_line = false;
  nomore_valid_tabs = false;
  rownum++;
  Make_tableentry_attr();
  latex_tabpos = 0;

	/*Process all content of the table */
  flag=OldFlag;
  fseek(wpd,FilePos,SEEK_SET);
  ReadXMLTag(false);
  while(!feof(wpd))
	{
/*	if(by==0 && (subby==10 || subby==13))
		{
		subby=' ';	// remove \n from cell text
		} */
	ProcessKey();
	if(by==TAG_DCB_ORDERLIST)
		{
		if(subby==1) break; /*End of itemize*/
		if(subby==2) fprintf(strip, "\\item ");
		}

	ReadXMLTag(false);
	}

  fprintf(strip, "\\end{itemize}");
  if(OldEnvir=='B') fprintf(strip, "}");
  if(char_on_line <= FIRST_CHAR_MINIPAGE) // Left one enpty line for ending enviroment.
	{
	fputc('%', table);fputc('%', strip);
	NewLine(this);
	}
  envir='^';		//Ignore enviroments after table
  fputc('%', table);
  NewLine(this);
  char_on_line = FIRST_CHAR_MINIPAGE;		// stronger false;

  recursion--;

  flag = OldFlag;
  envir = OldEnvir;
  TAG = "ITEMIZE";
strcpy(ObjType, "Itemize Start");
}


/// This function extracts some information from meta ?xml tag.
static void MetaXML(TconvertedPass1_XML *cq)
{
#ifdef DEBUG
  fprintf(cq->log,"\n#MetaXML() ");fflush(cq->log);
#endif
int i;
char *charset;
  //strcpy(cq->ObjType, "?xml");

  if((i=cq->TAG_Args IN "encoding")>=0)
	{
	charset = cq->TAG_Args.Member(i,1);
	if(charset==NULL) return;

	cq->SelectTranslator(charset);
	}
}


void TconvertedPass1_Docbook::Chapter(void)
{
#ifdef DEBUG
  fprintf(log,"\n#TconvertedPass1_Docbook::Chapter() ");fflush(log);
#endif
unsigned char OldFlag;
char OldEnvir;

OldFlag = flag;
OldEnvir = envir;
recursion++;

//fprintf(log,"!!!<chapter>");

do {
   TAG.erase();
   ProcessKey();

   //fprintf(log,TAG);

   if(by==TAG_DCB_CHAPTER)
	{
	if(subby==1) break; //</chapter>
	}

   if(by==TAG_DCB_TITLE)
     {
     if(subby == 0) StartSection(this,-1);  // <title>
     if(subby == 1) EndSection(this,-1);    // </title>
     }
   } while(!feof(wpd));

  recursion--;

  flag=OldFlag;
  envir=OldEnvir;
TAG="CHAPTER";
strcpy(ObjType, "chapter");
}


void TconvertedPass1_Docbook::Image(void)
{
#ifdef DEBUG
  fprintf(log,"\n#TconvertedPass1_Docbook::Image() ");fflush(log);
#endif
unsigned char OldFlag;
char OldEnvir;
string FileName;
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

 OldFlag = flag;
 OldEnvir = envir;
 recursion++;

 do
 {
   TAG.erase();
   ProcessKey();
   //fprintf(log,TAG);

   if(by==TAG_DCB_IMAGE)
   {
     if(subby==1) break;	// </imageobject>
     if(subby==3)		// <imagedata>
     {
       int i;
       if((i=TAG_Args IN "fileref")>=0 || (i=TAG_Args IN "FILEREF")>=0)
       {
         FileName = TAG_Args.Member(i,1);
       }
     }
   }
 } while(!feof(wpd));

 recursion--;

 if(!FileName.isEmpty())
     ImageWP(this, FileName(), Box);

 flag = OldFlag;
 envir = OldEnvir;
 TAG = "IMAGE";
 strcpy(ObjType, "image");
}


void TconvertedPass1_Docbook::ProcessKey(void)
{
#ifdef DEBUG
  fprintf(log,"\n#TconvertedPass1_Docbook::ProcessKey() ");fflush(log);
#endif
string loc_TAG;
const char *tag;
uint8_t loc_by, loc_subby;
int i;

 *ObjType = 0;
 if(TAG.isEmpty()) ReadXMLTag(false);
 loc_by = by;
 loc_subby = subby;

 switch(loc_by)
	{
	case XML_char:
               switch(subby)                        //Normal character
		  {
		  case 10:
		  case 13:loc_by=TAG_DCB_SRT;break; //CR
		  case  9:strcpy(ObjType, "!Tab");
		  case 32:loc_by=32;break;  //Space
		  }
	       break;
/*	case 1:if(TAG.isEmpty()) break;			//Extended chatacter &xxx;
	       loc_TAG=Ext_chr_str(TAG[0],cq)+copy(TAG,1,length(TAG)-1);
	       tag=TAG();
	       by=TAG_DCB_EXT_CHR;
	       break;*/
	case XML_extchar:
	case XML_badextchar:
               loc_TAG = copy(TAG,1,length(TAG)-2);   //Extended chatacter &xxx;
	       if( (tag=loc_TAG())==NULL) break;
	       if(loc_TAG=="nbsp")	{loc_by=TAG_DCB_H_SPACE;break;}  	//Hard space

	       if((i=(loc_TAG() IN HTMLChars))>0)
		  {
		  i--;
		  loc_by = TAG_DCB_EXT_CHR;
		  tag = Ext_chr_str(i, this, ConvertHTML); /*Translate HTML character set to WP5.x one*/
		  }
	       break;

	case XML_tag:
               loc_TAG = copy(TAG,1,length(TAG)-2);	//Normal tag <xxx>
	       if( (tag=loc_TAG())==NULL) break;
	       if(loc_TAG=="imageobject") {loc_by=TAG_DCB_IMAGE;loc_subby=0;break;}
	       if(loc_TAG=="emphasis")
	       {
		 loc_by = TAG_DCB_EMPH;
		 loc_subby = 0;							// itallic is the default
                 if((i=TAG_Args IN "role")>=0 || (i=TAG_Args IN "ROLE")>=0)
                 {
                   const char *Role = TAG_Args.Member(i,1);
                   if(Role != NULL)
                   {
		     if(!strcmp(Role,"bold") || !strcmp(Role,"strong")) {loc_subby=1;break;}
		     if(!strcmp(Role,"underline"))  {loc_subby=2;break;}
		     if(!strcmp(Role,"strikethrough"))  {loc_subby=3;break;}
                   }
                 }
	         break;
               }
	       goto XML_closedtagLT;
        case XML_closedtag:
               loc_TAG = copy(TAG,1,length(TAG)-2);	//Normal tag <xxx>
	       if( (tag=loc_TAG())==NULL) break;
XML_closedtagLT:
	       if(loc_TAG=="?xml")    {MetaXML(this);break;}
	       if(loc_TAG=="para")    {loc_by=TAG_DCB_PAR;break;} 	//new paragraph
	       if(loc_TAG=="chapter") {loc_by=TAG_DCB_CHAPTER;loc_subby=0;break;} //section level 1
	       if(loc_TAG=="title")   {loc_by=TAG_DCB_TITLE;loc_subby=0;break;}
	       if(loc_TAG=="orderedlist"){loc_by=TAG_DCB_ORDERLIST;loc_subby=0;break;}	//Start of itemize
	       if(loc_TAG=="imagedata"){loc_by=TAG_DCB_IMAGE;loc_subby=3;break;}		// Image contents.
	       if(loc_TAG=="listitem"){loc_by=TAG_DCB_ORDERLIST;loc_subby=2;break;}	//Begin of item
       	       if(loc_TAG=="emphasis") {loc_by=TAG_DCB_EMPH;loc_subby=128;break;}
	       break;

	case XML_closetag:
	case XML_closedclosetag:
               loc_TAG = copy(TAG,2,length(TAG)-3);	//Closing tag </xxx>
	       if((tag=loc_TAG())==NULL) break;

	       if(loc_TAG=="para")    {loc_by=TAG_DCB_PAREND;break;} 	//end paragraph
	       if(loc_TAG=="chapter") {loc_by=TAG_DCB_CHAPTER;loc_subby=1;break;} //section off level 1
	       if(loc_TAG=="title")	  {loc_by=TAG_DCB_TITLE;loc_subby=1;break;}
	       if(loc_TAG=="orderedlist"){loc_by=TAG_DCB_ORDERLIST;loc_subby=1;break;} //End of itemize
	       if(loc_TAG=="imageobject") {loc_by=TAG_DCB_IMAGE;loc_subby=1;break;}
	       if(loc_TAG=="listitem"){loc_by=TAG_DCB_ORDERLIST;loc_subby=3;break;} //End of item
       	       if(loc_TAG=="emphasis") {loc_by=TAG_DCB_EMPH;loc_subby=128;break;}
	       break;
	case XML_comment: 			//comment
        case XML_CDATA:
	       break;
	}

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

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

	case TAG_DCB_SRT:if(TablePos!=1 && TablePos!=3)
		   if(char_on_line)
			SoftReturn(this);
		 break;
	case TAG_DCB_EMPH: Emphasis(); break;
	case TAG_DCB_HRT:HardReturn(this);        break;
	case TAG_DCB_PAR:if(char_on_line) HardReturn(this);  //Paragraph on
		 SoftReturn(this);
		 break;
	case TAG_DCB_PAREND:if(char_on_line) HardReturn(this);  //Paragraph off
		 break;

	case TAG_DCB_CHAPTER:if(loc_subby==0) Chapter();
		 break;
	case TAG_DCB_IMAGE: if(loc_subby==0) Image();
		 break;

        case TAG_DCB_ORDERLIST:switch(loc_subby)
		   {
		   case 0:Itemize();break;
		   }
		 break;

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


 by = loc_by;
 subby = loc_subby;
 if (log != NULL)
    {   /**/
    if(loc_by==TAG_DCB_SRT) fputc('\n',log);
    else if(loc_by==' ' || by==TAG_DCB_H_SPACE) fputc(' ',log);
    else if(loc_by==0 || loc_by==TAG_DCB_EXT_CHR)
	{
	fprintf(log,"%s",tag);
	}
    else
	{
	fprintf(log, "\n%*s [%s %s]   ",
		  recursion * 2, "", TAG(), ObjType);
//	if(*ObjType==0) UnknownObjects++;
	}
    }

 ActualPos = ftell(wpd);
}


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

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

  TablePos=0;

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

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

      TAG.erase();
      ProcessKey();
      }

  Finalise_Conversion();
  return(1);
}

