/*****************************************************************************
* Generic parser for the "Irit" solid modeller.				     *
*									     *
* Written by:  Gershon Elber				Ver 0.2, Sep. 1991   *
*****************************************************************************/

#ifndef	IRIT_PRSR_GH
#define	IRIT_PRSR_GH

#include <setjmp.h>

#include "irit_sm.h"
#include "cagd_lib.h"
#include "genmat.h"

/* Dont change the order of these objects (or there values as overloaded     */
/* tables (see overload.c) are hardwired to it. If you add objects update    */
/* that module properly.						     */
typedef enum {
    IP_OBJ_UNDEF = 0,

    IP_OBJ_POLY,                     /* These are the objects in overload.c. */
    IP_OBJ_NUMERIC,
    IP_OBJ_POINT,
    IP_OBJ_VECTOR,
    IP_OBJ_PLANE,
    IP_OBJ_MATRIX,
    IP_OBJ_CURVE,
    IP_OBJ_SURFACE,
    IP_OBJ_STRING,
    IP_OBJ_LIST_OBJ,
    IP_OBJ_CTLPT,

    IP_OBJ_AUX_ATTR = 50,	 /* These are the auxiliary objects/structs. */
    IP_OBJ_AUX_VERTEX,
    IP_OBJ_AUX_POLY,
    IP_OBJ_AUX_CURVE,
    IP_OBJ_AUX_SURFACE,
    IP_OBJ_AUX_MATRIX,
    IP_OBJ_AUX_STRING,
    IP_OBJ_AUX_OLST,
    IP_OBJ_AUX_END,

    ANY_OBJ = 100		 /* Match any object type, in type checking. */
} IPObjStructType;

typedef enum {			 /* Possible error code during data parsing. */
    IP_NO_ERR = 0,

    IP_ERR_NUMBER_EXPECTED,
    IP_ERR_OPEN_PAREN_EXPECTED,
    IP_ERR_CLOSE_PAREN_EXPECTED,
    IP_ERR_LIST_COMP_UNDEF,
    IP_ERR_UNDEF_EXPR_HEADER,
    IP_ERR_PT_TYPE_EXPECTED,
    IP_ERR_OBJECT_EMPTY,
    IP_ERR_FILE_EMPTY,
    IP_ERR_MIXED_TYPES,
    IP_STR_NOT_IN_QUOTES,
    IP_ERR_OBJECT_EXPECTED,
    IP_ERR_CAGD_LIB_ERR,
    IP_ERR_STACK_OVERFLOW,
    IP_ERR_DEGEN_POLYGON,
    IP_ERR_DEGEN_NORMAL,
    IP_ERR_SOCKET_BROKEN,
    IP_ERR_SOCKET_TIME_OUT,
    IP_ERR_BIN_UNDEF_OBJ,

    IP_WRN_OBJ_NAME_TRUNC = 100
} IritPrsrErrType;

#define IP_LOAD_COLOR           14  /* Index color default - loaded objects. */

#define IRIT_DATA_HEADER(File, Name) \
	fprintf(File, "Irit %s, %s,\nCreator: %s,\nDate: %s.\n\n", \
		VERSION, COPYRIGHT, Name, IritRealTimeDate());

/*****************************************************************************
* Global data structures:						     *
* Objects in the system might be (real) scalars, (R3) vectors, matrices      *
* (4 by 4 - transformation matrix), strings of chars, lists of objects, or   *
* geometric objects. All but the last are simple and all their data is saved *
* in the object space itself. The last (geometric) object points on a	     *
* curve or a surface or a polygonal list of the form:			     *
*									     *
* Polygon -> Polygon -> Polygon -> Polygon -> .... -> NULL		     *
*    |		|	   |	      |					     *
*    V          V          V          V					     *
*  VList      VList      VList      VList	(VList = Vertex List)	     *
*									     *
* Each VList is a CIRCULAR vertex list. Each VList element (IPVertexStruct)  *
* implicitly defines an edge from this vertex, to the next. As each edge     *
* is used by exactly two polygons, a pointer to the other polygon using this *
* edge exists in the IPVertexStruct. Each polygon has also its Plane	     *
* definition for fast processing, with its normal pointing INTO the object.  *
*   Few other tags & flags are included in the data structures for different *
* modules.								     *
*   Note, vertices are not shared by few VLists/Polygons although it may     *
* decrease memory usage (suprisingly, not much). The main reason to that is  *
* the basic assumption of this solid modeller, which is simplicity...	     *
*****************************************************************************/

