/* An InfoBox is like an info window, but it displays
 * under the marker, opens quicker, and has flexible styling.
 * @param {GLatLng} latlng Point to place bar at
 * @param {Map} map The map on which to display this InfoBox.
 * @param {Object} opts Passes configuration options - content,
 *   offsetVertical, offsetHorizontal, className, height, width
 */

var curInfoBox;
 
// create the object InfoBox (with id blue_info_window)
function InfoBox(opts) {      

  if(curInfoBox != null) {
    curInfoBox.close();
  }
  
  //set opt parameters into parameters this object
  google.maps.OverlayView.call(this);
  this.latlng_ = opts.latlng;
  this.map_ = opts.map;
  //this.offsetVertical_ = -181;
  this.offsetVertical_ = -163;
  this.offsetHorizontal_ = -99;
  this.height_ = 90;
  this.width_ = 225;
  this.content = opts.content;
  this.idName = opts.className;
  this.borderSize_ = 3; 
  this.accordionHeight = 0;
    
  var div = document.createElement('div');
  div.innerHTML = opts.content;  
  
  
  var childLen = 0;
  childLen = $(div).children().length;
  // add offset to height and offsetVertical by Infobox size    
  this.height_ += 20 * childLen;
  this.offsetVertical_ -= 20 * childLen;
  
  //calculate accordion height for element positioning
      var tempElement = document.createElement('div');
      tempElement.id = this.idName;
      tempElement.style.visibility = 'hidden';
      document.body.appendChild(tempElement);
      tempElement = document.getElementById(this.idName);
      tempElement.innerHTML = this.content;
      this.accordionHeight = $(tempElement).find('h3').length*31 -31;  
      document.body.removeChild(tempElement);
  
  var me = this;
  this.boundsChangedListener_ =
    google.maps.event.addListener(this.map_, "bounds_changed", function() {
      return me.panMap.apply(me);
    });

  // Once the properties of this OverlayView are initialized, set its map so
  // that we can display it.  This will trigger calls to panes_changed and
  // draw.
  this.setMap(this.map_);
}

/* InfoBox extends GOverlay class from the Google Maps API
 */
InfoBox.prototype = new google.maps.OverlayView();

/* Creates the DIV representing this InfoBox
 */
InfoBox.prototype.remove = function() {
  if (this.div_) {
    this.div_.parentNode.removeChild(this.div_);
    this.div_ = null;
  }
};


/* Redraw the Bar based on the current projection and zoom level
 */
