/* Copyright (c) 2007 Google Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License. 
 *
 *
 * Author: Doug Ricket, others
 * 
 * Marker manager is an interface between the map and the user, designed
 * to manage adding and removing many points when the viewport changes.
 *
 *
 * Algorithm: The MM places its markers onto a grid, similar to the map tiles.
 * When the user moves the viewport, the MM computes which grid cells have
 * entered or left the viewport, and shows or hides all the markers in those
 * cells.
 * (If the users scrolls the viewport beyond the markers that are loaded,
 * no markers will be visible until the EVENT_moveend triggers an update.)
 *
 * In practical consequences, this allows 10,000 markers to be distributed over
 * a large area, and as long as only 100-200 are visible in any given viewport,
 * the user will see good performance corresponding to the 100 visible markers,
 * rather than poor performance corresponding to the total 10,000 markers.
 *
 * Note that some code is optimized for speed over space,
 * with the goal of accommodating thousands of markers.
 *
 */



/**
 * Creates a new MarkerManager that will show/hide markers on a map.
 *
 * @constructor
 * @param {Map} map The map to manage.
 * @param {Object} opt_opts A container for optional arguments:
 *   {Number} maxZoom The maximum zoom level for which to create tiles.
 *   {Number} borderPadding The width in pixels beyond the map border,
 *                   where markers should be display.
 *   {Boolean} trackMarkers Whether or not this manager should track marker
 *                   movements.
 */
function MarkerManager(map, opt_opts) {
  var me = this;
  me.map_ = map;
  me.mapZoom_ = map.getZoom();
  me.projection_ = map.getCurrentMapType().getProjection();

  opt_opts = opt_opts || {};
  me.tileSize_ = MarkerManager.DEFAULT_TILE_SIZE_;
  
  var maxZoom = MarkerManager.DEFAULT_MAX_ZOOM_;
  if(opt_opts.maxZoom != undefined) {
    maxZoom = opt_opts.maxZoom;
  }
  me.maxZoom_ = maxZoom;

  me.trackMarkers_ = opt_opts.trackMarkers;

  var padding;
  if (typeof opt_opts.borderPadding == "number") {
    padding = opt_opts.borderPadding;
  } else {
    padding = MarkerManager.DEFAULT_BORDER_PADDING_;
  }
  // The padding in pixels beyond the viewport, where we will pre-load markers.
  me.swPadding_ = new GSize(-padding, padding);
  me.nePadding_ = new GSize(padding, -padding);
  me.borderPadding_ = padding;

  me.gridWidth_ = [];

  me.grid_ = [];
  me.grid_[maxZoom] = [];
  me.numMarkers_ = [];
  me.numMarkers_[maxZoom] = 0;

  GEvent.bind(map, "moveend", me, me.onMapMoveEnd_);

  // NOTE: These two closures provide easy access to the map.
  // They are used as callbacks, not as methods.
  me.removeOverlay_ = function(marker) {
    marker.hide();
    map.removeOverlay(marker);
    me.shownMarkers_--;
  };
  me.addOverlay_ = function(marker) {
    map.addOverlay(marker);
    if(marker.isHidden()){marker.hide();}
    me.shownMarkers_++;
  };

  me.resetManager_();
  me.shownMarkers_ = 0;

  me.shownBounds_ = me.getMapGridBounds_();
};

// Static constants:
MarkerManager.DEFAULT_TILE_SIZE_ = 1024;
MarkerManager.DEFAULT_MAX_ZOOM_ = 17;
MarkerManager.DEFAULT_BORDER_PADDING_ = 100;
MarkerManager.MERCATOR_ZOOM_LEVEL_ZERO_RANGE = 256;


/**
 * Initializes MarkerManager arrays for all zoom levels
 * Called by constructor and by clearAllMarkers
 */ 
MarkerManager.prototype.resetManager_ = function() {
  var me = this;
  var mapWidth = MarkerManager.MERCATOR_ZOOM_LEVEL_ZERO_RANGE;
  for (var zoom = 0; zoom <= me.maxZoom_; ++zoom) {
    me.grid_[zoom] = [];
    me.numMarkers_[zoom] = 0;
    me.gridWidth_[zoom] = Math.ceil(mapWidth/me.tileSize_);
    mapWidth <<= 1;
  }
};

/**
 * Removes all currently displayed markers
 * and calls resetManager to clear arrays
 */
MarkerManager.prototype.clearMarkers = function() {
  var me = this;
  me.processAll_(me.shownBounds_, me.removeOverlay_);
  me.resetManager_();
};


/**
 * Gets the tile coordinate for a given latlng point.
 *
 * @param {LatLng} latlng The geographical point.
 * @param {Number} zoom The zoom level.
 * @param {GSize} padding The padding used to shift the pixel coordinate.
 *               Used for expanding a bounds to include an extra padding
 *               of pixels surrounding the bounds.
 * @return {GPoint} The point in tile coordinates.
 *
 */
MarkerManager.prototype.getTilePoint_ = function(latlng, zoom, padding) {
  var pixelPoint = this.projection_.fromLatLngToPixel(latlng, zoom);
  return new GPoint(
      Math.floor((pixelPoint.x + padding.width) / this.tileSize_),
      Math.floor((pixelPoint.y + padding.height) / this.tileSize_));
};


/**
 * Finds the appropriate place to add the marker to the grid.
 * Optimized for speed; does not actually add the marker to the map.
 * Designed for batch-processing thousands of markers.
 *
 * @param {Marker} marker The marker to add.
 * @param {Number} minZoom The minimum zoom for displaying the marker.
 * @param {Number} maxZoom The maximum zoom for displaying the marker.
 */
MarkerManager.prototype.addMarkerBatch_ = function(marker, minZoom, maxZoom) {
  var mPoint = marker.getPoint();
  // Tracking markers is expensive, so we do this only if the
  // user explicitly requested it when creating marker manager.
  if (this.trackMarkers_) {
    GEvent.bind(marker, "changed", this, this.onMarkerMoved_);
  }
  var gridPoint = this.getTilePoint_(mPoint, maxZoom, GSize.ZERO);

  for (var zoom = maxZoom; zoom >= minZoom; zoom--) {
    var cell = this.getGridCellCreate_(gridPoint.x, gridPoint.y, zoom);
    cell.push(marker);

    gridPoint.x = gridPoint.x >> 1;
    gridPoint.y = gridPoint.y >> 1;
  }
};


/**
 * Returns whether or not the given point is visible in the shown bounds. This
 * is a helper method that takes care of the corner case, when shownBounds have
 * negative minX value.
 *
 * @param {Point} point a point on a grid.
 * @return {Boolean} Whether or not the given point is visible in the currently
 * shown bounds.
 */
MarkerManager.prototype.isGridPointVisible_ = function(point) {
  var me = this;
  var vertical = me.shownBounds_.minY <= point.y &&
      point.y <= me.shownBounds_.maxY;
  var minX = me.shownBounds_.minX;
  var horizontal = minX <= point.x && point.x <= me.shownBounds_.maxX;
  if (!horizontal && minX < 0) {
    // Shifts the negative part of the rectangle. As point.x is always less
    // than grid width, only test shifted minX .. 0 part of the shown bounds.
    var width = me.gridWidth_[me.shownBounds_.z];
    horizontal = minX + width <= point.x && point.x <= width - 1;
  }
  return vertical && horizontal;
}


/**
 * Reacts to a notification from a marker that it has moved to a new location.
 * It scans the grid all all zoom levels and moves the marker from the old grid
 * location to a new grid location.
 *
 * @param {Marker} marker The marker that moved.
 * @param {LatLng} oldPoint The old position of the marker.
 * @param {LatLng} newPoint The new position of the marker.
 */
MarkerManager.prototype.onMarkerMoved_ = function(marker, oldPoint, newPoint) {
  // NOTE: We do not know the minimum or maximum zoom the marker was
  // added at, so we start at the absolute maximum. Whenever we successfully
  // remove a marker at a given zoom, we add it at the new grid coordinates.
  var me = this;
  var zoom = me.maxZoom_;
  var changed = false;
  var oldGrid = me.getTilePoint_(oldPoint, zoom, GSize.ZERO);
  var newGrid = me.getTilePoint_(newPoint, zoom, GSize.ZERO);
  while (zoom >= 0 && (oldGrid.x != newGrid.x || oldGrid.y != newGrid.y)) {
    var cell = me.getGridCellNoCreate_(oldGrid.x, oldGrid.y, zoom);
    if (cell) {
      if (me.removeFromArray(cell, marker)) {
        me.getGridCellCreate_(newGrid.x, newGrid.y, zoom).push(marker);
      }
    }
    // For the current zoom we also need to update the map. Markers that no
    // longer are visible are removed from the map. Markers that moved into
    // the shown bounds are added to the map. This also lets us keep the count
    // of visible markers up to date.
    if (zoom == me.mapZoom_) {
      if (me.isGridPointVisible_(oldGrid)) {
        if (!me.isGridPointVisible_(newGrid)) {
          me.removeOverlay_(marker);
          changed = true;
        }
      } else {
        if (me.isGridPointVisible_(newGrid)) {
          me.addOverlay_(marker);
          changed = true;
        }
      }
    }
    oldGrid.x = oldGrid.x >> 1;
    oldGrid.y = oldGrid.y >> 1;
    newGrid.x = newGrid.x >> 1;
    newGrid.y = newGrid.y >> 1;
    --zoom;
  }
  if (changed) {
    me.notifyListeners_();
  }
};


/**
 * Searches at every zoom level to find grid cell
 * that marker would be in, removes from that array if found.
 * Also removes marker with removeOverlay if visible.
 * @param {GMarker} marker The marker to delete.
 */
MarkerManager.prototype.removeMarker = function(marker) {
  var me = this;
  var zoom = me.maxZoom_;
  var changed = false;
  var point = marker.getPoint();
  var grid = me.getTilePoint_(point, zoom, GSize.ZERO);
  while (zoom >= 0) {
    var cell = me.getGridCellNoCreate_(grid.x, grid.y, zoom);

    if (cell) {
      me.removeFromArray(cell, marker);
    }
    // For the current zoom we also need to update the map. Markers that no
    // longer are visible are removed from the map. This also lets us keep the count
    // of visible markers up to date.
    if (zoom == me.mapZoom_) {
      if (me.isGridPointVisible_(grid)) {
          me.removeOverlay_(marker);
          changed = true;
      } 
    }
    grid.x = grid.x >> 1;
    grid.y = grid.y >> 1;
    --zoom;
  }
  if (changed) {
    me.notifyListeners_();
  }
};


/**
 * Add many markers at once.
 * Does not actually update the map, just the internal grid.
 *
 * @param {Array of Marker} markers The markers to add.
 * @param {Number} minZoom The minimum zoom level to display the markers.
 * @param {Number} opt_maxZoom The maximum zoom level to display the markers.
 */
MarkerManager.prototype.addMarkers = function(markers, minZoom, opt_maxZoom) {
  var maxZoom = this.getOptMaxZoom_(opt_maxZoom);
  for (var i = markers.length - 1; i >= 0; i--) {
    this.addMarkerBatch_(markers[i], minZoom, maxZoom);
  }

  this.numMarkers_[minZoom] += markers.length;
};


/**
 * Returns the value of the optional maximum zoom. This method is defined so
 * that we have just one place where optional maximum zoom is calculated.
 *
 * @param {Number} opt_maxZoom The optinal maximum zoom.
 * @return The maximum zoom.
 */
MarkerManager.prototype.getOptMaxZoom_ = function(opt_maxZoom) {
  return opt_maxZoom != undefined ? opt_maxZoom : this.maxZoom_;
}


/**
 * Calculates the total number of markers potentially visible at a given
 * zoom level.
 *
 * @param {Number} zoom The zoom level to check.
 */
