#include "munga.h"
#include "windows.h"
#pragma hdrstop

#include <direct.h>
#include "fileutil.h"
#include "notation.h"

char *WorkingDirectory = NULL;

//#############################################################################

const char *White_Space = " \t\n";

//#############################################################################

char
	*SourceDirectory = NULL,
	*ConfigDirectory = NULL,
	*MaterialDirectory = NULL,
	*TextureDirectory = NULL,
	*AnimationDirectory = NULL,
	*ProductionDirectory = NULL;
const char
	*OutputDirectory = NULL;

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	SetSourceDirectory(const char *input_file)
{
	Check_Pointer(input_file);

	static const char
		* const ARTTOOLS_FILENAME = ".arttoolsrc",
		* const DIRECTORIES_PAGE = "directories",
		* const CFG_DIR_ENTRY = "cfg_dir",
		* const MTL_DIR_ENTRY = "mtl_dir",
		* const TEX_DIR_ENTRY = "tex_dir",
		* const KIN_DIR_ENTRY = "kin_dir",
		* const PRD_DIR_ENTRY = "prd_dir";

	NotationFile
		*tools_info;
	char
		*cwd;
	const char
		*cp,
		*contents;

	//------------------------------------------------
	// parse the source directory from the input file
	//------------------------------------------------
	if ((cp = strrchr(input_file, '/')) == NULL)
	{
		//---------------------------------------------------
		// set source directory to current working directory
		//---------------------------------------------------
		cwd = _getcwd(NULL, 256);
		Verify( cwd );
		SourceDirectory = new char[strlen(cwd) + 2];
		Register_Pointer(SourceDirectory);
		strcpy(SourceDirectory, cwd);
		strcat(SourceDirectory, "/");
		free(cwd);
	}
	else
	{
		//------------------------------------------------------
		// set source directory to path specified in input file
		//------------------------------------------------------
		++cp;
		SourceDirectory = new char[cp - input_file + 1];
		Register_Pointer(SourceDirectory);
		*SourceDirectory = '\0';
		strncat(SourceDirectory, input_file, cp - input_file);
	}

	//-----------------------------------------------------------
	// set other directories from tools config file (if present)
	//-----------------------------------------------------------
	tools_info = new NotationFile(SourceFile(ARTTOOLS_FILENAME));
	Register_Object(tools_info);

	if (tools_info->GetEntry(DIRECTORIES_PAGE, CFG_DIR_ENTRY, &contents))
	{
		ConfigDirectory = new char[strlen(contents) + 2];
		Register_Pointer(ConfigDirectory);
		strcpy(ConfigDirectory, contents);
		cp = strchr(contents, '\0');
		if (cp > contents && *--cp != '/')
		{
			strcat(ConfigDirectory, "/");
		}
	}
	else
	{
		ConfigDirectory = SourceDirectory;
	}

	if (tools_info->GetEntry(DIRECTORIES_PAGE, MTL_DIR_ENTRY, &contents))
	{
		MaterialDirectory = new char[strlen(contents) + 2];
		Register_Pointer(MaterialDirectory);
		strcpy(MaterialDirectory, contents);
		cp = strchr(contents, '\0');
		if (cp > contents && *--cp != '/')
		{
			strcat(MaterialDirectory, "/");
		}
	}
	else
	{
		MaterialDirectory = SourceDirectory;
	}

	if (tools_info->GetEntry(DIRECTORIES_PAGE, TEX_DIR_ENTRY, &contents))
	{
		TextureDirectory = new char[strlen(contents) + 2];
		Register_Pointer(TextureDirectory);
		strcpy(TextureDirectory, contents);
		cp = strchr(contents, '\0');
		if (cp > contents && *--cp != '/')
		{
			strcat(TextureDirectory, "/");
		}
	}
	else
	{
		TextureDirectory = MaterialDirectory;	// this one is different!
	}

	if (tools_info->GetEntry(DIRECTORIES_PAGE, KIN_DIR_ENTRY, &contents))
	{
		AnimationDirectory = new char[strlen(contents) + 2];
		Register_Pointer(AnimationDirectory);
		strcpy(AnimationDirectory, contents);
		cp = strchr(contents, '\0');
		if (cp > contents && *--cp != '/')
		{
			strcat(AnimationDirectory, "/");
		}
	}
	else
	{
		AnimationDirectory = SourceDirectory;
	}

	if (tools_info->GetEntry(DIRECTORIES_PAGE, PRD_DIR_ENTRY, &contents))
	{
		ProductionDirectory = new char[strlen(contents) + 2];
		Register_Pointer(ProductionDirectory);
		strcpy(ProductionDirectory, contents);
		cp = strchr(contents, '\0');
		if (cp > contents && *--cp != '/')
		{
			strcat(ProductionDirectory, "/");
		}
	}
	else
	{
		ProductionDirectory = SourceDirectory;
	}

	OutputDirectory = SourceDirectory;

	Unregister_Object(tools_info);
	delete tools_info;

	return;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	SetOutputDirectory(const char *directory)
{
	Check_Pointer(directory);

	OutputDirectory = directory;
	return;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
const char*
	GetSourceDirectory()
{
	return SourceDirectory;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
const char*
	GetConfigDirectory()
{
	return ConfigDirectory;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
const char*
	GetMaterialDirectory()
{
	return MaterialDirectory;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
const char*
	GetTextureDirectory()
{
	return TextureDirectory;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
const char*
	GetAnimationDirectory()
{
	return AnimationDirectory;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
const char*
	GetProductionDirectory()
{
	return ProductionDirectory;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
const char*
	GetOutputDirectory()
{
	return OutputDirectory;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	ClearDirectories()
{
	//do not clear output directory

	if (ProductionDirectory && ProductionDirectory != SourceDirectory)
	{
		Unregister_Pointer(ProductionDirectory);
		delete ProductionDirectory;
	}
	if (AnimationDirectory && AnimationDirectory != SourceDirectory)
	{
		Unregister_Pointer(AnimationDirectory);
		delete AnimationDirectory;
	}
	if (TextureDirectory && TextureDirectory != MaterialDirectory)	//different!
	{
		Unregister_Pointer(TextureDirectory);
		delete TextureDirectory;
	}
	if (MaterialDirectory && MaterialDirectory != SourceDirectory)
	{
		Unregister_Pointer(MaterialDirectory);
		delete MaterialDirectory;
	}
	if (ConfigDirectory && ConfigDirectory != SourceDirectory)
	{
		Unregister_Pointer(ConfigDirectory);
		delete ConfigDirectory;
	}
	if (SourceDirectory)
	{
		Unregister_Pointer(SourceDirectory);
		delete SourceDirectory;
	}
	return;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
const char*
	DirectoryPlusFilename(
		const char *directory,
		const char *filename,
		const char *extension
	)
{
	//do not check directory here
	Check_Pointer(filename);
	//do not check extension here

	static char
		buffer[512];
	int
		length;

	if (!directory)  { directory = "\0"; }
	Check_Pointer(directory);

	length = strlen(directory);
	if (extension)
	{
		Check_Pointer(extension);
		length += strlen(StripExtension(StripDirectory(filename)));
		length += *extension == '.'?0:1;
		length += strlen(extension);
	}
	else
	{
		length += strlen(StripDirectory(filename));
	}

	if (length >= ELEMENTS(buffer))
	{
		DEBUG_STREAM <<
			":  Program Error - buffer[] too small in DirectoryPlusFilename().\n" << std::flush;
		PostQuitMessage(AbortExitCodeID);
	}
	strcpy(buffer, directory);
	if (extension)
	{
		strcat(buffer, StripExtension(StripDirectory(filename)));
		if (*extension != '.')
		{
			strcat(buffer, ".");
		}
		strcat(buffer, extension);
	}
	else
	{
		strcat(buffer, StripDirectory(filename));
	}
	return buffer;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
const char*
	SourceFile(
		const char *filename,
		const char *extension
	)
{
	return DirectoryPlusFilename(SourceDirectory, filename, extension);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
const char*
	ConfigFile(
		const char *filename,
		const char *extension
	)
{
	return DirectoryPlusFilename(ConfigDirectory, filename, extension);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
const char*
	MaterialFile(
		const char *filename,
		const char *extension
	)
{
	return DirectoryPlusFilename(MaterialDirectory, filename, extension);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
const char*
	TextureFile(
		const char *filename,
		const char *extension
	)
{
	return DirectoryPlusFilename(TextureDirectory, filename, extension);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
const char*
	AnimationFile(
		const char *filename,
		const char *extension
	)
{
	return DirectoryPlusFilename(AnimationDirectory, filename, extension);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
const char*
	OutputFile(
		const char *filename,
		const char *extension
	)
{
	return DirectoryPlusFilename(OutputDirectory, filename, extension);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//

const char*
	StripDirectory(const char *filename)
{
	Check_Pointer(filename);

	if (DirectoryIsSpecified(filename))
	{
		const char
			*p;

		//--------------------------------------
		// parse the filename from the filepath
		//--------------------------------------
		p = strchr(filename, '\0');
		Verify( p );
		while (*p != '\\' && p != filename)
		{
			--p;
		}
		if (*p == '\\')
		{
			++p;
		}
		filename = p;
	}
	return filename;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
const char*
	StripExtension(const char *filename)
{
	Check_Pointer(filename);

	static char
		buffer[512];
	char
		*p;

	if (strlen(filename) >= sizeof(buffer))
	{
		//DEBUG_STREAM << ProgName <<
		//	":  Program Error - buffer[] too small in StripExtension()." << std::endl;
		DEBUG_STREAM <<
			":  Program Error - buffer[] too small in StripExtension()." << std::endl << std::flush;
		
		PostQuitMessage(AbortExitCodeID);
	}
	strcpy(buffer, filename);

	//------------------------------------
	// remove the extension from filename
	//------------------------------------
	p = strchr(buffer, '\0');
	Verify( p );
	while (*p != '.' && p != buffer)
	{
		--p;
	}
	if (*p == '.')
	{
		*p = '\0';
	}

	return buffer;
}

//#############################################################################

char*
	Ind(int level)
{
	const int buf_len = 128;
	static char buf[buf_len];

	//---------------------------------------------------------
	// Return string of spaces used to indent an output stream
	//---------------------------------------------------------
	buf[0] = '\0';
	if (level > 63) level = 63; // floor((buf_len - 1)/number of spaces per indent)
	for (; level > 0; --level) 
	{
		strcat(buf, "  ");
	}
	return buf;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Logical GetLine(std::istream &stream, char *buffer, int size_of_buffer)
{
	static char temp_buffer[512];

	//-------------------------------------------------------------
	// read next line(s) from input stream automatically resolving
	// lines with a continuation character '\' at the end
	//-------------------------------------------------------------
	if (stream.getline(buffer, size_of_buffer))
	{
		char *p;
		int i;

		while (True)
		{
			if ((i = strlen(buffer)) > (size_of_buffer - 2))
			{
				//DEBUG_STREAM << ProgName << ":  ERROR - Input line too long." << std::endl << std::flush;
				
				DEBUG_STREAM << ":  ERROR - Input line too long." << std::endl << std::flush;
				break;
			}

			p = buffer + i;
			while (p-- > buffer && isspace(*p));	// find last non-blank character

			if (p >= buffer && *p == '\\')
			{
				if (stream.getline(temp_buffer, sizeof(temp_buffer)))
				{
					*p = ' ';
					++p;
					strncat(p, temp_buffer, size_of_buffer - (p - buffer));
				}
				else
				{
					break;
				}
			}
			else
			{
				break;
			}
		}
		return True;
	}
	else
	{
		*buffer = '\0';
		return False;
	}
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

#if 0
char*
	stripname(char filename[])
{

	// Doesn't work

	char
		file2[200];
	char
		*filetosendback; 

	int 
		wordlength, 
	   count,  
		countbackward, 
		length;


	length = strlen(filename);


	count = 0;
	countbackward = length-1;

	while (filename[countbackward-1] != '\\')
	{
		--countbackward;
	}

	wordlength = length - countbackward;

	for (count = 0; count < wordlength; ++count)
	{
		file2[count] = filename[countbackward];
		++countbackward;
	}

	file2[count] = '\0'; 

	filetosendback = strdup(file2);

	return filetosendback;	
}
#endif

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Scalar
	D2R(float degrees)
{
	return degrees*(3.14159259f/180.0f);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

char*
	MakeWorkingDirectory(
		 const char *file
	)
{
	char *directory;
	const char *p;
	int size;
	p = file;
	
	for (int i = (strlen(file) - 1 ); i >= 0; --i)
	{
		if ( (*p == '/') || (*p == '\\') )
		{
			size = strlen(file) - i + 1;
			
			directory = new char[size];
			strncpy(directory, file, size);
						
			return directory;
		}
		++p; 
	}

	// 
	// Else return local directory
	//
	#define BUFFER_SIZE (256)
	char buffer[BUFFER_SIZE];
	getcwd(buffer, BUFFER_SIZE);

	#if 0
		directory = strdup(buffer);
		strcat(directory, "\\");  // ECH 1/29/96 - This is an overwrite
	#else
		Str_Cat(buffer, "\\", BUFFER_SIZE);
		size = strlen(buffer) + 1;
		directory = new char[size];
		Str_Copy(directory, buffer, size);
	#endif

	//
	// This is "\\" for DOS
	//
	
	return directory;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Logical
	DirectoryIsSpecified(
	   const char *file
	)
{
	return strchr(file,'/') || strchr(file,':') || strchr(file,'\\');

#if 0
	const char *p;
	
	p = file;
	
	for (int i = 0; i < strlen(file); ++i)
	{
		if ( (*p == '/') || (*p == '\\') )
		{
			
			return True;
			
		} 
		
		++p;
	}
	return False;
#endif
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

char*
	MakePathedFilename(
		const char *directory,
		const char *name
	)
{
	char *filename;

	if (DirectoryIsSpecified(name))
	{
		filename = new char[  strlen(name) + 1];
		strcpy(filename, name);
		return filename;
	}

	if (directory == NULL)
	{
		filename = new char[strlen(name) + 1];
		strcpy(filename, name);
	}
	else
	{
		filename = new char[strlen(directory) + strlen(name) + 1];

		strcpy(filename, directory);
		strcat(filename, name);
	}

	return filename;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void OpenOutput(std::ofstream &stream, const char *directory, const char *filename)
{
	//do not check directory here
	Check_Pointer(filename);

	char 
		*file_to_open;
	
	if (DirectoryIsSpecified(filename) || directory == NULL)
	{
		file_to_open = new char[strlen(filename) + 1];
		Register_Pointer(file_to_open);
		strcpy(file_to_open, filename);
	}
	else
	{
		Check_Pointer(directory);
		file_to_open = new char[strlen(directory) + strlen(filename) + 1];
		Register_Pointer(file_to_open);
		strcpy(file_to_open, directory);
		strcat(file_to_open, filename);
	}
	
	stream.open(file_to_open);
	Unregister_Pointer(file_to_open);
	delete file_to_open;
	return;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

void OpenInput(std::ifstream &stream, char *directory, const char *filename)
{
	char tempfile[100];
	
	if (DirectoryIsSpecified(filename))
	{
		strcpy(tempfile, filename); 
	}
	else
	{
		if (directory != NULL)
		{
			strcpy(tempfile, directory);
			strcat(tempfile, filename);
		}
		else
		{
			strcpy(tempfile, filename);
		}
	}
	
	stream.open(tempfile);
	return;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Logical
	LabOnly(
		NotationFile
			*notation_file
	)
{

	if (notation_file->PageExists("LAB_ONLY"))
	{
		std::cout << "WARNING: LAB_ONLY" << std::endl;
		return True;
	}
	else
	{
		return False;
	}

}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

void
	AddLabOnly(
		NotationFile
			*notation_file
	)
{
	 if (!notation_file->PageExists("LAB_ONLY"))
	 {
		notation_file->AppendEntry("LAB_ONLY", NULL, NULL);
	 }

}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Logical
	DoesNotationFileExist(
		NotationFile
			*notation_file
	)
{
	Check(notation_file);
	Check_Pointer(notation_file->GetFileName());
	std::ifstream notation_file_stream(notation_file->GetFileName());
	return (notation_file_stream) ? True : False;
}

//=============================================================================
