if (!com) var com = {};
if (!com.hive) com.hive = {};
if (!com.hive.worldpop) com.hive.worldpop = {};

var gmap = null; // doesn't work unless it's global
var fieldApplet = null; // applet -> js doesn't work unless js is global?
var mouseOverCellTimeout = null;
var barChartOptions = {};
var waxConnection = null;
var taxConnection = null;
var globalAddress = null;
// min & max values for columns
var columnInfo = {
    growth_rate_pct: {
        min: -3.30,
        max: 3.69
    },
    sq_km: {
        min: 0,
        max: 17098242
    },
    density_km: {
        min: 0.026591742,
        max: 19994.5
    },
    death_rate_pct: {
        min: 2.11,
        max: 30.83
    }
};


/** FieldApplet Event Handlers **/
var mouseOverCell = function() {
    try {
        // get info from event payload
        var cellId = parseInt(fieldApplet.getMouseOverCellId());
        if (cellId != null && cellId != undefined && !isNaN(cellId)) {
            if (mouseOverCellTimeout != null) {
                window.clearTimeout(mouseOverCellTimeout);
                mouseOverCellTimeout = null;
            }
            mouseOverCellTimeout = window.setTimeout(function() {
                // get cell data
                var info = com.hive.worldpop.services.getCellInfo(cellId);
                // update displays
                com.hive.worldpop.services.updateInfo(info);
                //com.hive.worldpop.services.barChartRank('country_info_table', info, 237, barChartOptions);
                com.hive.worldpop.services.barChartActual('country_info_table', info, columnInfo);
            }, 100);
        }
    } catch(err) {
        alert('Error in mouseOverCell: Error Name: ' + err.name + '. Error Message: ' + err.message);
    }
};


/** com.hive.worldpop.controls **/
com.hive.worldpop.controls = {

    updateStatus: function() {
        $('#visible_count').html( parseInt(fieldApplet.countVisibleCells()) );
        $('#total_count').html( parseInt(fieldApplet.countAllCells()) );
    },

    buildSlider: function(def) {
        $('#'+def.slider_div).slider({
            range: true,
            min: def.min,
            max: def.max,
            values: [def.min, def.max],
            orientation: 'horizontal',
            animate: false,
            slide: function(event, ui) {
                var mi = ui.values[0];
                var ma = ui.values[1];
                if (mi == def.min && ma == def.max) {
                    com.hive.worldpop.controls.removeSlider(def.slider_div);
                }
                else {
                    com.hive.worldpop.controls.applySlider(def.field, def.slider_div, def.slider_div, mi, ma);
                }
                $('#'+def.values_div+' .min').val(ui.values[0]);
                $('#'+def.values_div+' .max').val(ui.values[1]);
                com.hive.worldpop.controls.updateStatus();
            }
        });
        $('#'+def.values_div+' .min').val(def.min);
        $('#'+def.values_div+' .max').val(def.max);
        $('#'+def.values_div+' .min').change(function() {
            var min = parseFloat($(this).val());
            var max = parseFloat($('#'+def.values_div+' .max').val());
            $('#'+def.slider_div).slider('values',0,min);
            $('#'+def.slider_div).slider('values',1,max);
            if (min == def.min && max == def.max) {
                com.hive.worldpop.controls.removeSlider(def.slider_div);
            }
            else {
                com.hive.worldpop.controls.applySlider(def.field, def.slider_div, def.slider_div, min, max);
            }
            com.hive.worldpop.controls.updateStatus();
        });
        $('#'+def.values_div+' .max').change(function() {
            var max = parseFloat($(this).val());
            var min = parseFloat($('#'+def.values_div+' .min').val());
            $('#'+def.slider_div).slider('values',0,min);
            $('#'+def.slider_div).slider('values',1,max);
            if (min == def.min && max == def.max) {
                com.hive.worldpop.controls.removeSlider(def.slider_div);
            }
            else {
                com.hive.worldpop.controls.applySlider(def.field, def.slider_div, def.slider_div, min, max);
            }
            com.hive.worldpop.controls.updateStatus();
        });
    },

    setGroup: function(field) {
        var xml = null;
        if (field != 'NONE') {
            xml = '<ControlSpec><HierarchySpec><GroupSpec level="1" attribute="'
                +field+'" enum="true"></GroupSpec></HierarchySpec></ControlSpec>';
        }
        else {
            xml = '<ControlSpec><HierarchySpec><GroupSpec level="1"'
                +' attribute="NONE"><SubGroupSpec><label value="All"/>'
                +'<description value="no grouping"/><operation value="ELSE"/>'
                +'</SubGroupSpec></GroupSpec></HierarchySpec></ControlSpec>';
        }
        fieldApplet.applyControlSpec(xml);
    },

    setSize: function(field) {
        var xml = "<ControlSpec><SizeSpec attribute='"+field+"'/></ControlSpec>";
        fieldApplet.applyControlSpec(xml);
    },

    setColor: function(field) {
        var xml = "<ControlSpec><ColorSpec attribute='"+field+"' color_range='"+field+"CLR'></ColorSpec></ControlSpec>";
        fieldApplet.applyControlSpec(xml);
    },

    applyFilter: function(field, filterGroup, filterId, operation, option) {
        var xml = "<ControlSpec><FilterSpec type='filter'><FilterDef filterGroup='"
            +filterGroup+"' id='"+filterId+"' attribute='"+field+"' operation='"+operation+"'><param value='"
            +option+"'/></FilterDef></FilterSpec></ControlSpec>"
        fieldApplet.applyControlSpec(xml);
    },

    applySlider: function(field, filterGroup, filterId, min, max) {
        var xml = "<ControlSpec>";
        xml += "<FilterSpec type='filter'><FilterDef filterGroup='"+filterGroup
            +"a' attribute='"+field+"' operation='GTE'><param value='"+min+"'/></FilterDef></FilterSpec>";
        xml += "<FilterSpec type='filter'><FilterDef filterGroup='"+filterGroup
            +"b' attribute='"+field+"' operation='LTE'><param value='"+max+"'/></FilterDef></FilterSpec>";
        xml += "</ControlSpec>";
        fieldApplet.applyControlSpec(xml);
    },

    removeSlider: function(filterGroup) {
        fieldApplet.removeFilterGroup(filterGroup+'a');
        fieldApplet.removeFilterGroup(filterGroup+'b');
    }

};