MarkerManager.prototype.getMarkerCount = function(zoom) {
  var total = 0;
  for (var z = 0; z <= zoom; z++) {
    total += this.numMarkers_[z];
  }
  return total;
};


/**
 * Add a single marker to the map.
 *
 * @param {Marker} marker The marker to add.
 * @param {Number} minZoom The minimum zoom level to display the marker.
 * @param {Number} opt_maxZoom The maximum zoom level to display the marker.
 */
MarkerManager.prototype.addMarker = function(marker, minZoom, opt_maxZoom) {
  var me = this;
  var maxZoom = this.getOptMaxZoom_(opt_maxZoom);
  me.addMarkerBatch_(marker, minZoom, maxZoom);
  var gridPoint = me.getTilePoint_(marker.getPoint(), me.mapZoom_, GSize.ZERO);
  if(me.isGridPointVisible_(gridPoint) && 
     minZoom <= me.shownBounds_.z &&
     me.shownBounds_.z <= maxZoom ) {
    me.addOverlay_(marker);
    me.notifyListeners_();
  }
  this.numMarkers_[minZoom]++;
};

/**
 * Returns true if this bounds (inclusively) contains the given point.
 * @param {Point} point  The point to test.
 * @return {Boolean} This Bounds contains the given Point.
 */
GBounds.prototype.containsPoint = function(point) {
  var outer = this;
  return (outer.minX <= point.x &&
          outer.maxX >= point.x &&
          outer.minY <= point.y &&
          outer.maxY >= point.y);
}

/**
 * Get a cell in the grid, creating it first if necessary.
 *
 * Optimization candidate
 *
 * @param {Number} x The x coordinate of the cell.
 * @param {Number} y The y coordinate of the cell.
 * @param {Number} z The z coordinate of the cell.
 * @return {Array} The cell in the array.
 */
MarkerManager.prototype.getGridCellCreate_ = function(x, y, z) {
  var grid = this.grid_[z];
  if (x < 0) {
    x += this.gridWidth_[z];
  }
  var gridCol = grid[x];
  if (!gridCol) {
    gridCol = grid[x] = [];
    return gridCol[y] = [];
  }
  var gridCell = gridCol[y];
  if (!gridCell) {
    return gridCol[y] = [];
  }
  return gridCell;
};


/**
 * Get a cell in the grid, returning undefined if it does not exist.
 *
 * NOTE: Optimized for speed -- otherwise could combine with getGridCellCreate_.
 *
 * @param {Number} x The x coordinate of the cell.
 * @param {Number} y The y coordinate of the cell.
 * @param {Number} z The z coordinate of the cell.
 * @return {Array} The cell in the array.
 */
MarkerManager.prototype.getGridCellNoCreate_ = function(x, y, z) {
  var grid = this.grid_[z];
  if (x < 0) {
    x += this.gridWidth_[z];
  }
  var gridCol = grid[x];
  return gridCol ? gridCol[y] : undefined;
};


/**
 * Turns at geographical bounds into a grid-space bounds.
 *
 * @param {LatLngBounds} bounds The geographical bounds.
 * @param {Number} zoom The zoom level of the bounds.
 * @param {GSize} swPadding The padding in pixels to extend beyond the
 * given bounds.
 * @param {GSize} nePadding The padding in pixels to extend beyond the
 * given bounds.
 * @return {GBounds} The bounds in grid space.
 */
MarkerManager.prototype.getGridBounds_ = function(bounds, zoom, swPadding,
                                                  nePadding) {
  zoom = Math.min(zoom, this.maxZoom_);
  
  var bl = bounds.getSouthWest();
  var tr = bounds.getNorthEast();
  var sw = this.getTilePoint_(bl, zoom, swPadding);
  var ne = this.getTilePoint_(tr, zoom, nePadding);
  var gw = this.gridWidth_[zoom];
  
  // Crossing the prime meridian requires correction of bounds.
  if (tr.lng() < bl.lng() || ne.x < sw.x) {
    sw.x -= gw;
  }
  if (ne.x - sw.x  + 1 >= gw) {
    // Computed grid bounds are larger than the world; truncate.
    sw.x = 0;
    ne.x = gw - 1;
  }
  var gridBounds = new GBounds([sw, ne]);
  gridBounds.z = zoom;
  return gridBounds;
};


/**
 * Gets the grid-space bounds for the current map viewport.
 *
 * @return {Bounds} The bounds in grid space.
 */
MarkerManager.prototype.getMapGridBounds_ = function() {
  var me = this;
  return me.getGridBounds_(me.map_.getBounds(), me.mapZoom_,
                           me.swPadding_, me.nePadding_);
};


/**
 * Event listener for map:movend.
 * NOTE: Use a timeout so that the user is not blocked
 * from moving the map.
 *
 */
MarkerManager.prototype.onMapMoveEnd_ = function() {
  var me = this;
  me.objectSetTimeout_(this, this.updateMarkers_, 0);
};


/**
 * Call a function or evaluate an expression after a specified number of
 * milliseconds.
 *
 * Equivalent to the standard window.setTimeout function, but the given
 * function executes as a method of this instance. So the function passed to
 * objectSetTimeout can contain references to this.
 *    objectSetTimeout(this, function() { alert(this.x) }, 1000);
 *
 * @param {Object} object  The target object.
 * @param {Function} command  The command to run.
 * @param {Number} milliseconds  The delay.
 * @return {Boolean}  Success.
 */
MarkerManager.prototype.objectSetTimeout_ = function(object, command, milliseconds) {
  return window.setTimeout(function() {
    command.call(object);
  }, milliseconds);
};


/**
 * Refresh forces the marker-manager into a good state.
 * <ol>
 *   <li>If never before initialized, shows all the markers.</li>
 *   <li>If previously initialized, removes and re-adds all markers.</li>
 * </ol>
 */
MarkerManager.prototype.refresh = function() {
  var me = this;
  if (me.shownMarkers_ > 0) {
    me.processAll_(me.shownBounds_, me.removeOverlay_);
  }
  me.processAll_(me.shownBounds_, me.addOverlay_);
  me.notifyListeners_();
};


/**
 * After the viewport may have changed, add or remove markers as needed.
 */
MarkerManager.prototype.updateMarkers_ = function() {
  var me = this;
  me.mapZoom_ = this.map_.getZoom();
  var newBounds = me.getMapGridBounds_();
  
  // If the move does not include new grid sections,
  // we have no work to do:
  if (newBounds.equals(me.shownBounds_) && newBounds.z == me.shownBounds_.z) {
    return;
  }

  if (newBounds.z != me.shownBounds_.z) {
    me.processAll_(me.shownBounds_, me.removeOverlay_);
    me.processAll_(newBounds, me.addOverlay_);
  } else {
    // Remove markers:
    me.rectangleDiff_(me.shownBounds_, newBounds, me.removeCellMarkers_);

    // Add markers:
    me.rectangleDiff_(newBounds, me.shownBounds_, me.addCellMarkers_);
  }
  me.shownBounds_ = newBounds;

  me.notifyListeners_();
};


/**
 * Notify listeners when the state of what is displayed changes.
 */
MarkerManager.prototype.notifyListeners_ = function() {
  GEvent.trigger(this, "changed", this.shownBounds_, this.shownMarkers_);
};


/**
 * Process all markers in the bounds provided, using a callback.
 *
 * @param {Bounds} bounds The bounds in grid space.
 * @param {Function} callback The function to call for each marker.
 */
MarkerManager.prototype.processAll_ = function(bounds, callback) {
  for (var x = bounds.minX; x <= bounds.maxX; x++) {
    for (var y = bounds.minY; y <= bounds.maxY; y++) {
      this.processCellMarkers_(x, y,  bounds.z, callback);
    }
  }
};


/**
 * Process all markers in the grid cell, using a callback.
 *
 * @param {Number} x The x coordinate of the cell.
 * @param {Number} y The y coordinate of the cell.
 * @param {Number} z The z coordinate of the cell.
 * @param {Function} callback The function to call for each marker.
 */
MarkerManager.prototype.processCellMarkers_ = function(x, y, z, callback) {
  var cell = this.getGridCellNoCreate_(x, y, z);
  if (cell) {
    for (var i = cell.length - 1; i >= 0; i--) {
      callback(cell[i]);
    }
  }
};


/**
 * Remove all markers in a grid cell.
 *
 * @param {Number} x The x coordinate of the cell.
 * @param {Number} y The y coordinate of the cell.
 * @param {Number} z The z coordinate of the cell.
 */
MarkerManager.prototype.removeCellMarkers_ = function(x, y, z) {
  this.processCellMarkers_(x, y, z, this.removeOverlay_);
};


/**
 * Add all markers in a grid cell.
 *
 * @param {Number} x The x coordinate of the cell.
 * @param {Number} y The y coordinate of the cell.
 * @param {Number} z The z coordinate of the cell.
 */
MarkerManager.prototype.addCellMarkers_ = function(x, y, z) {
  this.processCellMarkers_(x, y, z, this.addOverlay_);
};


/**
 * Use the rectangleDiffCoords function to process all grid cells
 * that are in bounds1 but not bounds2, using a callback, and using
 * the current MarkerManager object as the instance.
 *
 * Pass the z parameter to the callback in addition to x and y.
 *
 * @param {Bounds} bounds1 The bounds of all points we may process.
 * @param {Bounds} bounds2 The bounds of points to exclude.
 * @param {Function} callback The callback function to call
 *                   for each grid coordinate (x, y, z).
 */
MarkerManager.prototype.rectangleDiff_ = function(bounds1, bounds2, callback) {
  var me = this;
  me.rectangleDiffCoords(bounds1, bounds2, function(x, y) {
    callback.apply(me, [x, y, bounds1.z]);
  });
};


/**
 * Calls the function for all points in bounds1, not in bounds2
 *
 * @param {Bounds} bounds1 The bounds of all points we may process.
 * @param {Bounds} bounds2 The bounds of points to exclude.
 * @param {Function} callback The callback function to call
 *                   for each grid coordinate.
 */
MarkerManager.prototype.rectangleDiffCoords = function(bounds1, bounds2, callback) {
  var minX1 = bounds1.minX;
  var minY1 = bounds1.minY;
  var maxX1 = bounds1.maxX;
  var maxY1 = bounds1.maxY;
  var minX2 = bounds2.minX;
  var minY2 = bounds2.minY;
  var maxX2 = bounds2.maxX;
  var maxY2 = bounds2.maxY;

  for (var x = minX1; x <= maxX1; x++) {  // All x in R1
    // All above:
    for (var y = minY1; y <= maxY1 && y < minY2; y++) {  // y in R1 above R2
      callback(x, y);
    }
    // All below:
    for (var y = Math.max(maxY2 + 1, minY1);  // y in R1 below R2
         y <= maxY1; y++) {
      callback(x, y);
    }
  }

  for (var y = Math.max(minY1, minY2);
       y <= Math.min(maxY1, maxY2); y++) {  // All y in R2 and in R1
    // Strictly left:
    for (var x = Math.min(maxX1 + 1, minX2) - 1;
         x >= minX1; x--) {  // x in R1 left of R2
      callback(x, y);
    }
    // Strictly right:
    for (var x = Math.max(minX1, maxX2 + 1);  // x in R1 right of R2
         x <= maxX1; x++) {
      callback(x, y);
    }
  }
};


/**
 * Removes value from array. O(N).
 *
 * @param {Array} array  The array to modify.
 * @param {any} value  The value to remove.
 * @param {Boolean} opt_notype  Flag to disable type checking in equality.
 * @return {Number}  The number of instances of value that were removed.
 */
MarkerManager.prototype.removeFromArray = function(array, value, opt_notype) {
  var shift = 0;
  for (var i = 0; i < array.length; ++i) {
    if (array[i] === value || (opt_notype && array[i] == value)) {
      array.splice(i--, 1);
      shift++;
    }
  }
  return shift;
};




