// -*- C++ -*-
/*
 *  File:        math_defs.h
 *  Purpose:     Math editor definitions 
 *  Author:      Alejandro Aguilar Sierra <asierra@servidor.unam.mx> 
 *  Created:     January 1996
 *  Description: Math paragraph and objects for a WYSIWYG math editor.
 *
 *  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.
 */

#ifndef __MATH_DEFS__
#define __MATH_DEFS__

#include <stdio.h>
#include "array.h"

#ifdef _AIX32
#define inline
#endif

#define MATH_ALIGN_LEFT    1
#define MATH_ALIGN_RIGHT   2
#define MATH_ALIGN_BOTTOM  4
#define MATH_ALIGN_TOP     8
#define MATH_COLSEP 8
#define MATH_ROWSEP 8


// Standard Math Sizes (Math mode styles)
enum LyxMathStyles {
   LM_ST_DISPLAY=0,
   LM_ST_TEXT,
   LM_ST_SCRIPT,
   LM_ST_SCRIPTSCRIPT
};


// Standard LaTeX Math Environments
enum LyxMathEnvironment {
   LM_EN_INTEXT=0,
   LM_EN_DISPLAY,
   LM_EN_EQUATION,
   LM_EN_EQNARRAYAST,
   LM_EN_EQNARRAY,
   LM_EN_ARRAY
};

// The restrictions of a standard LaTeX math paragraph
// allows to get a small number of text codes (<30)

enum LyxMathTextCodes  {      
   LM_TC_MIN = 0,              //  This must be >= 0
   LM_TC_OPEN,                 //  Open and Close group
   LM_TC_CLOSE,
   LM_TC_TAB,              //  Tabulator
   LM_TC_CR,	       //  New line  
   LM_TC_INSET,	               //  Math Inset
   LM_TC_UP,	               //  Super and sub scripts
   LM_TC_DOWN,
   LM_TC_ACTIVE_INSET,         //  Editable Math Inset
   LM_TC_TEXT_INSET,           //  Editable Text Inset
     
   LM_TC_CONST,                //  Internal code for constants
   LM_TC_VAR,                  //  Internal code for variables 
   LM_TC_RM,       
   LM_TC_CAL,	
   LM_TC_BF,	
   LM_TC_SF,	
   LM_TC_TT,	
   LM_TC_IT, 
   LM_TC_TEXTRM,
   LM_TC_TEX,
   LM_TC_BOP,                //  Internal code for operators  
  
   LM_TC_SYMB,	             //  Internal code for symbols
   LM_TC_BOPS,               //  symbolic operators 
   LM_TC_BSYM,               //  Big non-operator symbols 
      
/*   LM_TC_DISPLAY,              //  Styles (font sizes)
   LM_TC_TEXT,
   LM_TC_SCRIPT,
   LM_TC_SCRIPTSCRIPT, */
     
   LM_TC_MAX                   //  This must be < 32 
};
 
#define LM_TC_NORMAL LM_TC_VAR
 
       
// Types of lyx-math insets 
enum LyxMathInsetTypes  {
   LM_OT_MIN = 0,
   LM_OT_PAR,           // A simple paragraph
   LM_OT_PARN,           // A simple numbered paragraph
   LM_OT_MPAR,          // A multiline paragraph
   LM_OT_MPARN,          // A multiline numbered paragraph
   LM_OT_MATRIX,	// An array
   LM_OT_BIGOP,		// A big operator
   LM_OT_UNDEF,         // A LaTeX macro
   LM_OT_FUNC,
   LM_OT_FUNCLIM,
   LM_OT_SCRIPT,
   LM_OT_SPACE,
   LM_OT_DOTS,
   LM_OT_FRAC,		// A fraction
   LM_OT_SQRT,		// A radical
   LM_OT_DELIM,		// A delimiter
   LM_OT_DECO,		// A decoration
   LM_OT_ACCENT,        // An accent
   LM_OT_MAX
};

enum MathedBinaryTypes {
    LMB_NONE = 0,
    LMB_RELATION,
    LMB_OPERATOR,
    LMB_BOP = (LMB_RELATION | LMB_OPERATOR)
};

class LyxMathInset;
class MathParInset;

