/*
* Search4j utility
* Command Line utility to search a system for java, launch a jar, or compare java versions
* base on launch4j
*/

#include "libsearch4j.h"

void usage();

enum Action {
	Find,
	Launch,
	Compare
};

enum JvmProperty {
	JavaHome,
	Version,
	Executable,
	Type
};

string actionToString( Action a ) {
	if ( a == Find ) 
		return "Find";
	else if ( a == Launch )
		return "Launch";
	else if ( a == Compare )
		return "Compare";
	return "Unknown";
}

string jvmPropertyToString( JvmProperty jp ) {
	if ( jp == JavaHome ) 
		return "JavaHome";
	else if ( jp == Version )
		return "Version";
	else if ( jp == Executable )
		return "Executable";
	else if ( jp == Type )
		return "Type";

	return "Unknown";
}


int main ( int argc, char** argv ) {

	bool verbose = false;
	string phint = "";
	string hint = "";
	bool use_minimum = false;
	bool useJavaw = false;
	bool jdkOnly = false;
	bool jreOnly = false;
	Jvm minimum;
	JvmProperty jvmProperty = JavaHome;
	Action action = Find;
	string arg1 = "";
	
	//parse commandline arguments
	for (int i=1; i<argc; i++) {

		//be verbose
		if ( strcmp(argv[i], "--verbose") == 0 ) {
			verbose = true;

		//show help
		} else if ( strcmp(argv[i], "--help") == 0 || strcmp(argv[i], "--usage") == 0 ) {
			usage();
			return 0;

		//show version
		} else if ( strcmp(argv[i], "-v") == 0 ) {
			jvmProperty = Version;

		//show path to executable
		} else if ( strcmp(argv[i], "-e") == 0 ) {
			jvmProperty = Executable;

		//show whether jre or jdk
		} else if ( strcmp(argv[i], "-t") == 0 ) {
			jvmProperty = Type;

		//compare found java with the given version string
		} else if ( strcmp(argv[i], "-c") == 0 ) {
			action = Compare;
			if ( i == argc-1 ) {
				usage();
				return -1;
			} else {
				arg1 = argv[++i];
			}

		//find only javas at or above the given version
		} else if ( strcmp(argv[i], "-m") == 0 ) {
			if ( i == argc-1 ) {
				usage();
				return -1;
			} else {
				if ( !minimum.setVersionFromString( argv[++i] ) ) {
					usage();
					return 0;
				}
				use_minimum = true;
			}

		//find only jdks
		} else if ( strcmp(argv[i], "-d") == 0 ) {
			jdkOnly = true;

		//find only jres
		} else if ( strcmp(argv[i], "-r") == 0 ) {
			jreOnly = true;

		//launch the named jar with the found java
		} else if ( strcmp(argv[i], "-l") == 0 ) {
			if ( i == argc-1 ) {
				usage();
				return -1;
			} else {
				action = Launch;
				arg1 = argv[++i];
			}

		//take the given priority hint
		} else if ( strcmp(argv[i], "-p") == 0 ) {
			if ( i == argc-1 ) {
				usage();
				return -1;
			} else {
				phint = argv[++i];
			}

		// take the following hint
		} else if ( strcmp(argv[i], "-h") == 0 ) {
			if ( i == argc-1 ) {
				usage();
				return -1;
			} else {
				hint = argv[++i];
			}

		#ifdef WINDOWS
		//show the path to the javaw executable
		} else if ( strcmp(argv[i], "-w") == 0 ) {
			useJavaw = true;
		#endif

		} else {
			cout << "unknown option: " << argv[i] << endl;
			return -1;
		}
	}
	
	//summarise commandline arguments
	if ( verbose ) {
		cout << "Action: " << actionToString( action ) << endl;
	}

	//find java
	Jvm foundJvm;
	bool found = find( foundJvm, use_minimum, minimum, jreOnly, jdkOnly, phint, hint, verbose );

	//check if it was found
	if ( found ) {
		if ( verbose ) cout << "Found JVM at '" << foundJvm.getJavaHome() << "'" << endl;
	} else {
		//not found - exit with -1
		if ( verbose ) cout << "JVM not found" << endl;
		return -1;
	}


	//Find Action
	//---------------
	if ( action == Find ) {

		if ( verbose ) cout << "Property to print: " << jvmPropertyToString( jvmProperty ) << endl;

		//found - print out info about it
		if ( jvmProperty == JavaHome ) {
			cout << foundJvm.getJavaHome() << endl;
		} else if ( jvmProperty == Version ) {
			cout << foundJvm.getVersion() << endl;
		} else if ( jvmProperty == Executable ) {
			#ifdef WINDOWS
			if ( useJavaw ) {
				cout << foundJvm.getWinExecutable() << endl;
			} else {
				cout << foundJvm.getExecutable() << endl;
			}
			#else
			cout << foundJvm.getExecutable() << endl;
			#endif
		} else if ( jvmProperty == Type ) {
			if ( foundJvm.getIsJdk() ) {
        cout << "JDK" << endl;
			} else {
	      cout << "JRE" << endl;
			}
		} else {
			return -1; //should never happen
		}
			

	//Compare Action
	//---------------
	} else if ( action == Compare ) {
		
		if ( verbose ) cout << "Compare to java at: " << arg1 << endl;

		//load a dummy jvm for comparison
		Jvm givenJvm;
		if ( !givenJvm.setVersionFromString(arg1) ) {
			if ( verbose ) cout << "Could not parse that version string" << endl;
			return -1;
		}
		
		//compare
		cout << foundJvm.compare( givenJvm );
		return 0;

		
	//Launch Action
	//---------------
	} else if ( action == Launch ) {

		if ( verbose ) cout << "Jar to launch: " << arg1 << endl;
		
		string cmd = "\"", output = "";
		#ifdef WINDOWS
		if ( useJavaw ) {
			cmd.append( foundJvm.getWinExecutable() );
		} else {
			cmd.append( foundJvm.getExecutable() );
		}
		#else
		cmd.append( foundJvm.getExecutable() );
		#endif
		cmd.append( "\" -jar " );
		cmd.append( arg1 );
		
		process( cmd, true );
		
	}
	
	return 0;
}

