<!DOCTYPE html>
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
        <style>
            body {
                margin: 0;
                overflow: hidden;
            }
            #map {
                width: 100%;
                height: 100%;
            }
            #data {
                position: absolute;
                left: 0;
                bottom: 0;
                right: 0;
                height: 64px;
                padding: 0;
                border: 0;
                background: rgba(0, 0, 0, 0.5);
                font-family: Consolas;
                font-size: 8px;
                color: rgb(255, 255, 255);
                overflow: auto;
                z-index: 1000;
            }
            #data:focus {
                outline: none;
            }
            .flag {
                position: absolute;
                width: 8px;
                height: 8px;
                margin-left: -4px;
                margin-top: -4px;
                -moz-border-radius: 1px;
                -webkit-border-radius: 1px;
                -moz-box-shadow: 1px 1px 2px rgba(0, 0, 0, 128);
                -webkit-box-shadow: 1px 1px 2px rgba(0, 0, 0, 128);
            }
            .flag:hover {
                width: 16px;
                height: 16px;
                margin-left: -8px;
                margin-top: -8px;
                opacity: 0.5;
                -moz-border-radius: 2px;
                -webkit-border-radius: 2px;
                -moz-box-shadow: 2px 2px 4px rgba(0, 0, 0, 128);
                -webkit-box-shadow: 2px 2px 4px rgba(0, 0, 0, 128);
            }
            .rect {
                position: absolute;
                border: 1px solid rgb(255, 255, 255);
                z-index: 1;
                -moz-box-shadow: 2px 2px 4px rgba(0, 0, 0, 128);
                -webkit-box-shadow: 2px 2px 4px rgba(0, 0, 0, 128);
            }
        </style>
        <script src="../../../build/Ox.js"></script>
        <script src="http://maps.google.com/maps/api/js?sensor=false"></script>
        <script>
            /*
                this adds the properties
                    area, east, lat, lng, north, south, west
            */
            Ox.load('UI', {debug: true}, function() {
                Ox.getJSON('../json/geo.json', function(geo) {
                    var $body = $('body'),
                        $map = $('<img>')
                            .attr({
                                id: 'map',
                                src: '../png/map.png'
                            })
                            .appendTo($body),
                        $data = $('<textarea>')
                            .attr({
                                id: 'data'
                            })
                            .appendTo($body),
                        geocoder = new google.maps.Geocoder(),
                        json = [],
                        logs = [],
                        timeout = 2000;
                    // fixme: getJSON fails in jQuery 1.5
                    $.ajax({
                        url: '../json/countries.json',
                        dataType: 'json',
                        success: function(countries) {
                            callGetData();
                            function callGetData() {
                                getData(countries.shift(), function(country) {
                                    addFlag(country);
                                    delete country.googleQuery;
                                    json.push(country);
                                    $data.html(
                                        JSON.stringify(json, null, 4)
                                    );
                                    window.status = json.length + '/' + countries.length + ' ' + country.name;
                                    Ox.print(logs);
                                    if (countries.length) {
                                        setTimeout(callGetData, timeout);
                                    } else {
                                        alert('Done');
                                    }
                                });
                            }
                        }
                    });
                    function addFlag(country) {
                        var $div,
                            center = Ox.getXYByLatLng({lat: country.lat, lng: country.lng}),
                            crossesDateline = country.west > country.east,
                            height = $map.height(),
                            northEast = Ox.getXYByLatLng({lat: country.north, lng: country.east}),
                            southWest = Ox.getXYByLatLng({lat: country.south, lng: country.west}),
                            width = $map.width();
                        if (crossesDateline) {
                            $div = [
                                $('<div>')
                                    .addClass('rect')
                                    .css({
                                        left: '-16px',
                                        top: (height * northEast.y) + 'px',
                                        right: (width - width * northEast.x) + 'px',
                                        bottom: (height - height * southWest.y) + 'px',
                                    })
                                    .hide()
                                    .appendTo($body),
                                $('<div>')
                                    .addClass('rect')
                                    .css({
                                        left: (width * southWest.x) + 'px',
                                        top: (height * northEast.y) + 'px',
                                        right: '-16px',
                                        bottom: (height - height * southWest.y) + 'px',
                                    })
                                    .hide()
                                    .appendTo($body),

                            ];
                        } else {
                            $div = [
                                $('<div>')
                                    .addClass('rect')
                                    .css({
                                        left: ($map.width() * southWest.x) + 'px',
                                        top: ($map.height() * northEast.y) + 'px',
                                        right: ($map.width() - $map.width() * northEast.x) + 'px',
                                        bottom: ($map.height() - $map.height() * southWest.y) + 'px',
                                    })
                                    .hide()
                                    .appendTo($body)
                            ];
                        }
                        $('<img>')
                            .attr({
                                src: '../png/icons/16/' + country.code + '.png',
                                title: country.name + ' ((' + country.south + ", " + country.west + "), (" + country.north + ", " + country.east + "))"
                            })
                            .addClass('flag')
                            .css({
                                left: (center.x * 100) + '%',
                                top: (center.y * 100) + '%'
                            })
                            .mouseenter(function() {
                                $(this).css({
                                    zIndex: Ox.uid()
                                });
                                $.each($div, function() {
                                    $(this).show();
                                });
                            })
                            .mouseleave(function() {
                                $.each($div, function() {
                                    $(this).hide();
                                });
                            })
                            .appendTo($body);
                    }
                    function toFixed(num) {
                        return parseFloat(num.toFixed(8));
                    }
                    function geocode(address, callback) {
                        Ox.print('geocode', address)
                        var bounds = geo.coordinates[address];
                        if (Ox.isUndefined(bounds)) {
                            geocoder.geocode({
                                language: 'en',
                                address: address
                            }, function(results, status) {
                                if (results && results.length) {
                                    var result = results[0];
                                    callback({
                                        bounds: result.geometry.bounds || result.geometry.viewport,
                                        location: result.geometry.location
                                    })
                                } else {
                                    logs.push([address, status])
                                    callback(null);
                                }
                            });
                        } else {
                            bounds = new google.maps.LatLngBounds(
                                new google.maps.LatLng(bounds.south, bounds.west),
                                new google.maps.LatLng(bounds.north, bounds.east)
                            );
                            callback({
                                bounds: bounds,
                                location: bounds.getCenter()
                            });
                        }
                    }
                    function getData(country, callback) {
                        if (country.lat) {
                            callback(country);
                            return;
                        }
                        Ox.print('getData', geo.google_query[country.name] || [country.name])
                        var addresses = geo.google_query[country.name] || [country.name],
                            length = addresses.length,
                            union;
                        getImageURLs(country, function(imageURLs) {
                            // this might be too much data
                            /*
                            Ox.extend(country, {
                                imageURLs: imageURLs
                            });
                            */
                            callGeocode();
                        });
                        function callGeocode() {
                            geocode(addresses.shift(), function(data) {
                                var center, lat, lng,
                                    northEast, southWest,
                                    east, north, south, west;
                                if (data) {
                                    union = !union ? data.bounds : union.union(data.bounds);
                                    if (addresses.length == 0) {
                                        if (length == 1) {
                                            lat = data.location.lat();
                                            lng = data.location.lng();
                                        } else {
                                            center = union.getCenter();
                                            lat = center.lat();
                                            lng = center.lng();
                                        }
                                        northEast = union.getNorthEast();
                                        southWest = union.getSouthWest();
                                        east = northEast.lng();
                                        north = northEast.lat();
                                        south = southWest.lat();
                                        west = southWest.lng();
                                        callback($.extend(country, {
                                            area: Ox.getArea(
                                                {lat: south, lng: west},
                                                {lat: north, lng: east}
                                            ),
                                            east: toFixed(east),
                                            lat: toFixed(lat),
                                            lng: toFixed(lng),
                                            north: toFixed(north),
                                            south: toFixed(south),
                                            west: toFixed(west)
                                        }));
                                    }
                                } else {
                                    callback(country);
                                }
                            });
                            if (addresses.length) {
                                setTimeout(callGeocode, timeout);
                            }
                        }
                    }
                    function getImageURLs(country, callback) {
                        Ox.print(country, '../png/icon/16/' + country.code + '.png')
                        var image = new Image();
                        image.onload = function() {
                            callback({
                                icon16: Ox.canvas(image).canvas.toDataURL()
                            });
                        };
                        image.src = '../png/icons/16/' + country.code + '.png';
                    }
                });
            });
        </script>
    </head>
    <body></body>
</html>