InfoBox.prototype.draw = function() {
  // Creates the element if it doesn't exist already.
  this.createElement();
  if (!this.div_) return;

  // Calculate the DIV coordinates of two opposite corners of our bounds to
  // get the size and position of our Bar
  var pixPosition = this.getProjection().fromLatLngToDivPixel(this.latlng_);
  if (!pixPosition) return;  
  
  // Now position our DIV based on the DIV coordinates of our bounds
  this.div_.style.width = this.width_ + "px";
  //this.div_.style.left = (pixPosition.x + this.offsetHorizontal_) + "px";
  this.div_.style.height = this.height_ + "px";
  //this.div_.style.top = (pixPosition.y + this.offsetVertical_) + "px";
  this.div_.style.display = 'block';
  
  var vars = [], hash;
    var hashes = window.location.href.slice(window.location.href.indexOf('?') + 1).split('&');
    for(var i = 0; i < hashes.length; i++)
    {
        hash = hashes[i].split('=');
        vars.push(hash[0]);
        vars[hash[0]] = hash[1];
    }
  if(parseInt(vars['section']) > 499)
  {
        $(".accordion").accordion({icons: null,
                                                           create: function(event, ui){
                                                               $(".accordion h3").removeClass('ui-state-active').removeClass('ui-state-focus').addClass('ui-state-active'); 
                                                               $(".accordion a.ui-state-default").removeClass('ui-state-active').addClass('ui-state-active').removeClass('ui-state-default');
                                                               var newHeader = $(".accordion").find("h3:first");
                                                               var newAnchor = newHeader.next().find("a.def_action"); 
                                                               newHeader.bind("click.redirect", function(){newAnchor.click();});                    
                                                              },
                                                           change: function(event, ui){
                                                                 $(".accordion h3").removeClass('ui-state-active').removeClass('ui-state-focus').addClass('ui-state-active');
                                                                 $(".accordion a.ui-state-default").removeClass('ui-state-active').addClass('ui-state-active').removeClass('ui-state-default');                                          
                                                                 ui.newHeader.bind("click.redirect", function(){ui.newContent.find("a.def_action").click();}); 
                                                                 ui.oldHeader.unbind("click.redirect");
                                                           }
      });
  }
  else
  {
   
      $(".accordion").accordion({icons: null,
                                                           create: function(event, ui){
                                                               $(".accordion h3").removeClass('ui-state-active').removeClass('ui-state-focus');
                                                               $(".accordion a.ui-state-default").removeClass('ui-state-active').addClass('ui-state-active').removeClass('ui-state-default');
                                                                var newHeader = $(".accordion").find("h3");
                                                                var newAnchor = newHeader.next().find("a");
                                                                var link = newAnchor.attr("href");                             
                                                                   newHeader.bind("click.redirect", function(){if(newAnchor.attr("onClick") === undefined) window.location.href = link; else newAnchor.click();});
                                                              },
                                                           change: function(event, ui){
                                                                 $(".accordion h3").removeClass('ui-state-active').removeClass('ui-state-focus');
                                                                 $(".accordion a.ui-state-default").removeClass('ui-state-active').addClass('ui-state-active').removeClass('ui-state-default');                                          
                                                                 var newHeader = ui.newHeader;
                                                                var newAnchor = newHeader.next().find("a");
                                                                var link = newAnchor.attr("href");                             
                                                                   newHeader.bind("click.redirect", function(){if(newAnchor.attr("onClick") === undefined) window.location.href = link; else newAnchor.click();});
                                                                ui.oldHeader.unbind("click.redirect");
                                                           }
      });
  }
  $(".button-close").button({text: false, icons: {primary: "ui-icon-closethick"}} );
};     

/* Creates the DIV representing this InfoBox in the floatPane.  If the panes
 * object, retrieved by calling getPanes, is null, remove the element from the
 * DOM.  If the div exists, but its parent is not the floatPane, move the div
 * to the new pane.
 * Called from within draw.  Alternatively, this can be called specifically on
 * a panes_changed event.
 */