void usage() {
	
	cout
		<< "-----------------" << endl
		<< " search4j: usage" << endl
		<< "-----------------" << endl
		<< "Three usage methods: find, compare and launch" << endl
		<< endl
		<< "find:     find java and print out information about it" << endl
		<< endl
		<< "          search4j [-v|-e|-t]" << endl
		<< "          eg: search4j -e" << endl
		<< endl
		<< "          by default, print JAVA_HOME. E.g., C:\\Program Files\\jre1.5.0_15, or" << endl
		<< "          if -v is specified, print the java version string. E.g. 1.5.0_15, or" << endl
		<< "          if -e is specified, print the path the to the java executable. E.g. C:\\Program Files\\jre1.5.0_15\\bin\\java.exe" << endl
		<< "          if -t is specified, print whether the found java is a JRE or a JDK" << endl
		<< endl
		<< "compare:  compare the found java with the given java version string" << endl
		<< endl
		<< "          search4j -c VERSION_STRING" << endl
		<< "          eg: search4j -c VERSION_STRING" << endl
		<< endl
		<< "          print -1 if found java is older" << endl
		<< "          print 0 if found java is same" << endl
		<< "          print 1 if found java is newer" << endl
		<< endl
		<< "launch:   launch the given executable jar with the found java" << endl
		<< endl
		<< "          search4j -l EXECUTABLE_JAR [-m VERSION_STRING]" << endl
		<< "          eg: search4j -l greenstone3.jar" << endl
		<< endl
		<< "          specify the location of the jar relative to the current directory" << endl
		<< endl
		<< "Global Options:" << endl
		<< "          -m VERSION_STRING: (minimum) find a java of the given version or newer, or fail" << endl
		<< "          -d : find only jdks" << endl
		<< "          -r : find only jres" << endl
		<< "          -p LOCATION: (priority hint) first look for java in LOCATION (treated as a JAVA_HOME)" << endl
		<< "          -h LOCATION: (hint) as a last resort look for java in LOCATION (treated as a JAVA_HOME)" << endl
		#ifdef WINDOWS
		<< "          -w: (windows) find and/or use the javaw.exe executable instead of java.exe (in windows only)" << endl
		#endif
		<< "          --verbose : have search4j print out information about what its doing" << endl
		<< "          --help : display this usage screen" << endl
		<< endl
		;
}
