/*****************************************************************************
* Filter to convert IRIT data files back to IRIT .irt files.		     *
*									     *
* 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 "attribut.h"
#include "getarg.h"
#include "genmat.h"

#ifdef NO_CONCAT_STR
static char *VersionStr =
	"Dat2Irit		Version 4.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);
static void DumpOnePolygon(FILE *f, IPPolygonStruct *PPolygon, int PolyNum,
							      int IsPolyline);
static void DumpOneSurface(FILE *f, char *Name, CagdSrfStruct *Srf);
static void DumpOneCurve(FILE *f, char *Name, CagdCrvStruct *Crv);
static void DumpCtlPt(FILE *f, CagdPointType PType, RealType **Points,
								int Index);
static void DumpKnotVector(FILE *f, RealType *KnotVector, int Length);

void Dat2IritExit(int ExitCode);

/*****************************************************************************
* Main routine - Read Parameter	line and do what you need...		     *
*****************************************************************************/
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: */
    if ((PObjects = IritPrsrGetDataFiles(FileNames, NumFiles, TRUE, FALSE)) ==
									NULL)
	Dat2IritExit(0);

    DumpDataForIrit(PObjects);

    Dat2IritExit(0);
}

/*****************************************************************************
* Dumps the data from the IRIT DAT file into stdout.			     *
*****************************************************************************/
static void DumpDataForIrit(IPObjectStruct *PObjects)
{
    int NameCount = 1;
    IPObjectStruct *PObj,
	*PObjHead = NULL;

    /* Reverse object list since it was loaded in reverse by iritprsr module.*/
    while (PObjects != NULL) {
	PObj = PObjects;
	PObjects = PObjects -> Pnext;
	PObj -> Pnext = PObjHead;
	PObjHead = PObj;
    }

    for (PObjects = PObjHead; PObjects != NULL; PObjects = PObjects -> Pnext)
	DumpOneObject(stdout, PObjects);

    printf("\n\ndat2irit = list(\n");
    for (PObjects = PObjHead; PObjects != NULL; PObjects = PObjects -> Pnext)
    if (PObjects -> Name == NULL || strlen(PObjects -> Name) == 0)
	printf("\tNoName%d%s\n",
	       NameCount++, PObjects -> Pnext == NULL ? "" : ",");
    else
	printf("\t%s%s\n",
	       PObjects -> Name, PObjects -> Pnext == NULL ? "" : ",");
    printf(");\n");

}

/*****************************************************************************
* Routine to dump one object PObject.					     *
*****************************************************************************/
static void DumpOneObject(FILE *f, IPObjectStruct *PObject)
{
    static int
	NameCount = 1;
    int i, j;
    char Name[LINE_LEN_LONG];
    CagdRType *R;
    CagdSrfStruct *Srf;
    CagdCrvStruct *Crv;
    IPPolygonStruct *Pl;

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

    switch (PObject -> ObjType) {
	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( ", 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\n");
	    break;
	case IP_OBJ_NUMERIC:
	    fprintf(f, "%s = %lg;\n\n", Name, PObject -> U.R);
	    break;
	case IP_OBJ_POINT:
	    fprintf(f, "%s = point(%lg, %lg, %lg);\n\n",
		    Name, PObject -> U.Pt[0], PObject -> U.Pt[1],
		    PObject -> U.Pt[2]);
	    break;
	case IP_OBJ_VECTOR:
	    fprintf(f, "%s = vector(%lg, %lg, %lg);\n\n",
		    Name, PObject -> U.Vec[0], PObject -> U.Vec[1],
		    PObject -> U.Vec[2]);
	    break;
	case IP_OBJ_PLANE:
	    fprintf(f, "%s = plane(%lg, %lg, %lg, %lg);\n\n",
		    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(", Name);
	    for(i = 0; i < 4; i++) {
		fprintf(f, "\n\tlist( ");
	        for (j = 0; j < 4; j++) {
		    fprintf(f, i == 3 && j == 3 ? "%lg) ) );\n\n"
						: (j == 3 ? "%lg ),"
						          : "%lg, "),
			    (*PObject -> U.Mat)[i][j]);
		}
	    }
	    break;
	case IP_OBJ_CURVE:
	    for (Crv = PObject -> U.Crvs; Crv != NULL; Crv = Crv -> Pnext)
		DumpOneCurve(f, Name, Crv);
	    break;
	case IP_OBJ_SURFACE:
	    for (Srf = PObject -> U.Srfs; Srf != NULL; Srf = Srf -> Pnext)
		DumpOneSurface(f, Name, Srf);
	    break;
	case IP_OBJ_STRING:
	    fprintf(f, "%s = \"%s\"\n\n;", Name, PObject -> U.Str);
	    break;
	case IP_OBJ_CTLPT:
	    R = PObject -> U.CtlPt.Coords;
	    fprintf(f, "%s = ", Name);
	    DumpCtlPt(f, PObject -> U.CtlPt.PtType, &R, -1);
	    fprintf(f, "\n\n");
	    break;
	default:
	    break;
    }
}

/*****************************************************************************
* Routine to dump one polygon.						     *
*****************************************************************************/
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( %lg, %lg, %lg );\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" );
}

/*****************************************************************************
* Routine to dump one surface.						     *
*****************************************************************************/
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 + Srf -> ULength);
	    fprintf(f, ",\n\t      ");
	    DumpKnotVector(f, Srf -> VKnotVector,
			   Srf -> VOrder + Srf -> VLength);
	    fprintf(f, " ) );\n");
	    break;
	default:
	    break;
    }
}

/*****************************************************************************
* Routine to dump one curve.						     *
*****************************************************************************/
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 + Crv -> Length);
	    fprintf(f, " );\n");
	    break;
	default:
	    break;
    }
}

/*****************************************************************************
* Routine to dump one control point.					     *
*****************************************************************************/
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, ", %lg", Pt[i]);
    }
    else {
	for (i = !IsRational; i <= MaxCoord; i++)
	    fprintf(f, ", %lg", Points[i][Index]);
    }

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

/*****************************************************************************
* Routine to dump one knot vector.					     *
*****************************************************************************/
static void DumpKnotVector(FILE *f, RealType *KnotVector, int Length)
{
    int i;

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

/*****************************************************************************
* Dat2Irit exit routine.						     *
*****************************************************************************/
void Dat2IritExit(int ExitCode)
{
    exit(ExitCode);
}
