general.namespace('SW.Regions');

(function () {
       
     
    //////////// CLASS DoubledRegion
    /* 
                
    */
        var DoubledRegion = SW.Regions.DoubledRegion = function (map, bounds, centerLat, centerLng, name, regionId, zoom, isNavRegion) {
            var borderWidth = 1; // width of border on one side, not both together
            
            this.map = map;
            this.bounds = bounds;
            this.center = new GLatLng(centerLat, centerLng);
            this.zoom = zoom; // the zoom level at which the region takes up the full screen (if there is no such region, set this to null)
            this.hidden = false;
            this.borderWidth = borderWidth || 0; 
            this.borderColor = 'red';
            
            this.name = name;
            this.regionId = regionId;
            this.zoom = zoom;
            this.isNavRegion = isNavRegion;
            
            this.inZoom = false;
                                    
            this.SW = this.bounds.getSouthWest();
            this.NE = this.bounds.getNorthEast();
            
            // setup visibility control
            this.setupDivs();  // child class must supply setupDivs()
            
            var currentZoom = this.map.getZoom();
            
            
            // initialize this.visible before calling this.updatePosition() for the first time
            if (this.inZoom === true && this.hidden === false) {
                this.initVisibility(true);
            } else {
                this.initVisibility(false);
            } 
            
            this.handlersEnabled = false;
            
            this.setupHandlers();  
        };
        
        DoubledRegion.prototype.constructor = DoubledRegion; 
        
        
        /* Remove the rectangle div(s) from the map pane */
        DoubledRegion.prototype.remove = function () {
            var parent = this.div.parentNode;
            
            parent.removeChild(this.div);
            parent.removeChild(this.doubleDiv);
        };
        

        /* Hide the overlay. (Does nothing if overlay is already hidden.) */
        DoubledRegion.prototype.hide = function () {
            if (this.hidden === false) {
                this.hidden = true;
                this.updateVisibility();
            }
        };
        
        
        /* Show the overlay. (Does nothing if overlay is already not hidden.) */
        DoubledRegion.prototype.show = function () {
            if (this.hidden === true) {
                this.hidden = false; // do this before updateVisibility() so that the redraw makes the image appear
                this.updateVisibility();
            }
        };
        
        
        /* If hidden, show the overlay. If shown, hide the overlay. */
        DoubledRegion.prototype.toggleHidden = function () {
            if (this.hidden === true) {
                this.show();
            } else {
                this.hide();
            }
        };
        
        
        /* When hidden status of overlay is changed, need to update the actual visibility of the 
            overlay main div and its double div. */
        DoubledRegion.prototype.updateVisibility = function () {
            
            var newVisibility = (this.inZoom === true && this.hidden === false);
            
            if (newVisibility === this.visible) { // nothing to change
                return; 
            } else if (newVisibility === true) { // make visible
                this.div.style.display = 'block';
                this.doubleDiv.style.display = 'block'; 
                this.visible = true;
            } else {         // make invisible
                this.div.style.display = 'none';
                this.doubleDiv.style.display = 'none';
                this.visible = false;
            }
        };
        
        
        /* Force visibility or invisibility without regard to previous visibility status or inZoom, hidden, or inView */
        DoubledRegion.prototype.initVisibility = function (newVisibility /* bool */) {
            
            if (newVisibility === true) {   // make visible
                /*Assume doubleDiv should be visible then call updatePosition() which will hide it if necessary. */
                this.div.style.display = 'block';
                this.doubleDiv.style.display = 'block'; 
                this.updatePosition();
                            
                this.visible = true;

            } else {           // make invisible
                this.div.style.display = 'none';
                this.doubleDiv.style.display = 'none';
                
                this.visible = false;
            }
        };
        
            /* */
        DoubledRegion.prototype.toString = function() {
            return 'DoubledRegion: ' + this.regionId + '; ' + this.name;
        };
        
        
        /* Creates the divs and their initial styles. (A second div is needed for 
           cases where the region is seen on both sides of the map view). */
        DoubledRegion.prototype.setupDivs = function() {
            // Create the DIV representing our rectangle
            this.div = SW.Regions.DIV.cloneNode(true);
            this.div.regionId = this.regionId; // so handlers can identify a region having identified the div
            
            this.blankImg = this.div.firstChild;
            
            SW.Regions.REGIONS_DOC_FRAG.appendChild(this.div);
                     
            // double the div so that it can be seen wrapping around the world
            this.doubleDiv = this.div.cloneNode(true);
            this.doubleDiv.regionId = this.regionId;
            
            this.doubleBlankImg = this.doubleDiv.firstChild;
            
            SW.Regions.REGIONS_DOC_FRAG.appendChild(this.doubleDiv);
        };
        
        
        DoubledRegion.prototype.setCursor = function(cursorStyle) {
            this.div.style.cursor = cursorStyle;
            this.doubleDiv.style.cursor = cursorStyle;
        };
        
      
        /* 
            Update the size and position of the divs. Called upon moveend and movezoom, but not during dragging. 
        
            Overridden to set the table cell height and width.
        */
        DoubledRegion.prototype.updatePosition = function() {
            
            // Calculate the DIV coordinates of two opposite corners of our bounds to
            // get the size and position of our rectangle
            
            var SWPoint = this.map.fromLatLngToDivPixel(this.SW);
            var NEPoint = this.map.fromLatLngToDivPixel(this.NE);
            
            // Now position our div based on the pixel coordinates of our bounds
            
            var width = NEPoint.x - SWPoint.x;
            
            // it may happend that the W and E are so close together that they have no pixel width at this zoom level;
            // in this case, need to look at actual W E to see which is on which side of the other
            if (width === 0) {
                var E = this.NE.lng();
                var W = this.SW.lng();
                if ((E > W) && ((E - W) < 350)) { // make sure width is not zero because the region is ~360 degrees wide
                    width = 1; // region would be invisible, otherwise
                }
            }
            
            var overlayed;
            // when NEPoint.x - SWPoint.x is positive, the div and its double are positioned on top of each other
            if (width > 0) {
                overlayed = true; // the div and its double are on top of each other
            } else { 
                overlayed = false;
                var zoomFactor = Math.pow(2, this.map.getZoom() - 1); // every zoom lvl, the world doubles in each dimension in terms of pixels
                width = (SWMap.info.mapWidth * zoomFactor) - Math.abs(width); // when not overlayed, the left edge and right edge coords of the region are wrapped around the world and so width needs different derivation
            }
            
                   
            var height = SWPoint.y - NEPoint.y;
            
            // if there's a border, need to shrink the div size in both dimensions by twice the border width
            if (this.borderEnabled) {   
                width -= 2; // border width is 1
                height -= 2;  
            }
            
            // make sure width and height are set to minimum of 1px wide and tall
            if (width <= 0) {
                width = 1;
            }
            if (height <= 0) {
                height = 1;
            }

            
            // set styles
            var top = NEPoint.y + "px";
            width = width + "px";
            height = height + "px"; 
            
            var divStyle = this.div.style;
            divStyle.width = width;
            divStyle.height = height;
            divStyle.left = SWPoint.x + "px";
            divStyle.top = top;
                    
            // update the doubleDiv
            var doubleDivStyle = this.doubleDiv.style;
            doubleDivStyle.width = width;
            doubleDivStyle.height = height;
            doubleDivStyle.right = -NEPoint.x + "px";
            doubleDivStyle.top = top;
            // when overlayed, you don't want to see both divs because then you'd see the one surface through the other if the div is transparent
            if (overlayed) {
                doubleDivStyle.display = 'none';
            } else if (this.visible) {
                doubleDivStyle.display = 'block';    
            }
            
            var blankImgStyle = this.blankImg.style;
            var doubleBlankImgStyle = this.doubleBlankImg.style;
                    
            blankImgStyle.width = width;
            blankImgStyle.height = height;
            
            doubleBlankImgStyle.width = width;
            doubleBlankImgStyle.height = height;
        };    
        

        /* 
            setup handlers for border highlighting on mouseover and centerAndZoom on clicking (but not dragging!) 
        */
        

        DoubledRegion.prototype.setupHandlers = function () {
            
            var handler;
            
            var me = this;
                            
            var mouseX;
            var mouseY;
            
            function mouseClickDown(e) {
                // make note of position on down to see how much user drags before releasing mouse button
                
                mouseX = e.clientX;
                mouseY = e.clientY;

            }
            
            
            function mouseClick(e) {
            
                if (handler) {
                    window.clearTimeout(handler);
                    handler = null;
                } else {
                    var upMouseX = e.clientX;
                    var upMouseY = e.clientY;
                    
                    handler = setTimeout(
                    
                        function() {
                            if (me.handlersEnabled) {
                                // only center and zoom on region if user doesn't move the mouse too much before releasing the button
                                if ( (mouseX < upMouseX + 5 && mouseX > upMouseX - 5)  &&  (mouseY < upMouseY + 5 && mouseY > upMouseY - 5) ) {
                                    me.centerAndZoomOnMe();
                                }
                            }
                            
                            handler = null;
                        },
                        0
                    );
                }
            }
            
            
            var addListener = general.addListener;
                   
            addListener(this.div, 'mousedown', mouseClickDown);  
            addListener(this.doubleDiv, 'mousedown', mouseClickDown);
            
            addListener(this.div, 'click', mouseClick);
            addListener(this.doubleDiv, 'click', mouseClick);
            
            addListener(this.div, 'mouseover', function() {me.showBorder();});
            addListener(this.doubleDiv, 'mouseover', function() {me.showBorder();});
            
            addListener(this.div, 'mouseout', function() {me.hideBorder();});
            addListener(this.doubleDiv, 'mouseout', function() {me.hideBorder();});
        };
        
        
        /* */
        DoubledRegion.prototype.hideBorder = function() {
            if (SW.Regions.hoveredRegionChangeable && this.handlersEnabled) {
            
                this.div.style.borderWidth = '0px';
                this.doubleDiv.style.borderWidth = '0px';
                
                SWMap.tooltip.hide();
            }
        };
        
            
        /* */
        DoubledRegion.prototype.showBorder = function() {
            if (SW.Regions.hoveredRegionChangeable && this.handlersEnabled) {
        
                // make sure last highlighted region gets cleared (in a few edge cases, its mouseout doesn't get called, such as when you have it highlighted as drag you drag cursor off map)
                if (SW.Regions.lastHighlightedRegion) {
                    SW.Regions.lastHighlightedRegion.hideBorder();    
                }
                SW.Regions.lastHighlightedRegion = this;
            
                this.div.style.borderWidth = '1px';
                this.doubleDiv.style.borderWidth = '1px';
                
                SWMap.tooltip.setMessage(this.name);
                SWMap.tooltip.show();
            }
        };
        

        
        /* */
        DoubledRegion.prototype.disableBorder = function() {
            
            // hide border
            this.div.style.borderWidth = '0px';
            this.doubleDiv.style.borderWidth = '0px';
            
            this.handlersEnabled = false;
            this.borderEnabled = false;
        };
        
        
        /**/
        DoubledRegion.prototype.enableBorder = function() {
            this.handlersEnabled = true;
            this.borderEnabled = true;
        };
        

        DoubledRegion.prototype.getSiblings = function() {
            if (this.parent) {
                var children = this.parent.children.slice(0); //make local copy
                
                for (var i = 0; i < children.length; i++) {
                    if (this === children[i]) {
                        children.splice(i, 1);
                        break;
                    }
                }
                            
                return children;
            } else {
                return [];
            }
        };
        
        
        DoubledRegion.prototype.centerAndZoomOnMe = function() {
            mapGeneral.centerAndZoomOnRegionAnimation(this);
        };

})();