/*****************************************************************************
* Vertex Type - holds single 3D point, including some attributes on it as    *
* Tags. The 3D coordinates are saved in Pt. Pointer to next in chain	     *
* is Pnext, and the pointer to the adjacent polygon (to the edge defined by  *
* this Vertex and Vertex -> Pnext) is PAdj.				     *
*****************************************************************************/

/* Internal edge, or edge generated by the polygon decomposition stage when  */
/* only convex polygons are allowed. This edge was not in the input	     */
/* non-convex polygon, and therefore one may not want to see/display it.     */
/* Note bits 4-7 (high nibble of Tags) are reserved for the different	     */
/* modules to perform their local tasks and so should not be used here.	     */
#define IP_VRTX_INTERNAL_TAG	0x01    /* Internal Tag - Edge is internal.  */
#define IP_VRTX_NORMAL_TAG	0x02     /* Normal Tag - Vertex has normal.  */

#define IP_IS_INTERNAL_VRTX(Vrtx)	(Vrtx -> Tags & IP_VRTX_INTERNAL_TAG)
#define IP_SET_INTERNAL_VRTX(Vrtx)	(Vrtx -> Tags |= IP_VRTX_INTERNAL_TAG)
#define IP_RST_INTERNAL_VRTX(Vrtx)	(Vrtx -> Tags &= IP_VRTX_INTERNAL_TAG)
#define IP_HAS_NORMAL_VRTX(Vrtx)	(Vrtx -> Tags & IP_VRTX_NORMAL_TAG)
#define IP_SET_NORMAL_VRTX(Vrtx)	(Vrtx -> Tags |= IP_VRTX_NORMAL_TAG)
#define IP_RST_NORMAL_VRTX(Vrtx)	(Vrtx -> Tags &= IP_VRTX_NORMAL_TAG)

typedef struct IPVertexStruct {
    struct IPVertexStruct *Pnext;		        /* To next in chain. */
    struct IPAttributeStruct *Attrs;
    struct IPPolygonStruct *PAdj;		     /* To adjacent polygon. */
    PointType Coord;			       /* Holds X, Y, Z coordinates. */
    NormalType Normal;		       /* Hold Vertex normal into the solid. */
    int Color;
    ByteType Count, Tags;				 /* Some attributes. */
} IPVertexStruct;

/*****************************************************************************
* Polygon Type - holds single polygon - Its Plane definition, and a pointer  *
* to its vertices contour list V. As for IPVertexStruct, different attributes*
* can be saved in Tags. PAux can be used locally by different modules, for   *
* local usage only, and nothing sould be assumed on entry.		     *
*****************************************************************************/

/* Note bits 4-7 (high nibble of Tags) are reserved for the different	     */
/* modules to perform their local tasks and so should not be used here.	     */
#define IP_POLY_CONVEX_TAG	0x01	   /* Convex Tag - Set if is convex. */
#define IP_POLY_BBOX_TAG	0x02  /* BBox Tag - Set if BBox is computed. */
#define IP_POLY_PLANE_TAG	0x04    /* Plane Tag - set of has plane def. */

#define	IP_IS_CONVEX_POLY(Poly)		((Poly) -> Tags & IP_POLY_CONVEX_TAG)
#define	IP_SET_CONVEX_POLY(Poly)	((Poly) -> Tags |= IP_POLY_CONVEX_TAG)
#define	IP_RST_CONVEX_POLY(Poly)	((Poly) -> Tags &= ~IP_POLY_CONVEX_TAG)
#define	IP_HAS_BBOX_POLY(Poly)		((Poly) -> Tags & IP_POLY_BBOX_TAG)
#define	IP_SET_BBOX_POLY(Poly)		((Poly) -> Tags |= IP_POLY_BBOX_TAG)
#define	IP_RST_BBOX_POLY(Poly)		((Poly) -> Tags &= ~IP_POLY_BBOX_TAG)
#define IP_HAS_PLANE_POLY(Poly)		((Poly) -> Tags & IP_POLY_PLANE_TAG)
#define IP_SET_PLANE_POLY(Poly)		((Poly) -> Tags |= IP_POLY_PLANE_TAG)
#define IP_RST_PLANE_POLY(Poly)		((Poly) -> Tags &= ~IP_POLY_PLANE_TAG)

typedef struct IPPolygonStruct {
    struct IPPolygonStruct *Pnext;		        /* To next in chain. */
    struct IPAttributeStruct *Attrs;
    VoidPtr PAux;
    PlaneType Plane;			 /* Holds Plane as Ax + By + Cz + D. */
    BBoxType BBox;					/* BBox of polygons. */
    IPVertexStruct *PVertex;		    		/* To vertices list. */
    ByteType Count, Tags;			         /* Some attributes. */
} IPPolygonStruct;

