/*
 *  File:        math_write.h
 *  Purpose:     Write math paragraphs in LaTeX
 *  Author:      Alejandro Aguilar Sierra <asierra@servidor.unam.mx> 
 *  Created:     January 1996
 *  Description: 
 *
 *  Dependencies: Xlib, XForms
 *
 *  Copyright: (c) 1996, Alejandro Aguilar Sierra
 *
 *   Version: 0.5beta, Mathed & Lyx project.
 *
 *   You are free to use and modify this code under the terms of
 *   the GNU General Public Licence version 2 or later.
 */

#include "config.h"
#include "math_inset.h"
#include "math_parser.h"


extern const char *latex_mathenv[];
extern char *latex_mathspace[];

// quite a hack i know. Should be done with return values...
static int number_of_newlines;

char *math_font_name[] = {
   "mathrm",
   "mathcal",
   "mathbf",
   "mathsf",
   "mathtt",
   "mathit"
};

void
MathSpaceInset::Write(FILE *outf)
{ 
   if (space>=0 && space<6)
     fprintf(outf, "\\%s ", latex_mathspace[space]);
}


void
MathDotsInset::Write(FILE *outf)
{
   fprintf(outf, "\\%s ", name);
}   

void MathSqrtInset::Write(FILE *outf)
{ 
   fprintf(outf, "\\%s{", name);
   MathParInset::Write(outf);  
   fprintf(outf, "}");
}

void MathDelimInset::Write(FILE *outf)
{ 
   latexkeys* l = lm_get_key_by_id(left, LM_TK_SYM);
   latexkeys* r = lm_get_key_by_id(right, LM_TK_SYM);
   fprintf(outf, "\\left");
   if (l) 
     fprintf(outf, "\\%s ", l->name);
   else {
      if (left=='{' || left=='}')
	fprintf(outf, "\\%c ", left);
      else
	fprintf(outf, "%c ", left);
   }
   MathParInset::Write(outf);  
   fprintf(outf, "\\right");
   if (r) 
     fprintf(outf, "\\%s ", r->name);
   else {
      if (right=='{' || right=='}')
        fprintf(outf, "\\%c ", right);
      else
        fprintf(outf, "%c ", right);
   }        
}


void MathDecorationInset::Write(FILE *outf)
{ 
   latexkeys* l = lm_get_key_by_id(deco, LM_TK_WIDE);
   fprintf(outf, "\\%s{", l->name);
   MathParInset::Write(outf);  
   fprintf(outf, "}");
}

void MathAccentInset::Write(FILE *outf)
{ 
   latexkeys* l = lm_get_key_by_id(code, LM_TK_ACCENT);
   fprintf(outf, "\\%s", l->name);
   if (fn==LM_TC_SYMB) {
      latexkeys *l = lm_get_key_by_id(c, LM_TK_SYM);
      if (l)
	fprintf(outf, "\\%s ", l->name);
      else 
	fprintf(stderr, "Illegal symbol code[%u %d]", c, fn);
   } else 
     fprintf(outf, " %c ", c);
}


void MathBigopInset::Write(FILE *outf)
{ 
   fprintf(outf, "\\%s", name);
   if (lims && (sym==LM_int || sym==LM_oint))
     fprintf(outf, "\\limits ");
   else 
   if (!lims && !(sym==LM_int || sym==LM_oint))
     fprintf(outf, "\\nolimits ");
   else 
     fprintf(outf, " ");
}


void MathFracInset::Write(FILE *outf)
{ 
   fprintf(outf, "\\%s{", name);
   MathParInset::Write(outf);  
   fprintf(outf, "}{");
   den->Write(outf);  
   fprintf(outf, "}");
}


