/****************************/
/*    MODEL LINKER          */
/* (c)2002 Pangea Software  */
/* By Brian Greenstone      */
/****************************/


/****************************/
/*    EXTERNALS             */
/****************************/


extern	short	gNumFilesToLink;
extern	long	gMakefileSize,gNumMaterials;
extern	Str255		gLinkSaveName;
extern	BG3DFileContainer		*gBG3DContainerList[];


/****************************/
/*    PROTOTYPES            */
/****************************/

static Boolean ScanForSaveName(void);
static short	CountLinks(void);
static Boolean LoadTheModelMakefile(void);
static void SaveNewFile(void);
static Ptr GetNextModelFileToLink(Ptr makefilePtr);
static void	BuildNewFile(void);
static void AttachModel(void);


/****************************/
/*    CONSTANTS             */
/****************************/

#define	MAX_MAKEFILE_SIZE		80000L		// assume makefile <



/*********************/
/*    VARIABLES      */
/*********************/

FSSpec	gLast3DMF_FSSpec;

Ptr		gModelFilePtr,gMakefilePtr;
long	gColonyFileSize;				// current working size of shape file

short	gTotalLinkedModels;


Str255		gLinkSaveName;
long		gMakefileSize;
short		gNumFilesToLink;


MOGroupObject	*gTheBG3DGroup = nil;				// group to contain linked BG3D files


/********************* EXECUTE COLONY MAKEFILE ************************/
//
// This single call takes care of everything.
//

void ExecuteMakefile(void)
{
Boolean			flag;

	InitMaterialsList();									// init texture removal stuff

	printf("*Material list initialized...\n");


			/***********************************/
			/* LOAD THE MAKEFILE & COUNT LINKS */
			/***********************************/
			
	gTotalLinkedModels = 0;	

	flag = LoadTheModelMakefile();						// load the makefile
	if (!flag)
		return;

	gNumFilesToLink = CountLinks();						// see how many links we need
	if (gNumFilesToLink == 0)
	{
		DoAlert ("\pNo Links in Makefile!");
		return;
	}
		
	printf("Number of Links: %d \n", gNumFilesToLink);	// print # links
	fflush(stdout);


			/***********************/
			/* INIT NEW BG3D GROUP */
			/***********************/
			
	printf("*Creating Base Group...\n");
			
	gTheBG3DGroup = MO_CreateNewObjectOfType(MO_TYPE_GROUP, 0, nil);
	if (gTheBG3DGroup == nil)
		DoFatalAlert("\pExecuteMakefile:  gTheBG3DGroup failed!");		
			
			
			
		/* SCAN MAKEFILE & ADD EACH 3DMF FILE ENCOUNTERED */
						
	BuildNewFile();

			
	printf("\n Number of Materials: %d \n", gNumMaterials);	// print # textures
	fflush(stdout);
	


					/* SAVE FILE & CLEANUP */

	SaveNewFile();
	DisposePtr(gMakefilePtr);								// get rid of the makefile
	gMakefilePtr = nil;		
	
	MO_DisposeObjectReference(gTheBG3DGroup);				// get rid of the object

	
}


/********************* LOAD MODEL MAKEFILE INTO MEMORY ************************/
//
// This lets the user select a makefile and then it loads it into memroy.
//

static Boolean LoadTheModelMakefile(void)
{
FSSpec		spec;
OSErr		iErr;
short		fRefNum;


					/* CHOOSE FILE */
				
	iErr = GetFileWithNavServices(nil, &spec, 0);
	if (iErr != noErr)
		return(false);

	printf("*Loading Makefile...\n");
		
					/* GET MEM FOR TEXT FILE */
						
	if ((gMakefilePtr = AllocPtr(MAX_MAKEFILE_SIZE)) == nil)
	{
		DoAlert("\pCant alloc gMakefilePtr in LoadTheMakefile!");
		return(false);
	}
	
					/*  OPEN THE FILE */
			
	if (FSpOpenDF(&spec, fsRdPerm, &fRefNum) != noErr)
		DoFatalAlert("\pLoadTheModelMakefile: FSpOpenDF failed");
	
	
				/* GET SIZE OF FILE */
		
	if	(GetEOF(fRefNum,&gMakefileSize) != noErr)			
		DoFatalAlert("\pGet EOF failed!");
	
				/*	READ THE DATA */
			
	iErr = FSRead(fRefNum,&gMakefileSize,gMakefilePtr);
	if (iErr)
		DoFatalAlert("\pError reading makefile!");
	
				/*  CLOSE THE FILE */
			
	FSClose(fRefNum);
	
	iErr = HSetVol(0,spec.vRefNum, spec.parID);			// set volume/path to makefile

	printf("*Close Makefile...\n");

	
	return(TRUE);							// got it !!! 
}


/**************** BUILD NEW FILE ****************/
//
// Scans for each LINK in a makefile and then attaches the LINK file
// to the new master file.
//

static void	BuildNewFile(void)
{
long	i;
Ptr		makefilePtr;

	gTotalLinkedModels = 0;

				/* SCAN MAKEFILE & ADD MODEL FILES */

	makefilePtr = gMakefilePtr;							// init ptr into makefile

	for (i=0; i < gNumFilesToLink; i++)
	{
		makefilePtr = GetNextModelFileToLink(makefilePtr);			// load next MODEL file (into gCurrentBG3DObject)
		RemoveDuplicateMaterials();									// remove dupe textures
		
		AttachModel(); 												// attach to new BG3D file
		DisposeBG3DContainer(0);									// dispose of this model file
	}		
}