// A TextualZoomControl is a GControl that displays textual "Zoom In"
 // and "Zoom Out" buttons (as opposed to the iconic buttons used in
 // Google Maps).
 // dev. By Endri D., Hamburg, 2008
     function MyNavigationControl() {
     }
     MyNavigationControl.prototype = new GControl();

     // Creates a one DIV for each of the buttons and places them in a container
     // DIV which is returned as our control element. We add the control to
     // to the map container and return the element for the map class to
     // position properly.
     MyNavigationControl.prototype.initialize = function(map) {
         var container = document.createElement("div");
         container.style.textAlign="center";
         container.style.width="40px";
         
         var navContainer = document.createElement("div");
         navContainer.style.width="40px";
         navContainer.style.height="60px";
         
         var upDiv = document.createElement("div");
         this.setButtonStyle_(upDiv);
         upDiv.style.position="absolute"; 
         upDiv.style.left="10px"; 
         upDiv.style.backgroundImage="url(img/up.png)"; 
         upDiv.style.backgroundRepeat="no-repeat"; 
         navContainer.appendChild(upDiv);
         GEvent.addDomListener(upDiv, "click", function() {
             map.panDirection(0,1);
         }); 
         
         var navLRContainer = document.createElement("div");
         navLRContainer.style.width="40px";
         navLRContainer.style.height="20px";
         navLRContainer.style.position="absolute"; 
         navLRContainer.style.left="0px"; 
         navLRContainer.style.top="20px"; 
         
         var leftDiv = document.createElement("div");
         this.setButtonStyle_(leftDiv);
         leftDiv.style.position="absolute"; 
         leftDiv.style.left="0px"; 
         leftDiv.style.backgroundImage="url(img/left.png)"; 
         leftDiv.style.backgroundRepeat="no-repeat"; 
         navLRContainer.appendChild(leftDiv);
         GEvent.addDomListener(leftDiv, "click", function() {
             map.panDirection(1,0);
         });

         var rightDiv = document.createElement("div");
         this.setButtonStyle_(rightDiv);
         rightDiv.style.position="absolute"; 
         rightDiv.style.left="20px"; 
         rightDiv.style.backgroundImage="url(img/right.png)"; 
         rightDiv.style.backgroundRepeat="no-repeat"; 
         navLRContainer.appendChild(rightDiv);
         GEvent.addDomListener(rightDiv, "click", function() {
             map.panDirection(-1,0);
         }); 
         
         navContainer.appendChild(navLRContainer);
         
         var downDiv = document.createElement("div");
         this.setButtonStyle_(downDiv);
         downDiv.style.position="absolute"; 
         downDiv.style.left="10px"; 
         downDiv.style.top="40px"; 
         downDiv.style.backgroundImage="url(img/down.png)"; 
         downDiv.style.backgroundRepeat="no-repeat"; 
         navContainer.appendChild(downDiv);
         GEvent.addDomListener(downDiv, "click", function() {
             map.panDirection(0,-1);
         });

         
         
         var zoomContainer = document.createElement("div");
         zoomContainer.style.margin="auto";
         zoomContainer.style.width="20px";
         var zoomInDiv = document.createElement("div");
         this.setButtonStyle_(zoomInDiv);
         zoomInDiv.style.backgroundImage="url(img/in.png)"; 
         zoomInDiv.style.backgroundRepeat="no-repeat"; 
         zoomInDiv.style.paddingBottom="1px"; 
         zoomContainer.appendChild(zoomInDiv);
         GEvent.addDomListener(zoomInDiv, "click", function() {
             map.zoomIn();
         });

        var zoomOutDiv = document.createElement("div");
        this.setButtonStyle_(zoomOutDiv);
        zoomOutDiv.style.backgroundImage="url(img/out.png)"; 
        zoomOutDiv.style.backgroundRepeat="no-repeat"; 
        zoomContainer.appendChild(zoomOutDiv);
        GEvent.addDomListener(zoomOutDiv, "click", function() {
            map.zoomOut();
        });
        container.appendChild(navContainer);
        container.appendChild(zoomContainer);
        map.getContainer().appendChild(container);
        return container;
    }

    // By default, the control will appear in the top left corner of the
    // map with 7 pixels of padding.
    MyNavigationControl.prototype.getDefaultPosition = function() {
        return new GControlPosition(G_ANCHOR_TOP_LEFT, new GSize(7, 7));
    }

    // Sets the proper CSS for the given button element.
    MyNavigationControl.prototype.setButtonStyle_ = function(button) {
        button.style.textAlign = "center";
        button.style.width = "20px";
        button.style.height = "20px";
        button.style.cursor = "pointer";
    }

    function MySmallNavigationControl() {}
    MySmallNavigationControl.prototype = new GControl();
    MySmallNavigationControl.prototype.setButtonStyle_ = function(button) {
        button.style.textAlign = "center";
        button.style.width = "20px";
        button.style.height = "20px";
        button.style.cursor = "pointer";
    }
    MySmallNavigationControl.prototype.initialize = function(map) {
         var zoomContainer = document.createElement("div");
         zoomContainer.style.margin="auto";
         zoomContainer.style.width="20px";
         var zoomInDiv = document.createElement("div");
         this.setButtonStyle_(zoomInDiv);
         zoomInDiv.style.backgroundImage="url(img/in.png)"; 
         zoomInDiv.style.backgroundRepeat="no-repeat"; 
         zoomInDiv.style.paddingBottom="1px"; 
         zoomContainer.appendChild(zoomInDiv);
         GEvent.addDomListener(zoomInDiv, "click", function() {
             map.zoomIn();
         });

        var zoomOutDiv = document.createElement("div");
        this.setButtonStyle_(zoomOutDiv);
        zoomOutDiv.style.backgroundImage="url(img/out.png)"; 
        zoomOutDiv.style.backgroundRepeat="no-repeat"; 
        zoomContainer.appendChild(zoomOutDiv);
        GEvent.addDomListener(zoomOutDiv, "click", function() {
            map.zoomOut();
        });
        map.getContainer().appendChild(zoomContainer);
        return zoomContainer;
    } 
    MySmallNavigationControl.prototype.getDefaultPosition = function() {
        return new GControlPosition(G_ANCHOR_TOP_LEFT, new GSize(7, 7));
    }

 
     function MyTypeControl() {}
     MyTypeControl.prototype = new GControl();

     // Creates a one DIV for each of the buttons and places them in a container
     // DIV which is returned as our control element. We add the control to
     // to the map container and return the element for the map class to
     // position properly.
     MyTypeControl.prototype.initialize = function(map) {
         var container = document.createElement("div");
         container.style.width = "170px";
         container.style.height = "24px";
         
         var upDiv = document.createElement("div");
         this.setButtonStyle_(upDiv);
         upDiv.style.position="absolute"; 
         upDiv.style.left="0px"; 
         upDiv.appendChild(document.createTextNode("harta"));
         container.appendChild(upDiv);
         GEvent.addDomListener(upDiv, "click", function() {
             map.setMapType(G_NORMAL_MAP);
         }); 
         
         
         var downDiv = document.createElement("div");
         this.setButtonStyle_(downDiv);
         downDiv.style.position="absolute"; 
         downDiv.style.left="70px"; 
         downDiv.appendChild(document.createTextNode("hibrid"));
         container.appendChild(downDiv);
         GEvent.addDomListener(downDiv, "click", function() {
             map.setMapType(G_HYBRID_MAP);
         });

         var downDiv = document.createElement("div");
         downDiv.style.position="absolute"; 
         downDiv.style.left="140px"; 
         downDiv.style.cursor = "pointer";
         downDiv.title = "Regjistro kanalin RSS per zonen  gjeografike te dukshme ne harte.";
         var rssImg = document.createElement("img");
	 rssImg.src="img/rss.png";
	 downDiv.appendChild(rssImg);
         container.appendChild(downDiv);
         GEvent.addDomListener(downDiv, "click", function() {
             var sw = map.getBounds().getSouthWest();
             var ne = map.getBounds().getNorthEast();
             //location.href="rss.php?type=georss&BBOUNDS="+sw.lng()+","+sw.lat()+","+ne.lng()+","+ne.lat();
             location.href="/rss/georss/"+sw.lng()+","+sw.lat()+","+ne.lng()+","+ne.lat()+"/";
          });


         map.getContainer().appendChild(container);
         return container;
     }

     // By default, the control will appear in the top left corner of the
     // map with 7 pixels of padding.
     MyTypeControl.prototype.getDefaultPosition = function() {
         return new GControlPosition(G_ANCHOR_TOP_RIGHT, new GSize(7, 7));
     }

     // Sets the proper CSS for the given button element.
     MyTypeControl.prototype.setButtonStyle_ = function(button) {
         button.style.backgroundImage="url(img/types.png)"; 
         button.style.backgroundRepeat="no-repeat"; 
         button.style.width = "69px";
         button.style.height = "22px";
         button.style.verticalAlign = "middle";
         button.style.lineHeight = "17px";
         button.style.color = "#ffffff";
         button.style.textAlign = "center";
         button.style.fontFamily = "Verdana";
         button.style.fontSize = "8pt";
         button.style.fontWeight = "bold";
         button.style.cursor = "pointer";
     }
 
 
 
     
     /*----------------------------------------------------------------------------\
|                                Range Class                                  |
|-----------------------------------------------------------------------------|
|                         Created by Erik Arvidsson                           |
|                  (http://webfx.eae.net/contact.html#erik)                   |
|                      For WebFX (http://webfx.eae.net/)                      |
|-----------------------------------------------------------------------------|
| Used to  model the data  used  when working  with  sliders,  scrollbars and |
| progress bars.  Based  on  the  ideas of  the javax.swing.BoundedRangeModel |
| interface  defined  by  Sun  for  Java;   http://java.sun.com/products/jfc/ |
| swingdoc-api-1.0.3/com/sun/java/swing/BoundedRangeModel.html                |
|-----------------------------------------------------------------------------|
|                Copyright (c) 2002, 2005, 2006 Erik Arvidsson                |
|-----------------------------------------------------------------------------|
| Licensed under the Apache License, Version 2.0 (the "License"); you may not |
| use this file except in compliance with the License.  You may obtain a copy |
| of the License at http://www.apache.org/licenses/LICENSE-2.0                |
| - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
| Unless  required  by  applicable law or  agreed  to  in  writing,  software |
| distributed under the License is distributed on an  "AS IS" BASIS,  WITHOUT |
| WARRANTIES OR  CONDITIONS OF ANY KIND,  either express or implied.  See the |
| License  for the  specific language  governing permissions  and limitations |
| under the License.                                                          |
|-----------------------------------------------------------------------------|
| 2002-10-14 | Original version released                                      |
| 2005-10-27 | Use Math.round instead of Math.floor                           |
| 2006-05-28 | Changed license to Apache Software License 2.0.                |
|-----------------------------------------------------------------------------|
| Created 2002-10-14 | All changes are in the log above. | Updated 2006-05-28 |
\----------------------------------------------------------------------------*/


function Range() {
	this._value = 0;
	this._minimum = 0;
	this._maximum = 100;
	this._extent = 0;

	this._isChanging = false;
}

Range.prototype.setValue = function (value) {
	value = Math.round(parseFloat(value));
	if (isNaN(value)) return;
	if (this._value != value) {
		if (value + this._extent > this._maximum)
			this._value = this._maximum - this._extent;
		else if (value < this._minimum)
			this._value = this._minimum;
		else
			this._value = value;
		if (!this._isChanging && typeof this.onchange == "function")
			 this.onchange();
	}
};

Range.prototype.getValue = function () {
	return this._value;
};

Range.prototype.setExtent = function (extent) {
	if (this._extent != extent) {
		if (extent < 0)
			this._extent = 0;
		else if (this._value + extent > this._maximum)
			this._extent = this._maximum - this._value;
		else
			this._extent = extent;
		if (!this._isChanging && typeof this.onchange == "function")
			this.onchange();
	}
};

