/*****************************************************************************
* Skeleton for an interface to a parser to read IRIT data files.	     *
*									     *
* Written by:  Gershon Elber				Ver 1.0, Feb 1993    *
*****************************************************************************/


#ifdef USE_VARARGS
#include <varargs.h>
#else
#include <stdarg.h>
#endif /* USE_VARARGS */
#include <stdio.h>
#include <ctype.h>
#include <math.h>
#include <string.h>
#include "irit_sm.h"
#include "iritprsr.h"
#include "attribut.h"
#include "allocate.h"
#include "getarg.h"
#include "genmat.h"
#include "ffcnvrt.h"
#include "ip_cnvrt.h"

static MatrixType CrntViewMat;			/* This is the current view! */
static int
    GlblFineNess = 10,
    FourPerFlat = FALSE,
    ReadOneObject = FALSE;

static void PrintData(IPObjectStruct *PObj, int Indent);
#ifdef USE_VARARGS
static void IFprintf(int Indent, char *va_alist, ...);
#else
static void IFprintf(int Indent, char *Format, ...);
#endif /* USE_VARARGS */
static char *Real2Str(RealType R);
static void SkelExit(int ExitCode);

/*****************************************************************************
* Main routine - read command line parameters and does what is needed...     *
*****************************************************************************/
void main(int argc, char **argv)
{
    IPObjectStruct *PObjects, *PObj;

    while (argc >= 2 && argv[1][0] == '-') {
	if (strcmp(argv[1], "-f") == 0) {
	    /* Surface to polygon approx. is controlled by GlblFineNess. */
	    GlblFineNess = atoi(argv[2]);
	    argv += 2;
	    argc -= 2;
	}
	else if (strcmp(argv[1], "-4") == 0) {
	    /* Create four triangle per flat instead of two in srf to polys. */
	    FourPerFlat = TRUE;
	    argv++;
	    argc--;
	}
	else if (strcmp(argv[1], "-1") == 0) {
	    /* Read one object at a time. */
	    ReadOneObject = TRUE;
	    argv++;
	    argc--;
	}
	else {
	    IritFatalError("Undefined command line option.\n");
	}
    }

    /* Get the data files: */
    if ((PObjects = IritPrsrGetDataFiles(argv + 1, argc - 1, TRUE, FALSE)) ==
									NULL)
	SkelExit(1);

    if (IritPrsrWasPrspMat)
	MatMultTwo4by4(CrntViewMat, IritPrsrViewMat, IritPrsrPrspMat);
    else
	GEN_COPY(CrntViewMat, IritPrsrViewMat, sizeof(MatrixType));

    printf("[OBJECT ALL\n");
    for (PObj = PObjects; PObj != NULL; PObj = PObj -> Pnext)
	PrintData(PObj, 4);
    printf("]\n");
}

/*****************************************************************************
* Routine to convert all surfaces into polygons as follows:		     *
*****************************************************************************/
IPObjectStruct *IritPrsrProcessFreeForm(IPObjectStruct *CrvObjs,
					IPObjectStruct *SrfObjs)
{
    CagdSrfStruct *Srf, *Srfs;
    IPObjectStruct *PObj;
    IPPolygonStruct *PPolygon, *PPolygonTemp;

    if (SrfObjs) {
        for (PObj = SrfObjs; PObj != NULL; PObj = PObj -> Pnext) {
	    Srfs = PObj -> U.Srfs;
	    PObj -> U.Pl = NULL;
	    PObj -> ObjType = IP_OBJ_POLY;
	    IP_SET_POLYGON_OBJ(PObj);

	    for (Srf = Srfs; Srf != NULL; Srf = Srf -> Pnext) {
	        PPolygon = PPolygonTemp =
		    IritSurface2Polygons(Srf, FourPerFlat, GlblFineNess, TRUE);
		while (PPolygonTemp -> Pnext)
		    PPolygonTemp = PPolygonTemp -> Pnext;
		PPolygonTemp -> Pnext = PObj -> U.Pl;
		PObj -> U.Pl = PPolygon;
	    }
	    CagdSrfFreeList(Srfs);
	}
    }
    
    return SrfObjs;
}

/*****************************************************************************
* ALL FUNCTIONS BELOW ARE FOR PRINTING THE DATA STRUCTURE IN IRIT FORMAT     *
*****************************************************************************/

