sourceSets.main.java.srcDirs = ["src/"]

import arc.struct.*
import arc.graphics.*
import arc.packer.*
import arc.util.*

import javax.imageio.*
import java.awt.Graphics2D
import java.awt.image.*
import java.util.concurrent.*

def genFolder = "../core/assets-raw/sprites_out/generated/"
def doAntialias = !project.hasProperty("disableAntialias")
def colorMap = new IntMap<List<Color>>(), colorIndexMap = new IntIntMap()
//on my machine, I have a native Nim AA implementation that is ~10x faster
//it's not compiled for other platforms so they don't get it
def useFastAA = System.getProperty("user.name") == "anuke"

def transformColors = { List<List<String>> list ->
    list.each{ colors ->
        def newColors = []
        colors.each{ hexc ->
            newColors += Color.valueOf(hexc)
        }

        newColors.each{ color ->
            colorMap.put(color.argb8888(), newColors)
            colorIndexMap.put(color.argb8888(), newColors.indexOf(color))
        }
    }
}


//d4816b
transformColors([["a387ea", "8a73c6", "5c5e9f"], ["6e7080", "989aa4", "b0bac0"], ["bc5452", "ea8878", "feb380"], ["de9458", "f8c266", "ffe18f"], ["feb380", "ea8878", "bc5452"], ["d4816b", "eab678", "ffd37f"]])

def antialias = { File file ->
    if(!doAntialias) return

    if(useFastAA){
        "antialias ${file.absolutePath}".execute().waitFor()
        return
    }

    def image = ImageIO.read(file)
    def out = ImageIO.read(file)
    def getRGB = { int ix, int iy ->
        //if(ix <= 0 || iy <= 0 || ix >= image.width || iy >= image.height) return 0
        return image.getRGB(Math.max(Math.min(ix, image.width - 1), 0), Math.max(Math.min(iy, image.height - 1), 0))
    }

    def color = new Color()
    def sum = new Color()
    def suma = new Color()
    int[] p = new int[9]

    for(int x = 0; x < image.getWidth(); x++){
        for(int y = 0; y < image.getHeight(); y++){
            int A = getRGB(x - 1, y + 1),
                B = getRGB(x, y + 1),
                C = getRGB(x + 1, y + 1),
                D = getRGB(x - 1, y),
                E = getRGB(x, y),
                F = getRGB(x + 1, y),
                G = getRGB(x - 1, y - 1),
                H = getRGB(x, y - 1),
                I = getRGB(x + 1, y - 1)

            Arrays.fill(p, E);

            if(D == B && D != H && B != F) p[0] = D
            if((D == B && D != H && B != F && E != C) || (B == F && B != D && F != H && E != A)) p[1] = B
            if(B == F && B != D && F != H) p[2] = F
            if((H == D && H != F && D != B && E != A) || (D == B && D != H && B != F && E != G)) p[3] = D
            if((B == F && B != D && F != H && E != I) || (F == H && F != B && H != D && E != C)) p[5] = F
            if(H == D && H != F && D != B) p[6] = D
            if((F == H && F != B && H != D && E != G) || (H == D && H != F && D != B && E != I)) p[7] = H
            if(F == H && F != B && H != D) p[8] = F

            suma.set(0)

            for(int val : p){
                color.argb8888(val)
                suma.r += color.r * color.a
                suma.g += color.g * color.a
                suma.b += color.b * color.a
                suma.a += color.a
            }

            float fm = suma.a <= 0.001f ? 0f : (float) (1f / suma.a)
            suma.mul(fm, fm, fm, fm)

            float total = 0
            sum.set(0)

            for(int val : p){
                color.argb8888(val)
                float a = color.a
                color.lerp(suma, (float) (1f - a))
                sum.r += color.r
                sum.g += color.g
                sum.b += color.b
                sum.a += a
                total += 1f
            }

            fm = (float)(1f / total)
            sum.mul(fm, fm, fm, fm)
            out.setRGB(x, y, sum.argb8888())
            sum.set(0)
        }
    }

    ImageIO.write(out, "png", file)
}

def medianBlur = { File file ->
    def image = ImageIO.read(file)
    def result = new BufferedImage(image.width, image.height, BufferedImage.TYPE_INT_ARGB)
    def radius = 4
    IntSeq array = new IntSeq()

    def getRGB = { int ix, int iy ->
        return image.getRGB(Math.max(Math.min(ix, image.width - 1), 0), Math.max(Math.min(iy, image.height - 1), 0))
    }

    for(int x = 0; x < image.width; x++){
        for(int y = 0; y < image.height; y++){
            array.clear()

            for(int dx = -radius; dx <= radius; dx ++){
                for(int dy = -radius; dy <= radius; dy ++){
                    if(dx*dx + dy*dy <= radius*radius){
                        array.add(getRGB(x + dx, y + dy))
                    }
                }
            }

            array.sort()

            result.setRGB(x, y, array.get((int)(array.size / 2)))
        }
    }

    ImageIO.write(result, "png", file)
}

