/*
 * build.gradle for Progressia
 */

plugins {
    // Apply the java-library plugin to add support for Java Library
    id 'java-library'
    
    /*
     * Uncomment the following line to enable the Eclipse plugin.
     * This is only necessary if you don't use Buildship plugin from the IDE
     */
    //id 'eclipse'
}

java {
	/*
	 * We're Java 8 for now.
	 * Why? As of 2020, most users have Oracle Java, which only supports Java 8.
	 */
    sourceCompatibility = JavaVersion.VERSION_1_8
    targetCompatibility = JavaVersion.VERSION_1_8
}

compileJava {
	/*
	 * We want to compile for Java 8.
	 * If we are using JDK 8, no further action is required.
	 * However, on JDK 9 and later versions, '--release' option is required,
	 * which is missing on JDK 8.
	 */
    if (JavaVersion.current() != JavaVersion.VERSION_1_8) {
        options.compilerArgs.addAll(['--release', '8'])
    }
}

/*
 * Dependencies
 */

repositories {
	mavenCentral()
    jcenter()
    
    /*
     * Specify Windcorp Maven repository
     * Currently used by:
     *   - ru.windcorp.fork.io.github.java-graphics:glm:1.0.1
     */
    maven { url 'https://windcorp.ru/./maven' }
}

dependencies {
	// Google Guava
	//   A generic utilities library
    implementation 'com.google.guava:guava:30.0-jre'
    
    // Trove4j
    //   Provides optimized Collections for primitive types
    implementation 'net.sf.trove4j:trove4j:3.0.3'
    
    // java-graphics
    //   A GLM (OpenGL Mathematics) port to Java
    //   Unfortunately, Maven Central Repository provides an outdated version of this library, which contains several critical bugs
    implementation 'ru.windcorp.fork.io.github.java-graphics:glm:1.0.1'

	// Log4j
	//   A logging library
	implementation group: 'org.apache.logging.log4j', name: 'log4j-api', version: '2.13.3'
	implementation group: 'org.apache.logging.log4j', name: 'log4j-core', version: '2.13.3'

	// JUnit
	//   A unit-testing library
	testImplementation 'junit:junit:4.12'
	
	// See LWJGL dependencies below
}

/*
 * Progressia uses the following LWJGL libraries:
 *   - Core libraries
 *   - OpenGL
 *   - OpenAL
 *   - GLFW
 *   - STB
 */

/*
 *          LWJGL
 * (auto-generated script)
 *   ((here be dragons))
 */

import org.gradle.internal.os.OperatingSystem

project.ext.lwjglVersion = "3.2.3"

switch (OperatingSystem.current()) {
	case OperatingSystem.LINUX:
		def osArch = System.getProperty("os.arch")
		project.ext.lwjglNatives = osArch.startsWith("arm") || osArch.startsWith("aarch64")
			? "natives-linux-${osArch.contains("64") || osArch.startsWith("armv8") ? "arm64" : "arm32"}"
			: "natives-linux"
		break
	case OperatingSystem.MAC_OS:
		project.ext.lwjglNatives = "natives-macos"
		break
	case OperatingSystem.WINDOWS:
		project.ext.lwjglNatives = System.getProperty("os.arch").contains("64") ? "natives-windows" : "natives-windows-x86"
		break
}

dependencies {
	implementation platform("org.lwjgl:lwjgl-bom:$lwjglVersion")

	implementation "org.lwjgl:lwjgl"
	implementation "org.lwjgl:lwjgl-glfw"
	implementation "org.lwjgl:lwjgl-openal"
	implementation "org.lwjgl:lwjgl-opengl"
	implementation "org.lwjgl:lwjgl-stb"
	
	runtimeOnly "org.lwjgl:lwjgl::$lwjglNatives"
    runtimeOnly "org.lwjgl:lwjgl-glfw::$lwjglNatives"
    runtimeOnly "org.lwjgl:lwjgl-openal::$lwjglNatives"
    runtimeOnly "org.lwjgl:lwjgl-opengl::$lwjglNatives"
    runtimeOnly "org.lwjgl:lwjgl-stb::$lwjglNatives"
}

// LWJGL END

/*
 * Tasks
 */

/*
 * Additional native libraries specification
 */

project.ext.platforms = new HashSet<>()

