/*****************************************************************************
* Filter to convert IRIT data files back to IRIT .irt files.		     *
******************************************************************************
* (C) Gershon Elber, Technion, Israel Institute of Technology                *
******************************************************************************
* Written by:  Gershon Elber				Ver 1.0, Sep 1991    *
*****************************************************************************/

#include <stdio.h>
#include <math.h>
#include <string.h>
#include "irit_sm.h"
#include "iritprsr.h"
#include "allocate.h"
#include "attribut.h"
#include "cagd_lib.h"
#include "symb_lib.h"
#include "triv_lib.h"
#include "trim_lib.h"
#include "getarg.h"
#include "genmat.h"

#ifdef NO_CONCAT_STR
static char *VersionStr =
	"Dat2Irit		Version 6.0,		Gershon Elber,\n\
	 (C) Copyright 1989/90/91/92/93 Gershon Elber, Non commercial use only.";
#else
static char *VersionStr = "Dat2Irit	" VERSION ",	Gershon Elber,	"
	__DATE__ ",   " __TIME__ "\n" COPYRIGHT ", Non commercial use only.";
#endif /* NO_CONCAT_STR */

static char
    *CtrlStr = "dat2irit z%- DFiles!*s";

static void DumpDataForIrit(IPObjectStruct *PObjects);
static void DumpOneObject(FILE *f, IPObjectStruct *PObject, int Level);
static void DumpOnePolygon(FILE *f,
			   IPPolygonStruct *PPolygon,
			   int PolyNum,
			   int IsPolyline);
static void DumpOneCurve(FILE *f, char *Name, CagdCrvStruct *Crv);
static void DumpOneSurface(FILE *f, char *Name, CagdSrfStruct *Srf);
static void DumpOneTrimmedSrf(FILE *f, char *Name, TrimSrfStruct *TrimSrf);
static void DumpOneTrivar(FILE *f, char *Name, TrivTVStruct *Trivar);
static void DumpCtlPt(FILE *f,
		      CagdPointType PType,
		      RealType **Points,
		      int Index);
static void DumpKnotVector(FILE *f, RealType *KnotVector, int Length);

void Dat2IritExit(int ExitCode);

/*****************************************************************************
* DESCRIPTION:                                                               M
* Main module of dat2irit - Read command line and do what is needed...	     M
*                                                                            *
* PARAMETERS:                                                                M
*   argc, argv:  Command line.                                               M
*                                                                            *
* RETURN VALUE:                                                              M
*   void                                                                     M
*                                                                            *
* KEYWORDS:                                                                  M
*   main                                                                     M
*****************************************************************************/
void main(int argc, char **argv)
{
    int Error,
	VerFlag = FALSE,
	NumFiles = 0;
    char
	**FileNames = NULL;
    IPObjectStruct *PObjects;

    if ((Error = GAGetArgs(argc, argv, CtrlStr,
			   &VerFlag, &NumFiles, &FileNames)) != 0) {
	GAPrintErrMsg(Error);
	GAPrintHowTo(CtrlStr);
	Dat2IritExit(1);
    }

    if (VerFlag) {
	fprintf(stderr, "\n%s\n\n", VersionStr);
	GAPrintHowTo(CtrlStr);
	Dat2IritExit(0);
    }

    if (!NumFiles) {
	fprintf(stderr, "No data file names were given, exit.\n");
	GAPrintHowTo(CtrlStr);
	Dat2IritExit(1);
    }

    /* Get the data files: */
    IritPrsrSetFlattenObjects(FALSE);
    if ((PObjects = IritPrsrGetDataFiles(FileNames, NumFiles, TRUE, FALSE)) ==
									NULL)
	Dat2IritExit(0);

    DumpDataForIrit(PObjects);

    Dat2IritExit(0);
}

