#!/usr/bin/env node

var options = argv = require('optimist').argv,
    _ = require('underscore'),
    Step = require('step'),
    utils = require('..').utils,
    MBTiles = require('..'),
    mbtiles,
    zooms = [];

// Show help.
if (argv.help || argv._.length === 0) {
    console.warn('Usage: mbcheck [FILE]');
    console.warn('  Check an mbtiles for missing metadata and tiles.');
    console.warn('Examples:');
    console.warn('  mbcheck world.mbtiles');
    process.exit();
}

// Wishlist:
// ---------
// - check that tiles exist for specified bounds

Step(
    function() { mbtiles = new MBTiles(argv._[0], this); },
    function() { mbtiles._integrity(this); },
    function(err) {
        if (err) throw err;
        mbtiles._exists('tiles', function(err, exists) {
            if (!exists) throw new Error('`tiles` table does not exist.');
            this();
        }.bind(this));
    },
    function(err) {
        if (err) throw err;
        mbtiles._exists('metadata', function(err, exists) {
            if (!exists) throw new Error('`metadata` table does not exist.');
            this();
        }.bind(this));
    },
    function(err) {
        if (err) throw err;
        mbtiles._metadata('name', this.parallel());
        mbtiles._metadata('type', this.parallel());
        mbtiles._metadata('desciption', this.parallel());
        mbtiles._metadata('version', this.parallel());
        mbtiles._metadata('format', this.parallel());
        mbtiles._metadata('bounds', this.parallel());
    },
    function(err, name, type, description, version, format, bounds) {
        console.warn('Metadata');
        utils.table([
            ['name', name],
            ['type', type],
            ['description', description],
            ['version', version],
            ['format', format],
            ['bounds', bounds]
        ]);
        this();
    },
    function(err) {
        if (err) throw err;
        Step(
            function() {
                var group = this.group(),
                    query = mbtiles._db.prepare(
                        'SELECT zoom_level AS zoom, ' +
                        'COUNT(zoom_level) AS count ' +
                        'FROM tiles ' +
                        'WHERE zoom_level = ?'
                    );
                for (var i = 0; i < 30; i++) {
                    query.get(i, group());
                }
                query.finalize();
            },
            function(err, rows) {
                if (err) throw err;
                zooms = rows;
                do {
                    var last = zooms.pop();
                    if (last.count) zooms.push(last);
                } while(!last.count);
                do {
                    var first = zooms.shift();
                    if (first.count) zooms.unshift(first);
                } while(!first.count);
                this();
            }.bind(this)
        );
    },
    function(err) {
        if (err) throw err;
        Step(
            function() {
                var group = this.group(),
                    query = mbtiles._db.prepare(
                        'SELECT MAX(tile_column) AS maxx, ' +
                        'MIN(tile_column) AS minx, ' +
                        'MAX(tile_row) AS maxy, ' +
                        'MIN(tile_row) AS miny, ' +
                        'zoom_level AS zoom ' +
                        'FROM tiles ' +
                        'WHERE zoom_level = ?'
                    );
                for (var i = 0; i < zooms.length; i++) {
                    query.get(zooms[i].zoom, group());
                }
                query.finalize();
            },
            function(err, rows) {
                if (err) throw err;

                var group = this.group(),
                    query = mbtiles._db.prepare(
                        'SELECT zoom_level AS zoom, ' +
                        'COUNT(zoom_level) AS count, ' +
                        '? AS expected ' +
                        'FROM tiles ' +
                        'WHERE zoom_level = ? AND ' +
                        'tile_column >= ? AND ' +
                        'tile_column <= ? AND ' +
                        'tile_row >= ? AND ' +
                        'tile_row <= ?'
                    );
                for (var i = 0; i < rows.length; i++) {
                    var expected = (rows[i].maxx - rows[i].minx + 1) * (rows[i].maxy - rows[i].miny + 1);
                    query.get(
                        expected,
                        rows[i].zoom,
                        rows[i].minx,
                        rows[i].maxx,
                        rows[i].miny,
                        rows[i].maxy,
                        group()
                    );
                }
                query.finalize();
            },
            function(err, rows) {
                if (err) throw err;
                console.warn('');
                var output = [];
                output.push(['Z', 'Tiles', 'Missing']);
                _(rows).each(function(row, index) {
                    output.push([
                        row.zoom,
                        zooms[index].count,
                        row.expected - row.count
                    ]);
                });
                utils.table(output);
                this();
            }.bind(this)
        );
    }
);