task addNativeDependencies {
	doFirst {
		def archs = project.ext.platforms
		
		switch (archs.size()) {
		case 0:
			println "Adding LWJGL native dependencies for local platform only:\n\t$lwjglNatives"
			archs.add project.ext.lwjglNatives
			break
		case 1:
			println "Adding LWJGL native dependencies for platform\n\t" + archs.get(0)
			break
		default:
			println "Adding LWJGL native dependencies for platforms:\n\t" + archs.join("\n\t")
		}
		
		if (project.ext.lwjglNatives.isEmpty()) println "WTF"
		
		dependencies {
			archs.each { arch ->
		        runtimeOnly "org.lwjgl:lwjgl::$arch"
		        runtimeOnly "org.lwjgl:lwjgl-glfw::$arch"
		        runtimeOnly "org.lwjgl:lwjgl-openal::$arch"
		        runtimeOnly "org.lwjgl:lwjgl-opengl::$arch"
		        runtimeOnly "org.lwjgl:lwjgl-stb::$arch"
		    }
	    }
    }
}

compileJava.mustRunAfter addNativeDependencies // Make sure runtimeOnly has not been resolved

task requestLinuxDependencies {
    description 'Adds linux, linux-arm64 and linux-arm32 native libraries to built artifacts.'
	doFirst {
		project.ext.platforms.addAll(['natives-linux', 'natives-linux-arm64', 'natives-linux-arm32'])
	}
}
task requestWindowsDependencies {
    description 'Adds windows and windows-x86 native libraries to built artifacts.'
	doFirst {
		project.ext.platforms.addAll(['natives-windows', 'natives-windows-x86'])
	}
}
task requestMacOSDependencies {
    description 'Adds macos native libraries to built artifacts.'
	doFirst {
		project.ext.platforms.addAll(['natives-macos'])
	}
}

def dependencySpecificationTasks = tasks.findAll { task -> task.name.startsWith('request') && task.name.endsWith('Dependencies') }

task requestCrossPlatformDependencies {
    description 'Adds native libraries for all available platforms to built artifacts.'
	dependsOn dependencySpecificationTasks
}

addNativeDependencies.mustRunAfter dependencySpecificationTasks

/*
 * Determines if the provided dependency should be packaged
 */
def isDependencyRequested(String dep) {
	if (dep.endsWith(".jar")) {
		dep = dep.substring(0, dep.length() - ".jar".length())
	}
	
	return !dep.contains("natives-") ||
			project.ext.platforms.contains(dep.substring(dep.indexOf("natives-"), dep.length()))
}

/*
 * Manifest specification
 */

task specifyLocalManifest {
	dependsOn addNativeDependencies // Make sure all native dependencies are specified

	doFirst {
		def classPath = []
		
		configurations.runtimeClasspath.each {
			if (isDependencyRequested(it.getName())) {
				classPath.add("lib/" + it.getName())
			} else {
				println "\tRemoving from JAR classpath (not requested):  " + it.getName()
			}
		}
		
		if (classPath.size() == configurations.runtimeClasspath.size()) {
			println "Nothing removed from JAR classpath"
		}
	
		jar {
		    manifest {
		        attributes(
		        	"Main-Class": "ru.windcorp.progressia.client.ProgressiaClientMain",
		        	"Class-Path": configurations.runtimeClasspath.collect { "lib/" + it.getName() } .findAll { isDependencyRequested(it) } .join(' ')
		        )
		    }
		}
	}
}

jar.dependsOn specifyLocalManifest

/*
 * Library export
 */
 
task exportLibs(type: Sync) {
	mustRunAfter addNativeDependencies

    into libsDirectory.get().getAsFile().getPath() + "/lib"
    exclude { !isDependencyRequested(it.getName()) }
    from configurations.runtimeClasspath
}

jar.dependsOn(exportLibs)

/*
 * Packaging
 */

task packageDebian(type: Exec) {
    description 'Builds the project and creates a Debain package.'
    group 'Progressia'
    
    dependsOn build
    dependsOn requestLinuxDependencies
    
    commandLine './buildPackages.sh', 'debian'
    
    doLast {
        println "Debian package available in build_packages/"
    }
}

task packageWindows(type: Exec) {
    description 'Builds the project and creates a Windows installer.'
    group 'Progressia'
    
    dependsOn build
    dependsOn requestWindowsDependencies
    
    commandLine './buildPackages.sh', 'windows'
    
    doLast {
        println "Windows installer available in build_packages/"
    }
}

task buildCrossPlatform {
    description 'Builds the project including native libraries for all available platforms.'
    group 'Progressia'
    
    dependsOn requestCrossPlatformDependencies
    dependsOn build
    
    doLast {
        println "Native libraries for all platforms have been added"
    }
}

task buildLocal {
    description "Builds the project including only native libraries for current platform ($lwjglNatives)."
    group 'Progressia'
    
    dependsOn build
    
    doLast {
        println "Native libraries only for platform $lwjglNatives have been added"
    }
}
