// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
const GLib = imports.gi.GLib;
const Gio = imports.gi.Gio;
const jsUnit = imports.jsUnit;

const MANIFEST_VERSION_NUMBER = "1.0";

GLib.setenv("GJS_DEBUG_TOPICS", "", true);

if (ARGV.length != 5) {
    printerr("incorrect arguments");
    throw new Error();
}

PATH = ARGV[0];
NAME = ARGV[2];
TOP_SRCDIR = ARGV[1]
OUT_DIR = TOP_SRCDIR + '/src/' + NAME;
OUT = OUT_DIR + '/manifest.json';
VERSION = ARGV[3];
NARCISSUS = ARGV[4];

function parseUnityInit(scriptSource) {
    var [res, content] = GLib.file_get_contents(NARCISSUS);

    eval(String(content));

    parsed = parse(String(scriptSource))

    function findUnityInitCalls(ast) {
        var res = [];
        var SYM = ['expression', 'varDecls', 'body', 'condition', 'thenPart', 'elsePart', 'statement', 'object'];
        for (var i in ast) {
            if (!ast.hasOwnProperty(i))
                continue;
            if (Number(i) != i && SYM.indexOf(i) == -1)
                continue;
            if (ast[i] != null) {
                res = res.concat(findUnityInitCalls(ast[i]));
            }

        }
        if (ast.type == CALL && ast[0].type == DOT
            && ast[0][0].type == IDENTIFIER && ast[0][1].type == IDENTIFIER
            && ast[0][0].value == 'Unity' && ast[0][1].value == 'init') {
            res.push(ast);
        }
        return res;
    }

    function handleParams(ast) {
        if (ast[1].type != LIST || ast[1][0].type != OBJECT_INIT) {
            throw new Error("Invalid Unity.init call (invalid argument)");
        }
        var obj = ast[1][0];

        var ignore = false;
        var icons = null;
        var domains = null;
        var domain = null;
        var homepage = null;
        for (var i = 0; i < obj.length; i++) {
            var prop = obj[i];

            jsUnit.assert("Invalid property declaration in Unity.init call", prop.type == PROPERTY_INIT);
            jsUnit.assert("Invalid property key type (not an identifier or string) in Unity.init call for property: '"
                              + prop[0].value + "'",
                          prop[0].type == IDENTIFIER || prop[0].type == STRING);

            if (prop[0].value == 'domains') {
                domains = eval(prop[1].getSource() + ']]');
                for (var k = 0; k < domains.length; k++) {
                    jsUnit.assert("Invalid 'domains' property definition", domains[k].length == 2);
                }
            }
            if (prop[0].value == 'homepage') {
                if (prop[1].type == STRING) {
                    homepage = prop[1].value;
                } else {
                    ignore = true;
                }
            }
            if (prop[0].value == 'iconUrl') {
                var ICON_DIR = TOP_SRCDIR + '/icon-themes/unity-webapps-applications/apps'
                if (icons)
                    throw new Error("Duplicate 'iconUrl' property");
                icons = {};

                if (prop[1].type == STRING) {
                    var iconName = prop[1].value.match('icon://(.+)');
                    if (iconName) {
                        iconName = iconName[1] + '.png';
                        var dir = Gio.file_new_for_path(ICON_DIR);
                        
                        var enumerator = dir.enumerate_children(Gio.FILE_ATTRIBUTE_STANDARD_NAME, Gio.FileQueryInfoFlags.NONE, null);
                        
                        for (var child = enumerator.next_file(null); child; child = enumerator.next_file(null)) {
                            var size = child.get_name();
                            child = dir.get_child(size);
                            
                            file = child.get_child(iconName);
                            if (file.query_exists(null)) {
                                icons[size] = size + '/' + iconName;
                            }
                        }
                    }
                }
            }
            if (prop[0].value == 'domain') {
                if (prop[1].type == STRING) {
                    domain = prop[1].value;
                } else {
                    ignore = true;
                }
            }
        }
        if (domains)
            return { domains: domains, icons: icons };
        if (domain && homepage) {
            return { domains: [[domain, homepage]], icons: icons };
        }
        if (ignore)
            return {};
        throw new Error('script should have domain/homepage')
    }
    return handleParams(findUnityInitCalls(parsed)[0]);
}

var res = {includes: [], requires: [], name: NAME,
           scripts: [NAME + '.user.js']}
res['maintainer'] = 'Webapps Team <webapps@lists.launchpad.net>';
res['license'] = 'GPL-3';
res['manifest-version'] = MANIFEST_VERSION_NUMBER;
res['integration-version'] = VERSION;
res['package-name'] = NAME;
res['description'] = 'Unity Webapp for ' + NAME

var [sucess, content] = GLib.file_get_contents(PATH);
var lines = String(content).split('\n');

for (var i = 0; i < lines.length; i++) {
    line = lines[i];

    let match = line.match('^//\\s+@([^\\s]+)\\s+(.+)$');
    if (match) {
        if (match[1] == 'include')
            res['includes'].push(match[2]);
        if (match[1] == 'require')
            res['requires'].push(match[2]);
    }
}

try {
    var extracted = parseUnityInit(String(content))
    var domains = extracted.domains;
    res['icons'] = extracted.icons;
    if (domains) {
        if (domains.length == 1) {
            res['domain'] = domains[0][0];
            res['homepage'] = domains[0][1];
            GLib.file_set_contents(OUT, JSON.stringify(res));
        } else {
            for (var i = 0; i < domains.length; i++) {
                res['domain'] = domains[i][0];
                res['homepage'] = domains[i][1];
                let filename = OUT_DIR + '/manifest-' + i + '.json';
                GLib.file_set_contents(filename, JSON.stringify(res));
            }
        }
    } else {
        GLib.file_set_contents(OUT, JSON.stringify(res));
    }
} catch (x) {
    printerr("Error while generating a manifest for: " + NAME);
    printerr(JSON.stringify(x));
    throw x;
}