def scaleImage = { File file ->
    def image = ImageIO.read(file)
    for(int iteration in 0..1){
        def scaled = new BufferedImage(image.width * 2, image.height * 2, BufferedImage.TYPE_INT_ARGB)

        def getRGB = { int ix, int iy ->
            return image.getRGB(Math.max(Math.min(ix, image.width - 1), 0), Math.max(Math.min(iy, image.height - 1), 0))
        }

        for(int x = 0; x < image.width; x++){
            for(int y = 0; y < image.height; y++){
                int p = image.getRGB(x, y)
                int p1 = p, p2 = p, p3 = p, p4 = p

                int A = getRGB(x - 1, y + 1),
                    B = getRGB(x, y + 1),
                    C = getRGB(x + 1, y + 1),
                    D = getRGB(x - 1, y),
                    E = getRGB(x, y),
                    F = getRGB(x + 1, y),
                    G = getRGB(x - 1, y - 1),
                    H = getRGB(x, y - 1),
                    I = getRGB(x + 1, y - 1),
                    J = getRGB(x, y + 2),
                    K = getRGB(x - 2, y),
                    L = getRGB(x + 2, y),
                    M = getRGB(x, y - 2)

                if(B == D && B != F && D != H && (E != A || E == C || E == G || A == J || A == K)) p1 = B
                if(B == F && B != D && F != H && (E != C || E == A || E == I || C == J || C == L)) p2 = F
                if(D == H && B != D && F != H && (E != G || E == A || E == I || G == K || G == M)) p3 = D
                if(F == H && B != F && D != H && (E != I || E == C || E == G || I == L || I == M)) p4 = H

                scaled.setRGB(x * 2, y * 2 + 1, p1)
                scaled.setRGB(x * 2 + 1, y * 2 + 1, p2)
                scaled.setRGB(x * 2, y * 2, p3)
                scaled.setRGB(x * 2 + 1, y * 2, p4)
            }
        }
        image = scaled
    }

    ImageIO.write(image, "png", file)
}

def tileImage = { File file ->
    def image = ImageIO.read(file)

    for(x in 0..image.width-1){
        for(y in 0..image.height-1){
            if(x > (image.height - 1 - y)){
                def rx = image.height - 1 - y
                def ry = x

                image.setRGB(x, y, image.getRGB(rx, image.height - 1 - ry))
            }
        }
    }

    def result = new BufferedImage(image.width * 2, image.height * 2, image.getType())
    Graphics2D graphics = result.createGraphics()
    graphics.drawImage(image, image.width, 0, -image.width, image.height, null)

    graphics.drawImage(image, image.width, 0, image.width, image.height, null)

    graphics.drawImage(image, image.width, image.height*2, -image.width, -image.height, null)

    graphics.drawImage(image, image.width, image.height*2, image.width, -image.height, null)

    for(int x = 0; x < result.width; x++){
        for(int y = 0; y < result.height; y++){
            int p = result.getRGB(x, y)
            if(x <= y){
                List<Color> list = colorMap.get(p)
                int index = colorIndexMap.get(p, -1)

                if(index != -1){
                    int resultIndex = (x == y ? 1 : index == 2 ? 0 : index == 0 ? 2 : 1);
                    result.setRGB(x, y, list[resultIndex].argb8888())
                }
            }
        }
    }

    ImageIO.write(result, "png", file)
}

task swapColors(){
    doLast{
        if(project.hasProperty("colors")){
            def carr = new File(getProperty("colors")).text.split("\n")
            def map = [:]
            def swaps = 0
            carr.each{ str -> map[Color.valueOf(str.split("=")[0]).argb8888()] = Color.valueOf(str.split("=")[1]).argb8888() }
            def tmpc = new Color()

            fileTree(dir: '../core/assets-raw/sprites', include: "**/*.png").visit{ file ->
                if(file.isDirectory()) return

                boolean found = false

                def img = ImageIO.read(file.file)
                for(x in (0..img.getWidth() - 1)){
                    for(y in (0..img.getHeight() - 1)){
                        def c = img.getRGB(x, y)
                        tmpc.argb8888(c)
                        if(tmpc.a < 0.1f) continue
                        if(map.containsKey(c)){
                            img.setRGB(x, y, (int)map.get(c))
                            found = true
                        }
                    }
                }
                if(found){
                    swaps++
                    ImageIO.write(img, "png", file.file)
                }
            }
            println "Swapped $swaps images."
        }else{
            throw new InvalidUserDataException("No replacement colors specified. Use -Pcolors=\"<path to color file>\"")
        }
    }
}