/*****************************************************************************
* Routine to print the data from given geometry object.			     *
*****************************************************************************/
static void PrintData(IPObjectStruct *PObj, int Indent)
{
    int i;
    char *UVVals;
    IPPolygonStruct *PPolygon;
    IPVertexStruct *PVertex;
    IPAttributeStruct
	*Attrs = AttrTraceAttributes(PObj -> Attrs);

    if (Attrs != NULL) {
	IFprintf(Indent, "[OBJECT\n");

	IFprintf(Indent + 4, "%s\n", Attr2String(Attrs));

	IFprintf(0, " %s\n", strlen(PObj -> Name) ? PObj -> Name : "NONE");
    }
    else
        IFprintf(Indent, "[OBJECT %s\n",
		 strlen(PObj -> Name) ? PObj -> Name : "NONE");

    Indent += 4;

    switch (PObj -> ObjType) {
	case IP_OBJ_POLY:
	    for (PPolygon = PObj -> U.Pl;
		 PPolygon != NULL;
		 PPolygon = PPolygon -> Pnext) {
		if (PPolygon -> PVertex == NULL) {
		    fprintf(stderr,"Dump: Attemp to dump empty polygon, exit\n");
		    SkelExit(1);
		}
		for (PVertex = PPolygon -> PVertex -> Pnext, i = 1;
		     PVertex != PPolygon -> PVertex && PVertex != NULL;
		     PVertex = PVertex -> Pnext, i++);
		IFprintf(Indent, "[%s %d\n",
			 IP_IS_POLYGON_OBJ(PObj) ? "POLYGON" : "POLYLINE", i);

		PVertex = PPolygon -> PVertex;
		do {		     /* Assume at least one edge in polygon! */
		    if ((UVVals = AttrGetStrAttrib(PVertex -> Attrs, "uvvals"))
								    == NULL)

			IFprintf(Indent + 4,
				 "[[NORMAL %s %s %s] %s %s %s]\n",
				 Real2Str(PVertex -> Normal[0]),
				 Real2Str(PVertex -> Normal[1]),
				 Real2Str(PVertex -> Normal[2]),
				 Real2Str(PVertex -> Coord[0]),
				 Real2Str(PVertex -> Coord[1]),
				 Real2Str(PVertex -> Coord[2]));
		    else
		        IFprintf(Indent + 4,
				 "[[NORMAL %s %s %s] [UV %s] %s %s %s]\n",
				 Real2Str(PVertex -> Normal[0]),
				 Real2Str(PVertex -> Normal[1]),
				 Real2Str(PVertex -> Normal[2]),
				 UVVals,
				 Real2Str(PVertex -> Coord[0]),
				 Real2Str(PVertex -> Coord[1]),
				 Real2Str(PVertex -> Coord[2]));

		    PVertex = PVertex -> Pnext;
		}
		while (PVertex != PPolygon -> PVertex && PVertex != NULL);
		IFprintf(Indent, "]\n");	       /* Close the polygon. */
	    }
	    break;
	default:
	    IFprintf(Indent + 4, "Non polygonal data is ignored.\n");
	    break;
    }

    Indent -= 4;
    IFprintf(Indent, "]\n");				/* Close the object. */
}

/*****************************************************************************
* Same as fprintf but with indentation.					     *
*****************************************************************************/
#ifdef USE_VARARGS
static void IFprintf(int Indent, char *va_alist, ...)
{
    char *Format, Line[LINE_LEN_LONG];
    int i;
    va_list ArgPtr;

    va_start(ArgPtr);
    Format = va_arg(ArgPtr, char *);
#else
static void IFprintf(int Indent, char *Format, ...)
{
    char Line[LINE_LEN_LONG];
    int i;
    va_list ArgPtr;

    va_start(ArgPtr, Format);
#endif /* USE_VARARGS */

    for (i = 0; i < Indent; i++)
	Line[i] = ' ';
    vsprintf(&Line[Indent], Format, ArgPtr);
    va_end(ArgPtr);

    printf(Line);
}

/*****************************************************************************
* Convert a real number into a string.					     *
* The routine maintains 6 different buffers simultanuously so up to 6 calls  *
* can be issued from same printf...					     *
*****************************************************************************/
static char *Real2Str(RealType R)
{
    static int j, k,
	i = 0;
    static char Buffer[6][LINE_LEN_SHORT];

    if (ABS(R) < EPSILON)
	R = 0.0;			    /* Round off very small numbers. */

    sprintf(Buffer[i], "%6lg", R);

    for (k = 0; !isdigit(Buffer[i][k]) && k < LINE_LEN; k++);
    if (k >= LINE_LEN) {
	fprintf(stderr, "Conversion of real number (%f) failed.\n", R);
	SkelExit(1);
    }

    for (j = strlen(Buffer[i]) - 1; Buffer[i][j] == ' ' && j > k; j--);
    if (strchr(Buffer[i], '.') != NULL)
	for (; Buffer[i][j] == '0' && j > k; j--);
    Buffer[i][j+1] = 0;

    j = i;
    i = (i + 1) % 6;
    return Buffer[j];
}

/*****************************************************************************
* Skeleton exit routine. 						     *
*****************************************************************************/
static void SkelExit(int ExitCode)
{
    exit(ExitCode);
}
