'use strict';

Ox.load.Geo = function(options, callback) {

    Ox.getJSON(Ox.PATH + 'Ox.Geo/json/Ox.Geo.json?' + Ox.VERSION, function(data) {

        //@ Constants

        /*@
        Ox.COUNTRIES <[o]> Array of countries
            A list of independent or de-facto independent countries and
            dependencies since January 1, 1970 (see 
            <a href="http://en.wikipedia.org/wiki/List of sovereign states" target="_blank">Wikipedia</a>),
            including other entities with
            <a href="http://en.wikipedia.org/wiki/ISO 3166-1 alpha-2" target="_blank">ISO 3166-1 alpha-2</a>
            country codes or country status at
            <a href="http://www.imdb.com/country/" target="_blank">IMDb</a> or
            <a href="http://www.fifa.com/worldranking/rankingtable/" target="_blank">FIFA</a>,
            grouped by continents and regions (see
            <a href="http://unstats.un.org/unsd/methods/m49/m49regin.htm">United Nations</a>).
            area <n> Area of the country's bounding box in square meters
            code <s> ISO 3166-1 alpha-2, ISO 3166-2 or ISO 3166-3 country code
            continent <s> The country's continent
            created <o|u> Present if the country was created since 1970
                country <[s]> Preceding country or countries
                created <s> "merged", "renamed" or "split"
                date <s> Date of creation ("YYYY" or "YYYY-MM-DD")
            dependencies <[s]|u> Array of dependencies of the country
            dependency <[s]|u> Array of countries the country is a dependency of
            disputed <[s]|u> Array of countries the country is disputed by
            disputes <[s]|u> Array of countries the country disputes
            dissolved <o|u> Present if the country was dissolved
                country <[s]> Succeeding country or countries
                date <s> Date of dissolution ("YYYY" or "YYYY-MM-DD")
                dissolved <s> "joined", "merged" or "renamed"
            east <n> Longitude of the country's eastern boundary
            exception <b> True for exceptionally reserved ISO 3166-1 alpha-2 codes
                (like "AC", "EU" or "UK")
            flagURL <s> The country's flag (Wikipedia, SVG)
            googleName <s|u> The country's name according to Google Maps
            imdbName <s|u> The country's name according to IMDb
            independence <o|u> Present if the country became independent since 1970
                country <[s]> Former country or countries
                date <s> Date of independence ("YYYY" or "YYYY-MM-DD")
            languages <[s]|u> Array of languages spoken in this country
                To be precise: languages that are spoken in this country more
                than in any other, i.e. each language only appears once. This
                can be used to map languages to flag icons.
            lat <n> Latitude of the center of the country's bounding box
            lng <n> Longitude of the center of the country's bounding box
            name <s> Name of the country
            north <n> Latitude of the country's northern boundary
            region <s> The country's region
            south <n> Latitude of the country's southern boundary
            wikipediaName <s|u> The country's name according to Wikipedia 
            west <n> Longitude of the country's western boundary
            <script>
                Ox.test.array = [
                    // Current independent countries
                    Ox.COUNTRIES.filter(function(c) {
                        return !c.dissolved && !c.dependency && !c.disputed && !c.exception
                    }).length,
                    // Current dependent countries
                    Ox.COUNTRIES.filter(function(c) {
                        return !c.dissolved && c.dependency && !c.exception
                    }).length,
                    // Current disputed countries
                    Ox.COUNTRIES.filter(function(c) {
                        return !c.dissolved && c.disputed && !c.exception
                    }).length,
                    // Current other entities
                    Ox.COUNTRIES.filter(function(c) {
                        return !c.dissolved && c.exception
                    }).length,
                    // Dissolved independent countries
                    Ox.COUNTRIES.filter(function(c) {
                        return c.dissolved && !c.dependency && !c.disputed && !c.exception
                    }).length,
                    // Dissolved dependent countries
                    Ox.COUNTRIES.filter(function(c) {
                        return c.dissolved && c.dependency && !c.exception
                    }).length,
                    // Dissolved disputed countries
                    Ox.COUNTRIES.filter(function(c) {
                        return c.dissolved && c.disputed && !c.exception
                    }).length,
                    // Dissolved other entities
                    Ox.COUNTRIES.filter(function(c) {
                        return c.dissolved && c.exception
                    }).length
                ];
            </script>
            > Ox.COUNTRIES.length
            353
            > Ox.sum(Ox.test.array)
            353
            > Ox.test.array
            [196, 73, 9, 8, 28, 24, 14, 1]
        @*/

        Ox.COUNTRIES = data;
        Ox.GEO_COLORS = {

            'North America': [0, 0, 255],
            'Northern America': [0, 0, 255],

            'South America': [0, 255, 0],
            'Southern America': [0, 255, 0],
            'Caribbean': [192, 255, 192],
            'Central America': [0, 128, 0],

            'Europe': [255, 255, 0],
            'Western Europe': [255, 255, 0],
            'Northern Europe': [255, 255, 192],
            'Southern Europe': [128, 128, 0],
            'Eastern Europe': [255, 192, 0],

            'Africa': [255, 0, 255],
            'Northern Africa': [255, 0, 255],
            'Southern Africa': [255, 128, 255],
            'Middle Africa': [128, 0, 128],
            'Western Africa': [128, 0, 255],
            'Eastern Africa': [255, 0, 128],

            'Asia': [255, 0, 0],
            'Eastern Asia': [255, 0, 0],
            'South-Eastern Asia': [255, 128, 128],
            'Southern Asia': [128, 0, 0],
            'Western Asia': [255, 128, 0],
            'Central Asia': [128, 64, 0],

            'Oceania': [0, 255, 255],
            'Australia and New Zealand': [0, 255, 255],
            'Micronesia': [192, 255, 255],
            'Melanesia': [0, 128, 128],
            'Polynesia': [128, 128, 255],

            'Antarctica': [128, 128, 128]

        };

        //@ Functions

        /*@
        Ox.getCountryByCode <f> Returns a country object for a given country code
            (code) -> <o> Country object
            code <s> ISO 3166 country code
            > Ox.getCountryByCode('US').name
            'United States'
        @*/
        Ox.getCountryByCode = Ox.getCountryByCountryCode = function(code) {
            var country;
            code = code.toUpperCase();
            Ox.forEach(Ox.COUNTRIES, function(c) {
                if (c.code == code) {
                    country = c;
                    Ox.Break();
                }
            });
            return country;
        };

        /*@
        Ox.getCountryByGeoname <f> Returns a country object for a given geoname
            (name) -> <o> Country object
            name <s> Geoname
            > Ox.getCountryByGeoname('Los Angeles, California, United States').code
            'US'
            > Ox.getCountryByGeoname('The Bottom, Saba, Bonaire, Sint Eustatius and Saba').code
            'BQ'
        @*/
        Ox.getCountryByGeoname = function(geoname) {
            // fixme: UAE correction doesn't belong here, fix in map
            geoname = (geoname || '').replace(' - United Arab Emirates', ', United Arab Emirates')
            return Ox.getCountryByName(
                geoname.split(', ').pop()
                .replace('Sint Eustatius and Saba', 'Bonaire, Sint Eustatius and Saba')
                .replace('Ascension and Tristan da Cunha', 'Saint Helena, Ascension and Tristan da Cunha')
            );
        }

        /*@
        Ox.getCountryByName <f> Returns a country object for a given country name
            (name) -> <o> Country object
            name <s> Country name
            > Ox.getCountryByName('United States').code
            'US'
            > Ox.getCountryByName('USA').code
            'US'
        @*/
        Ox.getCountryByName = function(name) {
            var country;
            Ox.forEach(Ox.COUNTRIES, function(c) {
                if (name == c.name || name == c.googleName || name == c.imdbName) {
                    country = c;
                    Ox.Break();
                }
            });
            return country;
        };

        /*@
        Ox.getFlagByCountryCode <f> Returns an image URL for a given country code
            (code[, size]) -> <s> Image URL
            code <s> Country code (like 'FR')
            size <n> Image size (16, 64 or 256)
        @*/
        Ox.getFlagByCountryCode = function(code, size) {
            var country = Ox.getCountryByCode(code);
            code = country ? country.code : 'NTHH';
            size = size || 16;
            return Ox.PATH + 'Ox.Geo/png/flags/' + size + '/' + code + '.png';
        };

        /*@
        Ox.getFlagByGeoname <f> Returns an image URL for a given geoname
            (geoname[, size]) -> <s> Image URL
            geoname <s> Geoname (like 'France' or 'Paris, France')
            size <n> Image size (16, 64 or 256)
        @*/
        Ox.getFlagByGeoname = function(geoname, size) {
            var country = Ox.getCountryByGeoname(geoname),
                code = country ? country.code : 'NTHH';
            size = size || 16;
            return Ox.PATH + 'Ox.Geo/png/flags/' + size + '/' + code + '.png';
        };

        /*@
        Ox.getFlagByLanguage <f> Returns an image URL for a given language
            (language[, size]) -> <s> Image URL
            language <s> Language (like "French")
            size <n> Image size (16, 64 or 256)
        @*/
        Ox.getFlagByLanguage = function(language, size) {
            var country, code;
            language = language.toLowerCase()
                .replace(' languages', '')
                .replace(' sign language', '');
            Ox.COUNTRIES.forEach(function(c) {
                if (c.languages && c.languages.map(function(language) {
                    return language.toLowerCase();
                }).indexOf(language) > -1) {
                    country = c;
                    return false;
                }
            });
            code = country ? country.flag || country.code : 'NTHH';
            return Ox.PATH + 'Ox.Geo/png/flags/' + size + '/' + code + '.png';
        };

        /*@
        Ox.getGeoColor <f> Returns a color for a continent or region
            (str) -> <a> RGB
            str <s> Continent or region
        @*/
        Ox.getGeoColor = function(str) {
            return Ox.GEO_COLORS[str] || [128, 128, 128];
        };

        callback(true);

    });

}