/** com.hive.worldpop.formatters **/
com.hive.worldpop.formatters = {

    addCommas: function(value) {
        var s = value + '';
        var x = s.split('.');
        var x1 = x[0];
        var x2 = x.length > 1 ? '.' + x[1] : '';
        var rgx = /(\d+)(\d{3})/;
        while (rgx.test(x1)) {
            x1 = x1.replace(rgx, '$1' + ',' + '$2');
        }
        return x1 + x2;
    },
    
    formatArea: function(value) {
        var v = parseFloat(value).toFixed(0);
        return com.hive.worldpop.formatters.addCommas(v) + ' sq km';
    },

    formatDensity: function(value) {
        var v = parseFloat(value).toFixed(3);
        return com.hive.worldpop.formatters.addCommas(v) + ' / sq km';
    }

};


/** com.hive.worldpop.services - Object for data services **/
com.hive.worldpop.services = {

    geocoder: null,

    init: function() {
        // Initialize Google Map
        var latlng = new google.maps.LatLng(32.5468,-23.2031);
        var myOptions = {
          zoom: 2,
          center: latlng,
          mapTypeId: google.maps.MapTypeId.TERRAIN
        };
        gmap = new google.maps.Map(document.getElementById("map_canvas"), myOptions);
        this.geocoder = new google.maps.Geocoder();
    },

    getCenterLatLngText: function() {
        return '(' + gmap.get_center().lat() + ', ' + gmap.get_center().lng() + ')';
    },

    geocode: function(address) {
        var args = {
            'partialmatch': true
        };
        if (address == 'Gaza Strip') {
            args.latLng = new google.maps.LatLng(31.25, 34.20);
            args.country = 'gz';
        }
        else if (address == 'Micronesia, Federated States of') {
            args.latLng = new google.maps.LatLng(6.92, 158.18);
            args.country = 'fm';
        }
        else {
            if (address == 'Georgia') {
                args.address = 'Georgia country';
            }
            else {
                args.address = address;
            }
        }
        this.geocoder.geocode(args, this.geocodeResult);
    },

    geocodeResult: function(results, status) {
        if (status == 'OK' && results.length > 0) {
            gmap.panTo(results[0].geometry.location);
            gmap.fitBounds(results[0].geometry.viewport);
        }
        else {
            //alert(status);
        }
    },

	weatherGeocode: function(address){
        $('#weather_bottom').addClass('invisible');
		this.geocoder.geocode({'address': address,'partialmatch': true, 'language': 'en'}, this.getWeatherInfo);
	},

    timeGeocode: function(address) {
        $('#time_span').addClass('invisible');
		this.geocoder.geocode({'address': address,'partialmatch': true, 'language': 'en'}, this.getTimeInfo);
    },

    getWeatherInfo: function(results, status) {
        try {
            if (status == 'OK' && results.length > 0) {
                var location_string = "";
                for(i = 0; i < results[0].address_components.length; i++){
                    if(results[0].address_components[i].long_name != "")
                        location_string += results[0].address_components[i].long_name;
                    if(i != results[0].address_components.length-1)
                        location_string += ",";
                }
                if (waxConnection != null) {
                    waxConnection.abort();
                }
                waxConnection = $.ajax({
                    url: 'php/google-weather.php?action=weather&location=' + location_string,
                    type: 'GET',
                    dataType: 'html',
                    timeout: 10000,
                    error: function(errortext){
                    },
                    success: function(data){
                        var info = eval('('+data+')');
                        $('#weather_condition_text').text( info.condition );
                        $('#wind_condition').text( info.wind );
                        $('#humidity').text( info.humidity );
                        $('#tempc_value').text( info.temp_c );
                        $('#tempf_value').text( info.temp_f );
                        $('#weather_icon img:first').attr('src', info.icon_url);
                        $('#weather_bottom').removeClass('invisible');
                    }
                });
            }
        } catch(err) {
            alert('Error in getWeatherInfo: Error Name: ' + err.name + '. Error Message: ' + err.message);
        }
    },

    getTimeInfo: function(results, status) {
        try {
            if (status == 'OK' && results.length > 0) {
                var lat = results[0].geometry.location.lat();
                var lng = results[0].geometry.location.lng();
                if (taxConnection != null) {
                    taxConnection.abort();
                }
                taxConnection = $.ajax({
                    url: 'php/google-weather.php?action=timezone&lat=' + lat + '&lng=' + lng,
                    type: 'GET',
                    dataType: 'html',
                    timeout: 10000,
                    error: function(errortext){
                    },
                    success: function(data) {
                        var info = eval('('+data+')');
                        $('#weekday').text( info.weekday );
                        $('#monthanddate').text( info.monthanddate );
                        $('#time').text( info.time );
                        $('#time_span').removeClass('invisible');
                    }
                });
            }
        } catch(err) {
            alert('Error in getTimeInfo: Error Name: ' + err.name + '. Error Message: ' + err.message);
        }
    },

	getWeather: function(results, status) {
		var lat;
		var lng;
		if (status == 'OK' && results.length > 0) {



			//alert(results[0].address_components.short_name);

			lat = results[0].geometry.location.lat();
			lng = results[0].geometry.location.lng();
			//alert(results[0].address_components.length);
			var location_string = "";
			for(i = 0; i < results[0].address_components.length; i++){
				if(results[0].address_components[i].long_name != "")
					location_string += results[0].address_components[i].long_name;
				if(i != results[0].address_components.length-1)
					location_string += ",";
			}
			//alert(location_string);
			//alert("timezone.php?lat="+lat+"&lng="+lng);

			//document.getElementById("weather_info").innerHTML = results[0].formatted_address;
			if(axConnection != null) axConnection.abort();
			//$('weather').load('google-weather.php?location=' + results[0].formatted_address + "&lat=" + lat + "&lng=" + lng);
			axConnection = $.ajax({
				url: 'php/google-weather.php?location=' + location_string + "&lat=" + lat + "&lng=" + lng,
				type: 'GET',
				dataType: 'html',
				timeout: 10000,
				error: function(errortext){
					//alert('error: ' + errortext);
				},
				success: function(data){
					// do something with xml
					//alert(data);
					if(data != "")
						document.getElementById("weather_widget").innerHTML = data;
					else
						document.getElementById("weather_widget").innerHTML = "No weather information available.";
				}
			});


			/*new Ajax.Updater('weather_info','google-weather.php?location=' + results[0].formatted_address + "&lat=" + lat + "&lng=" + lng, 
				{
					asynchronous:true, 
					onCreate: function(request) { axConnection = request; }, 
					onSuccess: function(data){
						document.getElementById("weather_info").innerHTML = data.responseText;
					}//,
					//onFailure: showError
				}
			);*/
		} else {
		//alert("Geocode was not successful for the following reason: " + status);
		}
	},
	
    
    setFlag: function(fips_code, elementId) {
        document.getElementById(elementId).innerHTML = '<img src="https://www.cia.gov/library/publications/the-world-factbook/graphics/flags/large/'
            + fips_code.toLowerCase() +'-lgflag.gif" />';
    },

    setCIAMap: function(fips_code, elementId) {
        document.getElementById(elementId).innerHTML = '<img src="https://www.cia.gov/library/publications/the-world-factbook/graphics/maps/small/'
            + fips_code.toLowerCase() +'-map.gif" />';
    },

    setCIATextLink: function(fips_code, elementId) {
        var a = 'https://www.cia.gov/library/publications/the-world-factbook/geos/'+fips_code.toLowerCase()+'.html';
        $('#'+elementId).attr('href', a);
    },

    setCountryName: function(country_name) {
        $('.country_name').html(country_name);
    },

    setCountryCapital: function(capital) {
        $('.capital').html(capital);
    },

    setCountryBackground: function(background, elementId) {
        document.getElementById(elementId).innerHTML = background;
    },

    barChartRank: function(containerId, info, max, options) {
        var dataElems = $('#'+containerId+' .bar'); 
        var containerWidth = $('#'+containerId+' td.bar_container:first').width();
        for (var i = 0; i < dataElems.length; i++) {
            var id = $(dataElems[i]).attr('id');
            var o = parseFloat($(dataElems[i]).html());
            var d = (max+1) - o; // invert ranking
            // create bar
            var bw = Math.ceil(parseInt(containerWidth) * (d/max));
            var elem = document.createElement('div');
            elem.style.width = bw+'px';
            $(dataElems[i]).html('');
            $(dataElems[i]).append(elem);
            $(elem).attr('id', id+'_cbar');
            $(elem).addClass('cbar');
            // add text
            var innerElem = document.createElement('div');
            if (options && options[id]) {
                var f = options[id].formatter;
                innerElem.innerHTML = f(info[id]);
            }
            else {
                innerElem.innerHTML = info[id]; // element id matches column name
            }
            $(elem).append(innerElem);
            $(innerElem).addClass('cbar_inner');
        }
    },

    barChartActual: function(containerId, cellInfo, attributeInfo) {
        var dataElems = $('#'+containerId+' .bar');
        var containerWidth = parseInt($('#'+containerId+' td.bar_container:first').width());

        var drawBar = function(id, container, left, width, isNegative) {
            var elem = document.createElement('div');
            elem.style.position = 'absolute';
            elem.style.top = '0';
            elem.style.left = left + 'px';
            elem.style.width = width + 'px';
            $(container).children('.bar_marker').remove();
            $(container).append(elem);
            $(elem).attr('id', id+'_marker');
            $(elem).addClass('bar_marker');
            // color - will eventually just be a background image
            if (isNegative) {
                $(elem).removeClass('marker_positive');
                $(elem).addClass('marker_negative');
            }
            else {
                $(elem).removeClass('marker_negative');
                $(elem).addClass('marker_positive');
            }
        };

        for (var i = 0; i < dataElems.length; i++) {
            var id = $(dataElems[i]).attr('id');
            var actualValue = parseFloat($(dataElems[i]).attr('value'));
            var columnMin = attributeInfo[id].min;
            var columnMax = attributeInfo[id].max;
            var width = 0;
            if (columnMin < 0) {
                $(dataElems[i]).removeClass('bar_positive');
                $(dataElems[i]).addClass('bar_negative');
                var negWidth = 50;
                if (actualValue < 0) {
                    var adjustedValue = Math.abs(actualValue);
                    var adjustedRange = Math.abs(columnMin);
                    width = Math.max( Math.ceil( negWidth * (adjustedValue / adjustedRange) ), 1);
                    var negLeft = negWidth - width;
                    drawBar(id, $(dataElems[i]), negLeft, width, true);
                }
                else {
                    var positiveWidth = containerWidth - negWidth;
                    var positiveRange = columnMax;
                    width = Math.max( Math.ceil( positiveWidth * (actualValue / positiveRange) ), 1);
                    drawBar(id, $(dataElems[i]), negWidth, width, false);
                }
            }
            else {
                $(dataElems[i]).removeClass('bar_negative');
                $(dataElems[i]).addClass('bar_positive');
                var range = columnMax - columnMin;
                width = Math.ceil( containerWidth * (actualValue / range) );
                drawBar(id, $(dataElems[i]), 0, width, false);
            }
        }
    },

    setInfoTable: function(info) {
        $('#growth_rate_pct').attr('value', parseFloat(info['growth_rate_pct'])); 
        $('#growth_rate_rank').html('#' + parseInt(info['growth_rate_rank'])); 
        
        $('#sq_km').attr('value', parseFloat(info['sq_km'])); 
        $('#area_rank').html('#' + parseInt(info['area_rank'])); 

        $('#density_km').attr('value', parseFloat(info['density_km'])); 
        $('#density_rank').html('#' + parseInt(info['density_rank'])); 

        $('#death_rate_pct').attr('value', parseFloat(info['death_rate_pct'])); 
        $('#death_rate_rank').html('#' + parseInt(info['death_rate_rank'])); 
    },

    updateInfo: function(info) {
        if (!$('#right_panel').hasClass('invisible')) {
            try {
                this.setCountryName(info['country_name']);
                this.setCountryCapital(info['capital']);
                this.setFlag(info['fips_code'], 'flag');
                this.setInfoTable(info);
                this.setCountryBackground(info['background'], 'country_background_text');
                this.setCIATextLink(info['fips_code'], 'read_more_link');
                this.geocode(info['country_name']);

                $('#weather_local_location').text( info['capital'] );
				this.timeGeocode(info['capital'] + ', ' + info['country_name']);
				this.weatherGeocode(info['capital'] + ', ' + info['country_name']);

                com.hive.worldpop.layout.resizeCountryName();
                com.hive.worldpop.layout.resizeCapitalText();
            } catch(err) {
                alert('Error in updateInfo: Error Name: ' + err.name + '. Error Message: ' + err.message);
            }
        }
    },

    getCellInfo: function(cellId) {
        try {
            // get data for cell
            var fips_code = String( fieldApplet.getCellDataforAttr(cellId,'fips_code') ).slice();
            var country_name = String( fieldApplet.getCellDataforAttr(cellId,'name') ).slice();
            var capital = String( fieldApplet.getCellDataforAttr(cellId,'capital') ).slice();
            var currency = String( fieldApplet.getCellDataforAttr(cellId,'currency_name') ).slice();
            var growth_rate_pct = String( fieldApplet.getCellDataforAttr(cellId,'growth_rate_pct') ).slice();
            var growth_rate_rank = String( fieldApplet.getCellDataforAttr(cellId,'growth_rate_rank') ).slice();
            var sq_km = String( fieldApplet.getCellDataforAttr(cellId,'sq_km') ).slice();
            var area_rank = String( fieldApplet.getCellDataforAttr(cellId,'area_rank') ).slice();
            var density_km = String( fieldApplet.getCellDataforAttr(cellId,'density_km') ).slice();
            var density_rank = String( fieldApplet.getCellDataforAttr(cellId,'density_rank') ).slice();
            var death_rate_pct = String( fieldApplet.getCellDataforAttr(cellId,'death_rate_pct') ).slice();
            var death_rate_rank = String( fieldApplet.getCellDataforAttr(cellId,'death_rate_rank') ).slice();
            var background = String( fieldApplet.getCellDataforAttr(cellId,'background') ).slice();
            var info = {
                'fips_code': fips_code,
                'country_name': country_name,
                'capital': capital,
                'currency': currency,
                'growth_rate_pct': growth_rate_pct,
                'growth_rate_rank': growth_rate_rank,
                'sq_km': sq_km,
                'area_rank': area_rank,
                'density_km': density_km,
                'density_rank': density_rank,
                'death_rate_pct': death_rate_pct,
                'death_rate_rank': death_rate_rank,
                'background': background
            };
            return info;
        } catch(err) {
            alert('Error in getCellInfo: Error Name: ' + err.name + '. Error Message: ' + err.message);
        }
    },

    preloadImages: function() {
        if (arguments && document.images) {
            for (var i = 0; i < arguments.length; i++) {
                var img = new Image();
                img.src = arguments[i];
            }
        }
    }

};