/*****************************************************************************
* DESCRIPTION:                                                               *
* Dumps the given Objects to stdout.                                         *
*                                                                            *
* PARAMETERS:                                                                *
*   PObject:    Objects todump                                               *
*                                                                            *
* RETURN VALUE:                                                              *
*   void                                                                     *
*****************************************************************************/
static void DumpDataForIrit(IPObjectStruct *PObjects)
{
    for ( ; PObjects != NULL; PObjects = PObjects -> Pnext)
	DumpOneObject(stdout, PObjects, 1);
}

/*****************************************************************************
* DESCRIPTION:                                                               *
* Dumps one object PObject to files.                                         *
*                                                                            *
* PARAMETERS:                                                                *
*   f:            File to dump object to.                                    *
*   PObject:      Object to dump to file f.                                  *
*                                                                            *
* RETURN VALUE:                                                              *
*   void                                                                     *
*****************************************************************************/
static void DumpOneObject(FILE *f, IPObjectStruct *PObject, int Level)
{
    static int
	NameCount = 1;
    int i, j;
    CagdRType *R;
    CagdSrfStruct *Srf;
    CagdCrvStruct *Crv;
    TrimSrfStruct *TrimSrf;
    TrivTVStruct *Trivar;
    IPPolygonStruct *Pl;
    IPObjectStruct *PTmp;
    IPAttributeStruct
	*Attr = AttrTraceAttributes(PObject -> Attrs, PObject -> Attrs);

    if (PObject -> Name == NULL || strlen(PObject -> Name) == 0)
	sprintf(PObject -> Name, "NoName%d", NameCount++);

    switch (PObject -> ObjType) {
	case IP_OBJ_LIST_OBJ:
	    for (i = 0; (PTmp = ListObjectGet(PObject, i)) != NULL; i++)
		DumpOneObject(f, PTmp, Level + 1);

	    if (PObject -> Name == NULL || strlen(PObject -> Name) == 0)
		sprintf(PObject -> Name, "NoName%d", NameCount++);
	    printf("%s%s = list( ",
		   PObject -> Name, PObject -> Pnext == NULL ? "" : ",");

	    for (j = 0; (PTmp = ListObjectGet(PObject, j)) != NULL; j++) {
		if (PTmp -> Name == NULL || strlen(PTmp -> Name) == 0)
		    sprintf(PTmp -> Name, "NoName%d", NameCount++);
		printf("%s%s%s",
		       j == 0 ? "" : "\t\t",
		       PTmp -> Name,
		       j == i - 1 ? " );\n" : ",\n");
	    }
	    break;
	case IP_OBJ_POLY:
	    for (Pl = PObject -> U.Pl, i = 1;
		 Pl != NULL; 
		 Pl = Pl -> Pnext, i++)
		DumpOnePolygon(f, Pl, i, IP_IS_POLYLINE_OBJ(PObject));
	    fprintf(f, "%s = mergePoly( list( ", PObject -> Name);
	    for (j = 1; j < i; j++) {
		if (j % 7 == 0)
		    fprintf(f, "\n\t\t");
		fprintf(f, "poly%d%s ", j, j == i - 1 ? "" : ",");
	    }
	    printf(") );\n");
	    break;
	case IP_OBJ_NUMERIC:
	    fprintf(f, "%s = %g;\n", PObject -> Name, PObject -> U.R);
	    break;
	case IP_OBJ_POINT:
	    fprintf(f, "%s = point(%g, %g, %g);\n",
		    PObject -> Name, PObject -> U.Pt[0], PObject -> U.Pt[1],
		    PObject -> U.Pt[2]);
	    break;
	case IP_OBJ_VECTOR:
	    fprintf(f, "%s = vector(%g, %g, %g);\n",
		    PObject -> Name, PObject -> U.Vec[0], PObject -> U.Vec[1],
		    PObject -> U.Vec[2]);
	    break;
	case IP_OBJ_PLANE:
	    fprintf(f, "%s = plane(%g, %g, %g, %g);\n",
		    PObject -> Name,
		    PObject -> U.Plane[0], PObject -> U.Plane[1],
		    PObject -> U.Plane[2], PObject -> U.Plane[3]);
	    break;
	case IP_OBJ_MATRIX:
	    fprintf(f, "%s = homomat( list( ", PObject -> Name);
	    for(i = 0; i < 4; i++) {
		fprintf(f, "\n\tlist( ");
	        for (j = 0; j < 4; j++) {
		    fprintf(f, i == 3 && j == 3 ? "%g) ) );\n"
						: (j == 3 ? "%g ),"
						          : "%g, "),
			    (*PObject -> U.Mat)[i][j]);
		}
	    }
	    break;
	case IP_OBJ_CURVE:
	    for (Crv = PObject -> U.Crvs; Crv != NULL; Crv = Crv -> Pnext)
		DumpOneCurve(f, PObject -> Name, Crv);
	    break;
	case IP_OBJ_SURFACE:
	    for (Srf = PObject -> U.Srfs; Srf != NULL; Srf = Srf -> Pnext)
		DumpOneSurface(f, PObject -> Name, Srf);
	    break;
	case IP_OBJ_TRIMSRF:
	    for (TrimSrf = PObject -> U.TrimSrfs;
		 TrimSrf != NULL;
		 TrimSrf = TrimSrf -> Pnext)
		DumpOneTrimmedSrf(f, PObject -> Name, TrimSrf);
	    break;
	case IP_OBJ_TRIVAR:
	    for (Trivar = PObject -> U.Trivars;
		 Trivar != NULL;
		 Trivar = Trivar -> Pnext)
		DumpOneTrivar(f, PObject -> Name, Trivar);
	    break;
	case IP_OBJ_STRING:
	    fprintf(f, "%s = \"%s\";\n", PObject -> Name, PObject -> U.Str);
	    break;
	case IP_OBJ_CTLPT:
	    R = PObject -> U.CtlPt.Coords;
	    fprintf(f, "%s = ", PObject -> Name);
	    DumpCtlPt(f, PObject -> U.CtlPt.PtType, &R, -1);
	    fprintf(f, "\n");
	    break;
	default:
	    break;
    }

    while (Attr) {
	if (Attr -> Type == IP_ATTR_OBJ) {
	    DumpOneObject(f, Attr -> U.PObj, Level + 1);
	    fprintf(f, "attrib(%s, \"%s\", %s);\n",
		    PObject -> Name, Attr -> Name, Attr -> U.PObj -> Name);
	}
	else {
	    fprintf(f, "attrib(%s, \"%s\", %s);\n",
		    PObject -> Name, Attr -> Name, Attr2String(Attr, FALSE));
	}
	Attr = AttrTraceAttributes(Attr, NULL);
    }
    fprintf(f, "\n\n");
}