InfoBox.prototype.createElement = function() {
  
  // This handler prevents an event in the InfoBox from being passed on to the map.
  var cancelHandler = function (e) {
      e.cancelBubble = true;
	  if (e.stopPropagation) {
         e.stopPropagation();
      }
  };
  
  var cancelHandlerIfMouseDown = function (e) {
      // global var, was set during map creating in module 20.tpl
	  if (!gmapMouseDown){
		  e.cancelBubble = true;
		  if (e.stopPropagation) {
	        e.stopPropagation();
	      }	
	  }
  };
   
  
  var panes = this.getPanes();
  var div = this.div_;
  
  if (!div) {
    // This does not handle changing panes.  You can set the map to be null and
    // then reset the map to move the div.    
    div = this.div_ = document.createElement("div");    

    this.eventListener1_ = google.maps.event.addDomListener(this.div_, "mousedown", cancelHandler);
    this.eventListener2_ = google.maps.event.addDomListener(this.div_, "mousemove", cancelHandlerIfMouseDown);
    this.eventListener3_ = google.maps.event.addDomListener(this.div_, "click", cancelHandler);
    this.eventListener4_ = google.maps.event.addDomListener(this.div_, "dblclick", cancelHandler);
    this.eventListener5_ = google.maps.event.addDomListener(this.div_, "mouseup", cancelHandlerIfMouseDown);
    
    div.style.border = "0px none";
    div.style.position = "absolute";    
    div.style.width = this.width_ + "px";
    div.style.height = this.height_ + "px";
    div.id = this.idName;
    this.container_ = document.createElement("div"); 
    this.container_.id = this.idName + '_contents';   
    this.container_.innerHTML = this.content;
          
    //set offset of marker overlay beak
    var beak_offset = (this.panMap())        
    var position_helper = -20;
    
    beak_offset['left'] = - beak_offset['left']-15;
    
    if(beak_offset['left'] > this.width_ / 2 - 13) //max left offset
      beak_offset['left'] = this.width_ / 2 - 13;
    if(beak_offset['left'] < -this.width_ / 2 + 13)
      beak_offset['left'] = -this.width_ / 2 + 13;
    var up = 1; // indicates infowindow position 1= up, 0= down
    if(beak_offset['top'] != 0)
    {
      up = 0;
      beak_offset['top'] = 28 - beak_offset['top'];   
      position_helper = 0;
    }
    
    // ------- added from exinfowindow for google API v2, formating infoBox ---------
    this.wrapperDiv_ = document.createElement('div');
    
    this.wrapperParts = {
      main:{t:0, l:0, w:0, h:0, domElement: null},
      beak:{t:0, l:0, w:0, h:0, domElement: null},
      close:{t:0, l:0, w:0, h:0, domElement: null}
    };
    for (var i in this.wrapperParts ) {
      var tempElement = document.createElement('div');
      tempElement.id = this.idName + '_' + i;
      tempElement.style.visibility = 'hidden';
      document.body.appendChild(tempElement);
      tempElement = document.getElementById(this.idName + '_' + i);
      var tempWrapperPart = this.wrapperParts[i];    
      tempWrapperPart.w = parseInt(this.getStyle_(tempElement, 'width'), 10);
      tempWrapperPart.h = parseInt(this.getStyle_(tempElement, 'height'), 10);      
      document.body.removeChild(tempElement);
    }    
    
    //Finish configuring wrapper parts that were not set in initialization
    this.wrapperParts.main.w = this.width_ + 2;
    this.wrapperParts.main.h = this.height_ + 50 + this.accordionHeight;
    this.wrapperParts.main.l = 0;
    this.wrapperParts.main.t = 0 + position_helper;
    
    this.wrapperParts.beak.l =  this.borderSize_ + (this.width_ / 2) - (this.wrapperParts.beak.w / 2) + beak_offset['left'];
    this.wrapperParts.beak.t = 15 + this.height_  - this.borderSize_ - 3 + beak_offset['top'] + 20;
    this.wrapperParts.close.l = this.width_ - this.wrapperParts.close.w - this.borderSize_;
    this.wrapperParts.close.t = this.borderSize_ + position_helper;
        
    var container_top_position = 15 + position_helper;
    if (up == 1)  //marker unravels up -> extend long elements
    {
     container_top_position = container_top_position -  this.accordionHeight;
     this.wrapperParts.close.t -= this.accordionHeight; 
     this.wrapperParts.main.t -= this.accordionHeight;
    }
    this.container_.style.position = 'absolute';
    this.container_.style.left = '0px';
    this.container_.style.top = container_top_position + 'px'; 
    
    for (var i in this.wrapperParts) {
      if (i == 'close' ) //first append the content so the close button is layered above it
        this.wrapperDiv_.appendChild(this.container_);
        
      var wrapperPartsDiv = null;
      if (this.wrapperParts[i].domElement == null) {
        wrapperPartsDiv = document.createElement('div');
        this.wrapperDiv_.appendChild(wrapperPartsDiv);
      } else {
        wrapperPartsDiv = this.wrapperParts[i].domElement;
      }
      
      if (i == 'close' ){
        google.maps.event.addDomListener(wrapperPartsDiv, 'click', function() { curInfoBox.close(); } ); 
      	wrapperPartsDiv.setAttribute("class", "button-close");
      	wrapperPartsDiv.style.width = "18px";
      }
      
      wrapperPartsDiv.id = this.idName + '_' + i;
      
      if (i == 'beak')
      {
         wrapperPartsDiv.style.margin = '0px 0px 0px -105px';  
         wrapperPartsDiv.style.backgroundPosition = '105px 0%';  
         if ( beak_offset['top'] != 0)
           wrapperPartsDiv.id = wrapperPartsDiv.id + '1';
      }  
      if (i == 'main'){
        wrapperPartsDiv.setAttribute("class", "ui-widget-content ui-corner-all");
      	wrapperPartsDiv.setAttribute("className", "ui-widget-content ui-corner-all");
        wrapperPartsDiv.style.borderStyle = "solid";
      }
        
      wrapperPartsDiv.style.position = 'absolute';
     // wrapperPartsDiv.style.width = this.wrapperParts[i].w + 'px'; //IE problem
      wrapperPartsDiv.style.height = this.wrapperParts[i].h + 'px';
      wrapperPartsDiv.style.top = this.wrapperParts[i].t + 'px';
      wrapperPartsDiv.style.left = this.wrapperParts[i].l + 'px';
      this.wrapperParts[i].domElement = wrapperPartsDiv;
    }
    //---------------------------------------------------------
    
    div.appendChild(this.wrapperDiv_);
    div.style.display = 'none';
    panes.floatPane.appendChild(div);        
    
  } 
  else if (div.parentNode != panes.floatPane) {
    // The panes have changed.  Move the div.
    //div.parentNode.removeChild(div);
    panes.floatPane.appendChild(div);
  } 
  else {
    // The panes have not changed, so no need to create or move the div.
  }
}