Range.prototype.getExtent = function () {
	return this._extent;
};

Range.prototype.setMinimum = function (minimum) {
	if (this._minimum != minimum) {
		var oldIsChanging = this._isChanging;
		this._isChanging = true;

		this._minimum = minimum;

		if (minimum > this._value)
			this.setValue(minimum);
		if (minimum > this._maximum) {
			this._extent = 0;
			this.setMaximum(minimum);
			this.setValue(minimum)
		}
		if (minimum + this._extent > this._maximum)
			this._extent = this._maximum - this._minimum;

		this._isChanging = oldIsChanging;
		if (!this._isChanging && typeof this.onchange == "function")
			this.onchange();
	}
};

Range.prototype.getMinimum = function () {
	return this._minimum;
};

Range.prototype.setMaximum = function (maximum) {
	if (this._maximum != maximum) {
		var oldIsChanging = this._isChanging;
		this._isChanging = true;

		this._maximum = maximum;

		if (maximum < this._value)
			this.setValue(maximum - this._extent);
		if (maximum < this._minimum) {
			this._extent = 0;
			this.setMinimum(maximum);
			this.setValue(this._maximum);
		}
		if (maximum < this._minimum + this._extent)
			this._extent = this._maximum - this._minimum;
		if (maximum < this._value + this._extent)
			this._extent = this._maximum - this._value;

		this._isChanging = oldIsChanging;
		if (!this._isChanging && typeof this.onchange == "function")
			this.onchange();
	}
};

Range.prototype.getMaximum = function () {
	return this._maximum;
};


/*----------------------------------------------------------------------------\
|                                 Timer Class                                 |
|-----------------------------------------------------------------------------|
|                         Created by Erik Arvidsson                           |
|                  (http://webfx.eae.net/contact.html#erik)                   |
|                      For WebFX (http://webfx.eae.net/)                      |
|-----------------------------------------------------------------------------|
| Object Oriented Encapsulation  of setTimeout  fires ontimer when the  timer |
| is triggered. Does not work in IE 5.00                                      |
|-----------------------------------------------------------------------------|
|                   Copyright (c) 2002, 2006 Erik Arvidsson                   |
|-----------------------------------------------------------------------------|
| Licensed under the Apache License, Version 2.0 (the "License"); you may not |
| use this file except in compliance with the License.  You may obtain a copy |
| of the License at http://www.apache.org/licenses/LICENSE-2.0                |
| - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
| Unless  required  by  applicable law or  agreed  to  in  writing,  software |
| distributed under the License is distributed on an  "AS IS" BASIS,  WITHOUT |
| WARRANTIES OR  CONDITIONS OF ANY KIND,  either express or implied.  See the |
| License  for the  specific language  governing permissions  and limitations |
| under the License.                                                          |
|-----------------------------------------------------------------------------|
| 2002-10-14 | Original version released                                      |
| 2006-05-28 | Changed license to Apache Software License 2.0.                |
|-----------------------------------------------------------------------------|
| Created 2002-10-14 | All changes are in the log above. | Updated 2006-05-28 |
\----------------------------------------------------------------------------*/

function Timer(nPauseTime) {
	this._pauseTime = typeof nPauseTime == "undefined" ? 1000 : nPauseTime;
	this._timer = null;
	this._isStarted = false;
}

Timer.prototype.start = function () {
	if (this.isStarted())
		this.stop();
	var oThis = this;
	this._timer = window.setTimeout(function () {
		if (typeof oThis.ontimer == "function")
			oThis.ontimer();
	}, this._pauseTime);
	this._isStarted = true;
};

Timer.prototype.stop = function () {
	if (this._timer != null)
		window.clearTimeout(this._timer);
	this._isStarted = false;
};

Timer.prototype.isStarted = function () {
	return this._isStarted;
};

Timer.prototype.getPauseTime = function () {
	return this._pauseTime;
};

Timer.prototype.setPauseTime = function (nPauseTime) {
	this._pauseTime = nPauseTime;
};


/*----------------------------------------------------------------------------\
|                                Slider 1.02                                  |
|-----------------------------------------------------------------------------|
|                         Created by Erik Arvidsson                           |
|                  (http://webfx.eae.net/contact.html#erik)                   |
|                      For WebFX (http://webfx.eae.net/)                      |
|-----------------------------------------------------------------------------|
| A  slider  control that  degrades  to an  input control  for non  supported |
| browsers.                                                                   |
|-----------------------------------------------------------------------------|
|                Copyright (c) 2002, 2003, 2006 Erik Arvidsson                |
|-----------------------------------------------------------------------------|
| Licensed under the Apache License, Version 2.0 (the "License"); you may not |
| use this file except in compliance with the License.  You may obtain a copy |
| of the License at http://www.apache.org/licenses/LICENSE-2.0                |
| - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
| Unless  required  by  applicable law or  agreed  to  in  writing,  software |
| distributed under the License is distributed on an  "AS IS" BASIS,  WITHOUT |
| WARRANTIES OR  CONDITIONS OF ANY KIND,  either express or implied.  See the |
| License  for the  specific language  governing permissions  and limitations |
| under the License.                                                          |
|-----------------------------------------------------------------------------|
| Dependencies: timer.js - an OO abstraction of timers                        |
|               range.js - provides the data model for the slider             |
|               winclassic.css or any other css file describing the look      |
|-----------------------------------------------------------------------------|
| 2002-10-14 | Original version released                                      |
| 2003-03-27 | Added a test in the constructor for missing oElement arg       |
| 2003-11-27 | Only use mousewheel when focused                               |
| 2006-05-28 | Changed license to Apache Software License 2.0.                |
|-----------------------------------------------------------------------------|
| Created 2002-10-14 | All changes are in the log above. | Updated 2006-05-28 |
\----------------------------------------------------------------------------*/

Slider.isSupported = typeof document.createElement != "undefined" &&
	typeof document.documentElement != "undefined" &&
	typeof document.documentElement.offsetWidth == "number";


function Slider(oElement, oInput, sOrientation) {
	if (!oElement) return;
	this._orientation = sOrientation || "horizontal";
	this._range = new Range();
	this._range.setExtent(0);
	this._range.setMinimum(0);
	this._range.setMaximum(396);
	this._blockIncrement = 36;
	this._unitIncrement = 36;
	this._step=36;
	this._timer = new Timer(2000);


	if (Slider.isSupported && oElement) {

		this.document = oElement.ownerDocument || oElement.document;

		this.element = oElement;
		this.element.slider = this;
		this.element.unselectable = "on";

		// add class name tag to class name
		this.element.className = this._orientation + " " + this.classNameTag + " " + this.element.className;

		// create line
		this.line = this.document.createElement("DIV");
		this.line.className = "line";
		this.line.unselectable = "on";
		this.line.appendChild(this.document.createElement("DIV"));
		this.element.appendChild(this.line);

		// create handle
		this.handle = this.document.createElement("DIV");
		this.handle.className = "handle";
		this.handle.unselectable = "on";
		this.handle.appendChild(this.document.createElement("DIV"));
		this.handle.firstChild.appendChild(
			this.document.createTextNode(String.fromCharCode(160)));
		this.element.appendChild(this.handle);
	}

	this.input = oInput;

	// events
	var oThis = this;
	this._range.onchange = function () {
		oThis.recalculate();
		if (typeof oThis.onchange == "function")
			oThis.onchange();
	};

	if (Slider.isSupported && oElement) {
		this.element.onfocus		= Slider.eventHandlers.onfocus;
		this.element.onblur			= Slider.eventHandlers.onblur;
		this.element.onmousedown	= Slider.eventHandlers.onmousedown;
		this.element.onmouseover	= Slider.eventHandlers.onmouseover;
		this.element.onmouseout		= Slider.eventHandlers.onmouseout;
		this.element.onkeydown		= Slider.eventHandlers.onkeydown;
		this.element.onkeypress		= Slider.eventHandlers.onkeypress;
		this.element.onmousewheel	= Slider.eventHandlers.onmousewheel;
		this.handle.onselectstart	=
		this.element.onselectstart	= function () { return false; };

		this._timer.ontimer = function () {
			oThis.ontimer();
		};

		// extra recalculate for ie
		window.setTimeout(function() {
			oThis.recalculate();
		}, 1);
	}
	else {
		this.input.onchange = function (e) {
			oThis.setValue(oThis.input.value);
		};
	}
}

