/*=============================================================================
	UCC.cpp: Unreal command-line launcher.
	Copyright 1997-1999 Epic Games, Inc. All Rights Reserved.

Revision history:
	* Created by Tim Sweeney.
=============================================================================*/

#if WIN32
#include <windows.h>
#endif

#include <stdio.h>
#include <io.h>
#include <direct.h>
#include <errno.h>
#include <stdio.h>
#include <sys/stat.h>
#include <malloc.h>
#include "Core.h"

/*-----------------------------------------------------------------------------
	Global variables.
-----------------------------------------------------------------------------*/

// General.
extern "C" {HINSTANCE hInstance;}
extern "C" {TCHAR GPackage[64]=TEXT("UCC");}

// Memory allocation.
#include "FMallocAnsi.h"
FMallocAnsi Malloc;

// Log.
#include "FOutputDeviceFile.h"
FOutputDeviceFile Log;

// Error.
#include "FOutputDeviceAnsiError.h"
FOutputDeviceAnsiError Error;

// Feedback.
#include "FFeedbackContextAnsi.h"
FFeedbackContextAnsi Warn;

// File manager.
#include "FFileManagerAnsi.h"
FFileManagerAnsi FileManager;

// Config.
#include "FConfigCacheIni.h"

/*-----------------------------------------------------------------------------
	Main.
-----------------------------------------------------------------------------*/