/** com.hive.worldpop.layout - Object for layout, resizing, hiding/showing, etc **/
com.hive.worldpop.layout = {

    headerHeight: 0,
    footerHeight: 0,
    treemapMarginLeft: 0,
    treemapMarginRight: 0,
    treemapPaddingTop: 0,
    treemapPaddingBottom: 0,
    countryNameFontSize: 14,
    capitalTextFontSize: 14,
    resizeTimeoutId: null,

    init: function() {
        /*this.headerHeight = parseInt($('#header').css('padding-top')) 
            + parseInt($('#header #logo').css('height')) + parseInt($('#header #navbar').css('height'))
            + parseInt($('#gallery_bar').outerHeight(true),0);*/
        this.headerHeight = parseInt($('#header #navbar').outerHeight(true))
            + parseInt($('#gallery_bar').outerHeight(true))
        this.footerHeight = parseInt($('#footer').outerHeight(true));
        this.treemapMarginLeft = parseInt($('#treemap').css('margin-left'),0);
        this.treemapMarginRight = parseInt($('#treemap').css('margin-right'),0);
        this.treemapPaddingTop = parseInt($('#treemap').css('padding-top'),0);
        this.treemapPaddingBottom = parseInt($('#treemap').css('padding-bottom'),0);
    },

    setDimensions: function() {
        if (this.resizeTimeoutId != null) {
            window.clearTimeout(this.resizeTimeoutId);
            this.resizeTimeoutId = null;
        }
        this.resizeTimeoutId = window.setTimeout('com.hive.worldpop.layout._setDimensions();', 150);
    },

    _setDimensions: function() {
        // Auto-corrects by calling resize back to back 
        // Calling with a single boolean param == false disables auto-correct
        this.__setDimensions();
        var autoCorrect = true;
        if (arguments) {
            if (arguments[0]) {
                autoCorrect = arguments[0];
            }
        }
        if (autoCorrect) {
            this.__setDimensions();
        }
    },

    __setDimensions: function() {
        var resizeFieldApplet = true;
        var resizePanels = true;
        if (arguments) {
            if (arguments[0]) {
                resizeFieldApplet = arguments[0];
            }
            if (arguments[1]) {
                resizePanels = arguments[1];
            }
        }
        var minHeight = parseInt($('#container').css('min-height'));
        var viewPortHeight = Math.max(minHeight, $(window).height());
        var mainHeight = viewPortHeight - this.headerHeight - this.footerHeight;
        var treemapHeight = mainHeight - parseInt($('#treemap').css('padding-top')) - parseInt($('#treemap').css('padding-bottom'));
        var rightPanelHeight = mainHeight - parseInt($('#right_panel').css('padding-top')) - parseInt($('#right_panel').css('padding-bottom'));
        var leftPanelHeight = mainHeight - parseInt($('#left_panel').css('padding-top')) - parseInt($('#left_panel').css('padding-bottom'));
        var fieldHeight = treemapHeight 
            - parseInt($('#field').css('margin-top'), 0)
            - parseInt($('#field').css('margin-bottom'), 0);
        if (!$('#hod_ad').hasClass('invisible')) {
            fieldHeight -= parseInt($('#hod_ad').outerHeight(true), 0);
        }
        if (!$('#controls').hasClass('invisible')) {
            fieldHeight -= parseInt($('#controls').outerHeight(true), 0);
        }
        $('#main').css('height', mainHeight+'px');
        $('#treemap').css('height', treemapHeight+'px');
        if (resizePanels) {
            $('#right_panel').css('height', rightPanelHeight+'px');
            $('#left_panel').css('height', leftPanelHeight+'px');
        }
        $('#field').css('height', fieldHeight+'px');

        // resize FieldApplet
        if (resizeFieldApplet) {
            var fieldWidth = parseInt($('#treemap').width());
            fieldApplet.width = fieldWidth;
            fieldApplet.height = fieldHeight;
        }

        if (resizePanels) {
            // resize scrollable filters
            var mainFiltersHeight = parseInt($('#left_panel').height()) 
                - parseInt($('#news_info').outerHeight(true), 0)
                - parseInt($('#quick_filters').outerHeight(true), 0)
                - parseInt($('#main_filters').css('padding-top'), 0)
                - parseInt($('#main_filters').css('padding-bottom'), 0)
                - parseInt($('#main_filters').css('margin-bottom'), 0)
                - parseInt($('#status').outerHeight(true), 0);
            var mainFiltersMiddleHeight = mainFiltersHeight
                - parseInt($('#main_filters_top').outerHeight(true), 0)
                - parseInt($('#main_filters_bottom').outerHeight(true), 0);
            $('#main_filters_inner_wrapper').css('height', mainFiltersMiddleHeight);
            $('#main_filters').css('height', mainFiltersHeight+'px');

            // resize background info
            var bgInfoHeight = parseInt($('#right_panel').css('height'))
                - parseInt($('#gmap').outerHeight(true))
                - parseInt($('#country_capital').outerHeight(true))
                - parseInt($('#flag_weather').outerHeight(true))
                - parseInt($('#country_info').outerHeight(true))
                - parseInt($('#country_background_text_wrapper').css('padding-top'), 0)
                - parseInt($('#country_background_text_wrapper').css('padding-bottom'), 0)
                - parseInt($('#background_info_top_wrapper').outerHeight(true))
                - parseInt($('#background_info_bottom_wrapper').outerHeight(true));
            $('#country_background_text_wrapper').css('height', bgInfoHeight+'px');
            // clamp background info text to the number of completely visible lines
            var bgtext = $('#country_background_text_wrapper');
            var line_height = parseInt(bgtext.css('line-height'));
            var text_top = parseInt(bgtext.position().top);
            //var visible_height = bgInfoHeight - text_top;
            var visible_height = bgInfoHeight;
            var visible_lines = Math.floor(visible_height / line_height);
            var new_height = parseInt((visible_lines-1) * line_height);
            $('#country_background_text').height(new_height);

            // hod ad
            var ad_width = $('#hod_ad').width();
            var ad_src = 'images/HODad_large.gif';
            if (ad_width < 600) {
                ad_src = 'images/HODad_small.gif';
            }
            $('#hod_ad').html( '<img src="' + ad_src + '"/>' );
        }

        // hide the color gradient if not enough space
        var controlsWidth = parseInt($('#controls').width(), 0);
        if (controlsWidth < 565) {
            if (!$('.color_legend').hasClass('invisible')) {
                $('.color_legend').addClass('invisible');
            }
        }
        else {
            if ($('.color_legend').hasClass('invisible')) {
                $('.color_legend').removeClass('invisible');
            }
        }

        // reset resize timeout
        this.resizeTimeoutId = null;
    },

    hideControls: function() {
        $('#left_panel').addClass('invisible');
        $('#right_panel').addClass('invisible');
        $('#controls').addClass('invisible');
        $('#hod_ad').addClass('invisible');
        $('#hod_ad').css('display','none');
        $('#treemap').css('margin-left', '5px');
        $('#treemap').css('margin-right', '5px');
        $('#treemap').css('padding-top', '0');
        $('#treemap').css('padding-bottom', '0');
        this.__setDimensions(true, false);
    },

    showControls: function() {
        $('#treemap').css('margin-left', this.treemapMarginLeft+'px');
        $('#treemap').css('margin-right', this.treemapMarginRight+'px');
        $('#treemap').css('padding-top', this.treemapPaddingTop+'px');
        $('#treemap').css('padding-bottom', this.treemapPaddingBottom+'px');
        $('#left_panel').removeClass('invisible');
        $('#right_panel').removeClass('invisible');
        $('#controls').removeClass('invisible');
        $('#hod_ad').removeClass('invisible');
        $('#hod_ad').css('display','block');
        this.__setDimensions();
        this.__setDimensions();
    },

    resizeCountryName: function() {
        var flagInfoHeight = parseInt($('#flag_info').innerHeight(), 0);
        var flagHeight = parseInt($('#flag_info #flag').innerHeight(), 0);
        var h = flagInfoHeight - flagHeight;
        var textHeight = parseInt($('#flag_info .country_name').height(), 14);
        var f = this.countryNameFontSize;
        $('#flag_info .country_name').css('font-size', f+'px'); 
        while (textHeight > h) {
            f -= 1; 
            $('#flag_info .country_name').css('font-size', f+'px'); 
            textHeight = parseInt($('#flag_info .country_name').height(), 14);
        }
    },

    resizeCapitalText: function() {
        var lineHeight = this.capitalTextFontSize;
        var textHeight = parseInt($('#country_capital span.text_wrapper').innerHeight());
        var outerHeight = parseInt($('#country_capital').innerHeight());
        var f = this.capitalTextFontSize;
        $('#country_capital').css('line-height', f+'px');
        $('#country_capital').css('font-size', f+'px');
        while (textHeight > outerHeight) {
            f -= 1;
            $('#country_capital').css('line-height', f+'px');
            $('#country_capital').css('font-size', f+'px');
            textHeight = parseInt($('#country_capital span.text_wrapper').outerHeight(true));
        }
    }

};