// Specialized array iterator for math paragraph 
class LyxMathIter {
 public:
   LyxMathIter(void);
   LyxMathIter(LyxArrayBase *);
   virtual ~LyxMathIter();
   int Empty(void) { return array->last<=1; }
   int OK(void) { return (pos < array->last); }
   int IsFirst(void) { return (pos==0); }
   byte GetChar();
   byte* GetString(int& len);
   LyxMathInset* GetInset();
   MathParInset* GetActiveInset();
   Bool IsInset();
   Bool IsActive();
   Bool IsFont();
   bool IsScript();
   bool IsTab();
   virtual void Reset(void);
   virtual void Insert(byte, LyxMathTextCodes c=LM_TC_CONST);
   virtual void Insert(LyxMathInset*, int t=LM_TC_INSET);
   virtual Bool Delete();
   virtual Bool Next();
   virtual Bool Prev();
   short FCode() const { return fcode; }
   void SetData(LyxArrayBase *a) { array = a; Reset(); }
   LyxArrayBase *GetData(void) { return array; }
   
   // Copy every object from position p1 to p2
   LyxArrayBase *Copy(int p1=0, int p2=10000);
   
   // Delete every object from position p1 to p2
   void Clean(int p1=0, int p2=10000);
   void Merge(LyxArrayBase*, int nc=0);
 protected:
   void split(int);
   void join(int);
   short fcode;
   int pos;
   LyxArrayBase *array;
};
  

// Abstract base class for all math insets. They are not general lyx insets
// but are only allowed inside a math paragraph
class LyxMathInset  {
 public: 
   LyxMathInset(char *nm, short ot, short st);
   LyxMathInset(LyxMathInset*);
   virtual ~LyxMathInset() { };
   
   // Draw the object on a drawable
   virtual void Draw(long unsigned int pm, int x, int baseline)=0;
   
   // Write LaTeX and Lyx code
   virtual void Write(FILE *file)=0; 
   virtual LyxMathInset *Clone(void)=0;
   
   // Metrics & position
   virtual void Metrics(void)=0;   // Compute the size of the object
   virtual int Ascent(void) const { return ascent; }
   virtual int Descent(void) const { return descent; }
   
   virtual int Width(void) const { return width; }
   virtual int Height(void) const { return ascent + descent; }
   virtual bool GetLimits(void) const { return false; }
   virtual void SetLimits(bool) { }   
      
   // Identification    
   char *GetName(void) const { return name; }
   short GetType(void) const { return objtype; }
   short GetStyle(void) const { return size; }
   
   // Don't use these functions if it's not strictly necessary
   virtual void  SetType(short t) { objtype = t; }
   virtual void  SetStyle(short st) { size = st; Metrics(); }
   virtual void  SetName(char* n) { name = n; }
 
 protected:
   char *name;
   short objtype;
   int width, ascent, descent;
   short size;
};


// A basic math paragraph. This is the base to build more complex objects
class MathParInset: public LyxMathInset  {
 public: 
   MathParInset(short st=LM_ST_TEXT, char *nm=NULL, short ot=LM_OT_MIN); 
   MathParInset(MathParInset*);
   virtual ~MathParInset();
   virtual LyxMathInset *Clone(void);   

   // Draw the object on a drawable
   virtual void Draw(long unsigned int pm, int x, int baseline);
   
   // Write LaTeX code
   virtual void Write(FILE *file);
   virtual void Metrics(void);
   virtual void UserSetSize(short);
 
   // Data is stored in a LyxArray
   virtual void SetData(LyxArrayBase *);
   virtual LyxArrayBase * GetData(void) { return array; }

   // Cursor position inside the paragraph 
   virtual void GetXY(int& x, int& y) const;
   virtual void SetFocus(int,int) { };
   virtual bool Inside(int, int);   
   
   // Tab stuff used by Matrix. 
   virtual void SetAlign(char, char*) { };
   virtual int GetTabPos(void) { return 0; }
   virtual int GetTab(int /*i=1*/) { return 0; }
   virtual int GetColumns() { return 1; }
   virtual int GetRows() { return 1; }
   
   // Vertical switching 
   virtual bool Up(void) { return false; }
   virtual bool Down(void) { return false; }
   virtual void Top(void) { }
   virtual void Bottom(void) { }
   virtual void SetStyle(short sz) {if (!fixedsz) LyxMathInset::SetStyle(sz);}
 protected: 
   virtual void SetTab(int) { }
   LyxArrayBase *array;
   int xo, yo;  // Cursor start position
 private:
   bool fixedsz;
   friend class InsetFormula;
};

class MathMatrixInset: public MathParInset {
 public: 
   MathMatrixInset(int m=1, int n=1, short st=LM_ST_TEXT);
   MathMatrixInset(MathMatrixInset*);
   LyxMathInset *Clone(void);   
   virtual ~MathMatrixInset();
   void Draw(long unsigned int, int, int);
   void Write(FILE *file);
   void Metrics(void);   
   void SetData(LyxArrayBase *);
   LyxArrayBase * GetData(void);
   void GetXY(int& x, int& y) const;
   void SetFocus(int,int);
   void AddRow(void);
   bool DelRow(void);

