// Load in dependencies
var fs = require('fs');
var Spritesmith = require('spritesmith');
var SpriteLibrary = require('./SpriteLibrary.js');
var exportSVG = require('./AnalyzeSVG.js');
var marginExtruder = require('./marginExtruder.js');

var timeStarted = Date.now();

// Hier alle Bitmap-Dateien (png) ablegen. 
// VORSICHT: Es werden nur diejenigen Bilder eingebunden, für die
// ein Eintrag in SpriteLibrary.js vorhanden ist!
let bitmap_dir = "./material/spritesheet_bitmap/"

// Alle svg-Dateien in diesem Verzeichnis werden analysiert:
let svg_dir = "./material/spritesheet_svg/";

let output_dir = "./htdocs/assets/graphics/"  // für Spritesheet und json-Datei

// Der Pfad zu Inkscape steht in AnalyzeSVG.js


// Generierung des Spritesheet:

let src = []; // Liste aller png-Dateien mit Pfad als Eingabe für Spritesmith zur Generierung der Gesamt-png-Datei

let filenameToNameMap = {}; // Mappt die Dateinamen der Einzelbilder auf die Namen

/**
 * Für alle Einzelbilder, die wiederum aus mehreren Tiles zusammengesetzt sind: Mappt die Dateinamen
 * der Einzelbilder auf ein Objekt, das die Struktur der Tiles beschreibt:
 * 
 * {
 *     minIndex: index,  // Index des ersten Bildes des Tilesets
 *     tilesX: tilesX,   // Anzahl der Tiles horizontal
 *     tilesY: tilesY    // Anzahl der Tiles vertikal
 * }
 * 
 */
let filenameToTilesMap = {};

let filenameToExtrudeMarginWidthMap = {};

exportSVG.exportSVG(generateSpritesheet, svg_dir);

let extrudeMarginInformation = [];
// type { left: number, top: number, width: number, height: number, marginWidth: number}

