general.namespace('SW.Regions');


(function() {

    var Regions = SW.Regions;

    Regions.hoveredRegionChangeable = true; // a flag used by clickable region divs to enable/disable changing of their mouseover/mouseout

    Regions.regionsInZoom = [];

    Regions.DIV = $C('div',
        {
            position: 'absolute',
            cursor: 'pointer',
            borderStyle: 'solid',
            borderWidth: '0px',
            borderColor: 'red',
            display: 'block',
            zIndex: '10'
        },
        $C('img', null, { src: '/assets/images/spacer.gif' })
    );

    Regions.REGIONS_DOC_FRAG = document.createDocumentFragment();

    /**/
    Regions.updateRegionsInZoom = function(newZoom) {


        var regions = SWMap.world.regions;
        var regionsInZoom = Regions.regionsInZoom = [];

        for (var i = 0; i < regions.length; i++) {
            var region = regions[i];

            region.inZoom = false;

            var regionZoom = region.zoom;

            var cursorStyle = (regionZoom <= newZoom) ? '' : 'pointer';
            region.setCursor(cursorStyle);

            if ((newZoom <= 2 && regionZoom <= 3) ||
                    (newZoom >= 3 && regionZoom >= newZoom && regionZoom <= newZoom + 4)) {
                regionsInZoom.push(region);
                region.inZoom = true;
                if (regionZoom > newZoom) {
                    region.enableBorder();
                } else {
                    region.disableBorder();
                }
            } else {
                region.disableBorder();
            }

            region.updateVisibility(); // can this be unrolled into here?
        }
    };

    /* order parent region's children array by north-to-south so that they are listed that way in the breadcrumb trail menu */
    Regions.sortChildrenNorthToSouth = function(regions) {

        for (var i = 0; i < regions.length; i++) {
            var r = regions[i];
            if (r.children) {
                var children = r.children;

                // bubble sort
                var N = children.length;
                for (var j = N - 1; j > 0; j--) {
                    for (var k = 0; k < j; k++) {
                        var val1 = children[k].latCenter;
                        var val2 = children[k + 1].latCenter;

                        if (val1 < val2) {
                            var temp = children[k];
                            children[k] = children[k + 1];
                            children[k + 1] = temp;
                        }
                    }
                }
            }
        }
    };

    /**/
    Regions.initRegions = function(regionData) {
        var i;
        var map = SWMap.map;
        var world = SWMap.world;
        var regions = world.regions;
        var regionsByZoom = world.regionsByZoom;
        var regionsById = world.regionsById; // used for matching each region with its parent

        // create the regions            
        for (var zoom = 0; zoom < regionData.length; zoom++) {

            regionsByZoom[zoom] = [];

            var Region = (zoom >= 4) ? SW.Regions.Region : SW.Regions.DoubledRegion;

            for (i = 0; i < regionData[zoom].length; i++) {
                var regionBO = regionData[zoom][i]; // the region BO from the database

                var bounds = mapGeneral.newBounds(regionBO.South, regionBO.West, regionBO.North, regionBO.East);

                var region = new Region(
                    map,
                    bounds,
                    regionBO.CenterLat,
                    regionBO.CenterLng,
                    regionBO.Name,
                    regionBO.Id,
                    zoom,
                    regionBO.isNavRegion // true if region is part of the navigation hierarchy of regions and is therefore hoverable/clickable; if false, the region is only seen in animations
                );

                // yes, it's inconsistent that some region properties are tacked on here instead of part of the 
                // constructor, but the region classes were originally intended as
                // generic regions, not animated regions. Something to refactor later.

                region.timezoneName = regionBO.TimeZoneName;
                region.timezoneOffset = regionBO.UtcOffset;

                region.hasGraphs = (regionBO.DefaultDataPointId_VirtualBuoy != null);
                region.associatedPerspectiveId = regionBO.DefaultDataPointId_PerspectiveView;

                region.latCenter = region.bounds.getCenter().lat();

                region.firstFrameDate = (regionBO.DateFirstAnimation) ? parseInt(regionBO.DateFirstAnimation) * 1000 : null; // convert to millisecond
                region.lastFrameDate = (regionBO.DateLatestAnimation) ? parseInt(regionBO.DateLatestAnimation) * 1000 : null; // convert to milliseconds

                region.hasWind = (zoom < mapGeneral.FIRST_ZOOM_LEVEL_WITHOUT_WIND) ? true : false;
                region.adCode = regionBO.AdCode;
                region.parentRegionId = regionBO.ParentRegionId;
                regionsById[region.regionId] = region;
                regions.push(region);
                regionsByZoom[zoom][i] = region;
            }
        }

        // add the region divs to the map
        map.getPane(G_MAP_MAP_PANE + 1).appendChild(Regions.REGIONS_DOC_FRAG);

        //match each region to its parent
        regions[0].parent = null; // the world region doesn't have a parent
        for (i = 1; i < regions.length; i++) {
            var r = regions[i];
            r.parent = regionsById[r.parentRegionId];
        }


        //find set of children for each region
        for (i = 0; i < regions.length; i++) {
            r = regions[i];
            if (r.parent) {
                if (!r.parent.children) {
                    r.parent.children = [];
                }
                r.parent.children.push(r);
            }
        }

        Regions.sortChildrenNorthToSouth(regions);

        // special settings for the world region
        world.worldRegion = regionsByZoom[1][0];
        world.worldRegion.timezoneOffset = (new Date()).getTimezoneOffset(); // get user's local timezone as an offset from GMT expressed in minutes
        world.worldRegion.timezoneName = ' you.';
        world.worldRegion.div.style.marginLeft = '-1px'; // fixes off by one because of the lng 179.5 kludge

        SWMap.animationControl.initToFirstRegion();

        SWMap.isMapReady = true;
        SWMap.initialRegionsData = null; // free up memory
    };

    /// REGION REQUEST HANDLERS 

    /**/
    Regions.requestRegions = function() {
        YAHOO.util.Connect.asyncRequest(
            'POST',
            '/WebServices/Regions.asmx/GetAll?r=' + general.rand(),
            {
                success: Regions.onRegionsSuccess,
                failure: Regions.onRegionsFailure
            },
            ''
        );
    };

    /**/
    Regions.onRegionsSuccess = function(response) {
        // TODO webservice will still be used at some point in future to update regions for users keeping page open for a long time
        var regionData = general.evalXmlResult(response.responseXML);
        if (regionData) {
            Regions.initRegions(regionData);
        }
        else {
            general.alert('Region data could not be loaded. Try again later.');
        }
    };

    /**/
    Regions.onRegionsFailure = function(response) {
        general.reportClientError('Region request failure: ' + response.statusText);
        general.alert('Region data could not be loaded. Try again later.');
    };
})();