/*****************************************************************************
* Object Type - main system structure, which holds all the objects defined   *
* in the system like Numeric, Geometric etc.				     *
*   Note that as the number of objects will be usually extermely low (100 is *
* high estimate!) we can waste some memory here...			     *
*****************************************************************************/

#define IP_IS_UNDEF_OBJ(Obj)	((Obj) -> ObjType == IP_OBJ_UNDEF)
#define IP_IS_POLY_OBJ(Obj)	((Obj) -> ObjType == IP_OBJ_POLY)
#define IP_IS_NUM_OBJ(Obj)	((Obj) -> ObjType == IP_OBJ_NUMERIC)
#define IP_IS_POINT_OBJ(Obj)	((Obj) -> ObjType == IP_OBJ_POINT)
#define IP_IS_VEC_OBJ(Obj)	((Obj) -> ObjType == IP_OBJ_VECTOR)
#define IP_IS_PLANE_OBJ(Obj)	((Obj) -> ObjType == IP_OBJ_PLANE)
#define IP_IS_CTLPT_OBJ(Obj)	((Obj) -> ObjType == IP_OBJ_CTLPT)
#define IP_IS_MAT_OBJ(Obj)	((Obj) -> ObjType == IP_OBJ_MATRIX)
#define IP_IS_STR_OBJ(Obj)	((Obj) -> ObjType == IP_OBJ_STRING)
#define IP_IS_OLST_OBJ(Obj)	((Obj) -> ObjType == IP_OBJ_LIST_OBJ)
#define IP_IS_CRV_OBJ(Obj)	((Obj) -> ObjType == IP_OBJ_CURVE)
#define IP_IS_SRF_OBJ(Obj)	((Obj) -> ObjType == IP_OBJ_SURFACE)

#define IP_IS_GEOM_OBJ(Obj)	(IP_IS_UNDEF_OBJ(Obj) || \
				 IP_IS_POLY_OBJ(Obj) || \
				 IP_IS_POINT_OBJ(Obj) || \
				 IP_IS_CTLPT_OBJ(Obj) || \
				 IP_IS_VEC_OBJ(Obj) || \
				 IP_IS_CRV_OBJ(Obj) || \
				 IP_IS_SRF_OBJ(Obj))

#define IP_IS_POLYGON_OBJ(Obj)	  (((Obj) -> Tags & 0x03) == 0)
#define IP_SET_POLYGON_OBJ(Obj)	  ((Obj) -> Tags = ((Obj) -> Tags & 0xfc))
#define IP_IS_POLYLINE_OBJ(Obj)	  (((Obj) -> Tags & 0x03) == 1)
#define IP_SET_POLYLINE_OBJ(Obj)  ((Obj) -> Tags = ((Obj) -> Tags & 0xfc) + 1)
#define IP_IS_POINTLIST_OBJ(Obj)  (((Obj) -> Tags & 0x03) == 2)
#define IP_SET_POINTLIST_OBJ(Obj) ((Obj) -> Tags = ((Obj) -> Tags & 0xfc) + 2)

/* Maximum size of object list to start with (reallocated dynamically). */
#define MAX_OBJ_LIST	10

typedef struct IPObjectStruct {
    struct IPObjectStruct *Pnext;		        /* To next in chain. */
    struct IPAttributeStruct *Attrs;
    char Name[OBJ_NAME_LEN];				  /* Name of object. */
    IPObjStructType ObjType;	    /* Object Type: Numeric, Geometric, etc. */
    ByteType Count;	       /* Count Number of references to this object. */
    unsigned int Tags;				         /* Some attributes. */
    union {
	IPPolygonStruct *Pl;		       	       /* Polygon/line list. */
	CagdCrvStruct *Crvs;			      /* Free form curve(s). */
	CagdSrfStruct *Srfs;			    /* Free form surface(s). */
	RealType R;				       /* Numeric real data. */
	PointType Pt;			         /* Numeric real point data. */
	VectorType Vec;			        /* Numeric real vector data. */
	PlaneType Plane;		         /* Numeric real plane data. */
	CagdCtlPtStruct CtlPt;			      /* Control point data. */
	MatrixType *Mat;	    /* Numeric 4 by 4 transformation matrix. */
	struct {
	    struct IPObjectStruct **PObjList;		 /* List of objects. */
	    int ListMaxLen;	      /* Maximum number of elements in list. */
	} Lst;
	char *Str;			  /* General string for text object. */
	VoidPtr *VPtr;
    } U;
} IPObjectStruct;

typedef void (*IritPrsrPrintFuncType)(char *);