Slider.eventHandlers = {

	// helpers to make events a bit easier
	getEvent:	function (e, el) {
		if (!e) {
			if (el)
				e = el.document.parentWindow.event;
			else
				e = window.event;
		}
		if (!e.srcElement) {
			var el = e.target;
			while (el != null && el.nodeType != 1)
				el = el.parentNode;
			e.srcElement = el;
		}
		if (typeof e.offsetX == "undefined") {
			e.offsetX = e.layerX;
			e.offsetY = e.layerY;
		}

		return e;
	},

	getDocument:	function (e) {
		if (e.target)
			return e.target.ownerDocument;
		return e.srcElement.document;
	},

	getSlider:	function (e) {
		var el = e.target || e.srcElement;
		while (el != null && el.slider == null)	{
			el = el.parentNode;
		}
		if (el)
			return el.slider;
		return null;
	},

	getLine:	function (e) {
		var el = e.target || e.srcElement;
		while (el != null && el.className != "line")	{
			el = el.parentNode;
		}
		return el;
	},

	getHandle:	function (e) {
		var el = e.target || e.srcElement;
		var re = /handle/;
		while (el != null && !re.test(el.className))	{
			el = el.parentNode;
		}
		return el;
	},
	// end helpers

	onfocus:	function (e) {
		var s = this.slider;
		s._focused = true;
		s.handle.className = "handle hover";
	},

	onblur:	function (e) {
		var s = this.slider
		s._focused = false;
		s.handle.className = "handle";
	},

	onmouseover:	function (e) {
		e = Slider.eventHandlers.getEvent(e, this);
		var s = this.slider;
		if (e.srcElement == s.handle)
			s.handle.className = "handle hover";
	},

	onmouseout:	function (e) {
		e = Slider.eventHandlers.getEvent(e, this);
		var s = this.slider;
		if (e.srcElement == s.handle && !s._focused)
			s.handle.className = "handle";
	},

	onmousedown:	function (e) {
		e = Slider.eventHandlers.getEvent(e, this);
		var s = this.slider;
		if (s.element.focus)
			s.element.focus();

		Slider._currentInstance = s;
		var doc = s.document;

		if (doc.addEventListener) {
			doc.addEventListener("mousemove", Slider.eventHandlers.onmousemove, true);
			doc.addEventListener("mouseup", Slider.eventHandlers.onmouseup, true);
		}
		else if (doc.attachEvent) {
			doc.attachEvent("onmousemove", Slider.eventHandlers.onmousemove);
			doc.attachEvent("onmouseup", Slider.eventHandlers.onmouseup);
			doc.attachEvent("onlosecapture", Slider.eventHandlers.onmouseup);
			s.element.setCapture();
		}

		if (Slider.eventHandlers.getHandle(e)) {	// start drag
			Slider._sliderDragData = {
				screenX:	e.screenX,
				screenY:	e.screenY,
				dx:			e.screenX - s.handle.offsetLeft,
				dy:			e.screenY - s.handle.offsetTop,
				startValue:	s.getValue(),
				slider:		s
			};
		}
		else {
			var lineEl = Slider.eventHandlers.getLine(e);
			s._mouseX = e.offsetX + (lineEl ? s.line.offsetLeft : 0);
			s._mouseY = e.offsetY + (lineEl ? s.line.offsetTop : 0);
			s._increasing = null;
			s.stepFromClick();
		}
	},

	onmousemove:	function (e) {
		e = Slider.eventHandlers.getEvent(e, this);

		if (Slider._sliderDragData) {	// drag
			var s = Slider._sliderDragData.slider;

			var boundSize = s.getMaximum() - s.getMinimum();
			var size, pos, reset;

			if (s._orientation == "horizontal") {
				size = s.element.offsetWidth - s.handle.offsetWidth;
				pos = e.screenX - Slider._sliderDragData.dx;
				reset = Math.abs(e.screenY - Slider._sliderDragData.screenY) > 100;
			}
			else {
				size = s.element.offsetHeight - s.handle.offsetHeight;
				pos = s.element.offsetHeight - s.handle.offsetHeight -
					(e.screenY - Slider._sliderDragData.dy);
				reset = Math.abs(e.screenX - Slider._sliderDragData.screenX) > 100;
			}
			s.setValue(reset ? Slider._sliderDragData.startValue :
						s.getMinimum() + boundSize * pos / size);
			return false;
		}
		else {
			var s = Slider._currentInstance;
			if (s != null) {
				var lineEl = Slider.eventHandlers.getLine(e);
				s._mouseX = e.offsetX + (lineEl ? s.line.offsetLeft : 0);
				s._mouseY = e.offsetY + (lineEl ? s.line.offsetTop : 0);
			}
		}

	},

	onmouseup:	function (e) {
		e = Slider.eventHandlers.getEvent(e, this);
		var s = Slider._currentInstance;
		var doc = s.document;
		var releaseVal = (s.getValue() - s.getMinimum())/s._step;
		var floorRelaseVal = Math.floor(releaseVal);
		if (doc.removeEventListener) {
			doc.removeEventListener("mousemove", Slider.eventHandlers.onmousemove, true);
			doc.removeEventListener("mouseup", Slider.eventHandlers.onmouseup, true);
		}
		else if (doc.detachEvent) {
			doc.detachEvent("onmousemove", Slider.eventHandlers.onmousemove);
			doc.detachEvent("onmouseup", Slider.eventHandlers.onmouseup);
			doc.detachEvent("onlosecapture", Slider.eventHandlers.onmouseup);
		        s.element.releaseCapture();
		}

		if (Slider._sliderDragData) {	// end drag
		    Slider._sliderDragData = null;
		    s.setValue(releaseVal-floorRelaseVal<=0.5? floorRelaseVal*s._step:(floorRelaseVal*s._step)+s._step);
		    s._timer.start();
		}
		else {
			//s._timer.stop();
			//s._timer.start();
			s._increasing = null;
		}
		Slider._currentInstance = null;
	},

	onkeydown:	function (e) {
		e = Slider.eventHandlers.getEvent(e, this);
		//var s = Slider.eventHandlers.getSlider(e);
		var s = this.slider;
		var kc = e.keyCode;
		switch (kc) {
			case 33:	// page up
				s.setValue(s.getValue() + s.getBlockIncrement());
				s._timer.start();
		                break;
			case 34:	// page down
				s.setValue(s.getValue() - s.getBlockIncrement());
				s._timer.start();
		                break;
			case 35:	// end
				s.setValue(s.getOrientation() == "horizontal" ?
					s.getMaximum() :
					s.getMinimum());
				s._timer.start();
		                break;
			case 36:	// home
				s.setValue(s.getOrientation() == "horizontal" ?
					s.getMinimum() :
					s.getMaximum());
				s._timer.start();
		                break;
			case 38:	// up
			case 39:	// right
				s.setValue(s.getValue() + s.getUnitIncrement());
				s._timer.start();
		                break;

			case 37:	// left
			case 40:	// down
				s.setValue(s.getValue() - s.getUnitIncrement());
				s._timer.start();
		                break;
		}

		if (kc >= 33 && kc <= 40) {
			return false;
		}
	},

	onkeypress:	function (e) {
		e = Slider.eventHandlers.getEvent(e, this);
		var kc = e.keyCode;
		if (kc >= 33 && kc <= 40) {
			return false;
		}
	},

	onmousewheel:	function (e) {
		e = Slider.eventHandlers.getEvent(e, this);
		var s = this.slider;
		if (s._focused) {
			s.setValue(s.getValue() + e.wheelDelta / 120 * s.getUnitIncrement());
			// windows inverts this on horizontal sliders. That does not
			// make sense to me
			return false;
		}
	}
};



Slider.prototype.classNameTag = "dynamic-slider-control",

Slider.prototype.setValue = function (v) {
	this._range.setValue(v);
	this.input.value = this.getValue();
};

Slider.prototype.getValue = function () {
	return this._range.getValue();
};

Slider.prototype.setMinimum = function (v) {
	this._range.setMinimum(v);
	this.input.value = this.getValue();
};

Slider.prototype.getMinimum = function () {
	return this._range.getMinimum();
};

Slider.prototype.setMaximum = function (v) {
	this._range.setMaximum(v);
	this.input.value = this.getValue();
};

Slider.prototype.getMaximum = function () {
	return this._range.getMaximum();
};

Slider.prototype.setUnitIncrement = function (v) {
	this._unitIncrement = v;
};

Slider.prototype.getUnitIncrement = function () {
	return this._unitIncrement;
};

Slider.prototype.setBlockIncrement = function (v) {
	this._blockIncrement = v;
};

Slider.prototype.getBlockIncrement = function () {
	return this._blockIncrement;
};

Slider.prototype.getStep = function () {
	return this._step;
};

Slider.prototype.setStep = function (v) {
	return this._step=v;
};


Slider.prototype.getOrientation = function () {
	return this._orientation;
};

Slider.prototype.setOrientation = function (sOrientation) {
	if (sOrientation != this._orientation) {
		if (Slider.isSupported && this.element) {
			// add class name tag to class name
			this.element.className = this.element.className.replace(this._orientation,
									sOrientation);
		}
		this._orientation = sOrientation;
		this.recalculate();

	}
};

Slider.prototype.recalculate = function() {
	if (!Slider.isSupported || !this.element) return;

	var w = this.element.offsetWidth;
	var h = this.element.offsetHeight;
	var hw = this.handle.offsetWidth;
	var hh = this.handle.offsetHeight;
	var lw = this.line.offsetWidth;
	var lh = this.line.offsetHeight;

	// this assumes a border-box layout

	if (this._orientation == "horizontal") {
		this.handle.style.left = (w - hw) * (this.getValue() - this.getMinimum()) /
			(this.getMaximum() - this.getMinimum()) + "px";
		this.handle.style.top = (h - hh) / 4 + "px";

		this.line.style.top = (h - lh) / 2 + "px";
		this.line.style.left = hw / 2 + "px";
		//this.line.style.right = hw / 2 + "px";
		this.line.style.width = Math.max(0, w - hw - 2)+ "px";
		this.line.firstChild.style.width = Math.max(0, w - hw - 4)+ "px";
	}
	else {
		this.handle.style.left = (w - hw) / 2 + "px";
		this.handle.style.top = h - hh - (h - hh) * (this.getValue() - this.getMinimum()) /
			(this.getMaximum() - this.getMinimum()) + "px";

		this.line.style.left = (w - lw) / 2 + "px";
		this.line.style.top = hh / 2 + "px";
		this.line.style.height = Math.max(0, h - hh - 2) + "px";	//hard coded border width
		//this.line.style.bottom = hh / 2 + "px";
		this.line.firstChild.style.height = Math.max(0, h - hh - 4) + "px";	//hard coded border width
	}
};

//Slider.prototype.ontimer = function () {
Slider.prototype.stepFromClick = function () {
	var hw = this.handle.offsetWidth;
	var hh = this.handle.offsetHeight;
	var hl = this.handle.offsetLeft;
	var ht = this.handle.offsetTop;
        if (this._orientation == "horizontal") {
		if (this._mouseX > hl + hw &&
			(this._increasing == null || this._increasing)) {
			this.setValue(this.getValue() + this.getBlockIncrement());
			this._increasing = true;
		}
		else if (this._mouseX < hl &&
			(this._increasing == null || !this._increasing)) {
			this.setValue(this.getValue() - this.getBlockIncrement());
			this._increasing = false;
		}
	}
	else {
		if (this._mouseY > ht + hh &&
			(this._increasing == null || !this._increasing)) {
			this.setValue(this.getValue() - this.getBlockIncrement());
			this._increasing = false;
		}
		else if (this._mouseY < ht &&
			(this._increasing == null || this._increasing)) {
			this.setValue(this.getValue() + this.getBlockIncrement());
			this._increasing = true;
		}
	}

	this._timer.start();
};



/**
 * SWFObject v1.5: Flash Player detection and embed - http://blog.deconcept.com/swfobject/
 *
 * SWFObject is (c) 2007 Geoff Stearns and is released under the MIT License:
 * http://www.opensource.org/licenses/mit-license.php
 *
 */
if(typeof deconcept == "undefined") var deconcept = new Object();
if(typeof deconcept.util == "undefined") deconcept.util = new Object();
if(typeof deconcept.SWFObjectUtil == "undefined") deconcept.SWFObjectUtil = new Object();
deconcept.SWFObject = function(swf, id, w, h, ver, c, quality, xiRedirectUrl, redirectUrl, detectKey) {
	if (!document.getElementById) { return; }
	this.DETECT_KEY = detectKey ? detectKey : 'detectflash';
	this.skipDetect = deconcept.util.getRequestParameter(this.DETECT_KEY);
	this.params = new Object();
	this.variables = new Object();
	this.attributes = new Array();
	if(swf) { this.setAttribute('swf', swf); }
	if(id) { this.setAttribute('id', id); }
	if(w) { this.setAttribute('width', w); }
	if(h) { this.setAttribute('height', h); }
	if(ver) { this.setAttribute('version', new deconcept.PlayerVersion(ver.toString().split("."))); }
	this.installedVer = deconcept.SWFObjectUtil.getPlayerVersion();
	if (!window.opera && document.all && this.installedVer.major > 7) {
		// only add the onunload cleanup if the Flash Player version supports External Interface and we are in IE
		deconcept.SWFObject.doPrepUnload = true;
	}
	if(c) { this.addParam('bgcolor', c); }
	var q = quality ? quality : 'high';
	this.addParam('quality', q);
	this.setAttribute('useExpressInstall', false);
	this.setAttribute('doExpressInstall', false);
	var xir = (xiRedirectUrl) ? xiRedirectUrl : window.location;
	this.setAttribute('xiRedirectUrl', xir);
	this.setAttribute('redirectUrl', '');
	if(redirectUrl) { this.setAttribute('redirectUrl', redirectUrl); }
}
deconcept.SWFObject.prototype = {
	useExpressInstall: function(path) {
		this.xiSWFPath = !path ? "expressinstall.swf" : path;
		this.setAttribute('useExpressInstall', true);
	},
	setAttribute: function(name, value){
		this.attributes[name] = value;
	},
	getAttribute: function(name){
		return this.attributes[name];
	},
	addParam: function(name, value){
		this.params[name] = value;
	},
	getParams: function(){
		return this.params;
	},
	addVariable: function(name, value){
		this.variables[name] = value;
	},
	getVariable: function(name){
		return this.variables[name];
	},
	getVariables: function(){
		return this.variables;
	},
	getVariablePairs: function(){
		var variablePairs = new Array();
		var key;
		var variables = this.getVariables();
		for(key in variables){
			variablePairs[variablePairs.length] = key +"="+ variables[key];
		}
		return variablePairs;
	},
	getSWFHTML: function() {
		var swfNode = "";
		if (navigator.plugins && navigator.mimeTypes && navigator.mimeTypes.length) { // netscape plugin architecture
			if (this.getAttribute("doExpressInstall")) {
				this.addVariable("MMplayerType", "PlugIn");
				this.setAttribute('swf', this.xiSWFPath);
			}
			swfNode = '<embed type="application/x-shockwave-flash" src="'+ this.getAttribute('swf') +'" width="'+ this.getAttribute('width') +'" height="'+ this.getAttribute('height') +'" style="'+ this.getAttribute('style') +'"';
			swfNode += ' id="'+ this.getAttribute('id') +'" name="'+ this.getAttribute('id') +'" ';
			var params = this.getParams();
			 for(var key in params){ swfNode += [key] +'="'+ params[key] +'" '; }
			var pairs = this.getVariablePairs().join("&");
			 if (pairs.length > 0){ swfNode += 'flashvars="'+ pairs +'"'; }
			swfNode += '/>';
		} else { // PC IE
			if (this.getAttribute("doExpressInstall")) {
				this.addVariable("MMplayerType", "ActiveX");
				this.setAttribute('swf', this.xiSWFPath);
			}
			swfNode = '<object id="'+ 'ie_'+ this.getAttribute('id') +'" classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" width="'+ this.getAttribute('width') +'" height="'+ this.getAttribute('height') +'" style="'+ this.getAttribute('style') +'">';
			swfNode += '<param name="movie" value="'+ this.getAttribute('swf') +'" />';
			var params = this.getParams();
			for(var key in params) {
			 swfNode += '<param name="'+ key +'" value="'+ params[key] +'" />';
			}
			var pairs = this.getVariablePairs().join("&");
			if(pairs.length > 0) {swfNode += '<param name="flashvars" value="'+ pairs +'" />';}
			swfNode += "</object>";
		}
		return swfNode;
	},
	write: function(elementId){
		if(this.getAttribute('useExpressInstall')) {
			// check to see if we need to do an express install
			var expressInstallReqVer = new deconcept.PlayerVersion([6,0,65]);
			if (this.installedVer.versionIsValid(expressInstallReqVer) && !this.installedVer.versionIsValid(this.getAttribute('version'))) {
				this.setAttribute('doExpressInstall', true);
				this.addVariable("MMredirectURL", escape(this.getAttribute('xiRedirectUrl')));
				document.title = document.title.slice(0, 47) + " - Flash Player Installation";
				this.addVariable("MMdoctitle", document.title);
			}
		}
		if(this.skipDetect || this.getAttribute('doExpressInstall') || this.installedVer.versionIsValid(this.getAttribute('version'))){
			var n = (typeof elementId == 'string') ? document.getElementById(elementId) : elementId;
			n.innerHTML = this.getSWFHTML();
			return true;
		}else{
			if(this.getAttribute('redirectUrl') != "") {
				document.location.replace(this.getAttribute('redirectUrl'));
			}
		}
		return false;
	}
}