// Unreal command-line applet executor.
FString RightPad( FString In, INT Count )
{
	while( In.Len()<Count )
		In += TEXT(" ");
	return In;
}
INT StringCompare( FString* A, FString* B )
{
	return appStricmp( **A, **B );
}
void ShowBanner( FOutputDevice& Warn )
{
	Warn.Logf( TEXT("=======================================") );
	Warn.Logf( TEXT("ucc.exe: UnrealOS execution environment") );
	Warn.Logf( TEXT("Copyright 1999 Epic Games Inc") );
	Warn.Logf( TEXT("=======================================") );
	Warn.Logf( TEXT("") );
}
int main( int argc, char* argv[] )
{
	INT ErrorLevel = 0;
	GIsStarted     = 1;
	try
	{
		GIsGuarded = 1;

		// Parse command line.
		TCHAR CmdLine[1024], *CmdLinePtr=CmdLine;
#if WIN32
		ANSICHAR* Ch = GetCommandLineA();
		while( *Ch && *Ch!=' ' )
			Ch++;
		while( *Ch==' ' )
			Ch++;
		while( *Ch )
			*CmdLinePtr++ = *Ch++;

#else
		for( INT a=2; a<argc; a++ )
		{
			if( a>2 )
				*CmdLinePtr++ = ' ';
			char* ch;
			for( ch=argv[a]; *ch; ++ch )
				if( *ch==' ' )
					break;
			UBOOL NeedQuotes = (*ch!=0);
			if( NeedQuotes )
				*CmdLinePtr++ = '\"';
			for( ch=argv[a]; *ch; ++ch )
				*CmdLinePtr++ = FromAnsi(*ch);
			if( NeedQuotes )
				*CmdLinePtr++ = '\"';
		}
#endif
		*CmdLinePtr++ = 0;

		// Init.
		appInit( TEXT("Unreal"), CmdLine, &Malloc, &Log, &Error, &Warn, &FileManager, FConfigCacheIni::Factory, 1 );
		FString Token = argc>1 ? appFromAnsi(argv[1]) : TEXT("");
		TArray<FRegistryObjectInfo> List;
		UObject::GetRegistryObjects( List, UClass::StaticClass(), UCommandlet::StaticClass(), 0 );
		GIsClient = GIsServer = GIsEditor = GIsScriptable = 1;
		GLazyLoad = 0;
		UBOOL Help = 0;
		DWORD LoadFlags = LOAD_NoWarn | LOAD_Quiet;
		if( Token==TEXT("") )
		{
			ShowBanner( Warn );
			Warn.Logf( TEXT("Use \"ucc help\" for help") );
		}
		else if( Token==TEXT("HELP") )
		{
			ShowBanner( Warn );
			verify(UObject::StaticLoadClass( UCommandlet::StaticClass(), NULL, TEXT("Core.Commandlet"), NULL, LOAD_NoFail, NULL )==UCommandlet::StaticClass());
			const TCHAR* Tmp = appCmdLine();
			GIsEditor = 0; // To enable loading localized text.
			if( !ParseToken( Tmp, Token, 0 ) )
			{
				INT i;
				Warn.Logf( TEXT("Usage:") );
				Warn.Logf( TEXT("   ucc <command> <parameters>") );
				Warn.Logf( TEXT("") );
				Warn.Logf( TEXT("Commands for \"ucc\":") );
				TArray<FString> Items;
				for( i=0; i<List.Num(); i++ )
				{
					UClass* Class = UObject::StaticLoadClass( UCommandlet::StaticClass(), NULL, *List(i).Object, NULL, LoadFlags, NULL );
					if( Class )
					{
						UCommandlet* Default = (UCommandlet*)Class->GetDefaultObject();
						Items.AddItem( FString(TEXT("   ucc ")) + RightPad(Default->HelpCmd,21) + TEXT(" ") + Default->HelpOneLiner );
					}
				}
				Items.AddItem( TEXT("   ucc help <command>        Get help on a command") );
				appQsort( &Items(0), Items.Num(), sizeof(FString), (QSORT_COMPARE)StringCompare );
				for( i=0; i<Items.Num(); i++ )
					Warn.Log( Items(i) );
			}
			else
			{
				Help = 1;
				goto Process;
			}
			/*else if( Token==TEXT("MASTER") )
			{
				Warn.Logf( TEXT("Usage:") );
				Warn.Logf( TEXT("   ucc master <configfilename> [parameter=value]...") );
				Warn.Logf( TEXT("") );
				Warn.Logf( TEXT("Parameters for \"ucc master\":") );
				Warn.Logf( TEXT("   MasterPath= Root directory to copy source files from") );
				Warn.Logf( TEXT("   SrcPath=    Root directory to copy install files to") );
				Warn.Logf( TEXT("   RefPath=    Path for delta-compressed patch reference") );
				Warn.Logf( TEXT("   Tree=       False to place all files in a single directory") );
			}
			else if( Token==TEXT("MAKE") )
			{
				Warn.Logf( TEXT("Usage:") );
				Warn.Logf( TEXT("   ucc make [-option]... [parameter=value]...") );
				Warn.Logf( TEXT("") );
				Warn.Logf( TEXT("Parameters for \"ucc make\":") );
				Warn.Logf( TEXT("   -silent     No prompts; assume 'yes' to all questions") );
				Warn.Logf( TEXT("   -nobind     Don't force native functions to be bound to DLLs") );
				Warn.Logf( TEXT("   -all        Clean rebuild (otherwise rebuild is incremental)") );
			}
			else if( Token==TEXT("SERVER") )
			{
				Warn.Logf( TEXT("Usage:") );
				Warn.Logf( TEXT("   ucc server [-option]... [parameter=value]...") );
				Warn.Logf( TEXT("") );
				Warn.Logf( TEXT("Parameters for \"ucc server\":") );
			}*/
		}
		else
		{
			// Look it up.
			if( Token==TEXT("Make") )
				LoadFlags |= LOAD_DisallowFiles;
		Process:
			UClass* Class = UObject::StaticLoadClass( UCommandlet::StaticClass(), NULL, *Token, NULL, LoadFlags, NULL );
			if( !Class )
				Class = UObject::StaticLoadClass( UCommandlet::StaticClass(), NULL, *(Token+TEXT("Commandlet")), NULL, LoadFlags, NULL );
			if( !Class )
			{
				for( INT i=0; i<List.Num(); i++ )
				{
					FString Str = List(i).Object;
					while( Str.InStr(TEXT("."))>=0 )
						Str = Str.Mid(Str.InStr(TEXT("."))+1);
					if( Token==Str || Token+TEXT("Commandlet")==Str )
						break;
				}
				if( i<List.Num() )
					Class = UObject::StaticLoadClass( UCommandlet::StaticClass(), NULL, *List(i).Object, NULL, LoadFlags, NULL );
			}
			if( Class )
			{
				UCommandlet* Default = (UCommandlet*)Class->GetDefaultObject();
				if( Help )
				{
					// Get help on it.
					if( Default->HelpUsage!=TEXT("") )
					{
						Warn.Logf( TEXT("Usage:") );
						Warn.Logf( TEXT("   ucc %s"), *Default->HelpUsage );
					}
					if( Default->HelpParm[0]!=TEXT("") )
					{
						Warn.Logf( TEXT("") );
						Warn.Logf( TEXT("Parameters for \"ucc server\":") );
						for( INT i=0; i<ARRAY_COUNT(Default->HelpParm) && Default->HelpParm[i]!=TEXT(""); i++ )
							Warn.Logf( TEXT("   %s %s"), *RightPad(Default->HelpParm[i],16), *Default->HelpDesc[i] );
					}
					if( Default->HelpWebLink!=TEXT("") )
					{
						Warn.Logf( TEXT("") );
						Warn.Logf( TEXT("For more info, see") );
						Warn.Logf( TEXT("   %s"), *Default->HelpWebLink );
					}
				}
				else
				{
					// Run it.
					if( Default->LogToStdout )
					{
						Warn.AuxOut = GLog;
						GLog        = &Warn;
					}
					if( Default->ShowBanner )
					{
						ShowBanner( Warn );
					}
					debugf( TEXT("Executing %s"), Class->GetFullName() );
					GIsClient = Default->IsClient;
					GIsServer = Default->IsServer;
					GIsEditor = Default->IsEditor;
					GLazyLoad = Default->LazyLoad;
					UCommandlet* Commandlet = ConstructObject<UCommandlet>( Class );
					Commandlet->InitExecution();
					Commandlet->ParseParms( appCmdLine() );
					Commandlet->Main( appCmdLine() );
					if( Commandlet->ShowErrorCount )
						GWarn->Logf( TEXT("Success - 0 error(s), %i warnings"), Warn.WarningCount );
					if( Default->LogToStdout )
					{
						Warn.AuxOut = NULL;
						GLog        = &Log;
					}
				}
			}
			else
			{
				ShowBanner( Warn );
				Warn.Logf( TEXT("Commandlet %s not found"), *Token );
			}
		}
		appPreExit();
		GIsGuarded = 0;
	}
	catch( ... )
	{
		// Crashed.
		ErrorLevel = 1;
		GIsGuarded = 0;
		Error.HandleError();
	}
	appExit();
	GIsStarted = 0;
	return ErrorLevel;
}

/*-----------------------------------------------------------------------------
	The End.
-----------------------------------------------------------------------------*/