   bool Up(void);
   bool Down(void);
   void Top(void);
   void Bottom(void);

   void SetAlign(char, char*);
   char *GetAlign(char* vv) {
      *vv = v_align;
      return h_align;
   }
   int GetTab(int i=1);
   int GetTabPos(void) { return ct; }
   int GetColumns() { return nc; }
   int GetRows() { return nr; }
   int GetRowIdx();
    
   // Labeling and numbering stuff
   void SetLabel(char* l) { crow->label = l; }
   const char* GetLabel(void) { return crow->label; }
   bool IsNumbered(void) {  return crow->numbered; }
   void SetNumbered(bool nf) { crow->numbered = nf; }
 protected:
   bool mflag;
   void SetTab(int);
   int nc, nr;    //  Number of columns & rows
   int ct, *ws;   //  Current tab & tabs
   char v_align;
   char* h_align;
   struct rowst {
      int asc, desc, y;
      int *w; 
      char *label;
      bool numbered;
      LyxArrayBase *array;
      rowst *prev, *next;
      rowst(int n) {
	 w = new int[n+1];
	 array = NULL;
	 label = NULL;
	 numbered = true;
      }      
      ~rowst() {
	 delete[] w;
	 delete array;
	 if (label) delete[] label;
      }      
   } *row, *crow;
};



/*************************  Prototypes  **********************************/
 
LyxArrayBase *mathed_parse(unsigned flags=0, LyxArrayBase *data=NULL, MathParInset **mt=NULL);

void mathed_write(MathParInset*, FILE *, int*, char fragile, const char* label=NULL);
 
void mathed_parser_file(FILE*);

int MathedLookupBOP(short);

/************************ Inline functions ********************************/

 
#define MathIsInset(x)  (LM_TC_INSET<=(x) && (x)<=LM_TC_ACTIVE_INSET)
 
#define MathIsFont(x)  (LM_TC_CONST<=(x) && (x)<=LM_TC_BSYM)
 
#define MathIsAlphaFont(x)  (LM_TC_VAR<=(x) && (x)<=LM_TC_IT)

#define MathIsActive(x)  (LM_TC_INSET<(x) && (x)<=LM_TC_ACTIVE_INSET) 

#define MathIsUp(x)    ((x)==LM_TC_UP) 

#define MathIsDown(x)  ((x)==LM_TC_DOWN)

#define MathIsScript(x)  ((x)==LM_TC_DOWN || (x)==LM_TC_UP)  

#define MathIsBOPS(x)    (MathedLookupBOP(x)>LMB_NONE)


inline bool MathIsBinary(short x)
{
    return (x==LM_TC_BOP || x==LM_TC_BOPS);
}

inline bool MathIsSymbol(short x) {
    return (LM_TC_SYMB<=x && x<=LM_TC_BSYM);
}

inline
Bool LyxMathIter::IsInset()
{
   return MathIsInset(array->bf[pos]);
}
 
inline
Bool LyxMathIter::IsActive()
{
   return MathIsActive(array->bf[pos]);
}

inline
Bool LyxMathIter::IsFont()
{
   return MathIsFont(array->bf[pos]);
}


inline
bool LyxMathIter::IsScript()
{
   return MathIsScript(array->bf[pos]);
}   

inline
bool LyxMathIter::IsTab()
{
   return (array->bf[pos]==LM_TC_TAB);
}   

inline
LyxMathIter::LyxMathIter()
{
   pos = 0;
   fcode = 0;
   array = NULL;
}

inline
LyxMathIter::LyxMathIter(LyxArrayBase *d): array(d)
{
   pos = 0;
   fcode = (array && IsFont()) ? array->bf[0]: 0;
}
     
inline
LyxMathIter::~LyxMathIter()
{
   
}

inline 
LyxMathInset::LyxMathInset(char *nm, short ot, short st):
  name(nm), objtype(ot), size(st) 
{
   width = ascent = descent = 0;
}

inline
bool MathParInset::Inside(int x, int y) 
{
  return (x>=xo && x<=xo+width && y<=yo+descent && y>=yo-ascent);
}

inline
void MathParInset::SetData(LyxArrayBase *a)
{
   array = a;
   Metrics();
}

inline
void MathParInset::GetXY(int& x, int& y) const
{
   x = xo; y = yo;
}

inline
void MathParInset::UserSetSize(short sz)
{
   if (sz>=0) {
       size = sz;      
       fixedsz = true;
   }
}

#endif

