#!/usr/bin/python3


import sys
import subprocess
import os.path
import os
import datetime
import pathlib



LINUX = True
JAVA_HOME = "/opt/jdk1.8.0_91"

JAVAC_EXEC = None
JAR_EXEC = None
JAVA_SRC_PACKAGES = list()
FONT_PACKAGE = "allegro/fonts"
JAVAC_ERROR_LOG_FILE_NAME = "javac-err.log"
JAR_NAME = "jllegro.jar"

SO_NAME = "allegro_interface"
GCC_ERROR_LOG_FILE_NAME = "gcc-err.log"
C_SRC_DIRECTORIES = list()
C_ALLEGRO_LINKS = list()

FIND_EXECUTABLE_TEMP_FILE_NAME = "findExecutable.dat"



## Configuration

def findJavaExecutables():
	global JAVAC_EXEC, JAR_EXEC
	if(LINUX):
		if(JAVAC_EXEC == None):
			JAVAC_EXEC = findExecutable("javac")
		if(JAR_EXEC == None):
			JAR_EXEC = findExecutable("jar")
	else:
		if(JAVAC_EXEC == None):
			JAVAC_EXEC = findExecutable("javac.exe")
		if(JAR_EXEC == None):
			JAR_EXEC = findExecutable("jar.exe")

def createCSourceDirectoryList():
	C_SRC_DIRECTORIES.append(".")
	C_SRC_DIRECTORIES.append("display")
	C_SRC_DIRECTORIES.append("resources")
	C_SRC_DIRECTORIES.append("input")
	C_SRC_DIRECTORIES.append("utilities")

def createCAllegroLinksList():
	C_ALLEGRO_LINKS.append("allegro")
	C_ALLEGRO_LINKS.append("allegro_primitives")
	C_ALLEGRO_LINKS.append("allegro_image")
	C_ALLEGRO_LINKS.append("allegro_font")

def createJavaAllegroPackageList():
	JAVA_SRC_PACKAGES.append(JavaPackage("allegro"))
	JAVA_SRC_PACKAGES.append(JavaPackage("allegro/display"))
	JAVA_SRC_PACKAGES.append(JavaPackage("allegro/display/primitives"))
	JAVA_SRC_PACKAGES.append(JavaPackage("allegro/engine"))
	JAVA_SRC_PACKAGES.append(JavaPackage("allegro/gui"))
	JAVA_SRC_PACKAGES.append(JavaPackage("allegro/input"))
	JAVA_SRC_PACKAGES.append(JavaPackage("allegro/input/events"))
	JAVA_SRC_PACKAGES.append(JavaPackage("allegro/math"))
	JAVA_SRC_PACKAGES.append(JavaPackage("allegro/resources"))

def printSettings():
	CSI = "\033["

	sys.stdout.write("\n\nBuild Settings:\n\n")

	sys.stdout.write(CSI + "31mLinux:               " + CSI + "34m" + str(LINUX) + "\n")
	sys.stdout.write(CSI + "31mJava Home:           " + CSI + "34m" + str(JAVA_HOME) + "\n")
	sys.stdout.write(CSI + "31mJavac path:          " + CSI + "34m" + str(JAVAC_EXEC) + "\n")
	sys.stdout.write(CSI + "31mJar path:            " + CSI + "34m" + str(JAR_EXEC) + "\n")
	sys.stdout.write(CSI + "31mJar Name:            " + CSI + "34m" + str(JAR_NAME) + "\n")
	sys.stdout.write(CSI + "31mNative Library name: " + CSI + "34m" + str(SO_NAME) + "\n")
	
	sys.stdout.write(CSI + "39m\n\n")

## Utilities

def findExecutable(name):
	global FIND_EXECUTABLE_TEMP_FILE_NAME, LINUX
	if(LINUX):
		whereis = "whereis"
	else:
		whereis = "where"
	outFile = open(FIND_EXECUTABLE_TEMP_FILE_NAME, "w")
	subprocess.call(whereis + " " + name, shell=True, stdout=outFile)
	outFile.close()

	outFile = open(FIND_EXECUTABLE_TEMP_FILE_NAME, "r")
	dataString = outFile.read()
	outFile.close()

	os.remove(FIND_EXECUTABLE_TEMP_FILE_NAME)

	if(LINUX):
		dataString = dataString[len(name) + 2:]

	data = dataString.split(" ")

	for entry in data:
		if(LINUX):
			entrySplit = entry.split("/")
		else:
			entrySplit = entry.split("\n")

		if(entrySplit[-1] != name):
			continue
		if(entrySplit[-2] != "bin"):
			continue

		return entry

	return None

def drillDirectory(path):
	if(not pathlib.Path(path).is_dir()):
		os.mkdir(path)