/*****************************************************************************
* DESCRIPTION:                                                               *
* Dumps one polygon.                                                         *
*                                                                            *
* PARAMETERS:                                                                *
*   f:		  File to dump polygon to. 		                     *
*   PPolygon:     Polygon to dump to file f.                                 *
*   PolyNum:      Number of polygon.                                         *
*   IsPolyline:   Is it a polyline or a polygon?                             *
*                                                                            *
* RETURN VALUE:                                                              *
*   void		                                                     *
*****************************************************************************/
static void DumpOnePolygon(FILE *f,
			   IPPolygonStruct *PPolygon,
			   int PolyNum,
			   int IsPolyline)
{
    int i,
	VCount = 1;
    IPVertexStruct
	*V = PPolygon -> PVertex,
	*VFirst = V;

    do {
	fprintf(f, "vrtx%d = vector( %g, %g, %g );\n", VCount++,
		V -> Coord[0], V -> Coord[1], V -> Coord[2]);
	V = V -> Pnext;
    }
    while (V != VFirst && V != NULL);

    fprintf(f, "poly%d = poly( list( ", PolyNum );
    for (i = 1; i < VCount; i++) {
	if (VCount % 9 == 0)
	    fprintf(f, "\n\t\t");
	fprintf(f, "vrtx%d%s ", i, i == VCount - 1 ? "" : "," );
    }
    fprintf(f, "), %s );\n\n", IsPolyline ? "true" : "false" );
}

