//
//  main.swift
//  map_preprocessor
//
//  Created by Dan Crosby on 6/4/19.
//  Copyright © 2019 Dan Crosby. All rights reserved.
//

import Foundation
import Cocoa

let provinces = """
[{"i":1,"color":"#fccde5","name":"Shumal","expansionism":1,"capital":1,"type":"Generic","center":663,"culture":10},{"i":2,"color":"#ff724c","name":"Motcia","expansionism":1,"capital":2,"type":"River","center":3778,"culture":8},{"i":3,"color":"#6e40aa","name":"Laufarvia","expansionism":1,"capital":3,"type":"Generic","center":4525,"culture":4},{"i":4,"color":"#eb4298","name":"Berkorszag","expansionism":1,"capital":4,"type":"River","center":1293,"culture":9},{"i":5,"color":"#ff5473","name":"Musland","expansionism":1,"capital":5,"type":"Highland","center":4259,"culture":11},{"i":6,"color":"#5b5bcf","name":"Soria","expansionism":1,"capital":6,"type":"Generic","center":4296,"culture":4},{"i":7,"color":"#8dd3c7","name":"Oryslia","expansionism":1,"capital":7,"type":"River","center":1329,"culture":1},{"i":8,"color":"#b3de69","name":"Atfordia","expansionism":1,"capital":8,"type":"Generic","center":4128,"culture":2},{"i":9,"color":"#ccebc5","name":"Bolve","expansionism":1,"capital":9,"type":"Generic","center":4326,"culture":4},{"i":10,"color":"#ff625e","name":"Vovimaria","expansionism":1,"capital":10,"type":"Generic","center":3941,"culture":4},{"i":11,"color":"#3193e0","name":"Garholtia","expansionism":1,"capital":11,"type":"Generic","center":3945,"culture":4},{"i":12,"color":"#f99a32","name":"Pozia","expansionism":1,"capital":12,"type":"River","center":4861,"culture":8},{"i":13,"color":"#d7c432","name":"Al Raala","expansionism":1,"capital":13,"type":"Generic","center":1564,"culture":10},{"i":14,"color":"#25a7da","name":"Onmaa","expansionism":1,"capital":14,"type":"River","center":3559,"culture":3},{"i":15,"color":"#33f07f","name":"Pieksa","expansionism":1,"capital":15,"type":"River","center":3675,"culture":3},{"i":16,"color":"#1bdba9","name":"Oscasland","expansionism":1,"capital":16,"type":"Generic","center":3863,"culture":2},{"i":17,"color":"#4e6ddb","name":"Hofolen","expansionism":1,"capital":17,"type":"Generic","center":4741,"culture":4},{"i":18,"color":"#873eb1","name":"Alah","expansionism":1,"capital":18,"type":"Generic","center":839,"culture":10},{"i":19,"color":"#bc80bd","name":"Hella","expansionism":1,"capital":19,"type":"Generic","center":4301,"culture":4},{"i":20,"color":"#ffed6f","name":"Elekes","expansionism":1,"capital":20,"type":"River","center":808,"culture":9},{"i":21,"color":"#19ccbd","name":"Sigkarl","expansionism":1,"capital":21,"type":"Generic","center":4222,"culture":4},{"i":22,"color":"#fc4a86","name":"Chipingia","expansionism":1,"capital":22,"type":"Generic","center":4239,"culture":2},{"i":23,"color":"#d53ea6","name":"Eivikia","expansionism":1,"capital":23,"type":"Generic","center":4437,"culture":4},{"i":24,"color":"#bebada","name":"Tatoros","expansionism":1,"capital":24,"type":"River","center":184,"culture":9},{"i":25,"color":"#664cbe","name":"Fluria","expansionism":1,"capital":25,"type":"Generic","center":4209,"culture":4},{"i":26,"color":"#b6e84f","name":"Reigia","expansionism":1,"capital":26,"type":"Generic","center":4217,"culture":4},{"i":27,"color":"#bd3caf","name":"Chapellia","expansionism":1,"capital":27,"type":"River","center":4272,"culture":8},{"i":28,"color":"#1dbace","name":"Kezonoria","expansionism":1,"capital":28,"type":"River","center":1432,"culture":9},{"i":29,"color":"#e9af2e","name":"Mesh","expansionism":1,"capital":29,"type":"River","center":1663,"culture":1},{"i":30,"color":"#fb8072","name":"Tegrot","expansionism":1,"capital":30,"type":"River","center":2180,"culture":9},{"i":31,"color":"#c5d73d","name":"Nikemi","expansionism":1,"capital":31,"type":"River","center":3427,"culture":3},{"i":32,"color":"#fdb462","name":"Ingia","expansionism":1,"capital":32,"type":"Generic","center":4291,"culture":4},{"i":33,"color":"#80b1d3","name":"Usvol","expansionism":1,"capital":33,"type":"Generic","center":4951,"culture":4},{"i":34,"color":"#a23db3","name":"Turton","expansionism":1,"capital":34,"type":"River","center":277,"culture":9},{"i":35,"color":"#24e794","name":"Tumala","expansionism":1,"capital":35,"type":"Generic","center":685,"culture":10},{"i":36,"color":"#48f56d","name":"Pemeria","expansionism":1,"capital":36,"type":"River","center":1209,"culture":1},{"i":37,"color":"#d9d9d9","name":"Yuetia","expansionism":1,"capital":37,"type":"Naval","center":1367,"culture":12},{"i":38,"color":"#ffffb3","name":"Wichel","expansionism":1,"capital":38,"type":"Generic","center":3646,"culture":2},{"i":39,"color":"#62f75f","name":"Kojaria","expansionism":1,"capital":39,"type":"River","center":3914,"culture":3},{"i":40,"color":"#ff853c","name":"Faluria","expansionism":1,"capital":40,"type":"Generic","center":4304,"culture":4},{"i":41,"color":"#a0f258","name":"Parnia","expansionism":1,"capital":41,"type":"Generic","center":4401,"culture":5},{"i":42,"color":"#80f558","name":"Grytrand","expansionism":1,"capital":42,"type":"Generic","center":4892,"culture":4},{"i":43,"color":"#3f7fe1","name":"Chia","expansionism":1,"capital":43,"type":"Naval","center":110,"culture":12}]
"""