/* ---- detection functions ---- */
deconcept.SWFObjectUtil.getPlayerVersion = function(){
	var PlayerVersion = new deconcept.PlayerVersion([0,0,0]);
	if(navigator.plugins && navigator.mimeTypes.length){
		var x = navigator.plugins["Shockwave Flash"];
		if(x && x.description) {
			PlayerVersion = new deconcept.PlayerVersion(x.description.replace(/([a-zA-Z]|\s)+/, "").replace(/(\s+r|\s+b[0-9]+)/, ".").split("."));
		}
	}else if (navigator.userAgent && navigator.userAgent.indexOf("Windows CE") >= 0){ // if Windows CE
		var axo = 1;
		var counter = 3;
		while(axo) {
			try {
				counter++;
				axo = new ActiveXObject("ShockwaveFlash.ShockwaveFlash."+ counter);
//				document.write("player v: "+ counter);
				PlayerVersion = new deconcept.PlayerVersion([counter,0,0]);
			} catch (e) {
				axo = null;
			}
		}
	} else { // Win IE (non mobile)
		// do minor version lookup in IE, but avoid fp6 crashing issues
		// see http://blog.deconcept.com/2006/01/11/getvariable-setvariable-crash-internet-explorer-flash-6/
		try{
			var axo = new ActiveXObject("ShockwaveFlash.ShockwaveFlash.7");
		}catch(e){
			try {
				var axo = new ActiveXObject("ShockwaveFlash.ShockwaveFlash.6");
				PlayerVersion = new deconcept.PlayerVersion([6,0,21]);
				axo.AllowScriptAccess = "always"; // error if player version < 6.0.47 (thanks to Michael Williams @ Adobe for this code)
			} catch(e) {
				if (PlayerVersion.major == 6) {
					return PlayerVersion;
				}
			}
			try {
				axo = new ActiveXObject("ShockwaveFlash.ShockwaveFlash");
			} catch(e) {}
		}
		if (axo != null) {
			PlayerVersion = new deconcept.PlayerVersion(axo.GetVariable("$version").split(" ")[1].split(","));
		}
	}
	return PlayerVersion;
}
deconcept.PlayerVersion = function(arrVersion){
	this.major = arrVersion[0] != null ? parseInt(arrVersion[0]) : 0;
	this.minor = arrVersion[1] != null ? parseInt(arrVersion[1]) : 0;
	this.rev = arrVersion[2] != null ? parseInt(arrVersion[2]) : 0;
}
deconcept.PlayerVersion.prototype.versionIsValid = function(fv){
	if(this.major < fv.major) return false;
	if(this.major > fv.major) return true;
	if(this.minor < fv.minor) return false;
	if(this.minor > fv.minor) return true;
	if(this.rev < fv.rev) return false;
	return true;
}
/* ---- get value of query string param ---- */
deconcept.util = {
	getRequestParameter: function(param) {
		var q = document.location.search || document.location.hash;
		if (param == null) { return q; }
		if(q) {
			var pairs = q.substring(1).split("&");
			for (var i=0; i < pairs.length; i++) {
				if (pairs[i].substring(0, pairs[i].indexOf("=")) == param) {
					return pairs[i].substring((pairs[i].indexOf("=")+1));
				}
			}
		}
		return "";
	}
}
/* fix for video streaming bug */
deconcept.SWFObjectUtil.cleanupSWFs = function() {
	var objects = document.getElementsByTagName("OBJECT");
	for (var i = objects.length - 1; i >= 0; i--) {
		objects[i].style.display = 'none';
		for (var x in objects[i]) {
			if (typeof objects[i][x] == 'function') {
				objects[i][x] = function(){};
			}
		}
	}
}
// fixes bug in some fp9 versions see http://blog.deconcept.com/2006/07/28/swfobject-143-released/
if (deconcept.SWFObject.doPrepUnload) {
	if (!deconcept.unloadSet) {
		deconcept.SWFObjectUtil.prepUnload = function() {
			__flash_unloadHandler = function(){};
			__flash_savedUnloadHandler = function(){};
			window.attachEvent("onunload", deconcept.SWFObjectUtil.cleanupSWFs);
		}
		window.attachEvent("onbeforeunload", deconcept.SWFObjectUtil.prepUnload);
		deconcept.unloadSet = true;
	}
}
/* add document.getElementById if needed (mobile IE < 5) */
if (!document.getElementById && document.all) { document.getElementById = function(id) { return document.all[id]; }}