void MathParInset::Write(FILE *outf)
{
   if (!array) return;
   int brace = 0;
   latexkeys *l;
   LyxMathIter data(array);
   
   data.Reset();
    
   if (fixedsz) { 
       l = lm_get_key_by_id(size, LM_TK_STY);
       if (l) fprintf(outf, "\\%s ", l->name);
   }
   while (data.OK()) {
      byte cx = data.GetChar();
      if (cx>=' ') {
//	 fprintf(outf, "OUT<%d %d>", data.FCode(), cx);
	 int ls;
	 byte *s = data.GetString(ls);
       
	 if (data.FCode()>=LM_TC_RM && data.FCode()<=LM_TC_TT)
	   fprintf(outf, "\\%s{", math_font_name[data.FCode()-LM_TC_RM]);
	 while (ls>0) {
	    if (MathIsSymbol(data.FCode())) {
		l = lm_get_key_by_id(*s,(data.FCode()==LM_TC_BSYM)?LM_TK_BIGSYM:LM_TK_SYM);
	       if (l)
		 fprintf(outf, "\\%s ", l->name);
	       else 
		 fprintf(stderr, "Illegal symbol code[%u %d %d]", *s, ls, data.FCode());
	    } else {
	       // Is there a standard logical XOR?
	       if ((*s=='{' || *s=='}') && (data.FCode()!=LM_TC_TEX) ||
		   !(*s=='{' || *s=='}') && (data.FCode()==LM_TC_TEX))
		 fprintf(outf, "\\");
	       else {
		  if (*s=='{') brace++;
		  if (*s=='}') brace--;
	       }
	       if (*s=='}' && data.FCode()==LM_TC_TEX && brace<0) 
		 fprintf(stderr, "Math warning: Unexpected closing brace.\n");
	       else	       
		 fprintf(outf, "%c", *s);
	    }
	    s++; ls--;
	 }
	 if (data.FCode()>=LM_TC_RM && data.FCode()<=LM_TC_TT)
	   fprintf(outf, "}");	 
      } else     
      if (MathIsInset(cx)) {
	 LyxMathInset *p = data.GetInset();
	 if (cx==LM_TC_UP)
	   fprintf(outf, "^{");
	 if (cx==LM_TC_DOWN)
	   fprintf(outf, "_{");
	 p->Write(outf);
	 if (cx==LM_TC_UP || cx==LM_TC_DOWN)
	   fprintf(outf, "}");
	 data.Next();
      } else
      	switch(cx) {
	 case LM_TC_TAB:
	    {
	       fprintf(outf, " & ");
	       data.Next();
	       break;
	    }
	 case LM_TC_CR:
	    { 
	       fprintf(outf, "\\\\\n");
	       number_of_newlines++;
	       data.Next();
	       break;
	    }
	 default:
	   fprintf(stderr, "WMath Error: unrecognized code[%d]", cx);
	   return;
	}     
   }
   while (brace>0) {
      fprintf(outf, "}");
      brace--;
   }
}

void MathMatrixInset::Write(FILE *outf)
{
   rowst *r = row;
   //char s[80]; // unused

   if (GetType() == LM_OT_MATRIX){
     fprintf(outf, "\\begin{%s}{%s}\n", name, h_align);
     number_of_newlines++;
   }
   while (r) {
      array = r->array;
      if (r->label) 
	 fprintf(outf,"\\label{%s} ", r->label);
      MathParInset::Write(outf);
      if (!r->numbered) 
	fprintf(outf,"\\nonumber ");
      if (r->next) {
	fprintf(outf,"\\\\\n");
	number_of_newlines++;
      }
      r = r->next;      
   }
   if (GetType() == LM_OT_MATRIX){
     fprintf(outf, "\n\\end{%s}\n", name);  
     number_of_newlines+=2;
   }
}

void mathed_write(MathParInset* p,  FILE* outf, int* newlines,  char fragile, const char* label)
{  
   number_of_newlines = 0;
   short mathed_env = p->GetType();

   if (mathed_env==LM_EN_INTEXT) {
     if (fragile) fprintf(outf, "\\protect");
     fprintf(outf," \\( ");
   }
   else if (mathed_env==LM_EN_DISPLAY){
     fprintf(outf,"\n\\[\n");
     number_of_newlines+=2;
   }
   else {
     fprintf(outf,"\n\\begin{%s}\n", latex_mathenv[mathed_env]);
     number_of_newlines+=2;
   }
   
   if (label && mathed_env==LM_EN_EQUATION){
     fprintf(outf,"\\label{%s}\n", label);
     number_of_newlines++;
   }

   p->Write(outf);
   
   if (mathed_env==LM_EN_INTEXT){
     if (fragile) fprintf(outf, "\\protect");
     fprintf(outf," \\)");
   }
   else if (mathed_env==LM_EN_DISPLAY){
     fprintf(outf,"\\]\n");
     number_of_newlines++;
   }
   else {
     fprintf(outf,"\n\\end{%s}\n", latex_mathenv[mathed_env]);
     number_of_newlines+=2;
   }
   fflush(outf);
   *newlines = number_of_newlines;
}