function generateSpritesheet() {

    // png-Grafiken ins Spritesheet integrieren
    // im Array SpriteLibrary sind auch schon die konvertierten svg-Grafiken enthalten.
    for (let sle of SpriteLibrary) {
        src.push(bitmap_dir + sle.filename);
        let name = sle.name;
        let index = sle.index;
        let tilesX = sle.tilesX;
        let tilesY = sle.tilesY;
        let spacingX = sle.spacingX;
        let spacingY = sle.spacingY;

        if (typeof tilesX == "undefined") {
            if (typeof index != "undefined") {
                name += "#" + index;
            }
        } else {
            filenameToTilesMap[sle.filename] = {
                minIndex: index,
                tilesX: tilesX,
                tilesY: tilesY,
                spacingX: spacingX || 0,
                spacingY: spacingY || 0
            }
        }

        filenameToNameMap[sle.filename] = name;

        if (sle.extrudeMarginWidth > 0) {
            filenameToExtrudeMarginWidthMap[sle.filename] = sle.extrudeMarginWidth;
        }
    }

    console.log("Running Spritesmith ...");
    /**
     * Spritesmith erzeugt das Gesamt-png-Bild und gibt das Bild sowie eine Datenstruktur,
     * die die Lage der Einzelbilder darin beschreibt, zurück.
     */
    Spritesmith.run({
        src: src,
        padding: 2,
        //   algorithm: 'alt-diagonal'
    }, function handleResult(err, result) {
        // If there was an error, throw it
        if (err) {
            throw err;
        }
        console.log("\u001b[1;32m Done!");

        let filename1 = output_dir + 'spritesheet.png';
        console.log("Saving " + filename1 + " ...");

        // Output the image
        fs.writeFileSync(filename1, result.image);
        console.log("\u001b[1;32m Done!");



        console.log("Generating " + output_dir + 'spritesheet.json' + " ...");
        // Rahmenstruktur der json-Datei, die das Spritesheet beschreibt
        let pixi = {
            "frames": {},  // Hier kommen die Informationen zu den einzelnen Sprites rein..
            "meta": {
                "app": "",
                "version": "1.0",
                "image": "spritesheet.png",
                "format": "RGBA8888",
                "size": { "w": 0, "h": 0 },
                "scale": "1"
            }
        };

        /**
         * result.coordinates ist ein javascript-Objekt, dessen Attributbezeichner
         * die Dateinamen sind. Der Wert der Attribute ist jeweils die Geometrieinformation
         * dazu.
         * Dien Informationen stecken in result.coordinates und result.properties
         */
        for (var filename in result.coordinates) {
            if (Object.prototype.hasOwnProperty.call(result.coordinates, filename)) {

                let data = result.coordinates[filename];  // Geometrie-Information zur Datei filename
                filename = filename.replace(bitmap_dir, ""); // Schneide den Verzeichnisanteil weg

                // Ist das Einzelbild in Tiles aufgeteilt?
                let tiles = filenameToTilesMap[filename];
                let emw = filenameToExtrudeMarginWidthMap[filename];
                if (typeof tiles == "undefined") {
                    // Keine Tiles => Schreibe die Informationen zum Einzelbild in die json-Datei:
                    let frame = { x: Math.round(data.x), y: Math.round(data.y), w: Math.round(data.width), h: Math.round(data.height) };

                    pixi.frames[filenameToNameMap[filename]] = {
                        frame: frame,
                        "rotated": false,
                        "trimmed": false,
                        "spriteSourceSize": { x: 0, y: 0, w: Math.round(data.width), h: Math.round(data.height) },
                        "sourceSize": { "w": Math.round(data.width), "h": Math.round(data.height) },
                        "pivot": { "x": 0.5, "y": 0.5 }
                    }

                    if (emw) {
                        extrudeMarginInformation.push({ left: frame.x, top: frame.y, width: frame.w, height: frame.h, marginWidth: emw })
                    }

                } else {
                    /**
                     * Das Einzelbild ist in Tiles aufgeteilt:
                     * => Iteriere über die Tiles.
                     */
                    let number = tiles.minIndex ? tiles.minIndex : 0;
                    let w = Math.round((data.width - (tiles.tilesX - 1) * tiles.spacingX) / tiles.tilesX);
                    let h = Math.round((data.height - (tiles.tilesY - 1) * tiles.spacingY) / tiles.tilesY);
                    for (let row = 0; row < tiles.tilesY; row++) {
                        for (let column = 0; column < tiles.tilesX; column++) {
                            // Berechne Breite, Höhe und die Koordinaten der linken oberen Ecke des Tiles:
                            let x = data.x + w * column + column * tiles.spacingX;
                            let y = data.y + h * row + row * tiles.spacingY;
                            pixi.frames[filenameToNameMap[filename] + "#" + number] = {
                                frame: { x: x, y: y, w: w, h: h },
                                "rotated": false,
                                "trimmed": false,
                                "spriteSourceSize": { x: 0, y: 0, w: w, h: h },
                                "sourceSize": { "w": w, "h": h },
                                "pivot": { "x": 0.5, "y": 0.5 }
                            }
                            number++;

                            if (emw) {
                                extrudeMarginInformation.push({ left: x, top: y, width: w, height: h, marginWidth: emw })
                            }
                        }
                    }
                }
            }
        }

        // json-Datei schreiben
        fs.writeFileSync(output_dir + 'spritesheet.json', JSON.stringify(pixi, null, 2), 'utf-8');
        console.log("\u001b[1;32m Done!");


        console.log("Extrude margins...");
        // Avoid tile-bleeding by extruding sprite margins
        marginExtruder.extrudeMargin(extrudeMarginInformation, filename1);
        console.log("\u001b[1;32m Done!");


        var timeNeeded = Math.round(Date.now() - timeStarted);
        console.log("\u001b[1;33m Spritesheet exported in " + timeNeeded + " ms.");

    });

}