/*****************************************************************************
* DESCRIPTION:                                                               *
* Dumps one curve.                                                           *
*                                                                            *
* PARAMETERS:                                                                *
*   f:		  File to dump curve to.   		                     *
*   Name:	  Name of curve.			                     *
*   Crv:   	  To dump to f.				                     *
*                                                                            *
* RETURN VALUE:                                                              *
*   void		                                                     *
*****************************************************************************/
static void DumpOneCurve(FILE *f, char *Name, CagdCrvStruct *Crv)
{
    int i;

    switch (Crv -> GType) {
	case CAGD_CBEZIER_TYPE:
	    fprintf(f, "%s = cbezier(\n", Name);
	    break;
	case CAGD_CBSPLINE_TYPE:
	    fprintf(f, "%s = cbspline( %d,\n", Name, Crv -> Order);
	    break;
	default:
	    fprintf(stderr, "Unsupported curve type ignored.\n");
	    return;
    }

    /* Print the control polygon: */
    fprintf(f, "\tlist( ");
    for (i = 0; i < Crv -> Length; i++) {
	DumpCtlPt(f, Crv -> PType, Crv -> Points, i);
	if (i < Crv -> Length - 1)
	    fprintf(f, ",\n\t      ");
    }

    switch (Crv -> GType) {
	case CAGD_CBEZIER_TYPE:
	    fprintf(f, " ) );\n");
	    break;
	case CAGD_CBSPLINE_TYPE:
	    fprintf(f, " ),\n\t ");
	    DumpKnotVector(f, Crv -> KnotVector,
			   Crv -> Order + CAGD_CRV_PT_LST_LEN(Crv));
	    fprintf(f, " );\n");
	    break;
	default:
	    break;
    }
}

/*****************************************************************************
* DESCRIPTION:                                                               *
* Dumps one surface.                                                         *
*                                                                            *
* PARAMETERS:                                                                *
*   f:		  File to dump surface to.           		             *
*   Name:	  Name of surface.			                     *
*   Srf:   	  To dump to f.				                     *
*                                                                            *
* RETURN VALUE:                                                              *
*   void		                                                     *
*****************************************************************************/
static void DumpOneSurface(FILE *f, char *Name, CagdSrfStruct *Srf)
{
    int i, j, k;

    switch (Srf -> GType) {
	case CAGD_SBEZIER_TYPE:
	    fprintf(f, "%s = sbezier(\n", Name);
	    break;
	case CAGD_SBSPLINE_TYPE:
	    fprintf(f, "%s = sbspline( %d, %d, \n", Name,
		    Srf -> UOrder, Srf -> VOrder);
	    break;
	default:
	    fprintf(stderr, "Unsupported surface type ignored.\n");
	    return;
    }

    /* Print the control mesh: */
    for (i = k = 0; i < Srf -> VLength; i++) {
	for (j = 0; j < Srf -> ULength; j++) {
	    fprintf(f, "%s", i == 0 && j == 0 ? "\tlist( " : "\t      ");
	    fprintf(f, "%s", j == 0 ? "list( " : "      ");
	    DumpCtlPt(f, Srf -> PType, Srf -> Points, k++);
	    fprintf(f, "%s", j == Srf -> ULength - 1 ? " )" : ",\n" );
	}
	if (i < Srf -> VLength - 1)
	    fprintf(f, ",\n");
    }

    switch (Srf -> GType) {
	case CAGD_SBEZIER_TYPE:
	    fprintf(f, " ) );\n");
	    break;
	case CAGD_SBSPLINE_TYPE:
	    fprintf(f, " ),\n\tlist( ");
	    DumpKnotVector(f, Srf -> UKnotVector,
			   Srf -> UOrder + CAGD_SRF_UPT_LST_LEN(Srf));
	    fprintf(f, ",\n\t      ");
	    DumpKnotVector(f, Srf -> VKnotVector,
			   Srf -> VOrder + CAGD_SRF_VPT_LST_LEN(Srf));
	    fprintf(f, " ) );\n");
	    break;
	default:
	    break;
    }
}

