package com.gradle

import com.android.build.api.transform.*
import com.google.common.collect.ImmutableSet
import com.google.common.io.Files
import org.apache.commons.codec.digest.DigestUtils
import org.apache.commons.io.FileUtils
import org.gradle.api.Project

/**
 * Created by Glen on 2017/2/7.
 */

public abstract class ModifyClassTransform extends Transform {
    protected Project project;

    public ModifyClassTransform(Project project) {
        if (project != null) {
            this.project = project
            MyLogger.init(project.name)
        }
    }

    @Override
    public String getName() {
        return "Modify"
    }

    @Override
    public Set<QualifiedContent.ContentType> getInputTypes() {
        return ImmutableSet.of(QualifiedContent.DefaultContentType.CLASSES)
    }

    @Override
    public Set<QualifiedContent.Scope> getScopes() {
        return ImmutableSet.of(
                QualifiedContent.Scope.PROJECT,// app class
                QualifiedContent.Scope.PROJECT_LOCAL_DEPS,// app libs local jar
                QualifiedContent.Scope.SUB_PROJECTS,//sub lib class
                QualifiedContent.Scope.SUB_PROJECTS_LOCAL_DEPS,//sub lib libs local jar
                QualifiedContent.Scope.EXTERNAL_LIBRARIES//compile dependencies
        )
    }

    @Override
    public boolean isIncremental() {
        return false
    }

    @Override
    void transform(TransformInvocation transformInvocation) throws TransformException, InterruptedException, IOException {
        long time = System.currentTimeMillis()
        // Collecting inputs.
        transformInvocation.inputs.each { input ->
            input.directoryInputs.each { dirInput ->
                if (transformInvocation.incremental) {
                    File dirOutput = transformInvocation.outputProvider.getContentLocation(dirInput.file.name, dirInput.contentTypes, dirInput.scopes, Format.DIRECTORY)
                    if (!dirOutput.exists()) {
                        dirOutput.mkdirs()
                    }
                    dirInput.changedFiles.each { changedFile ->
                        File fileInput = changedFile.getKey()
                        File fileOutput = new File(fileInput.getAbsolutePath().replace(
                                dirInput.file.getAbsolutePath(), dirOutput.getAbsolutePath()))
                        if (!fileOutput.exists()) {
                            fileOutput.getParentFile().mkdirs()
                        }
                        switch (changedFile.value) {
                            case Status.ADDED:
                            case Status.CHANGED:
                                if (fileInput.isDirectory()) {
                                    return // continue.
                                }
                                handleChangedFile(fileInput)
                                if (fileInput.getName().endsWith('.class')) {
                                    Files.copy(fileInput, fileOutput)
                                }
                                break
                            case Status.REMOVED:
                                if (fileOutput.exists()) {
                                    if (fileOutput.isDirectory()) {
                                        fileOutput.deleteDir()
                                    } else {
                                        fileOutput.delete()
                                    }
                                }
                                break
                        }
                    }
                } else {
                    dirInput.file.eachFileRecurse { File file ->
                        handleChangedFile(file)
                    }
                    //output modify class file
                    File file = transformInvocation.outputProvider.getContentLocation(dirInput.file.name, dirInput.contentTypes, dirInput.scopes, Format.DIRECTORY)
                    if (file.exists()) file.deleteDir()
                    FileUtils.copyDirectory(dirInput.file, file)
                }
            }
            input.jarInputs.each { jarInput ->
                File file = transformInvocation.outputProvider.getContentLocation(getUniqueFileName(jarInput.file), jarInput.contentTypes, jarInput.scopes, Format.JAR)
                switch (jarInput.status) {
                    case Status.NOTCHANGED:
                        if (transformInvocation.incremental) break
                    case Status.ADDED:
                    case Status.CHANGED:
                        file.deleteOnExit()
                        handleChangedFile(jarInput.file)
                        //output modify jar file
                        FileUtils.copyFile(jarInput.file, file)
                        break
                    case Status.REMOVED:
                        file.deleteOnExit()
                        break
                }
            }
        }

        MyLogger.error(name + ":consume time " + (System.currentTimeMillis() - time) + "ms")
    }

    /**
     * 生成唯一文件名
     * @param fileInput
     * @return
     */
    protected String getUniqueFileName(File fileInput) {
        final String fileInputName = fileInput.getName()
        if (fileInput.isDirectory()) {
            return fileInputName
        }
        final String parentDirPath = fileInput.getParentFile().getAbsolutePath()
        final String pathMD5 = DigestUtils.md5Hex(parentDirPath.getBytes()).substring(0, 6)
        final int extSepPos = fileInputName.lastIndexOf('.')
        final String fileInputNamePrefix =
                (extSepPos >= 0 ? fileInputName.substring(0, extSepPos) : fileInputName)

        return fileInputNamePrefix + '_' + pathMD5
    }

    /**
     * 增量文件
     * @param input
     */
    protected abstract void handleChangedFile(File input)
}