def trace(string):
	sys.stdout.write("[ " + str(datetime.datetime.now()) + " ] : " + string + "\n")


## Compiling C code

def compileC():
	global JAVA_HOME, C_SRC_DIRECTORIES, C_ALLEGRO_LINKS, LINUX, GCC_ERROR_LOG_FILE_NAME

	if(JAVA_HOME == None):
		raise Exception("Java home path not set")

	commandString = "gcc "
	for directory in C_SRC_DIRECTORIES:
		commandString += directory + "/*.c "

	for link in C_ALLEGRO_LINKS:
		commandString += "-l " + link + " "

	if(LINUX):
		outputFileName = "lib" + SO_NAME + ".so"
		commandString += "-o " + outputFileName + " "
	else:
		outputFileName = "lib" + SO_NAME + ".dll"
		commandString += "-o " + outputFileName + " "

	commandString += "-shared "
	commandString += "-g "
	commandString += "-fPIC "
	commandString += "-I " + JAVA_HOME + "/include "
	if(LINUX):
		commandString += "-I " + JAVA_HOME + "/include/linux"

	os.chdir("C")


	errorFile = open(GCC_ERROR_LOG_FILE_NAME, "w")
	subProcRet = subprocess.call(commandString, shell=True, stderr=errorFile)
	errorFile.close()

	os.chdir("..")

	subprocess.call("cp C/" + outputFileName + " " + outputFileName, shell=True) 

	if(subProcRet == 0):
		os.remove("C/" + GCC_ERROR_LOG_FILE_NAME)
	else:
		raise Exception("Could not compile native code")


## Compiling Java code

class JavaPackage:
	def __init__(self, string):
		self.path = list()
		for sub in string.split("/"):
			self.path.append(sub)

	def getPath(self):
		return self.getCompoundString("/")

	def getPackage(self):
		return self.getCompoundString(".")

	def getCompoundString(self, delimitChar):
		if(len(self.path) > 0):
			ret = self.path[0]
			for i in range(1, len(self.path)):
				ret += delimitChar + self.path[i]
			return ret
		else:
			return ""
		

def compileJava():
	global JAVAC_EXEC, JAVA_SRC_PACKAGES, JAVAC_ERROR_LOG_FILE_NAME, JAVA_SRC_PACKAGES

	if(JAVAC_EXEC == None):
		raise Exception("javac executable path not set")

	javacCommandString = JAVAC_EXEC + " "
	
	for pack in JAVA_SRC_PACKAGES:
		javacCommandString += pack.getPath() + "/*.java "

	os.chdir("Java/src")

	javacErrorFile = open(JAVAC_ERROR_LOG_FILE_NAME, "w")
	javacProcRet = subprocess.call(javacCommandString, shell=True, stderr=javacErrorFile)
	javacErrorFile.close()
	
	os.chdir("..")

	if(javacProcRet != 0):
		raise Exception("javac failed to build")

	for pack in JAVA_SRC_PACKAGES:
		srcPath = "src/" + pack.getPath() + "/*.class"
		binPath = "bin/" + pack.getPath()
		drillDirectory(binPath)
		binPath = binPath + "/"

		subprocess.call("cp " + srcPath + " " + binPath, shell=True)
		subprocess.call("rm " + srcPath, shell=True)

	os.chdir("..")

def createJar():
	global JAR_EXEC, JAVA_SRC_PACKAGES, FONT_PACKAGE, JAR_NAME

	if(JAR_EXEC == None):
		raise Exception("jar executable path not set")

	os.chdir("Java/bin")

	# Create Manifest
	manifestFile = open("Manifest.txt", "w")
	manifestFile.write("Manifest-Version: 1.0\n")
	manifestFile.close()

	jarCommandString = JAR_EXEC + " cfm " + JAR_NAME + " Manifest.txt "
	
	for pack in JAVA_SRC_PACKAGES:
		jarCommandString += pack.getPath() + " "

	jarCommandString += FONT_PACKAGE + "/*.ttf " + FONT_PACKAGE + "/default-typefaces.xml"

	jarProcRet = subprocess.call(jarCommandString, shell=True)

	# Destroy Manifest
	os.remove("Manifest.txt")

	os.chdir("../..")

	subprocess.call("cp Java/bin/" + JAR_NAME + " " + JAR_NAME, shell=True)

	if(jarProcRet != 0):
		raise Exception("Jar could not be created")

def main():
	try:

		trace("Configuring...")

		findJavaExecutables()
		createCSourceDirectoryList()
		createCAllegroLinksList()
		createJavaAllegroPackageList()

		printSettings()

		trace("Compiling native code...")
		compileC()
		trace("Compiling java code...")
		compileJava()
		trace("Creating jar file...")
		createJar()
		trace("Complete!")

	except Exception as e:
		print("Exception: " + str(e))
	
	
main()