/*****************************************************************************
* DESCRIPTION:                                                               *
* Dumps one trimmed surface.                                                 *
*                                                                            *
* PARAMETERS:                                                                *
*   f:		  File to dump surface to.           		             *
*   Name:	  Name of trimmed surface.			             *
*   TrimSrf:  	  To dump to f.				                     *
*                                                                            *
* RETURN VALUE:                                                              *
*   void		                                                     *
*****************************************************************************/
static void DumpOneTrimmedSrf(FILE *f, char *Name, TrimSrfStruct *TrimSrf)
{
    static int
	TrimmedSrfCount = 1;
    int i,
	TrimmedCrvCount = 1;
    char SrfName[LINE_LEN], CrvsName[LINE_LEN];
    CagdCrvStruct *TrimCrvs, *TrimCrv;

    sprintf(SrfName, "TSrf%dSrf", TrimmedSrfCount);
    DumpOneSurface(f, SrfName, TrimSrf -> Srf);

    sprintf(CrvsName, "TSrf%dCrvs", TrimmedSrfCount++);
    TrimCrvs = TrimGetTrimmingCurves(TrimSrf, TRUE, TRUE);
    for (TrimCrv = TrimCrvs; TrimCrv != NULL; TrimCrv = TrimCrv -> Pnext) {
	char CrvName[LINE_LEN];

	sprintf(CrvName, "%s%d", CrvsName, TrimmedCrvCount++);
	DumpOneCurve(f, CrvName, TrimCrv);
    }

    fprintf(f, "%s = trimsrf( %s,\n\t\tlist( ", Name, SrfName);
    for (i = 1; i < TrimmedCrvCount; i++) {
	char CrvName[LINE_LEN];

	sprintf(CrvName, "%s%d", CrvsName, i);
	if (i == 1)
	    fprintf(f, "%s,\n", CrvName);
	else if (i == TrimmedCrvCount - 1)
	    fprintf(f, "\t\t     %s),\n\t\ttrue );\n", CrvName);
	else
	    fprintf(f, "\t\t     %s,\n", CrvName);
    }
}

/*****************************************************************************
* DESCRIPTION:                                                               *
* Dumps one trivariate function.                                             *
*                                                                            *
* PARAMETERS:                                                                *
*   f:		  File to dump trivariate function to. 		             *
*   Name:	  Name of trivariate.			                     *
*   Trivar:   	  To dump to f.				                     *
*                                                                            *
* RETURN VALUE:                                                              *
*   void		                                                     *
*****************************************************************************/
static void DumpOneTrivar(FILE *f, char *Name, TrivTVStruct *Trivar)
{
    int i, j, k, l;

    switch (Trivar -> GType) {
	case TRIV_TVBEZIER_TYPE:
	    fprintf(f, "%s = tbezier(\n", Name);
	    break;
	case TRIV_TVBSPLINE_TYPE:
	    fprintf(f, "%s = tbspline( %d, %d, %d,\n", Name,
		    Trivar -> UOrder, Trivar -> VOrder, Trivar -> WOrder);
	    break;
	default:
	    fprintf(stderr, "Unsupported trivariate type ignored.\n");
	    return;
    }

    /* Print the control mesh: */
    for (k = l = 0; k < Trivar -> WLength; k++) {
	for (j = 0; j < Trivar -> VLength; j++) {
	    for (i = 0; i < Trivar -> ULength; i++) {
		fprintf(f, "%s", i == 0 && j == 0 && k == 0 ? "\tlist( "
							    : "\t      ");
		fprintf(f, "%s", j == 0 && i == 0 ? "list( " : "      ");
		fprintf(f, "%s", i == 0 ? "list( " : "      ");
		DumpCtlPt(f, Trivar -> PType, Trivar -> Points, l++);
		fprintf(f, "%s", i == Trivar -> ULength - 1 ? " )" : ",\n" );
	    }
	    fprintf(f, "%s", j == Trivar -> VLength - 1 ? " )" : ",\n" );
	}
	if (k < Trivar -> WLength - 1)
	    fprintf(f, ",\n");
    }

    switch (Trivar -> GType) {
	case TRIV_TVBEZIER_TYPE:
	    fprintf(f, " ) );\n");
	    break;
	case TRIV_TVBSPLINE_TYPE:
	    fprintf(f, " ),\n\tlist( ");
	    DumpKnotVector(f, Trivar -> UKnotVector,
			   Trivar -> UOrder + TRIV_TV_UPT_LST_LEN(Trivar));
	    fprintf(f, ",\n\t      ");
	    DumpKnotVector(f, Trivar -> UKnotVector,
			   Trivar -> VOrder + TRIV_TV_VPT_LST_LEN(Trivar));
	    fprintf(f, ",\n\t      ");
	    DumpKnotVector(f, Trivar -> VKnotVector,
			   Trivar -> WOrder + TRIV_TV_WPT_LST_LEN(Trivar));
	    fprintf(f, " ) );\n");
	    break;
	default:
	    break;
    }
}