extension NSColor {
    var rgbColor: NSColor {
        return self.usingColorSpace(NSColorSpace.genericRGB) ?? self
    }

    var hexString: String {
        let rgbc = rgbColor

        let red = Int(round(rgbc.redComponent * 0xFF))
        let green = Int(round(rgbc.greenComponent * 0xFF))
        let blue = Int(round(rgbc.blueComponent * 0xFF))
        let hexString = NSString(format: "#%02X%02X%02X", red, green, blue)
        return hexString as String
    }

    var asInt: Int {
        let rgbc = rgbColor

        let red = Int(round(rgbc.redComponent * 0xFF))
        let green = Int(round(rgbc.greenComponent * 0xFF))
        let blue = Int(round(rgbc.blueComponent * 0xFF))

        return red << 16 | green << 8 | blue
    }
}

struct RawMapProvince: Decodable {
    let i: Int
    let color: String
    let name: String
}

public struct Province {
    let id: UInt8
    let color: Int
    let name: String
    var neighbors: Set<UInt8>
}

guard let provincesData = provinces.data(using: String.Encoding.ascii) else {
    print("Unable to get data from provinces string")
    abort()
}

guard let rawProvinces = try? JSONDecoder().decode([RawMapProvince].self, from: provincesData) else {
    print("Unable to decode")
    abort()
}

var provincesByColor = Dictionary<Int, Province>()

for province in rawProvinces {
    let colorInt = Int(province.color.dropFirst(), radix: 16)!
    provincesByColor[colorInt] = Province(id: UInt8(province.i), color: colorInt, name: province.name, neighbors: Set<UInt8>())
}

let imageURL = URL(fileURLWithPath: "/Users/dancrosby/Downloads/dankmap_colors_nolabels.png")
let imageData = try! Data(contentsOf: imageURL)

let bitmap = NSBitmapImageRep(data: imageData)!
let width = Int(bitmap.size.width)
let height = Int(bitmap.size.height)

let idMap = MapBitmap(bitmap: bitmap, provincesByColor: provincesByColor)

let flippedIdMap = FlipArray(array: idMap, stride: width)
let rawData = Data(bytes: flippedIdMap, count: flippedIdMap.count)
try! rawData.write(to: URL(fileURLWithPath: "/Users/dancrosby/Downloads/rawGray.bytes"))

var provincesById = provincesByColor
    .values
    .reduce([UInt8 : Province]()) { (dict, province) -> [UInt8 : Province] in
        var dict = dict
        dict[province.id] = province
        return dict
}

let maxPixelsOut = 3

// find neighbors
for y in 0..<height {
    for x in 0..<width {
        let currentValue = idMap[y * width + x]
        if currentValue != 0 && currentValue != 0xFF {
            for pixelsOut in 1...maxPixelsOut {
                if x + pixelsOut < width {
                    let rightPosition = y * width + x + pixelsOut
                    let rightValue = idMap[rightPosition]
                    if rightValue != 0 && rightValue != 0xFF && rightValue != currentValue {
                        provincesById[currentValue]!.neighbors.insert(rightValue)
                        provincesById[rightValue]!.neighbors.insert(currentValue)
                    }
                }

                if y + pixelsOut < height {
                    let downPosition = (y+pixelsOut) * width + x
                    let downValue = idMap[downPosition]
                    if downValue != 0xFF && downValue != 0 && downValue != currentValue {
                        provincesById[currentValue]!.neighbors.insert(downValue)
                        provincesById[downValue]!.neighbors.insert(currentValue)
                    }
                }
            }
        }
    }
}

var tsv = "id\tname\tneighbors\tneighborNames\n"
for province in provincesById.values {
    tsv += "\(province.id)\t\(province.name)\t"
    for n in province.neighbors {
        tsv += "\(n),"
    }
    tsv.remove(at: tsv.index(before: tsv.endIndex))
    tsv += "\t"
    for n in province.neighbors {
        tsv += "\(provincesById[n]!.name),"
    }
    tsv.remove(at: tsv.index(before: tsv.endIndex))
    tsv += "\n"
}

print(tsv)

try! tsv.write(to: URL(fileURLWithPath: "/Users/dancrosby/Downloads/province_map.tsv"), atomically: true, encoding: String.Encoding.ascii)

let images = MasksForProvinces(idMap: idMap, provinceIds: Array(provincesById.keys))

for (id, cgImage) in images {
    let bitmap = NSBitmapImageRep(cgImage: cgImage)

    guard let pngData = bitmap.representation(using: .png, properties: [:]) else {
        print("unable to make png")
        break
    }

    try! pngData.write(to: URL(fileURLWithPath: "/Users/dancrosby/Downloads/grayPngs/\(id).png"))
}