com.hive.worldpop.finishInit = function() {
    // Should do this based on lookup of IP address to find user's country
    var info = com.hive.worldpop.services.getCellInfo(1);
    com.hive.worldpop.services.updateInfo(info);
    //com.hive.worldpop.services.barChartRank('country_info_table', info, 237, barChartOptions);
    com.hive.worldpop.services.barChartActual('country_info_table', info, columnInfo);

    // filters
    var unFilterGroup = 'un_filter_group';
    $('input#UN_checkbox').click(function() {
        if (this.checked) {
            com.hive.worldpop.controls.applyFilter('un_recognized',unFilterGroup,'un_recognized_filter', 'EQ', '1');
        }
        else {
            fieldApplet.removeFilterGroup(unFilterGroup);
        }
        com.hive.worldpop.controls.updateStatus();
    });
    var popRankFilterGroup = 'pop_rank_filter_group';
    $('input#top25_population_checkbox').click(function() {
        if (this.checked) {
            com.hive.worldpop.controls.applyFilter('pop_rank',popRankFilterGroup,'pop_rank_filter', 'LTE', '25');
        }
        else {
            fieldApplet.removeFilterGroup(popRankFilterGroup);
        }
        com.hive.worldpop.controls.updateStatus();
    });
    var bestLiveFilterGroup = 'best_place_live_top_25_filter_group';
    $('input#top25_best_checkbox').click(function() {
        if (this.checked) {
            com.hive.worldpop.controls.applyFilter('best_place_live_top25',bestLiveFilterGroup,'best_live_filter', 'EQ', '1');
        }
        else {
            fieldApplet.removeFilterGroup(bestLiveFilterGroup);
        }
        com.hive.worldpop.controls.updateStatus();
    });
    var continentFilterGroup = 'continent_filter_group';
    $('select#continent_filter').click(function() {
        var options = $(this).children('option');
        for (var i = 0; i < options.length; i++) {
            var option = $(options[i]);
            if (option.val()) {
                var filterName = 'continentFilter_' + option.val();
                if (option.attr('selected')) {
                    com.hive.worldpop.controls.applyFilter('continent', continentFilterGroup, filterName, 'EQ', option.val());
                }
                else {
                    fieldApplet.removeFilter(continentFilterGroup, filterName);
                }
            }
        }
        com.hive.worldpop.controls.updateStatus();
    });
    $('#continent_filter_deselect').click(function() {
        var options = $('select#continent_filter').children('option');
        for (var i = 0; i < options.length; i++) {
            var option = $(options[i]);
            if (option.val()) {
                var filterName = 'continentFilter_' + option.val();
                if (option.attr('selected')) {
                    fieldApplet.removeFilter(continentFilterGroup, filterName);
                    option.removeAttr('selected');
                }
            }
        }
        com.hive.worldpop.controls.updateStatus();
    });

    // text search filter
    var originalTextSearchValue = $('#text_search_filter input.text').val();
    $('#text_search_filter input.text').focus(function() {
        if ($(this).val() == originalTextSearchValue || $(this).val().length < 1) {
            $(this).val('');
        }
        com.hive.worldpop.controls.updateStatus();
    });
    $('#text_search_filter input.text').blur(function() {
        var v = $(this).val();
        if (v == null || v == undefined || v.length < 1) {
            $(this).val(originalTextSearchValue);
        }
        com.hive.worldpop.controls.updateStatus();
    });
    $('#text_search_filter input.text').change(function() {
        var v = $(this).val();
        if (v == null || v == undefined || v.length < 1 || v == originalTextSearchValue) {
            fieldApplet.removeFilterGroup('text_search_group');
        }
        else {
            com.hive.worldpop.controls.applyFilter(v, 'text_search_group', 'text_search_name', 'HAS_TEXT', 'name');
            com.hive.worldpop.controls.applyFilter(v, 'text_search_group', 'text_search_capital', 'HAS_TEXT', 'capital');
        }
        com.hive.worldpop.controls.updateStatus();
    });
    $('#text_search_filter input.text').keyup(function() {
        $(this).change();
    });

    // sliders
    var sliderDefs = [
        {
            'min': 1,
            'max': 237,
            'field': 'pop_rank',
            'slider_div': 'slider_population',
            'values_div': 'slider_population_values'
        },
        {
            'min': 1,
            'max': 237,
            'field': 'growth_rate_rank',
            'slider_div': 'slider_growth_rate',
            'values_div': 'slider_growth_rate_values'
        },
        {
            'min': 1,
            'max': 237,
            'field': 'area_rank',
            'slider_div': 'slider_area',
            'values_div': 'slider_area_values'
        },
        {
            'min': 1,
            'max': 237,
            'field': 'density_rank',
            'slider_div': 'slider_density',
            'values_div': 'slider_density_values'
        },
        {
            'min': 1,
            'max': 237,
            'field': 'death_rate_rank',
            'slider_div': 'slider_death_rate',
            'values_div': 'slider_death_rate_values'
        }
    ];
    for (var i = 0; i < sliderDefs.length; i++) {
        com.hive.worldpop.controls.buildSlider(sliderDefs[i]);
    }

    // mobox events
    var moCellSub = null;
    while (moCellSub == null || moCellSub == undefined || moCellSub < 0) {
        moCellSub = fieldApplet.subscribe("MouseOverCellEvent", "mouseOverCell");
    }

    // update status
    //$('#visible_count').html( parseInt(fieldApplet.countVisibleCells()) );
    //$('#total_count').html( parseInt(fieldApplet.countAllCells()) );

    // resize
    com.hive.worldpop.layout.__setDimensions(true);
    $(window).resize(function() {
        com.hive.worldpop.layout.setDimensions();
    });

    // hide/show controls
    $('#hide_show_controls').toggle(
        function() {
            $(this).html('Show All Panels');
            com.hive.worldpop.layout.hideControls();
        },
        function() {
            $(this).html('Hide All Panels');
            com.hive.worldpop.layout.showControls();
        }
    );

    // gallery title image swap
    var swipeFlag = false;
    var swipeGalleryTitle = function(s) {
        var y = s ? 50 : 0;
        var z = s ? 0 : 50;
        $('#gallery_title').css({backgroundPosition: '0px '+z+'px'}).stop().animate({backgroundPosition:'(0px '+y+'px)'},{duration:1000});
    };
    swipeGalleryTitle(true);
    window.setInterval(function() {
        swipeGalleryTitle(swipeFlag);
        swipeFlag = !swipeFlag;
    }, 10000);

    // parse group, size, color state from URL
    var h = parent.location.hash.substring(1);
    var states = h.split('&');
    if (states.length != 1) {
        $('#group_control').val( states[0].substring(2) );
        $('#group_control').change();
        $('#size_control').val( states[1].substring(2) );
        $('#size_control').change();
        $('#color_control').val( states[2].substring(2) );
        $('#color_control').change();
    }

};