/* add some aliases for ease of use/backwards compatibility */
var getQueryParamValue = deconcept.util.getRequestParameter;
var FlashObject = deconcept.SWFObject; // for legacy support
var SWFObject = deconcept.SWFObject;





 /*
 Developed by Endri D. Hamburg. 2008
 */
 
 
 var so = new SWFObject("/gall/", "mymovie", "438", "150", "9", "#f8f8f8");
 so.addParam("quality", "best");
 so.addParam("scale", "noScale");
 //so.addParam("wmode", "opaque");
 so.addParam("allowFullScreen", "true");
 so.addParam("FlashVars", "xmlFile="+escape("/gallflash/bo/"+new Date().getTime()+"/"));
 so.write("flashcontent");
 
 
 var finishedDragging=true;
 var last=0;
 var refYear = new Date().getFullYear();
 var mapcoord, mManager1, myMarker, baseIcons, bBaseIcon, eventIcon; 
 var markerArray=[];
 var myOrgCategoryArray=[1,2,3,4,5,6,7,8];
 
 function loadMyMap(idOrg, latFromIp, lngFromIp, zoomFromIp){
     mapcoord = new GMap(document.getElementById("hartacoordinates"));
     mapcoord.addControl(new MyNavigationControl());
     mapcoord.addControl(new MyTypeControl());
     mapcoord.centerAndZoom(new GLatLng(47.279229002570816,0.703125), 14);
     mManager1= new MarkerManager(mapcoord);
     
     baseIcons = createIcon("img/organizata.png");
     
     bBaseIcon = new GIcon();
     bBaseIcon.image="img/organizate-madhe.png";
     bBaseIcon.iconSize = new GSize(25, 25);
     bBaseIcon.iconAnchor = new GPoint(13, 25);
     bBaseIcon.infoWindowAnchor = new GPoint(10, 2); 
     
     
     eventIcon = new GIcon();
     eventIcon.image="img/aktivitet.png";
     eventIcon.iconSize = new GSize(20.0, 20.0);
     eventIcon.iconAnchor = new GPoint(10.0, 20.0);
     eventIcon.infoWindowAnchor = new GPoint(7.0, 2.0);
    
     
     if(idOrg == 0){
         var gxml = new GDownloadUrl("/geoorg/bo/" + new Date().getTime()+"/", function(data){
	     displayMapOrganizations(data);
	     mapcoord.centerAndZoom(new GLatLng(latFromIp, lngFromIp), zoomFromIp);
         });
         GEvent.addListener(mapcoord, 'moveend', function(){myMoveEndFunc(2500);});
         GEvent.addListener(mapcoord, 'zoomend', function(){myMoveEndFunc(2500);});
         GEvent.addListener(mapcoord, 'movestart', function(){finishedDragging=false;});
         GEvent.addListener(mapcoord, 'zoomstart', function(){finishedDragging=false;});
	 //myMoveEndFunc(0);
	 var sliderDiv = document.getElementById("slider-1");
	 var s = new Slider(sliderDiv,document.getElementById("slider-input-1"));
	 s.setValue(s.getMaximum());
	 sliderDiv.style.visibility="visible"
	 s.ontimer=function(){
	     refYear= (new Date().getFullYear() - 11)+((s.getValue()-s.getMinimum())/s.getStep());
	     displayOrgOfTime();
	     myMoveEndFunc(0);
	 };
     }
     else if(idOrg > 0){
         var gxml = new GDownloadUrl("/geoorg/"+idOrg+"/bo/" + new Date().getTime()+"/", function(data){displayMapOrganizations(data, idOrg);});
         
     }
 }
 
 function updateDisplayCategory(box){
     if(!box.checked){myOrgCategoryArray[box.value]=-10}
     else{myOrgCategoryArray[box.value]= parseInt(box.value) + 1}
     displayOrgOfTime();
     myMoveEndFunc(0);
	 
 }
 
 function displayMapOrganizations(data,orgId){
 
     var xml = GXml.parse(data);
     var xmlMarkers = xml.documentElement.getElementsByTagName("mapOrganization");
     var oId, name, site, email, lat, lng, point, description, xmlDescription, xmlActivities;
     var orgContent = document.getElementById("orgContents");
     
     for(var i = 0; i<xmlMarkers.length;i++){
         oId = xmlMarkers[i].getAttribute("id");
         name = xmlMarkers[i].getAttribute("name");
         site = xmlMarkers[i].getAttribute("site");
         email = xmlMarkers[i].getAttribute("email");
         lat = xmlMarkers[i].getAttribute("lat");
         lng = xmlMarkers[i].getAttribute("lng");
         point = new GLatLng(parseFloat(lat),parseFloat(lng));
	 var orgCreation = xmlMarkers[i].getAttribute("creation");
         var category = xmlMarkers[i].getAttribute("category");
	 if(orgId===undefined ){
	     if(i<10){displayMyOrganization(xmlMarkers[i], orgContent, true);}
	     myMarker=createMarker(point, new Array(new GInfoWindowTab(name, "<div style='float:left;width:180px;text-align:left;'><div style='float:left;width:100%;'><b style='font-family:Verdana;font-size:8pt;'>"+name+"</b></div><div style='float:left;width:100%;'><b style='font-family:Verdana;font-size:8pt;'>"+site+" : "+email+"</b></div></div>")), baseIcons, name);
             if(orgCreation!=""){
		 var dateParts = orgCreation.split('.');
		 var startDate = new Date(parseInt(dateParts[2], 10),parseInt(dateParts[1], 10)-1,parseInt(dateParts[0], 10)); 
	         myMarker.id = oId;
	         myMarker.creation = startDate;
	         myMarker.numberactivities = xmlMarkers[i].getAttribute("numberactivities");
	         myMarker.orgName = xmlMarkers[i].getAttribute("name");
	         myMarker.category = xmlMarkers[i].getAttribute("category");
	         markerArray[i]=myMarker;
	     }
	 }else{
	     myMarker=createMarker(point, new Array(new GInfoWindowTab(name, "<div style='float:left;width:180px;text-align:left;'><div style='float:left;width:100%;'><b style='font-family:Verdana;font-size:8pt;'>"+name+"</b></div><div style='float:left;width:100%;'><b style='font-family:Verdana;font-size:8pt;'>"+site+" : "+email+"</b></div></div>")), bBaseIcon, name);
             mManager1.addMarker(myMarker, 0, 17);
	     displayMyFullOrganization(xmlMarkers[i], orgContent);
	     var xmlMarker = xmlMarkers[i];   
	     var linkEvent = document.getElementById('addEventLink');
	     linkEvent.href=linkEvent.href + 'la/'+xmlMarker.getAttribute("lat")+'/lo/'+xmlMarker.getAttribute("lng")+'/';
         }
	 
	 if((orgId == oId && i==0) || (orgId===undefined && i==xmlMarkers.length-1) ){
             mapcoord.centerAndZoom((orgId===undefined && i==xmlMarkers.length-1)?new GLatLng(47.279229002570816,0.703125):point, (orgId == oId && i==0)?6:15);
	 }
	 
	 if(orgId===undefined ){
	     addMarkerToMgr(i, myMarker)
	 }
	 
     }
         
 }
 
 function myMoveEndFunc(delay){
     var myPlaceNumber=++last;
     finishedDragging=true;
     //setTimeout("initEndFunc("+sw.lng()+","+sw.lat()+","+ne.lng()+","+ne.lat()+","+myPlaceNumber+")",delay);
     setTimeout(function(){
     
     if(!finishedDragging || myPlaceNumber<last)
         return;
	 var markersInsideArray = getMarkersInsideBound(mapcoord.getBounds());
	 var mArray=markersInsideArray[0];
	 var myDivNum =document.getElementById('numberMarkersDiv');
	 if(markersInsideArray[1]>0){myDivNum.innerHTML="Numri i organizatave n&euml; k&euml;te zon&euml;: "+mArray.length+" <br/> Zmadho hart&euml;n p&euml;r t&euml; par&euml; "+markersInsideArray[1]+" t&euml; tjerat.";}
         else if(myDivNum.innerHTML!=""){myDivNum.innerHTML="";}
	 var myContent = document.getElementById("orgContents");
         displayMyOrganizations(mArray, myContent);
	 
	 var myImageDiv = document.getElementById("chartImageDiv");
	 var cachedImage = new Image();
	 
	 var chartLabel="&chl="; 
         var chartData="&chd=t:";
         var chartURL = "http://chart.apis.google.com/chart?cht=p3&chco=0189DF&chs=400x150&chf=bg,s,f8f8f8";            
         
	 for(var i = 0; i<markersInsideArray[2].length;i++){
	     if(markersInsideArray[2][i][0]!=0){
	         chartLabel += markersInsideArray[2][i][1]+"%20("+calculatePercentage(markersInsideArray[2][i][0], mArray.length)+"%25)"+"|";
                 chartData += markersInsideArray[2][i][0]+",";
	     }
	 }
         chartLabel=chartLabel.substring(0,chartLabel.length-1);
	 chartData=chartData.substring(0,chartData.length-1);
         chartURL+=chartLabel+chartData;
         
	 cachedImage.src=chartURL;
	 
	 
	 
	 reloadChartImage(cachedImage, myImageDiv);
	 /*mArray.sort(function(a,b){return b.creation<=a.creation?b.creation!=a.creation?-1:a.id-b.id:1;}); 
         var myDivSorted = document.getElementById("sortedMarkerDiv");
         myDivSorted.innerHTML=displayCreationSortedMarkers(mArray);*/
         
     },delay);
 }
 function reloadChartImage(cachedImage, myImageDiv){
     if(cachedImage.complete){
	 myImageDiv.style.background = "#f8f8f8 url('"+cachedImage.src+"') no-repeat 30% 30%";
     }else{
	 setTimeout(function(){reloadChartImage(cachedImage, myImageDiv);},300);
     }
 }
 
 
 function displayMyOrganization(xmlMarker, contentDiv, isXmlMarker){
     var myDiv = document.createElement('div');
     myDiv.setAttribute('style', 'width:100%;margin-top:5px;');
	
     var myLink = document.createElement('a');
     myLink.href='/mode/edit/'+(isXmlMarker?xmlMarker.getAttribute("id"):xmlMarker.id)+'/';
     myLink.title='Ndrysho te dhenat per organizaten';
     myLink.className='orgLink';
     myLink.appendChild(displayLinkedIconImage("[ndrysho]"));
     
     var mySpanLink = document.createElement('span');
     mySpanLink.className='orgSpanLink';
     mySpanLink.appendChild(myLink);
     
     var showOrgLink = document.createElement('a');
     showOrgLink.href='/rss/org/'+(isXmlMarker?xmlMarker.getAttribute("id"):xmlMarker.id)+'/';
     showOrgLink.title='Regjistrohu tek ky kanal RSS per te ndjekur aktivitetet e reja te kesaj organizate';
     
     var myOrgContent = document.createElement("img");
     myOrgContent.src="img/rssforsite.png";
     myOrgContent.style.border="0px solid #ffffff";
     myOrgContent.style.marginRight="7px";
     myOrgContent.style.width="15px";
     myOrgContent.style.height="15px";
     showOrgLink.appendChild(myOrgContent);
     
     //var myOrgContent = document.createTextNode("Organizata: ");
     
     var subDiv= document.createElement('div');
     subDiv.className='subOrg';
     myDiv.appendChild(mySpanLink);
     //subDiv.appendChild(myOrgContent);
     
     subDiv.appendChild(showOrgLink);
     
     showOrgLink = document.createElement('a');
     showOrgLink.href='/mode/show/'+(isXmlMarker?xmlMarker.getAttribute("id"):xmlMarker.id)+'/';
     showOrgLink.title='Shih te dhenat per organizaten';
     showOrgLink.className='orgLink';
     
     myOrgContent = document.createTextNode(isXmlMarker?displayHTMLWithEntities(xmlMarker.getAttribute("name")):displayHTMLWithEntities(xmlMarker.orgName));
     showOrgLink.appendChild(myOrgContent);
     
     subDiv.appendChild(showOrgLink);
     myOrgContent = document.createTextNode(" ("+(isXmlMarker?xmlMarker.getAttribute("numberactivities"):xmlMarker.numberactivities)+")");
     
     subDiv.appendChild(myOrgContent);
     
     var hLine = document.createElement('div');
     hLine.className='hOrgLine';
     //subDiv.appendChild(hLine);
     myDiv.appendChild(subDiv);
     myDiv.appendChild(hLine);
     		    
     contentDiv.appendChild(myDiv);
        
 }
 
 function displayMyFullOrganization(xmlMarker, contentDiv){
     displayMyOrganization(xmlMarker, contentDiv, true);
     
     var myDiv = document.createElement('div');
     myDiv.className="orgDescription";
     var myOrgDescription = null;
     var xmlDescription = xmlMarker.getElementsByTagName("description");
     var myOrgDescription = document.createElement('div');
     myOrgDescription.innerHTML = displayHTMLWithBB(GXml.value(xmlDescription[0]));
     var allInfOrg = document.createElement('div');
     allInfOrg.className = "imageLogoDiv";
     var lineAllInfOrg = document.createElement('div');
     lineAllInfOrg.className = "infLogoDiv";
     
     if(xmlMarker.getAttribute("logo")!="" && xmlMarker.getAttribute("logo")!=null){
         var logoOrg = document.createElement('span');
         logoOrg.className="logoSpan";
         
         var logoImg = document.createElement('img');
	 logoImg.className="logoImg";
	 logoImg.src = xmlMarker.getAttribute("logo");
	 
	 if(xmlMarker.getAttribute("site")!="" && xmlMarker.getAttribute("site")!=null){
             var linkOrg = document.createElement('a');
	     linkOrg.href = xmlMarker.getAttribute("site");
             linkOrg.target = "_blank";
             linkOrg.appendChild(logoImg);
             logoOrg.appendChild(linkOrg);
	 }else
	 logoOrg.appendChild(logoImg);
	 
	 allInfOrg.appendChild(logoOrg);
     }	 
     logoOrg = document.createElement('span');
     logoOrg.className="infOrgSpan";
     var textEl = document.createTextNode("Adresa: "+xmlMarker.getAttribute("address"));
     logoOrg.appendChild(textEl);
     lineAllInfOrg.appendChild(logoOrg);
	 
     logoOrg = document.createElement('span');
     logoOrg.className="infOrgSpan";
     textEl = document.createTextNode("Email: "+xmlMarker.getAttribute("email"));
     logoOrg.appendChild(textEl);
     lineAllInfOrg.appendChild(logoOrg);
	 
     logoOrg = document.createElement('span');
     logoOrg.className="infOrgSpan";
     textEl = document.createTextNode("Krijimi: "+xmlMarker.getAttribute("creation").substr(3));
     logoOrg.appendChild(textEl);
     lineAllInfOrg.appendChild(logoOrg);
	 
     myDiv.appendChild(allInfOrg);
     myDiv.appendChild(lineAllInfOrg);
         
     myDiv.appendChild(myOrgDescription);
     contentDiv.appendChild(myDiv);
     
     var xmlActivity = xmlMarker.getElementsByTagName("mapActivity");
     var dateTimeArr = [];
     var dateParts = [];
     var albYears = [];
     var albMonths = [[0,"Jan"],[0,"Shkur"],[0,"Mar"],[0,"Pri"],[0,"Maj"],[0,"Qer"],[0,"Korr"],[0,"Gush"],[0,"Shtat"],[0,"Tet"],[0,"Nent"],[0,"Dhjet"]];
     var thisMonthCharts = new Date().getMonth();
     var thisYearCharts = new Date().getFullYear();
     for(var j = 0; j<=11;j++){albYears[j]=[0,""+((thisYearCharts-11)+j)]}
     
     for(var j = 0; j<xmlActivity.length;j++){
         if(j<10)
	     displayMyEvent(xmlActivity[j], contentDiv, xmlMarker.getAttribute("id"))
         
	 dateTimeArr = xmlActivity[j].getAttribute("startEvent").split(" ");
	 dateParts=dateTimeArr[0].split("-");
	 if(dateParts[0]==thisYearCharts)
	     albMonths[parseInt(""+dateParts[1],10)-1][0]++;
         if(thisYearCharts-dateParts[0]<=11)
	     albYears[11-(thisYearCharts-dateParts[0])][0]++;
     }
     
     var myImageChartDiv = document.getElementById("chartImageDiv");
     var cachedImage = new Image();
	 
     var chartLabel="&chxt=y,x&chxl=0:|0|1|2|3|Aktiv. 4|1:|"; 
     var chartData="&chls=3,5,3&chd=t:";
     var chartURL = "http://chart.apis.google.com/chart?cht=bvg&chco=0189DF&chs=400x150&chf=bg,s,f8f8f8";            
     for(var j = 0; j<=thisMonthCharts && j<albMonths.length; j++){
         chartLabel+=albMonths[j][1]+"|";
	 chartData+=(albMonths[j][0]*25)+","
     }
     chartData=chartData.substring(0,chartData.length-1);
     chartURL+=chartLabel+chartData;
     cachedImage.src=chartURL
     reloadChartImage(cachedImage, myImageChartDiv);
     chartURL = "http://chart.apis.google.com/chart?cht=bvg&chco=0189DF&chs=440x150&chf=bg,s,f8f8f8";            
     chartLabel="&chxt=y,x&chxl=0:|0|5|10|15|Aktiv. 20|1:|"; 
     chartData="&chls=3,5,3&chd=t:";
     
     for(var j = 0; j<albYears.length; j++){
         chartLabel+=albYears[j][1]+"|";
	 chartData+=(albYears[j][0]*5)+","
     }
     chartData=chartData.substring(0,chartData.length-1);
     chartURL+=chartLabel+chartData;
     var cachedSecImage= new Image();
     cachedSecImage.src=chartURL;
     myImageChartDiv = document.getElementById("chartImageSecDiv");
     reloadChartImage(cachedSecImage, myImageChartDiv);
 }
 
 function displayMyEvent(xmlMarker, contentDiv, orgId){
     if(xmlMarker.getAttribute("eventTitle")!=null && xmlMarker.getAttribute("eventTitle")!=""){
        var myDiv = document.createElement('div');
        myDiv.className="orgEvent";
	var eventOrg = document.createElement('span');
        eventOrg.className="eventSpan";
        var linkEvent = document.createElement('a');
	linkEvent.href='/mode/event/'+orgId+'/act/'+xmlMarker.getAttribute("activityId")+'/';
        linkEvent.className='orgLink';
     
	linkEvent.appendChild(displayLinkedIconImage("[ndrysho]"));
	eventOrg.appendChild(linkEvent);
	myDiv.appendChild(eventOrg);
	
	var dateTimeArr = xmlMarker.getAttribute("startEvent").split(" ");
	var dateParts = dateTimeArr[0].split("-");
	var timeParts = dateTimeArr[1].split(":");
	
	linkEvent = document.createElement('a');
	linkEvent.href='javascript:blowMarkerInArray('+markerArray.length+')';
        linkEvent.className='orgLink';
	var myOrgEvent = document.createTextNode(displayHTMLWithEntities(xmlMarker.getAttribute("eventTitle")));
	linkEvent.appendChild(myOrgEvent);
	myDiv.appendChild(linkEvent);
	
        var startDate = new Date(parseInt(dateParts[0], 10),parseInt(dateParts[1], 10)-1,parseInt(dateParts[2], 10),parseInt(timeParts[0],10),parseInt(timeParts[1],10),parseInt(timeParts[2],10)); 
	myOrgEvent = document.createTextNode(" ("+(startDate.getDate()<10?"0"+startDate.getDate():startDate.getDate())+"."+((startDate.getMonth()+1)<10?"0"+(startDate.getMonth()+1):(startDate.getMonth()+1))+"."+startDate.getFullYear()+", Ora "+(startDate.getHours()<10?"0"+startDate.getHours():startDate.getHours())+":"+(startDate.getMinutes()<10?"0"+startDate.getMinutes():startDate.getMinutes())+")");
	
	
	var lat = xmlMarker.getAttribute("eventLat");
        var lng = xmlMarker.getAttribute("eventLng");
        var point = new GLatLng(parseFloat(lat),parseFloat(lng));
	
	var myEventDescription = "";
	var xmlDescription = xmlMarker.getElementsByTagName("description");
        for(var j = 0; j<xmlDescription.length;j++){
	    myEventDescription = GXml.value(xmlDescription[j]);
        }
	
	var htmlCont =  "<div style='float:left;width:280px;text-align:left;'><div style='float:left;width:100%;'><b style='font-family:Verdana;font-size:8pt;color:#888888;'>"+xmlMarker.getAttribute("eventTitle")+"</b></div><div style='float:left;width:100%;'><b style='font-family:Verdana;font-size:8pt;color:#888888;'>"
	+(startDate.getDate()<10?"0"+startDate.getDate():startDate.getDate())+"."+((startDate.getMonth()+1)<10?"0"+(startDate.getMonth()+1):(startDate.getMonth()+1))+"."+startDate.getFullYear()
	+" (Ora "+(startDate.getHours()<10?"0"+startDate.getHours():startDate.getHours())+":"+(startDate.getMinutes()<10?"0"+startDate.getMinutes():startDate.getMinutes())+")"+"</b></div>"
	+"<div style='float:left;width:100%;color:#888888;'>"+myEventDescription+"</div>"
	
	+"</div>"
	
        myMarker=createMarker(point, new Array(new GInfoWindowTab(xmlMarker.getAttribute("eventTitle"), htmlCont)), eventIcon, xmlMarker.getAttribute("eventTitle"));
        mManager1.addMarker(myMarker, 0, 17);
	markerArray.push(myMarker);
	
	myDiv.appendChild(myOrgEvent);
	contentDiv.appendChild(myDiv);
     }
         
 }
 
 function displayMyOrganizations(xmlMarkers, contentNode){
     if(xmlMarkers.length>0)
	removeChildrenFromNode(contentNode);
     for(var i=0; i<xmlMarkers.length && i<10;i++){
	 displayMyOrganization(xmlMarkers[i], contentNode, false);
     }
 
 }
 
 function displayHTMLWithEntities(myString){
     myString = myString.replace(/\&quot;/ig, "\"");
     myString = myString.replace(/\&quote;/ig, "'");
     return myString;
 } 
 
 function displayHTMLWithBB(myString){
     myString = myString.replace(/\&lt;\s*(b|i|li|ul|ol)\s*\&gt;/ig, "<$1>");
     myString = myString.replace(/\&lt;\s*a\s*href\s*=\&quot;(.*?)\&quot;\s*\&gt;/ig, "<a href=\"$1\">");
     myString = myString.replace(/\&lt;\s*\/\s*(b|i|a|li|ul|ol)\s*\&gt;/ig, "</$1>");
     myString = myString.replace(/\&lt;\s*img\s*src\s*=\s*\&quot;(.*?)\&quot;\s*\/\s*\&gt;/ig, "<img src=\"$1\"/>");
     return myString;
 } 
 
 function displayLinkedIconImage(message){
     var myImg = document.createTextNode(message);
     return myImg;
 }
 
 function createMarker(point, tab, myIcon, myTitle) {
    var marker = new GMarker(point, {icon:myIcon, title:myTitle, draggable:false});
    GEvent.addListener(marker, "click", function() {
        marker.openInfoWindowTabsHtml(tab);
    });
    return marker;
  }
  
 function removeChildrenFromNode(node){
    if(node === undefined && node == null){
       return;
    }
    while (node.hasChildNodes()){
       node.removeChild(node.firstChild);
    }
 }
 
 function minusTimePoint(){
     var pointImage = document.getElementById('timelinePoint');
     if(pointImage.style.left!='0px'){
         pointImage.style.left=parseInt(pointImage.style.left)-40 +'px';
         updateVisibleMarkers(1999+(parseInt(pointImage.style.left)/40));
     }
 }
 
 function plusTimePoint(){
     var pointImage = document.getElementById('timelinePoint');
     if(pointImage.style.left!='360px'){
         pointImage.style.left=parseInt(pointImage.style.left)+40 +'px';
         updateVisibleMarkers(1999+(parseInt(pointImage.style.left)/40));
     }
 }
 
 function setTimePoint(position){
     var pointImage = document.getElementById('timelinePoint');
     pointImage.style.left=(40*position) +'px';
     updateVisibleMarkers(1999+position);
 }
 
 function updateVisibleMarkers(year){
     var actualDate = new Date(year+1, 00, 01, 00, 00, 00);
     for(var i= 0; i<markerArray.length;i++){
	 if(markerArray[i].creation<actualDate){
	     if(markerArray[i].isHidden())
	         markerArray[i].show();
	 }else{
             if(!markerArray[i].isHidden())
	         markerArray[i].hide();
	 }
     }
 }
 
 function addMarkerToMgr(i, marker){
     if(i>=0 && i<100)             
         mManager1.addMarker(marker, 0, 17);
     else if(i>=100 && i<200)             
         mManager1.addMarker(marker, 8, 17);
     else if(i>=200 && i<450)             
         mManager1.addMarker(marker, 8, 17);
     else if(i>=450 && i<1000)             
         mManager1.addMarker(marker, 11, 17);
     else if(i>=1000)
         mManager1.addMarker(marker, 15, 17);
 }
 
 function displayCreationSortedMarkers(arrMarkers){
     var result="";
     for(var i=0;  i<arrMarkers.length && i<5; i++){
         result+="<div class='subOrg'><a href='rss.php?type=org&id="+arrMarkers[i].id+"' " 
	 result+="title='Regjistrohu tek ky kanal RSS per te ndjekur aktivitetet e reja te kesaj organizate'><img src='img/rssforsite.png' style='border: 0px solid rgb(255, 255, 255); margin-right: 7px; width: 15px; height: 15px;'/></a><a href='?mode=show&id="+arrMarkers[i].id+"' "
	 result+="title='Shih te dhenat per organizaten' class='orgLink'>"+arrMarkers[i].orgName+"</a></div>";
     }
     return result;	 
 }
 
 function displayMostActive(){
     markerArray.sort(function(a,b){
         var result = b.numberactivities - a.numberactivities;
         return result==0?a.id-b.id:result;
     }); 
     mManager1.clearMarkers();
     for(var i = 0; i<markerArray.length;i++){
	 addMarkerToMgr(i, markerArray[i]);
     }
 }
 
 function displayOrgOfTime(){
     mManager1.clearMarkers();
     var j=0;
     for(var i = 0; i<markerArray.length;i++){
	 if(markerArray[i].creation.getFullYear()<=refYear && arrayCategoryContains(markerArray[i].category)){
	     addMarkerToMgr(j, markerArray[i]);
	     j++;
	 }
     }
 }
 
 
 
 function getMarkersInsideBound(myBounds){
     var markersInsideArray=[];
     var categoryMarkersArray = [[0,"Stud"], [0,"Alum"], [0,"Akad"], [0,"Kult"], [0,"Rin"], [0,"Pol"], [0,"Fet"], [0,"Tjeter"]];
     var myHiddenNumber = 0;
     var j=0;
     for(var i = 0; i < markerArray.length; i++){
	 if(myBounds.containsLatLng(markerArray[i].getLatLng())){
             if(markerArray[i].creation.getFullYear()<=refYear && arrayCategoryContains(markerArray[i].category)){
	         markersInsideArray[j++] = markerArray[i];
	         categoryMarkersArray[markerArray[i].category-1][0]++;
	         if(markerArray[i].isHidden())
	             myHiddenNumber++;
	     }
	 }
     }
     return [markersInsideArray, myHiddenNumber, categoryMarkersArray];
 }
 
 
 function arrayCategoryContains(element){
      for (var i = 0; i < myOrgCategoryArray.length; i++){
          if (myOrgCategoryArray[i] == element){
              return true;
          }
      }
      return false;
  }
 
 
 function blowMarkerInArray(index){
     mapcoord.panTo(markerArray[index].getLatLng());
     GEvent.trigger(markerArray[index], 'click');
 }
 
 function createIcon(path){
     var iconCreated = new GIcon();
     iconCreated.image=path;
     iconCreated.iconSize = new GSize(20, 20);
     iconCreated.iconAnchor = new GPoint(10, 20);
     iconCreated.infoWindowAnchor = new GPoint(7, 2); 
     return iconCreated;
 }
 
 function calculatePercentage(piece, sum){
     if(piece==0) return 0;
     if(sum==0) return 0;
     var percent = 0;
     percent = (piece/sum) * 10000;
     var percentFloor = Math.floor(percent);
     if(percent - percentFloor <=0.5){
         percent = percentFloor/100;
     }else{
         percent = (percentFloor+1)/100;
     }
     return percent;
 }
 