task genPalette(){
    doLast{
        def total = 0
        def size = 32
        def outImage = new BufferedImage(size, size, BufferedImage.TYPE_INT_ARGB)
        def colorsUsed = new IntSet()

        fileTree(dir: '../core/assets-raw/sprites/blocks', include: "**/*.png").visit{ file ->
            if(file.isDirectory()) return

            def img = ImageIO.read(file.file)
            for(x in (0..img.getWidth() - 1)){
                for(y in (0..img.getHeight() - 1)){
                    def c = img.getRGB(x, y)

                    if(Tmp.c1.argb8888(c).a > 0.999f && colorsUsed.add(c)){
                        outImage.setRGB((int)(total / size), total % size, c)
                        total ++
                    }
                }
            }
        }

        ImageIO.write(outImage, "png", new File("palette.png"))
        println "Found $total colors."

    }
}

task antialiasImages(){
    doLast{
        for(def img : project.getProperty("images").split(",")){
            println(project.getProperty("startdir") + "/" + img)
            antialias(new File(project.getProperty("startdir") + "/" + img))
        }
    }
}

task scaleImages(){
    doLast{
        for(def img : project.getProperty("images").split(",")){
            println(project.getProperty("startdir") + "/" + img)
            scaleImage(new File(project.getProperty("startdir") + "/" + img))
        }
    }
}

task tileImages(){
    doLast{
        for(def img : project.getProperty("images").split(",")){
            println(project.getProperty("startdir") + "/" + img)
            tileImage(new File(project.getProperty("startdir") + "/" + img))
        }
    }
}

task pack(dependsOn: classes){

    doLast{
        //cleanup old sprites
        delete{
            delete "../core/assets-raw/sprites_out/"
        }

        //copy in new sprites
        copy{
            from "../core/assets-raw/sprites/"
            into "../core/assets-raw/sprites_out/"
        }

        //run generation task; generate all needed sprites
        file(genFolder).mkdirs()
        javaexec{
            main = "mindustry.tools.ImagePacker"
            classpath = sourceSets.main.runtimeClasspath
            workingDir = genFolder
        }

        copy{
            from "../core/assets-raw/sprites_out/ui/icons"
            into "../core/assets-raw/sprites_out/ui/"
        }

        delete{
            delete "../core/assets-raw/sprites_out/ui/icons"
        }

        ExecutorService executor = Executors.newFixedThreadPool(16)
        long ms = System.currentTimeMillis()

        //antialias everything except UI elements
        fileTree(dir: '../core/assets-raw/sprites_out/', include: "**/*.png").visit{ file ->
            if(file.isDirectory() || (file.toString().replace("\\", "/").contains("/ui/") && file.toString().startsWith("icon-")) || file.toString().contains(".9.png")) return

            executor.submit{
                antialias(file.file)
            }
        }

        executor.shutdown()
        try{
            executor.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS)
        }catch(InterruptedException e){
            e.printStackTrace()
        }

        println "Time taken for AA: ${(System.currentTimeMillis() - ms) / 1000f}"

        println("\n\nPacking normal 4096 sprites...\n\n")

        //pack normal sprites
        TexturePacker.process("core/assets-raw/sprites_out/", "core/assets/sprites/", "sprites.atlas")

        println("\n\nPacking fallback 2048 sprites...\n\n")

        //replace config file contents
        fileTree(dir: '../core/assets-raw/sprites_out/', include: "**/*.json").visit{ file ->
            if(!file.isDirectory()) file.file.text = file.file.text.replace("4096", "2048")
        }

        //pack fallback 2048x2048 sprites
        TexturePacker.process("core/assets-raw/sprites_out/", "core/assets/sprites/fallback/", "sprites.atlas")
    }
}

task genSprites(dependsOn: classes, type: JavaExec){
    finalizedBy 'antialiasGen'

    main = "mindustry.tools.ImagePacker"
    classpath = sourceSets.main.runtimeClasspath
    jvmArgs("-Djava.awt.headless=true")
    standardInput = System.in
    workingDir = genFolder
}

task updateBundles(dependsOn: classes, type: JavaExec){
    file(genFolder).mkdirs()

    main = "mindustry.tools.BundleLauncher"
    classpath = sourceSets.main.runtimeClasspath
    standardInput = System.in
    workingDir = "../core/assets/bundles/"
}

task fontgen(dependsOn: classes, type: JavaExec){
    main = "mindustry.tools.FontGenerator"
    classpath = sourceSets.main.runtimeClasspath
    standardInput = System.in
    workingDir = "../"
}