com.hive.worldpop.waitForData = function() {
    // just doing this to make sure the data is loaded... need a better way to know that...
    // also, can't seem to figure out how to actually get cell ids from this method...
    /*var allCellIds = fieldApplet.getAllCellIds();
    while (allCellIds.length() < 3) {
        allCellIds = fieldApplet.getAllCellIds();
    }*/
    var cellCount = fieldApplet.countAllCells();
    if (cellCount < 237) {
        window.setTimeout(com.hive.worldpop.waitForData, 250);
    }
    else {
        com.hive.worldpop.finishInit();
    }
};


com.hive.worldpop.ready = function() {
    barChartOptions = {
        'sq_km': { formatter: com.hive.worldpop.formatters.formatArea },
        'density_km': { formatter: com.hive.worldpop.formatters.formatDensity },
        'growth_rate_pct': {
            formatter: function(v) { return v + ' %'; }
        },
        'death_rate_pct': {
            formatter: function(v) { return v + ' %'; }
        }
    };
    fieldApplet = document.getElementById('fieldApplet');
    com.hive.worldpop.layout.init();
    com.hive.worldpop.services.init();

    // resize html elements but not the field applet
    com.hive.worldpop.layout.__setDimensions(false);

    // controls
    var updateUrl = function() {
        var g = $('#group_control').val();
        var s = $('#size_control').val();
        var c = $('#color_control').val();
        parent.location.hash = 'g='+g+'&s='+s+'&c='+c;
    };

    $('select#group_control').change(function() {
        var field = $('select#group_control').val();
        com.hive.worldpop.controls.setGroup(field);
        updateUrl();
    });
    $('select#size_control').change(function() {
        var field = $('select#size_control').val();
        com.hive.worldpop.controls.setSize(field);
        updateUrl();
    });
    $('select#color_control').change(function() {
        var field = $('select#color_control').val();
        com.hive.worldpop.controls.setColor(field);
        var bg = 'url(images/color_' + field + '.png)';
        $('#color_legend_image').css('background-image', bg);
        updateUrl();
    });

    // wait for field applet to initialize...
    var fieldId = null;
    while (fieldId == null) {
        fieldId = fieldApplet.getID();
    }

    com.hive.worldpop.waitForData();

};


/** Document initialization **/
$(document).ready(function() {
    $.preloadCssImages();
    com.hive.worldpop.services.preloadImages(
        'images/world-map-background.jpg',
        'images/color_death_rate_pct.png',
        'images/color_density_km.png',
        'images/color_growth_rate_pct.png',
        'images/color_population.png',
        'images/color_sq_km.png'
    );
    $('.menu_item').hover(function() {
        var id = $(this).attr('id');
        $('.menu_item').removeClass('menu_item_selected');
        $(this).addClass('menu_item_selected');
        $('.menu_content').addClass('invisible');
        $('#'+id+'_content').removeClass('invisible');
    });
    $('#app_info').click(function() {
        var opts = 'scrollbars=yes,width=581,height=610';
        window.open('readmore.html', 'About The World Population Application', opts);
    });
    var readyTimeout = window.setTimeout(com.hive.worldpop.ready, 250);
});