/* Pan the map to fit the InfoBox.
 */
InfoBox.prototype.panMap = function() {
  // if we go beyond map, pan map
  var map = this.map_;
  var bounds = map.getBounds();
  if (!bounds) return;

  // The position of the infowindow
  var position = this.latlng_;

  // The dimension of the infowindow
  var iwWidth = this.width_;
  var iwHeight = this.height_;

  // The offset position of the infowindow
  var iwOffsetX = this.offsetHorizontal_;
  var iwOffsetY = this.offsetVertical_ - this.accordionHeight;

  // Padding on the infowindow
  var padX = 3;
  var padY = 17;

  // The degrees per pixel
  var mapDiv = map.getDiv();
  var mapWidth = mapDiv.offsetWidth;
  var mapHeight = mapDiv.offsetHeight;
  var boundsSpan = bounds.toSpan();
  var longSpan = boundsSpan.lng();
  var latSpan = boundsSpan.lat();
  var degPixelX = longSpan / mapWidth;
  var degPixelY = latSpan / mapHeight;

  // The bounds of the map
  var mapWestLng = bounds.getSouthWest().lng();
  var mapEastLng = bounds.getNorthEast().lng();
  var mapNorthLat = bounds.getNorthEast().lat();
  var mapSouthLat = bounds.getSouthWest().lat();

  // The bounds of the infowindow
  var iwWestLng = position.lng() + (iwOffsetX - padX) * degPixelX;
  var iwEastLng = position.lng() + (iwOffsetX + iwWidth + padX) * degPixelX;
  var iwNorthLat = position.lat() - (iwOffsetY - padY) * degPixelY;
  var iwSouthLat = position.lat() - (iwOffsetY + iwHeight + padY) * degPixelY;

  // calculate center shift
  /*var shiftLng =
      (iwWestLng < mapWestLng ? mapWestLng - iwWestLng : 0) +
      (iwEastLng > mapEastLng ? mapEastLng - iwEastLng : 0);
  var shiftLat =
      (iwNorthLat > mapNorthLat ? mapNorthLat - iwNorthLat : 0) +
      (iwSouthLat < mapSouthLat ? mapSouthLat - iwSouthLat : 0);

  // The center of the map
  var center = map.getCenter();

  // The new map center
  var centerX = center.lng() - shiftLng;
  var centerY = center.lat() - shiftLat;*/

  // center the map to the new shifted center
  //map.setCenter(new google.maps.LatLng(centerY, centerX));

  if (this.getProjection() == null)
	return;
  var pixPosition = this.getProjection().fromLatLngToDivPixel(this.latlng_);
  if (!pixPosition) return;  
  
  var topPosition = pixPosition.y + this.offsetVertical_;
  var leftPosition = pixPosition.x + this.offsetHorizontal_;
  var positionOffset = new Array();
  positionOffset['top'] = 0;
  positionOffset['left'] = -15;    //-markerimage div 2
  
  var westTranscend = mapWestLng <= iwWestLng ? false : true;
  var eastTranscend = mapEastLng >= iwEastLng ? false : true;
  var southTranscend = mapSouthLat <= iwSouthLat ? false : true;
  var northTranscend = mapNorthLat >= iwNorthLat ? false : true;
  
  var pixelDistance_NorthEast = pixel_distance(mapNorthLat,mapEastLng,iwNorthLat,iwEastLng,map.zoom);
  var pixelDistance_SouthWest = pixel_distance(mapSouthLat,mapWestLng,iwSouthLat,iwWestLng,map.zoom);    
  
  if(westTranscend)
    positionOffset['left'] = pixelDistance_SouthWest['width'];
  else if(eastTranscend)
    positionOffset['left'] = 0 - pixelDistance_NorthEast['width'];
  
  leftPosition += positionOffset['left']; 
  
  if(southTranscend)
    positionOffset['top'] = 0 - iwHeight - 72;
  else if(northTranscend)
    positionOffset['top'] = iwHeight + 72; 
    
  topPosition += positionOffset['top'];
  
  this.div_.style.top = topPosition + "px";
  this.div_.style.left = leftPosition + "px";
  
  // Remove the listener after panning is complete.
  google.maps.event.removeListener(this.boundsChangedListener_);
  this.boundsChangedListener_ = null;  
  
  return positionOffset;
};