/************** GET NEXT MODEL FILE TO LINK *******************/
//
// Scans the makefile for the next LINK keyword and then loads the 3DMF file specified
// by the link.
//
// INPUT: makefilePtr is a Ptr into the current makefile position.
//
// OUTPUT:	Ptr = new makefileHandle ptr value
//			gCurrent3DMFFile = object contained in 3DMF file.
//


static Ptr GetNextModelFileToLink(Ptr makefilePtr)
{
short	strLength;
long	i2;
static	Str255	fileName;
char	c[255];

		/* SEARCH FOR LINK MARKER */
		
	while ((*makefilePtr != 'L') ||					// search for 'LINK' marker
			(*(makefilePtr+1) != 'I') ||
			(*(makefilePtr+2) != 'N') ||
			(*(makefilePtr+3) != 'K'))
	{
		makefilePtr++;
	}
	printf("[LINK] ");
	makefilePtr += 4;								// skip over 'LINK' marker


		/* SEARCH FOR FILENAME OF BG3D FILE TO LINK */
		
	while ((*makefilePtr == ' ') ||	(*makefilePtr == CHAR_TAB))		// skip spaces & tabs
	{
		putchar(*makefilePtr);
		makefilePtr++;
	}

	strLength = 0;									// copy filename to string
	i2 = 1;
	while (*makefilePtr != CHAR_RETURN)
	{
		fileName[i2] = *makefilePtr++;
		strLength++;
		i2++;
	}
	fileName[0] = strLength;						// set pascal string length


	CopyPascalStringToC(fileName, c);
	printf(c);
	printf("\n");
	fflush(stdout);


		/* LOAD THIS BG3D FILE */
		
	if (FSMakeFSSpec(0, 0, fileName, &gLast3DMF_FSSpec))			// create fsspec for the file
		DoFatalAlert("\pFSMakeFSSpec failed!");
		
	ImportBG3D(&gLast3DMF_FSSpec, 0);				// load it
		

			/* DISPLAY IT */
		
	return(makefilePtr);
}




/*********** ATTACH MODEL  *******************/
//
// Adds current BG3D data to gTheBG3DGroup (while resolving duplicate texture references)
//

static void AttachModel(void)
{
MetaObjectHeader	*header;
MOGroupObject		*group;

		/* IF ONLY ONE GEOMETRY IN GROUP, THEN EXTRACT FROM GROUP TO INSERT INTO THE-GROUP */
			
	header = (MetaObjectHeader *)gBG3DContainerList[0]->root;				// make sure the root is a group
	if (header->type == MO_TYPE_GROUP)
	{	
		group = gBG3DContainerList[0]->root;							// point to group
		if (group->objectData.numObjectsInGroup == 1)					// see if only one thing in the group
		{
			MO_AppendToGroup(gTheBG3DGroup, group->objectData.groupContents[0]);	// attach the object that's in the group
			return;
		}
	}
	
		/* THE GROUP LOOKS LIKE IT HAS >1 OBJECT IN IT, SO WRITE THE WHOLE GROUP */
		
	MO_AppendToGroup(gTheBG3DGroup, gBG3DContainerList[0]->root);		// attach the root object from the file's container to the group
}



/******************* COUNT LINKS ********************/
// Count the # of "LINK" symbols in the file.
// The 'LINK' symbol denotes a link file marker
//

static short	CountLinks(void)
{
long	i;
Ptr		filePtr;
short	count=0;

	printf("*Counting LINKs...\n");

	filePtr = gMakefilePtr;					// get ptr to file

	for (i=0;i<gMakefileSize;i++)
	{
		if ((*filePtr == 'L') &&				// see if char is 'LINK'
			(*(filePtr+1) == 'I') &&
			(*(filePtr+2) == 'N') &&
			(*(filePtr+3) == 'K'))
		{
			count++;
		}
			
		filePtr++;
	}
	
	return(count);
}



/******************* SAVE COLONY FILE ******************/
//
// When called it scans the file for the save name and then saves the file.
//

static void SaveNewFile(void)
{
FSSpec	theSpec;
OSErr	iErr;
short	vRefNum;
long	dirID;
Str255 volName;

	if (!ScanForSaveName())											// find the output file name (if any)
		DoFatalAlert("\pNo save name specified in makefile!");


	iErr = HGetVol(volName, &vRefNum, &dirID);
	iErr = FSMakeFSSpec(vRefNum, dirID, gLinkSaveName, &theSpec);		// init fsspec
	if (iErr)
		if (iErr != fnfErr)
			DoFatalAlert("\pFSMakeFSSpec failed!");


	SaveBG3DModel(&theSpec);

}


/******************* SCAN FOR SAVE NAME ********************/
//
// Scan file for the % save token.
//
// OUTPUT: true/false if found name
//			gLikeSaveName = filename path
//

static Boolean ScanForSaveName(void)
{
long	i,i2;
char	*filePtr;
char	cs[255];
	
	gLinkSaveName[0] = 0;						// assume wont find anything
	
	filePtr = gMakefilePtr;						// get ptr to file
	
	for (i=0;i<gMakefileSize;i++)
	{
		if (*filePtr++ == '%')					// see if char is %
		{
			i2 = 1;								// copy filename into string
			while (*filePtr != CHAR_RETURN)
			{
				gLinkSaveName[i2++] = *filePtr++;
				gLinkSaveName[0]++;
			}
			
			CopyPascalStringToC(gLinkSaveName, cs);
			printf("\n");
			printf("SAVING FILE AS: %s", cs);
			fflush(stdout);
			
			return(TRUE);
		}
	}
	return(FALSE);
}














