/*****************************************************************************
* Skeleton for an interface to a parser to read IRIT data files.	     *
******************************************************************************
* (C) Gershon Elber, Technion, Israel Institute of Technology                *
******************************************************************************
* 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 "iritgrap.h"
#include "getarg.h"
#include "genmat.h"
#include "ffcnvrt.h"
#include "ip_cnvrt.h"

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);

/*****************************************************************************
* DESCRIPTION:                                                               M
* Main module of skeletn1 - 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)
{
    IPObjectStruct *PObjects, *PObj;
    MatrixType CrntViewMat;

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

    /* Get the data files: */
    IritPrsrSetFlattenObjects(TRUE);
    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) {
	if (IP_IS_FFGEOM_OBJ(PObj))
	    PObj = ProcessFreeForm(PObj, &FFCState);
	
	PrintData(PObj, 4);
    }
    printf("]\n");
}

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

/*****************************************************************************
* DESCRIPTION:                                                               *
* Prints the data from given geometry object.				     *
*                                                                            *
* PARAMETERS:                                                                *
*   PObj:       Object to print.                                             *
*   Indent:     Column of indentation.                                       *
*                                                                            *
* RETURN VALUE:                                                              *
*   void                                                                     *
*****************************************************************************/
static void PrintData(IPObjectStruct *PObj, int Indent)
{
    int i;
    char *UVVals;
    IPPolygonStruct *PPolygon;
    IPVertexStruct *PVertex;
    IPAttributeStruct
	*Attrs = AttrTraceAttributes(PObj -> Attrs, PObj -> Attrs);

    if (Attrs != NULL) {
	IFprintf(Indent, "[OBJECT\n");
	while (Attrs) {
	    IFprintf(Indent + 4, "%s\n", Attr2String(Attrs, TRUE));
	    Attrs = AttrTraceAttributes(Attrs, NULL);
	}
	IFprintf(0, "\t%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 (IP_IS_POLYGON_OBJ(PObj)) {
			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]));
		    }
		    else if (IP_IS_POLYLINE_OBJ(PObj)) {
			  IFprintf(Indent + 4, "[%s %s %s]\n",
				   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. */
}

/*****************************************************************************
* DESCRIPTION:                                                               *
* Same as printf but with indentation.					     *
*                                                                            *
* PARAMETERS:                                                                *
*   Indent:      Column of indentation.                                      *
*   va_alist:    Do "man stdarg".                                            *
*                                                                            *
* RETURN VALUE:                                                              *
*   void                                                                     *
*****************************************************************************/
#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);
}

/*****************************************************************************
* DESCRIPTION:                                                               *
* Converts a real number into a string.					     *
*   The routine maintains 6 different buffers simultanuously so up to 6      *
* calls can be issued from same printf...				     *
*                                                                            *
* PARAMETERS:                                                                *
*   R:          To convert to a string.                                      *
*                                                                            *
* RETURN VALUE:                                                              *
*   char *:     A string representation for R.                               *
*****************************************************************************/
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], "%6g", 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];
}

/*****************************************************************************
* DESCRIPTION:                                                               *
* SkelExit exit routine.						     *
*                                                                            *
* PARAMETERS:                                                                *
*   ExitCode:                                                                *
*                                                                            *
* RETURN VALUE:                                                              *
*   void                                                                     *
*****************************************************************************/
static void SkelExit(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 */
