package ca.uwaterloo.cs858.FindCrypto

import com.ibm.wala.dalvik.classLoader.DexFileModule
import com.ibm.wala.dalvik.util.AndroidAnalysisScope
import com.ibm.wala.ipa.callgraph.AnalysisScope
import com.ibm.wala.types.ClassLoaderReference
import com.ibm.wala.util.config.AnalysisScopeReader
import edu.purdue.cs.toydroid.utils.SimpleConfig
import org.apache.logging.log4j.LogManager
import java.io.File
import java.io.FileNotFoundException
import java.io.IOException

class AnalysisScopeUtil {
    private val logger = LogManager.getLogger(AnalysisScopeUtil::class.java)
    private val WALA_CLASSLOADER = AnalysisScopeReader::class.java.classLoader
    private val BASIC_FILE = "primordial.txt"
    private val EXCLUSIONS = "AndroidRegressionExclusions.txt"
    private val PrimordialTag = "Primordial"
    private val ApplicationTag = "Application"

    @Throws(IOException::class, FileNotFoundException::class)
    fun makeAnalysisScope(): AnalysisScope {
        val scope: AnalysisScope
        val androidJar = SimpleConfig.getAndroidJar()
        var exclusionFile = SimpleConfig.getExclusionFile()
        logger.info("AndroidJar: {}", androidJar)
        if (exclusionFile == null) {
            exclusionFile = "AndroidRegressionExclusions.txt"
        }
        logger.info("ExclusionFile: {}", exclusionFile)
        scope = AnalysisScopeReader.readJavaScope("primordial.txt", File(exclusionFile), WALA_CLASSLOADER)
        AndroidAnalysisScope.addClassPathToScope(androidJar, scope, ClassLoaderReference.Primordial)
        scope.setLoaderImpl(ClassLoaderReference.Application, "com.ibm.wala.dalvik.classLoader.WDexClassLoaderImpl")
        val iter: Iterator<*> = SimpleConfig.iteratorAdditionalJars()
        while (iter.hasNext()) {
            val additionalJar = iter.next() as String
            val idx = additionalJar.indexOf(44.toChar())
            if (idx > 0) {
                val ref = additionalJar.substring(0, idx)
                val path = additionalJar.substring(idx + 1)
                var clRef: ClassLoaderReference? = null
                logger.info("AdditionalJar[{}]: {}", ref, path)
                if (ref.startsWith("Primordial")) {
                    clRef = scope.primordialLoader
                } else if (ref.startsWith("Application")) {
                    clRef = scope.applicationLoader
                } else {
                    logger.warn("Unrecognized ADDITIONAL_JARS in Config.properties.")
                }
                if (clRef != null) {
                    AndroidAnalysisScope.addClassPathToScope(path, scope, clRef)
                }
            }
        }
        return scope
    }

    @Throws(IOException::class, FileNotFoundException::class)
    fun makeAnalysisScope(apkFile: String?): AnalysisScope? {
        var scope: AnalysisScope?
        val androidJar = SimpleConfig.getAndroidJar()
        var exclusionFile = SimpleConfig.getExclusionFile()
        logger.info("AndroidJar: {}", androidJar)
        if (exclusionFile == null) {
            exclusionFile = "AndroidRegressionExclusions.txt"
        }
        logger.info("ExclusionFile: {}", exclusionFile)
        scope = AnalysisScopeReader.readJavaScope("primordial.txt", File(exclusionFile), WALA_CLASSLOADER)
        AndroidAnalysisScope.addClassPathToScope(androidJar, scope, ClassLoaderReference.Primordial)
        scope.setLoaderImpl(ClassLoaderReference.Application, "com.ibm.wala.dalvik.classLoader.WDexClassLoaderImpl")
        scope.addToScope(ClassLoaderReference.Application, DexFileModule.make(File(apkFile!!)))
        return scope
    }
}