/*****************************************************************************
* DESCRIPTION:                                                               *
* Dumps one control point.                                                   *
*                                                                            *
* PARAMETERS:                                                                *
*   f:		  File to dump control point to.	                     *
*   PType:	  Type of control point.				     *
*   Points:	  The coefficients of the control p;oints (possibly from a   *
*		  curve or surface).					     *
*   Index:   	  Into Points. -1 denotes Points are in fact (RealType *).   *
*                                                                            *
* RETURN VALUE:                                                              *
*   void		                                                     *
*****************************************************************************/
static void DumpCtlPt(FILE *f,
		      CagdPointType PType,
		      RealType **Points,
		      int Index)
{
    int i,
	IsRational = CAGD_IS_RATIONAL_PT(PType),
	MaxCoord = CAGD_NUM_OF_PT_COORD(PType);

    fprintf(f, "ctlpt( ");
    fprintf(f, IsRational ? "P%d" : "E%d", MaxCoord);

    if (Index == -1) {
	RealType
	    *Pt = *Points;

	for (i = !IsRational; i <= MaxCoord; i++)
	    fprintf(f, ", %g", Pt[i]);
    }
    else {
	for (i = !IsRational; i <= MaxCoord; i++)
	    fprintf(f, ", %g", Points[i][Index]);
    }

    fprintf(f, Index == -1 ? " );" : " )");
}

/*****************************************************************************
* DESCRIPTION:                                                               *
* Dumps one knot vector.						     *
*                                                                            *
* PARAMETERS:                                                                *
*   f:		  File to dump control point to.	                     *
*   KnotVector:   Coefficients of knot vector.                               *
*   Length:       Length of knot vector.                                     *
*                                                                            *
* RETURN VALUE:                                                              *
*   void                                                                     *
*****************************************************************************/
static void DumpKnotVector(FILE *f, RealType *KnotVector, int Length)
{
    int i;

    fprintf(f, "list( ");
    for (i = 0; i < Length; i++)
	fprintf(f, "%g%s ", KnotVector[i], i < Length -1 ? "," : "");
    fprintf(f, ")");
}

/*****************************************************************************
* DESCRIPTION:                                                               *
* Dat2Irit Irit2Ray exit routine.					     *
*                                                                            *
* PARAMETERS:                                                                *
*   ExitCode:                                                                *
*                                                                            *
* RETURN VALUE:                                                              *
*   void                                                                     *
*****************************************************************************/
void Dat2IritExit(int ExitCode)
{
    exit(ExitCode);
}

#ifdef DEBUG

/*****************************************************************************
* DESCRIPTION:                                                               *
*    Dummy function to link at debugging time.                               *
*                                                                            *
* PARAMETERS:                                                                *
*                                                                            *
* RETURN VALUE:                                                              *
*   void                                                                     *
*                                                                            *
* KEYWORDS:                                                                  *
*****************************************************************************/
void DummyLinkCagdDebug(void)
{
    IritPrsrDbg();
}

#endif /* DEBUG */