//functions taken from module_20.php
var OFFSET = 268435456;
var RADIUS  = 85445659.4471 // $offset / pi()
var SLIDE_SPEED = 500;
function lon_to_x(lon) {
    return Math.round(OFFSET + RADIUS * lon * Math.PI / 180);        
}
function lat_to_y(lat) {
    return Math.round(OFFSET - RADIUS * 
                Math.log((1 + Math.sin(lat * Math.PI / 180)) / 
                (1 - Math.sin(lat * Math.PI / 180))) / 2);
}
function pixel_distance(lat1, lon1, lat2, lon2, zoom) {
    var x1 = lon_to_x(lon1);
    var y1 = lat_to_y(lat1);

    var x2 = lon_to_x(lon2);
    var y2 = lat_to_y(lat2);
    
    var distance = new Array();
    distance['width'] = Math.abs(x1 - x2)>>(21 - zoom);
    distance['height'] = Math.abs(y1 - y2)>>(21 - zoom);
    
    return distance;
}

/**
 * Private function derived from Prototype.js to get a given element's
 * value that is associated with the passed style
 * @private
 * @param {Object} element The DOM element that will be checked.
 * @param {String} style The style name that will be have it's value returned.
 * @return {Object}
 */
InfoBox.prototype.getStyle_ = function(element, style) {
  var found = false;
  style = this.camelize_(style);
  if (element.id == this.idName && style == 'width' && element.style.display == 'none') {
    element.style.visibility = 'hidden';
    element.style.display = '';
  }
  var value = element.style[style];
  if (!value) {
    if (document.defaultView && document.defaultView.getComputedStyle) {
      var css = document.defaultView.getComputedStyle(element, null);
      value = css ? css[style] : null;
    } else if (element.currentStyle) {
      value = element.currentStyle[style];
    }
  }
  if((value == 'auto') && (style == 'width' || style == 'height') && (this.getStyle_(element, 'display') != 'none')) {
    if( style == 'width' ) {
      value = element.offsetWidth;
    }else {
      value = element.offsetHeight;
    }
  }
  if (element.id == this.idName && style == 'width' && element.style.display != 'none') {
    element.style.display = 'none';
    element.style.visibility = 'visible';  
  }
  return (value == 'auto') ? null : value;
};

