#!/usr/bin/env node

var path = require('path'),
    fs = require('fs'),
    carto = require('../lib/carto'),
    url = require('url'),
    _ = require('lodash'),
    util = require('../lib/carto/util');

var existsSync = require('fs').existsSync || require('path').existsSync

var yargs = require('yargs')
            .version(false)
            .usage("Usage: $0 <source MML file>")
            .options('h', {alias:'help', describe:'Display this help message'})
            .options('v', {alias:'version', boolean:true, describe:'Display version information'})
            .options('b', {alias:'benchmark', boolean:true, describe:'Outputs total compile time'})
            .options('l', {alias:'localize', boolean:true, default:false, describe:'Use millstone to localize resources when loading an MML'})
            .options('n', {alias:'nosymlink', boolean:true, describe:'Use absolute paths instead of symlinking files'})
            .options('a', {alias:'api', describe:'Specify Mapnik API version'})
            .options('f', {alias:'file', describe:'Outputs to the given file instead of stdout.'})
            .options('o', {alias:'output', describe:'Specify output format (mapnik, json)', default:'mapnik'})
            .options('q', {alias:'quiet', boolean:true, default:false, describe:'Do not output any warnings'})
            .options('ppi', {describe:'Pixels per inch used to convert m, mm, cm, in, pt, pc to pixels', default:90.714});

var options = yargs.argv;

if (options.help) {
    yargs.showHelp();
    process.exit(0);
}

if (options.version) {
    console.error("carto " + carto.version.join('.') + " (Carto map stylesheet compiler)");
    process.exit(0);
}

var input = options._[0];
if (input && input[0] != '/') {
    input = path.join(process.cwd(), input);
}

if (!input) {
    console.error("carto: no input files ('carto -h or --help' for help)");
    process.exit(1);
}

if (options.benchmark) {
    var start = +new Date;
}

var ext = path.extname(input);

if (!ext) {
    console.error("carto: please pass either a .mml file or .mss file");
    process.exit(1);
}

if (!existsSync(input)) {
    console.error("carto: file does not exist: '" + input + "'");
    process.exit(1);
}

try {
    var data = fs.readFileSync(input, 'utf-8');
} catch(err) {
    console.error("carto: " + err.message.replace(/^[A-Z]+, /, ''));
    process.exit(1);
}

if (ext === '.mml') {
    var mml = new carto.MML(options);
    mml.load(path.dirname(input), data, compile);
} else if (ext === '.mss') {
    compile(null, data);
} else {
    console.error("carto: please pass either a .mml file or .mss file");
}


function compile(err, data) {
    if (err) {
        console.error(err);
        process.exit(1);
    }

    var renderer = new carto.Renderer({
        filename: input,
        benchmark: options.benchmark,
        ppi: options.ppi,
        quiet: options.quiet,
        outputFormat: options.output,
        version: options.api
    });
    try {
        var output;
        if (ext === '.mml') {
            output = renderer.render(data);
        } else if (ext === '.mss') {
            output = renderer.renderMSS(data);
        }

        if (_.has(output, 'msg') && _.isArray(output.msg) &&
            output.msg.length > 0) {
            var hasError = false;
            _.forEach(output.msg, function (v) {
                if (v.type === 'error') {
                    console.error(util.getMessageToPrint(v));
                    hasError = true;
                }
                else if (v.type === 'warning') {
                    console.warn(util.getMessageToPrint(v));
                }
            });

            if (hasError) {
                process.exit(1);
            }
        }
    } catch (e) {
        if (e.stack) {
            console.error(e.stack);
        } else if (e.message) {
            console.error(e.message);
        }
        else {
            console.error(e);
        }
        process.exit(1);
    }
    if (!options.benchmark) {
        if (!_.isNil(output.data)) {
            if (options.file) {
                try {
                    fs.writeFileSync(options.file, output.data);
                }
                catch (e) {
                    console.error(e);
                    console.error('Writing to given file ' + options.file + ' failed. Falling back to stdout output.');
                    console.log(output.data);
                }
            }
            else {
                console.log(output.data);
            }
        }
    } else {
        var duration = (+new Date) - start;
        console.log('TOTAL: ' + (duration) + 'ms');
    }
};