extern jmp_buf
    _IritPrsrLongJumpBuffer;
extern int
    _IritPrsrPolyListCirc,
    _IritPrsrReadSocket,
    _IritPrsrWriteSocket,
    _IritPrsrReadWriteBinary;

#if defined(__cplusplus) || defined(c_plusplus)
extern "C" {
#endif
FILE *IritPrsrOpenDataFile(char *FileName, int Read, int Messages);
void IritPrsrCloseDataFile(FILE *f);
IPObjectStruct *IritPrsrGetDataFiles(char **DataFileNames, int NumOfDataFiles,
				     int Messages, int MoreMessages);
IPObjectStruct *IritPrsrGetObjects(FILE *f);
IPObjectStruct *IritPrsrProcessReadObject(IPObjectStruct *PObj);
void IritPrsrStdoutObject(IPObjectStruct *PObj);
void IritPrsrPutObject(FILE *f, IPObjectStruct *PObj);
int IritPrsrParseError(char **ErrorMsg);
void IritPrsrSetPrintFunc(IritPrsrPrintFuncType PrintFunc);
void IritPrsrSetFloatFormat(char *FloatFormat);
void IritPrsrSetBinaryFormat(int BinFormat);
void IritPrsrPropagateAttrs(IPObjectStruct *PObj, IPAttributeStruct *Attrs);
void IritPrsrReadSocket(int ReadSocket);
void IritPrsrWriteSocket(int WriteSocket);
void IritPrsrInputUnGetC(char c);
void IritPrsrSetPolyListCirc(int Circ);
void IritPrsrSetFlattenObjects(int Flatten);
void IritPrsrSetReadOneObject(int OneObject);
void IritPrsrFatalError(char *Msg);
void IritPrsrUpdatePolyPlane(IPPolygonStruct *PPoly);
void IritPrsrUpdatePolyPlane2(IPPolygonStruct *PPoly, VectorType Vin);
void IritPrsrUpdateVrtxNrml(IPPolygonStruct *PPoly, VectorType DefNrml);
IPObjectStruct *IritPrsrReverseObjList(IPObjectStruct *PObj);
void IritPrsrReverseVrtxList(IPPolygonStruct *Pl);
void IritPrsrParserAbort(IritPrsrErrType ErrNum, char *Msg);

/* Binary stream functions. */
IPObjectStruct *IritPrsrGetBinObject(void *f);
void IritPrsrPutBinObject(void *f, IPObjectStruct *PObj);

/* If set to TRUE (default) polygons will have their vertex lists circular   */
/* or last vertex point on first. If set to FALSE, regular list list.	     */
extern int IritPrsrPolyListCirc;

/* Will be set to VIEW_MAT and PERS_MAT respectively if found in parsed data.*/
extern MatrixType IritPrsrViewMat, IritPrsrPrspMat;
extern int IritPrsrWasViewMat, IritPrsrWasPrspMat;

/* Variable is used internally. It should not be accessed by applications. */
extern int _IritPrsrPolyListCirc;

/* External variables/functions that should be provided by the application:  */

/* Gets two list of all curves and surfaces in the datafile and process them */
/* as needed. May return a processed version to be put on returned list from */
/* IritPrsrGetObjects (polygonal approximation of the free form data for     */
/* example), or NULL otherwise.						     */
/* This function is responsible to free crvs/srfs if not needed any more.    */
IPObjectStruct *IritPrsrProcessFreeForm(IPObjectStruct *CrvObjs,
					IPObjectStruct *SrfObjs);

/* Convexity test for a polygon. */
int IritPrsrIsConvexPolygon(IPPolygonStruct *Pl);

/* Last element retrieval routines. */
IPObjectStruct *IritPrsrGetLastObj(IPObjectStruct *OList);
IPObjectStruct *IritPrsrGetPrevObj(IPObjectStruct *OList, IPObjectStruct *O);
IPPolygonStruct *IritPrsrGetLastPoly(IPPolygonStruct *PList);
IPPolygonStruct *IritPrsrGetPrevPoly(IPPolygonStruct *PList, IPPolygonStruct *P);
IPVertexStruct *IritPrsrGetLastVrtx(IPVertexStruct *VList);
IPVertexStruct *IritPrsrGetPrevVrtx(IPVertexStruct *VList, IPVertexStruct *V);
int IritPrsrObjListLen(IPObjectStruct *O);
int IritPrsrPolyListLen(IPPolygonStruct *P);
int IritPrsrVrtxListLen(IPVertexStruct *V);

#if defined(__cplusplus) || defined(c_plusplus)
}
#endif

#endif	/* IRIT_PRSR_GH */