/**
 * Private function pulled from Prototype.js that will change a hyphened
 * style name into camel case.
 * @private
 * @param {String} element The string that will be parsed and made into camel case
 * @return {String}
 */
InfoBox.prototype.camelize_ = function(element) {
  var parts = element.split('-'), len = parts.length;
  if (len == 1) return parts[0];
  var camelized = element.charAt(0) == '-'
    ? parts[0].charAt(0).toUpperCase() + parts[0].substring(1)
    : parts[0];

  for (var i = 1; i < len; i++) {
    camelized += parts[i].charAt(0).toUpperCase() + parts[i].substring(1);
  }
  return camelized;
};

InfoBox.prototype.resize = function(){
  
  //Create temporary DOM node for new contents to get new height
  //This is done because if you manipulate this.contentDiv_ directly it causes visual errors in IE6
  var tempElement = this.container_.cloneNode(true);
  tempElement.id = this.infoWindowId_ + '_tempContents';
  tempElement.style.visibility = 'hidden';  
  tempElement.style.height = 'auto';
  document.body.appendChild(tempElement); 
  tempElement = document.getElementById(this.infoWindowId_ + '_tempContents');
  var contentHeight = tempElement.offsetHeight;
  document.body.removeChild(tempElement);

  //Set the new height to eliminate visual defects that can be caused by font resizing in browser
  this.container_.style.height = contentHeight + 'px';

  var contentWidth = this.container_.offsetWidth;
  var pixelLocation = this.map_.fromLatLngToDivPixel(this.marker_.getPoint());

  var oldWindowHeight = this.wrapperParts.t.domElement.offsetHeight + this.wrapperParts.l.domElement.offsetHeight + this.wrapperParts.b.domElement.offsetHeight;  
  var oldWindowPosTop = this.wrapperParts.t.domElement.offsetTop;

  //resize info window to look correct for new height
  this.wrapperParts.l.domElement.style.height = contentHeight + 'px';
  this.wrapperParts.r.domElement.style.height = contentHeight + 'px';
  var newPosTop = this.wrapperParts.b.domElement.offsetTop - contentHeight;
  this.wrapperParts.l.domElement.style.top = newPosTop + 'px';
  this.wrapperParts.r.domElement.style.top = newPosTop + 'px';
  this.container_.style.top = newPosTop + 'px';
  windowTHeight = parseInt(this.wrapperParts.t.domElement.style.height, 10);
  newPosTop -= windowTHeight;
  this.wrapperParts.close.domElement.style.top = newPosTop + this.borderSize_ + 'px';
  this.wrapperParts.tl.domElement.style.top = newPosTop + 'px';
  this.wrapperParts.t.domElement.style.top = newPosTop + 'px';
  this.wrapperParts.tr.domElement.style.top = newPosTop + 'px';

  this.repositionMap_();
};


/**
 * Removes the InfoBox from the map.
 * Is calling after onclick on closeImg to the currently displayed overlay
 */
InfoBox.prototype.close = function () {
  if (this.closeListener_) {

    google.maps.event.removeListener(this.closeListener_);
    this.closeListener_ = null;
  }

  this.setMap(null);
};

/**
 * Invoked when <tt>close</tt> is called. Do not call it directly.
 * Is calling always after call setMap() with parameter null. For example in method clearMyOverlay()
 */
InfoBox.prototype.onRemove = function () {
  if (this.div_) {
    this.div_.parentNode.removeChild(this.div_);
    this.div_ = null;
  }
};

/**
 * Returns the function to call when the user clicks the close box of an InfoBox.
 * @private
 */

// markers array is created by create all markers, this is the best way for clearing markers  
google.maps.Map.prototype.clearMyOverlays = function() {
  while(markers[0]){
     markers.pop().setMap(null);
  }
}

// this method clearing current overlay, is called after onmouseover on other marker
google.maps.Map.prototype.clearMyOverlay = function(marker) {
  marker.setMap(null);  
}


