﻿// # DEPENDANCIES: helpers.js
// # DEPENDANCIES: epoly.js
//#################################################################################################### CLASS TABLE ###
//# CLASS CDebug - defines the advanced debug control
//--------------------------------------------------------------------------------------------------------------------
function CGMap(gmapLayerName, gmapOptions){ 
  // DATA ATTRIBUTES:
  this.map = new GMap2(document.getElementById(gmapLayerName));
  this.xmlToObject = new XML.ObjTree();   this.xmlToObject.force_array = ["marker"];
  this.dumper = new JKL.Dumper();
  this.baseIcon = new Array();
  this.icon = new Array();	
  this.marker = new Array(); this.marker_n = 0;
  this.data =new Array();
  this.request = new Array();  
  this.gmapLayerName = gmapLayerName; 
  this.markerCounter = 0;
  this.requestCounter = 0;
  
  this.mm;
  this.mmZoomForGroup = new Array();
  
  // STATE`S ATTRIBUTES:
  this.lng;           // LONGTITUDE
  this.lat;           // LATITUDE
  this.zoom           // ZOOM
  this.maptype;       // MAPTYPE
  this.url;           // URL TO CENTER POINT OF MAP AREA
  
  // EVENT`S ATTRIBUTES:
  this.markerLastId = 1;
  this.lastMarker = new GOverlay();
  this.lastIcon = new GIcon(G_DEFAULT_ICON);
  this.lastInfo = "";
  
  this.dirn1 = new GDirections();
  this.dirn2 = new GDirections();
  this.dirn3 = new GDirections();
  this.dirnMsg = "";

  this.firstpoint = true;
  this.gmarkers = [];
  this.gpolys = [];
  this.lastindex = 0;
  
  //OBJECT`S ATTRIBUTES:
  this.debug;       			// DEBUGGER OBJECT (type: CDebug)

  this.dlg_addMarker;
  
  //this.mnu_clickedPixel = new Array(0, 0);
  this.overlay = null;
  this.polygon = null;
  this.polygonPoints = new Array();
  this.clickX = 0;              // LAST CLICK MOUSE X COORDINAT
  this.clickY = 0;              // LAST CLICK MOUSE Y COORDINATE
  this.clickObjX = 0;           // LAST CLICKED OBJECT MOUSE X COORDINATE
  this.clickObjY = 0;           // LAST CLICKED OBJECT MOUSE Y COORDINATE  
  this.mouseX = 0;              // CURRENT MOUSE X COORDINATE
  this.mouseY = 0;              // CURRENT MOUSE Y COORDINATE

  this.mnu = new Array();;

  this.mapName;

  this.onMapInit_before = function(){};
  this.onMapInit_after = function(){};
  this.map_onClick_before = function(){};
  this.map_onClick_after = function(){};
  this.mapToPoint_onClick_before = function(){}; 
  this.mapToPoint_onClick_after = function(){};  			
  this.mapToMarker_onClick_before = function(){}; 
  this.mapToMarker_onClick_after = function(){};
  this.mapToPolygon_onClick_before = function(){}; 
  this.mapToPolygon_onClick_after = function(){};   
  this.map_onSinglerightclick_before = function(){};
  this.map_onSinglerightclick_after = function(){};  
  this.map_onMovestart_before = function(){};
  this.map_onMovestart_after = function(){};
  this.map_onMoveend_before = function(){};
  this.map_onMoveend_after = function(){};
  this.map_onMapTypeChanged_before = function(){};
  this.map_onMapTypeChanged_after = function(){};
  this.map_onMapZoomend_before = function(){};
  this.map_onMapZoomend_after = function(){};  
  this.marker_onClick_before = function(){};
  this.marker_onClick_after = function(){};
  this.marker_onDblClick_before = function(){};
  this.marker_onDblClick_after = function(){};
  this.marker_onSinglerightclick_before = function(){};
  this.marker_onSinglerightclick_after = function(){};
  this.marker_onDrag_before = function(){};
  this.marker_onDrag_after = function(){};    
  this.marker_onDragend_before = function(){};
  this.marker_onDragend_after = function(){};  
  this.polygon_onClick_before = function(){};
  this.polygon_onClick_after = function(){};
  this.polygon_onDblClick_before = function(){};
  this.polygon_onDblClick_after = function(){};
  this.onMarkersRequest_before = function(){};
  this.onMarkersRequestMapLoaded_before = function(){}; 
  this.onMarkersRequest_after = function(){};  
  
  this.gmapOptions = gmapOptions;
  
  if(this.gmapOptions.map.smoothZoomEnabled) this.map.enableContinuousZoom();
//--------------------------------------------------------------------------------------------------------------------
// ADDS DEBUGGER (THAT TRACES AND OUTPUTS DETAILS OF EVERY SINGLE METHOD)
//--------------------------------------------------------------------------------------------------------------------
  this.addDebugger = function(debuggerObj){	
    this.debug = debuggerObj;				
  }
//--------------------------------------------------------------------------------------------------------------------
// INIATATES SETUP OF BASIC MAP PARAMETRS (CENTER POINT, ZOOM, MAPTYPE)
//--------------------------------------------------------------------------------------------------------------------
  this.initMap = function(gmapObj, point, zoom, maptype){	
    this.debug.addEvent("initMap(point, zoom, maptype)", Array("point: "+point,"zoom: "+zoom,"maptype: "+maptype), "INIATATES SETUP OF BASIC MAP PARAMETRS (CENTER POINT, ZOOM, MAPTYPE)");
    /*EVENT*/ gmapObj.onMapInit_before();
    this.lng = point.x;
    this.lat = point.y;
    this.zoom = zoom;
    this.maptype = maptype;
    this.map.addControl(new GLargeMapControl());
    this.map.addControl(new GMapTypeControl());
    this.map.enableScrollWheelZoom();		
    this.map.setCenter(point, zoom, maptype);	
    this.mm = new GMarkerManager(this.map);
    /*EVENT*/ gmapObj.onMapInit_after();
    this.debug.print();
  }   
//--------------------------------------------------------------------------------------------------------------------
// ADDS NEW BASE ICON (A TEMPLATE THAT APPLIES TO MOST ICONS)
//--------------------------------------------------------------------------------------------------------------------
  this.addBaseIcon = function(id, size, shadowSize, anchor, infoWindowAnchor){	
    this.debug.addEvent("addBaseIcon(id, size, shadowSize, anchor, infoWindowAnchor)", Array("id: "+id,"size: "+size,"shadowSize: "+shadowSize,"anchor: "+anchor,"infoWindowAnchor: "+infoWindowAnchor), "ADDS NEW BASE ICON (A TEMPLATE THAT APPLIES TO MOST ICONS)");
    this.baseIcon[id] = new GIcon();	
    this.baseIcon[id].iconSize = size;
    this.baseIcon[id].shadowSize = shadowSize;
    this.baseIcon[id].iconAnchor = anchor;
    this.baseIcon[id].infoWindowAnchor = infoWindowAnchor;			
    this.debug.print();
  }
//--------------------------------------------------------------------------------------------------------------------
// ADDS NEW ICON (SMALL IMAGE THAT IS DISPLAYED ON MARKERS)
//--------------------------------------------------------------------------------------------------------------------
  this.addIcon = function(id, baseIconName, fileName){	
    this.debug.addEvent("addIcon(id, baseIconName, fileName)", Array("id: "+id,"baseIconName: "+baseIconName,"fileName: "+fileName), "ADDS NEW ICON (SMALL IMAGE THAT IS USED ON MARKERS)");	
    if(baseIconName!=null && fileName!=null){
      this.icon[id] = new GIcon(this.baseIcon[baseIconName], fileName);	
    }
    else{
      this.icon[id] = new GIcon(G_DEFAULT_ICON);
    }
    this.debug.print();		
  }	
//--------------------------------------------------------------------------------------------------------------------
// ADDS NEW MARKER TO MAP AND CONTAINER
//--------------------------------------------------------------------------------------------------------------------
  this.addMarker = function(gmapObj, point, icon, draggable){
    marker = new GMarker(point, {icon:icon, draggable:draggable});  
    gmapObj.marker.push(marker);   

    var marker = gmapObj.marker[gmapObj.marker.length-1];
    GEvent.addListener(marker, "click", function(overlay){		 //alert("1");
      gmapObj.debug.addEvent("marker click(overlay)", Array("overlay: "+overlay),"EVENT OCCURES WHEN USER CLICKS THE MARKER");
      /*EVENT*/ gmapObj.marker_onClick_before();
      /*EVENT*/ gmapObj.marker_onClick_after();
      gmapObj.debug.print()
    });
    GEvent.addListener(marker, "dblclick", function(overlay){
      gmapObj.debug.addEvent("marker click(overlay)", Array("overlay: "+overlay),"EVENT OCCURES WHEN USER DOUBLE CLICKS THE MARKER");
      /*EVENT*/ gmapObj.marker_onDblClick_before();
      /*EVENT*/ gmapObj.marker_onDblClick_after();
      gmapObj.debug.print()
    });    
    GEvent.addListener(marker, "drag", function(){										   
      /* NO OVERLAY IS SET WITHIN THIS METHOD (MUST CLICK TO SELECT OVERLAY TO PERFORM OPERATION)*/  
      var point = marker.getLatLng();
      gmapObj.debug.addEvent("marker drag", Array("lat: "+point.y, "lng: "+point.x), "EVENT OCCURES WHILE USER IS DRAGING  THE MARKER");	
      /*EVENT*/ gmapObj.marker_onDrag_before();
      gmapObj.overlay.lat = marker.getLatLng().lat();
      gmapObj.overlay.lng = marker.getLatLng().lng();		
      /*EVENT*/ gmapObj.marker_onDrag_after();	  
      gmapObj.debug.print();
    });		
    GEvent.addListener(marker, "dragend", function(){  
      /*EVENT*/ gmapObj.marker_onDragend_before();
      var point = marker.getLatLng();
      setTimeout('if(gmap.overlay != null) if((gmap.overlay.ext_type == null) && (gmap.overlay.draggingEnabled())) gmap.overlay.disableDragging()', gmapObj.gmapOptions.overlay.deactivateTimeout);
      gmapObj.clickObjX = gmapObj.map.fromLatLngToContainerPixel(marker.getPoint()).x;
      gmapObj.clickObjY = gmapObj.map.fromLatLngToContainerPixel(marker.getPoint()).y;	  
      gmapObj.overlay.lat = marker.getLatLng().lat();
      gmapObj.overlay.lng = marker.getLatLng().lng();
      gmapObj.debug.addEvent("marker dragend", Array("lat: "+point.y, "lng: "+point.x), "EVENT OCCURES WHEN USER STOPS TO DRAG THE MARKER");	
      /*EVENT*/ gmapObj.marker_onDragend_after();	  
      gmapObj.debug.print();
    });

    gmapObj.marker[gmapObj.marker.length-1] = marker;    
    return gmapObj.marker[gmapObj.marker.length-1];
  }
//--------------------------------------------------------------------------------------------------------------------
// ADDS NEW POLYGON TO MAP AND CONTAINER
//--------------------------------------------------------------------------------------------------------------------
  this.addPolygon = function(gmapObj, pts, borderColor, opacity){
    polygon = new GPolygon(pts, null, 5, 0.7, borderColor, opacity);
    gmapObj.marker.push(polygon);   

    var marker = gmapObj.marker[gmapObj.marker.length-1];
    GEvent.addListener(marker, "click", function(overlay){		 //alert("1");
      gmapObj.debug.addEvent("marker click(overlay)", Array("overlay: "+overlay),"EVENT OCCURES WHEN USER CLICKS THE MARKER");
      /*EVENT*/ gmapObj.polygon_onClick_before();
      /*EVENT*/ gmapObj.polygon_onClick_after();
      gmapObj.debug.print()
    });
    GEvent.addListener(marker, "dblclick", function(overlay){
      gmapObj.debug.addEvent("marker click(overlay)", Array("overlay: "+overlay),"EVENT OCCURES WHEN USER DOUBLE CLICKS THE MARKER");
      /*EVENT*/ gmapObj.polygon_onDblClick_before();
      /*EVENT*/ gmapObj.polygon_onDblClick_after();
      gmapObj.debug.print()
    });    

    gmapObj.marker[gmapObj.marker.length-1] = polygon;    
    return gmapObj.marker[gmapObj.marker.length-1];
  }
//--------------------------------------------------------------------------------------------------------------------
// ADDS NEW MARKER (GUI ELEMENT THAT IS USED TO DISPLAY INFO)
//--------------------------------------------------------------------------------------------------------------------
  this.loadMarker = function(gmapObj, id, point, html, icon, draggable){
    var marker = new GMarker(point, {icon:icon, draggable:draggable});

    GEvent.addListener(marker, "click", function(overlay){		 //alert("1");
      gmapObj.debug.addEvent("marker click(overlay)", Array("overlay: "+overlay),"EVENT OCCURES WHEN USER CLICKS THE MARKER");
      /*EVENT*/ gmapObj.marker_onClick_before();
      /*EVENT*/ gmapObj.marker_onClick_after();
      gmapObj.debug.print()
    });
    GEvent.addListener(marker, "drag", function(){										   
      /* NO OVERLAY IS SET WITHIN THIS METHOD (MUST CLICK TO SELECT OVERLAY TO PERFORM OPERATION)*/  
      var point = marker.getLatLng();
      gmapObj.debug.addEvent("marker drag", Array("lat: "+point.y, "lng: "+point.x), "EVENT OCCURES WHILE USER IS DRAGING  THE MARKER");	
      /*EVENT*/ gmapObj.marker_onDrag_before();
      gmapObj.overlay.lat = marker.getLatLng().lat();
      gmapObj.overlay.lng = marker.getLatLng().lng();		
      /*EVENT*/ gmapObj.marker_onDrag_after();	  
      gmapObj.debug.print();
    });		
    GEvent.addListener(marker, "dragend", function(){  
      /*EVENT*/ gmapObj.marker_onDragend_before();
      var point = marker.getLatLng(); 
      if(gmap.overlay != null){
        if((gmap.overlay.ext_type == null) && (gmap.overlay.draggingEnabled())){   // MARKER SELECTED           
	        setTimeout('gmap.overlay.disableDragging()', gmapObj.gmapOptions.overlay.deactivateTimeout);
	      }
	    }
      gmapObj.clickObjX = gmapObj.map.fromLatLngToContainerPixel(marker.getPoint()).x;
      gmapObj.clickObjY = gmapObj.map.fromLatLngToContainerPixel(marker.getPoint()).y;	  
      gmapObj.overlay.lat = marker.getLatLng().lat();
      gmapObj.overlay.lng = marker.getLatLng().lng();
      gmapObj.debug.addEvent("marker dragend", Array("lat: "+point.y, "lng: "+point.x), "EVENT OCCURES WHEN USER STOPS TO DRAG THE MARKER");	
      /*EVENT*/ gmapObj.marker_onDragend_after();	  
      gmapObj.debug.print();
    });

    return marker;
  }  
//--------------------------------------------------------------------------------------------------------------------
// ADDS NEW OVERLAY (GUI ELEMENT TO INTERACT WITH MAP)
//--------------------------------------------------------------------------------------------------------------------
  this.addOverlay = function(gmapObj, point, icon, draggable){
    this.debug.addEvent("addOverlay(gmapObj, point, icon, draggable)", Array("gmapObj: "+gmapObj,"point: "+point,"icon: "+icon,"draggable: "+draggable), "ADDS NEW OVERLAY (GUI ELEMENT TO INTERACT WITH MAP)"); 	
    var overlay = this.addMarker(gmapObj, point, icon, draggable); 
    this.map.addOverlay(overlay);
    this.debug.print();	
    return overlay;
  }
//--------------------------------------------------------------------------------------------------------------------
// REMOVOS ALL OVERLAYS FROM THE MAP
//--------------------------------------------------------------------------------------------------------------------
  this.clearOverlays = function(gmapObj){
    gmapObj.debug.addEvent("clearOverlays(gmapObj)", Array("gmapObj: "+gmapObj), "REMOVOS ALL OVERLAYS FROM THE MAP");   
    // REMOVE DIRECTIONS
    gmapObj.dirn1.clear();
    gmapObj.dirn2.clear();
    gmapObj.dirn3.clear();
    gmapObj.firstpoint = true;
    gmapObj.gmarkers = [];
    gmapObj.gpolys = [];
    gmapObj.lastindex = 0;
    // REMOVE OVERLAYS
    gmapObj.map.clearOverlays();
    gmapObj.marker = [];
    // RESET STATUS
    gmapObj.overlay = null;
    gmapObj.polygon = null;
    gmapObj.polygonPoints = null;
    gmapObj.markerCounter = 0;
    gmapObj.requestCounter = 0;
    gmapObj.debug.print();	
  }  
//--------------------------------------------------------------------------------------------------------------------
// SETS OVERLAY TO A PREDIFINED MODE OF OPERATION
//--------------------------------------------------------------------------------------------------------------------
  this.setInteractionMode = function(gmapObj, mode){
    this.debug.addEvent("setInteractionMode(gmapObj, mode)", Array("gmapObj: "+gmapObj,"mode: "+mode), "SETS MAP TO PREDIFINED MODE OF INTERACTION WITH CLIENT");	  
    switch(mode){
      case "populate":{
        GEvent.addListener(this.map, "click", function(overlay, point){	//alert("Got You =)");
          removePolygonHelpers();
          finishPolygon(); 
          
          /*EVENT*/ gmapObj.map_onClick_before();
          gmapObj.clickX = gmapObj.mouseX;
          gmapObj.clickY = gmapObj.mouseY;

          if(point){
            /*EVENT*/ gmapObj.mapToPoint_onClick_before();       
            gmapObj.debug.addEvent("map click(overlay, point)", Array("overlay: "+overlay,"point: "+point), "EVENT FIRES WHEN USER CLICKS ON MAP AREA (EMPTY AREA)");
            gmapObj.debug.print();
            /*EVENT*/ gmapObj.mapToPoint_onClick_after();		
          }
          else{         
            // DISABLE DRAGING OF LAST SELECTED OVERLAY
            if(gmapObj.overlay != null){
              if(gmapObj.overlay instanceof GMarker){              
                if(gmap.overlay.ext_type == null){
                  if(gmap.overlay.draggingEnabled()){
                    gmapObj.overlay.disableDragging();
                  }
                }
              }
              else if(gmapObj.overlay instanceof GPolygon){              
              }
            }
            // PREPARE TO SELECT NEW OVERLAY
                         
            if(overlay instanceof GMarker){        // NEW OVERLAY WE ARE SELECTING IS MARKER 
              /*EVENT*/ gmapObj.mapToMarker_onClick_before();            
              gmapObj.overlay = overlay;
              gmapObj.clickObjX = gmapObj.map.fromLatLngToContainerPixel(overlay.getPoint()).x;
              gmapObj.clickObjY = gmapObj.map.fromLatLngToContainerPixel(overlay.getPoint()).y;	 
              
              //<summary>USER DEFINED OPTION</summary>
              //<description>Defines if selected marker becomes draggable</description>
              if(gmapObj.gmapOptions.overlay.draggableOnClick == true) gmapObj.overlay.enableDragging();             
                          
              /* MAKE DRAGABLE ON CLICK*/ 
              lat = overlay.lat = overlay.getLatLng().lat();
              lng = overlay.lng = overlay.getLatLng().lng();
              gmapObj.debug.addEvent("map click(overlay, point)", Array("overlay: "+overlay+" (x: "+gmapObj.mouseX+", y: "+gmapObj.mouseY+")"+", (lat: "+lat+", lng: "+lng+")","point: "+point), "EVENT OCCURES WHEN USER CLICKS THE MAP AREA");			
              gmapObj.lastIcon = overlay.getIcon();
              gmapObj.debug.print();   
              /*EVENT*/ gmapObj.mapToMarker_onClick_after();                           
            }
            else if(overlay instanceof GPolygon){  // NEW OVERLAY WE ARE SELECTING IS POLYGON 
              /*EVENT*/ gmapObj.mapToPolygon_onClick_before();             
            	gmapObj.overlay = overlay;   
              gmapObj.polygon = overlay;         
              if(gmapObj.polygonPoints == null) gmapObj.polygonPoints = new Array();               
              //addPolygonHelpers();
              
              polyPointsCount = overlay.getVertexCount();
              polyPoints = Array();
              for(i=0; i<polyPointsCount; i++){
                polyPoints[i] = overlay.getVertex(i);
              }
              
              minIndex = 0
              for(i=0; i<polyPoints.length; i++){
                if(polyPoints[i] < polyPoints[minIndex]){
                  minIndex = i;
                }
              }
            
              gmapObj.clickObjX = gmapObj.map.fromLatLngToContainerPixel(overlay.getVertex(minIndex)).x;
              gmapObj.clickObjY = gmapObj.map.fromLatLngToContainerPixel(overlay.getVertex(minIndex)).y;              
              lat = overlay.lat = overlay.getVertex(minIndex).lat();
              lng = overlay.lng = overlay.getVertex(minIndex).lng();
              gmapObj.debug.addEvent("map click(overlay, point)", Array("overlay: "+overlay+" (x: "+gmapObj.mouseX+", y: "+gmapObj.mouseY+")"+", (lat: "+lat+", lng: "+lng+")","point: "+point), "EVENT OCCURES WHEN USER CLICKS THE MAP AREA");			
              gmapObj.debug.print();
              /*EVENT*/ gmapObj.mapToPolygon_onClick_after();                        
            }
          }
          /*EVENT*/ gmapObj.map_onClick_after();	
        });		

        GEvent.addListener(this.map, "movestart", function(){
          /*EVENT*/ gmapObj.map_onMovestart_before();	  
          /*EVENT*/ gmapObj.map_onMovestart_after();
        });	
        GEvent.addListener(this.map, "moveend", function(){
          /*EVENT*/ gmapObj.map_onMoveend_before();
          /*EVENT*/ gmapObj.map_onMoveend_after();
        });
        GEvent.addListener(this.map, "maptypechanged", function(){
          /*EVENT*/ gmapObj.map_onMapTypeChanged_before();
          this.mapName = convertBalticToLatin(gmapObj.map.getCurrentMapType().getName());
          /*EVENT*/ gmapObj.map_onMapTypeChanged_after();		  
        });	
        GEvent.addListener(this.map, "zoomend", function(){
          /*EVENT*/ gmapObj.map_onMapZoomend_before();
          /*EVENT*/ gmapObj.map_onMapZoomend_after();		        
          // PROBLEM: we fail to provide markers positions (in pixels) for map dialogs to markers while zooming
        });
      }    
    }
  }  
//--------------------------------------------------------------------------------------------------------------------
// COPY OBJECT
//--------------------------------------------------------------------------------------------------------------------  
  this.copyObj = function(dupeObj){
    var retObj = new Object();
    if(typeof(dupeObj) == 'object'){
      if(typeof(dupeObj.length) != 'undefined')
        var retObj = new Array();
      for(var objInd in dupeObj){   
        if(typeof(dupeObj[objInd]) == 'object'){
          retObj[objInd] = this.copyObj(dupeObj[objInd]);
        } 
        else if((typeof(dupeObj[objInd]) == 'string') || (typeof(dupeObj[objInd]) == 'number')){
          retObj[objInd] = dupeObj[objInd];
        }
        else if(typeof(dupeObj[objInd]) == 'boolean'){
          retObj[objInd] = (dupeObj[objInd] == true ? true : false);
        }
      }
    }
    else{
      retObj = dupeObj;
    }
    return retObj;
  }  
//--------------------------------------------------------------------------------------------------------------------
// GETS DATA FROM *.XML FILE
//--------------------------------------------------------------------------------------------------------------------
  this.setDataFromXml = function(gmapObj, reqData, xmlVersion, dLat, dLng){
    //gmapObj.debug.addEvent("setDataFromXml(gmapObj, fileName)", Array( "gmapObj: "+gmapObj, "fileName: "+fileName), "GETS DATA FROM *.XML FILE");
    xmlVersion = (xmlVersion != null ? xmlVersion : "0.1");
    dLat = (dLat != null ? dLat : 0);
    dLng = (dLng != null ? dLng : 0);	

    var fileName = reqData.target + "?";
    for(p in reqData.params) if(reqData.params[p]) fileName += (fileName.substr(fileName.length-1, 1) != "?" ? "&" : "") + p + "=" + reqData.params[p];

    var request = Helper.Ajax.CreateHttpRequest();               
    requestId = fileName;

    requestDetails.file.name = fileName;
    requestDetails.data = reqData;
    requestDetails.transfer.start = Helper.Time.Get();
    
    this.request[requestId] = requestDetails;
    request.open("GET", fileName, true);
    // DISABLE CACHING
    request.setRequestHeader("If-Modified-Since", "Sat, 1 Jan 2000 00:00:00 GMT");
    request.setRequestHeader("Cache-Control", "no-cache");

    request.onreadystatechange = function(){
      if(request.readyState == 4){
          RID = requestId;

        /*EVENT*/ gmapObj.onMarkersRequest_before(); 
        if(RID == gmapObj.request[RID].file.name){
          d1 = gmapObj.request[RID].transfer.start;
          d2 = gmapObj.request[RID].transfer.end = Helper.Time.Get();          
          gmapObj.request[RID].transfer.delay = d2 - d1;          
          gmapObj.request[RID].storage.start = gmapObj.marker.length;           
        }        

        if(request.responseText <= 0){
          /*EVENT*/ gmapObj.onMarkersRequest_after(RID);
          return -1;
        }

        switch(xmlVersion){
          case "0.1":{
            alert('CGMap.js: XML v.0.1 IS NOT LONGER SUPPORTED');	 
            break;
          }	
          case "0.2":{         
            var markersTree = gmapObj.xmlToObject.parseXML(request.responseText);
            
            var markers = new Array();
            markers[0] = markersTree.data.item;
            if(markersTree.data.item.length != null){
              markers = markersTree.data.item
            }
      
            gmapObj.debug.addEvent("markerCounter, requestCounter", Array( "markers: "+gmapObj.markerCounter, "requests: "+ gmapObj.requestCounter ), "COUNTER OF MARKERS");             

            for(var i = 0; i < markers.length; i++){
              gmapObj.data[i] = markers[i];
              
              try{
                var groups = "";
                var pieces = gmapObj.copyObj(gmapObj.data[i]["-group"]);
                var piece = pieces.split(", ");
                
                for(j=0; j < gmapObj.gmapOptions.search.groups_depth; j++){
                  if(piece[j] != null){
                    groups += (j >= 1 ? gmapObj.gmapOptions.search.groups_separator : "");                
                    groups += piece[j];
                  }
                } 
                gmapObj.data[i]["-group"] = groups;               
              }
              catch(ex){}              

              try{
                var categories = "";
                var pieces = gmapObj.copyObj(gmapObj.data[i]["-category"]);
                var piece = pieces.split(gmapObj.gmapOptions.search.categories_separator);

                for(j=0; j < gmapObj.gmapOptions.search.categories_depth; j++){
                  if(piece[j] != null){
                    categories += (j >= 1 ? gmapObj.gmapOptions.search.categories_separator : "");                
                    categories += piece[j];
                  }
                } 
                gmapObj.data[i]["-category"] = categories;               
              }
              catch(ex){}
            }            
            /*EVENT*/ gmapObj.onMarkersRequestMapLoaded_before(); 
                      
            for(var i = 0; i < markers.length; i++){
              var point   = new GLatLng(gmapObj.data[i]["-lat"], gmapObj.data[i]["-lng"]);
              min = (gmapObj.mmZoomForGroup[gmapObj.data[i]["-group"]] != null ? gmapObj.mmZoomForGroup[gmapObj.data[i]["-group"]]["min"] : 10);
              max = (gmapObj.mmZoomForGroup[gmapObj.data[i]["-group"]] != null ? gmapObj.mmZoomForGroup[gmapObj.data[i]["-group"]]["max"] : 17);	  
	            subAttributes = parseAttribute('custom', gmapObj.data[i]["-custom"]);
	            points = (subAttributes['points'] != null ? subAttributes['points'].value : '');
	            pts = Array();
	            	                                    
	            if(points == ''){
                // ADD MARKER
                marker = gmapObj.addMarker(gmapObj, point, gmapObj.icon[gmapObj.data[i]["-icon"]], true);
                marker.data               = gmapObj.copyObj(gmapObj.data[i]); 
                marker.data["+icon_path"] = marker.getIcon().image;
                marker.data["+country"]   = "Lietuva"; 
                marker.data.GetProperty   = OVERLAY.GetProperty;
                               
                marker.disableDragging();
	            }
	            else{
	              // ADD POLYGON
                piece = points.split(";");
                for(j=0; j<piece.length; j++){
                  piece[j] = piece[j].replace(' ', '');
                  coords = piece[j].split(",");
                  lat = (coords[0] != null ? coords[0].replace(' ', '') : null); 
                  lng = (coords[1] != null ? coords[1].replace(' ', '') : null);                   
                  if((lat != null) && (lng != null)) pts[j] = new GLatLng(lat, lng);
                }
                polygon = gmapObj.addPolygon(gmapObj, pts, "#aaaaff", 0.5); 
                polygon.data               = gmapObj.copyObj(gmapObj.data[i]);
                polygon.data["+icon_path"] = "";
                polygon.data["+country"]   = "Lietuva";
                polygon.data.GetProperty   = OVERLAY.GetProperty;
	            }
            }	
            //gmapObj.data = null;
            
            gmapObj.request[RID].storage.end   = gmapObj.marker.length;  
	          gmapObj.request[RID].storage.count = gmapObj.request[RID].storage.end - gmapObj.request[RID].storage.start;
	          
	          gmapObj.markerCounter += markers.length;	
            gmapObj.requestCounter++;
          }	
          default:{
          }	  		
        }    
        /*EVENT*/ gmapObj.onMarkersRequest_after(RID);        
        gmapObj.mm.refresh();	  
      }
    }	
    request.send(null);    
    //this.debug.print();
  }  
//--------------------------------------------------------------------------------------------------------------------
// RENDERS OVERLAYS ON THE MAP
//--------------------------------------------------------------------------------------------------------------------
  this.renderOverlays = function(gmapObj, requestId){
    if(gmapObj.request[requestId] != null){
      gmapObj.request[requestId].render.start = Helper.Time.Get();

      //gmapObj.debug.addEvent("RenderOverlays(gmapObj, requestId)", Array( "gmapObj: "+gmapObj, "requestId: "+requestId), "RENDERS OVERLAYS ON THE MAP");
      for(i=gmapObj.request[requestId].storage.start; i<gmapObj.request[requestId].storage.end; i++){
        gmapObj.map.addOverlay(gmapObj.marker[i]);
      }
      //gmapObj.debug.print();
      
      d1 = gmapObj.request[requestId].render.start;
      d2 = gmapObj.request[requestId].render.end = Helper.Time.Get();          
      gmapObj.request[requestId].render.delay = d2 - d1;  
    }      
  } 
//--------------------------------------------------------------------------------------------------------------------
// SETS MAP LAYOUT (LONTITUDE, LATITUDE, ZOOM, MAP TYPE) FROM URL PARAMETERS
//--------------------------------------------------------------------------------------------------------------------
  this.setLayoutFromURL = function(lat, lng, zoom, maptype){  
    this.debug.addEvent("setLayoutFromURL([lat, lng, zoom, maptype])", Array("lat: "+lat,"lng: "+lng,"zoom: "+zoom,"maptype: "+maptype), "SETS MAP LAYOUT (LONTITUDE, LATITUDE, ZOOM, MAP TYPE) FROM URL PARAMETERS");	  
    if(lat) this.lat = lat;
    if(lng) this.lng = lng;
    if(zoom) this.zoom = zoom;
    if(maptype) this.maptype = maptype;

    var query = location.search.substring(1);

    // split the rest at each "&" character to give a list of  "argname=value"  pairs
    var pairs = query.split("&");
    for(var i=0; i<pairs.length; i++) {
      // break each pair at the first "=" to obtain the argname and value
      var pos = pairs[i].indexOf("=");
      var argname = pairs[i].substring(0,pos).toLowerCase();
      var value = pairs[i].substring(pos+1).toLowerCase();

      // process each possible argname
      if(argname == "lat"){ this.lat = parseFloat(value); }
      if(argname == "lng"){ this.lng = parseFloat(value); }
      if(argname == "zoom"){this.zoom = parseInt(value); }
      if(argname == "type"){
        if(value == "m"){ this.maptype = G_NORMAL_MAP; }
        if(value == "k"){ this.maptype = G_SATELLITE_MAP; }
        if(value == "h"){ this.maptype = G_HYBRID_MAP; }
      }
    }

    this.map.setCenter(new GLatLng(this.lat,this.lng), this.zoom, this.maptype);	
    this.debug.print();	
  }
//--------------------------------------------------------------------------------------------------------------------
// RETURNS URL OF THE VISIBLE MAP AREA
//--------------------------------------------------------------------------------------------------------------------
  this.getUrl = function(urlBase){ 
    this.debug.addEvent("getUrl(urlBase)", Array("urlBase: "+urlBase), "RETURNS URL OF THE VISIBLE MAP AREA");
    var url = (urlBase == null ? document.location.href : urlBase);
	  url += "?lat=" + this.map.getCenter().lat().toFixed(6)
         + "&lng=" + this.map.getCenter().lng().toFixed(6)
         + "&zoom=" + this.map.getZoom()
         + "&type=" + this.map.getCurrentMapType().getUrlArg();
    this.debug.print(url);
    return url;
  }
//--------------------------------------------------------------------------------------------------------------------
// ADDS EVENT TO TRACK AND COMPOSE THE URL OF THE VISIBLE MAP AREA
//--------------------------------------------------------------------------------------------------------------------  
  this.addEventToSetUrlFromLayout = function(gmapObj){ 
    GEvent.addListener(this.map, 'moveend', function(){ 
      gmapObj.debug.addEvent("addEventToSetUrlFromLayout(gmapObj)", Array("gmapObj: "+gmapObj), "ADDS EVENT TO TRACK AND COMPOSE THE URL OF THE VISIBLE MAP AREA");
      gmapObj.url = gmapObj.getUrl();
      gmapObj.debug.print();	
    });
  } 
//--------------------------------------------------------------------------------------------------------------------
// ZOOM TO FIT OVERLAYS
//--------------------------------------------------------------------------------------------------------------------  
  this.zoomToFit = function(gmapObj){ 
    var bounds = new GLatLngBounds();      
    for(i=0; i<gmapObj.marker.length; i++){
      bounds.extend(new GLatLng(gmapObj.marker[i].data["-lat"], gmapObj.marker[i].data["-lng"]));
    }
    if(gmapObj.marker.length > 0){
      gmapObj.map.setZoom((gmapObj.map.getBoundsZoomLevel(bounds) < 16 ? gmapObj.map.getBoundsZoomLevel(bounds) : 16));
      gmapObj.map.setCenter(bounds.getCenter());
    }
  }
  
//--------------------------------------------------------------------------------------------------------------------
// SETS MINIMUM AND MAXIMUM ZOOM BOUNDARY
//--------------------------------------------------------------------------------------------------------------------
  this.setZoomBounds = function(minValue, maxValue, mapType){//mapType: m - map, k - satellite or h - hybrid
    this.debug.addEvent("setZoomBounds(minValue, maxValue, mapType)", Array("minValue: "+minValue,"maxValue: "+maxValue,"mapType: "+mapType), "SETS MINIMUM AND MAXIMUM ZOOM BOUNDARY");	  
    var mt = this.map.getMapTypes();
    // Overwrite the getMinimumResolution() and getMaximumResolution() methods for map
    for (var i=0; i<mt.length; i++) {
      if(mt[i].getUrlArg() == mapType){
        mt[i].getMinimumResolution = function() {return minValue;}
        mt[i].getMaximumResolution = function() {return maxValue;}
      }
    }
    this.debug.print();
  }
//--------------------------------------------------------------------------------------------------------------------
// RESTRICTS MAP BOUNDARIES TO GIVEN COORDINATES
//--------------------------------------------------------------------------------------------------------------------
  this.addEventToRestrictMapBounds = function(gmapObj, MinYX, MaxYX){
    this.debug.addEvent("addEventToRestrictMapBounds(gmapObj, MinYX, MaxYX)", Array("gmapObj: "+gmapObj,"minX: "+MinYX.x,"minY: "+MinYX.y, "maxX: "+MaxYX.x, "maxY: "+MaxYX.y), "RESTRICTS MAP CENTER BOUNDARIES TO GIVEN COORDINATES");	
	if(MinYX.x > MaxYX.x) {
	  alert("setMapBounds(): Min x > Max x !!");
	  this.debug.print();
	  return;
	}
	if(MinYX.y > MaxYX.y) {
	  alert("setMapBounds(): Min y > Max y !!");
	  this.debug.print();
	  return;
	}
    // The allowed region which the whole map must be within
    var allowedBounds = new GLatLngBounds(MinYX, MaxYX);
    GEvent.addListener(this.map, "move", function() {						
      if (allowedBounds.contains(gmapObj.map.getCenter())) {
         return;
      }
      // It`s not OK, so find the nearest allowed point and move there
      var C = gmapObj.map.getCenter();
      var X = C.lng();
      var Y = C.lat();
  
      if (X < MinYX.x) {X = MinYX.x;}
      if (X > MaxYX.x) {X = MaxYX.x;}
      if (Y < MinYX.y) {Y = MinYX.y;}
      if (Y > MaxYX.y) {Y = MaxYX.y;}
      //alert ("Restricting "+Y+" "+X);
      gmapObj.map.setCenter(new GLatLng(Y,X));
    });
  }
//--------------------------------------------------------------------------------------------------------------------
// RETURNS TRUE IF MAP CENTER IS IN BOUNDARIES
//--------------------------------------------------------------------------------------------------------------------
  this.checkBounds = function(gmapObj, MinYX, MaxYX){
    this.debug.addEvent("setMapBounds(gmapObj, MinYX, MaxYX)", Array("gmapObj: "+gmapObj,"minX: "+MinYX.x,"minY: "+MinYX.y, "maxX: "+MaxYX.x, "maxY: "+MaxYX.y), "RETURNS TRUE IF MAP CENTER IS IN BOUNDARIES");	
   var allowedBounds = new GLatLngBounds(MinYX, MaxYX);
     // Perform the check and return if OK
   if (allowedBounds.contains(this.map.getCenter())) {
     this.debug.print();
     return true;
   }	
   this.debug.print();
   return false;
  }  
//--------------------------------------------------------------------------------------------------------------------
// AUTO ZOOM AND FIT TO SCREEN FOR GIVEN POINTS
//--------------------------------------------------------------------------------------------------------------------
  this.setZoomAndFit = function(gmapObj, latLngs){
    this.debug.addEvent("setZoomAndFit(gmapObj, latLngs)", Array("gmapObj: "+gmapObj,"latLngs: "+latLngs), "AUTO ZOOM AND FIT TO SCREEN FOR GIVEN POINTS");	
    var bounds = new GLatLngBounds();
    for (var i=0; i < latLngs.length; i++){
      bounds.extend(latLngs[i]);
    }
    // ===== determine the zoom level from the bounds =====
    this.map.setZoom(this.map.getBoundsZoomLevel(bounds));

    // ===== determine the centre from the bounds ======
    this.map.setCenter(bounds.getCenter());
  } 
//--------------------------------------------------------------------------------------------------------------------
// SETS MIN, MAX ZOOM BOUNDS FOR OBJECTS TO BE VISIBLE IN PARTICULAR GROUP
//--------------------------------------------------------------------------------------------------------------------
  this.setZoomForGroup = function(groupId, minZoom, maxZoom){	
    this.debug.addEvent("setZoomForGroup(groupId, minZoom, maxZoom)", Array("groupId: "+groupId,"minZoom: "+minZoom,"maxZoom: "+maxZoom), "SETS MIN, MAX ZOOM BOUNDS FOR OBJECTS TO BE VISIBLE IN PARTICULAR GROUP)");
    this.mmZoomForGroup[groupId] = new Array(2);
    this.mmZoomForGroup[groupId]["min"] = minZoom;
    this.mmZoomForGroup[groupId]["max"] = maxZoom;
    this.debug.print();
  }  
//--------------------------------------------------------------------------------------------------------------------
// AUTO ZOOM AND FIT TO SCREEN FOR GIVEN POINTS
//--------------------------------------------------------------------------------------------------------------------
  this.setZoomAndFit = function(gmapObj, points){
    this.debug.addEvent("setMapBounds(gmapObj, points)", Array("gmapObj: "+gmapObj,"points: "+points), "AUTO ZOOM AND FIT TO SCREEN FOR GIVEN POINTS");	
    var bounds = new GLatLngBounds();
    for (var i=0; i < points.length; i++){
      bounds.extend(latLngs[i]);
    }
    // ===== determine the zoom level from the bounds =====
    this.map.setZoom(this.map.getBoundsZoomLevel(bounds));

    // ===== determine the centre from the bounds ======
    this.map.setCenter(bounds.getCenter());
  }  
//--------------------------------------------------------------------------------------------------------------------
// CREATE CONTEXT MENU IN MAP
//--------------------------------------------------------------------------------------------------------------------
  this.addContextMenu = function(gmapObj, innerHTML, id, width, height){
    this.debug.addEvent("addEventContextMenu", Array("gmapObj: "+gmapObj,"innerHTML: "+innerHTML,"id: "+id), "CREATE CONTEXT MENU IN MAP");	
    mnu_x = document.createElement("div");
    mnu_x.id = id;
    mnu_x.className = 'mnu';
    if(width != null && height != null){
      mnu_x.width  = width;     mnu_x.style.width  = width + 'px';
      mnu_x.height = height;
    }
    mnu_x.style.visibility = "hidden";	
    mnu_x.style.display = "none";
    mnu_x.innerHTML = innerHTML;
//  this.map.getContainer().appendChild(mnu_x);
    document.body.appendChild(mnu_x);	

    GEvent.addListener(this.map, "click", function(overlay, point){
      document.getElementById(id).style.display = "none";
    });	

    GEvent.addListener(this.map, "singlerightclick", function(point, src, overlay){
      document.getElementById(id).style.display = "none"; //a = gmapObj.map.fromDivPixelToLatLng(point); alert(a.lat()+", "+a.lng());
      gmapObj.clickX = point.x;
      gmapObj.clickY = point.y;

      if((overlay instanceof GMarker) || (overlay instanceof GPolygon)){                                // MARKER OR POLYLINE SELECTED
        gmapObj.debug.addEvent("marker_singleRightClick", Array("gmapObj: "+gmapObj, "overlay: "+overlay, "src.id: "+src.id), "EVENT FIRES WHEN USER CLICKS RIGHT MOUSE BUTTON ON MARKER");
        /*EVENT*/ gmapObj.marker_onSinglerightclick_before();

        if(overlay instanceof GMarker){    
          gmapObj.clickObjX = gmapObj.map.fromLatLngToContainerPixel(overlay.getPoint()).x;
          gmapObj.clickObjY = gmapObj.map.fromLatLngToContainerPixel(overlay.getPoint()).y;
	
	        gmapObj.overlay = overlay;
          gmapObj.overlay.lat = overlay.getLatLng().lat();
          gmapObj.overlay.lng = overlay.getLatLng().lng();		
          gmapObj.lastMarker = overlay;
          gmapObj.lastIcon = overlay.getIcon();
          if(gmapObj.gmapOptions.overlay.draggableOnClick == true) gmapObj.overlay.enableDragging();          
        }
        else if(overlay instanceof GPolygon){
          if((gmapObj.polygon != null) && (gmapObj.polygon != overlay)){
            removePolygonHelpers();
            finishPolygon();
          }        
          gmapObj.overlay = overlay;
          gmapObj.polygon = overlay;
        
          polyPointsCount = overlay.getVertexCount();
          polyPoints = Array();
          for(i=0; i<polyPointsCount; i++){
            polyPoints[i] = overlay.getVertex(i);
          }
          
          minIndex = 0
          for(i=0; i<polyPoints.length; i++){
            if(polyPoints[i] < polyPoints[minIndex]){
              minIndex = i;
            }
          }
                  
          gmapObj.clickObjX = gmapObj.map.fromLatLngToContainerPixel(overlay.getVertex(minIndex)).x;
          gmapObj.clickObjY = gmapObj.map.fromLatLngToContainerPixel(overlay.getVertex(minIndex)).y;

          gmapObj.overlay.lat = overlay.getVertex(minIndex).lat();
          gmapObj.overlay.lng = overlay.getVertex(minIndex).lng();		
          gmapObj.lastMarker = overlay;  
        }
        /*EVENT*/ gmapObj.marker_onSinglerightclick_after();
        gmapObj.debug.print();		
      } 
      else if(src.className == "mnu" || src.className == "mnu-item" || src.className == "mnu-item-text"){  // MENU SELECTED		  
      }	 															  
      else{	                                                                                                // MAP SELECTED 
	      gmapObj.debug.addEvent("map_singleRightClick", Array("gmapObj: "+gmapObj, "src.id:: "+src.id), "EVENT FIRES WHEN USER CLICKS RIGHT MOUSE BUTTON ON MAP AREA");
        /*EVENT*/ gmapObj.map_onSinglerightclick_before();
        /*EVENT*/ gmapObj.map_onSinglerightclick_after();
        gmapObj.debug.print();		
      }
    });

    GEvent.addListener(this.map, "movestart", function(){
      document.getElementById(id).style.display = "none";
    });	
    GEvent.addListener(this.map, "moveend", function(){
      document.getElementById(id).style.display = "none";
    });

    this.debug.print();
    return mnu_x;
  }
//--------------------------------------------------------------------------------------------------------------------
// ON EVENT SHOW CONTEXT MENU
//--------------------------------------------------------------------------------------------------------------------
  this.showContextMenu = function(mnuObj, point){
    this.debug.addEvent("showContextMenu(point, contextMenu, mnuType)", Array("mnuObj: "+mnuObj, "point.x: "+point.x, "point.y: "+point.y), "ON EVENT SHOW CONTEXT MENU");	
//  x = point.x;
//  y = point.y;
//  var pos = new GControlPosition(G_ANCHOR_TOP_LEFT, new GSize(x,y)); 
//  pos.apply(mnuObj);
    mnuObj.style.left = (point.x) + "px";
    mnuObj.style.top  = (point.y) + "px";
    mnuObj.style.display = "block";
    mnuObj.style.visibility = "visible";
    this.debug.print();
  }
//--------------------------------------------------------------------------------------------------------------------
// CREATE "ADD MARKER" DIALOG
//--------------------------------------------------------------------------------------------------------------------
  this.addDialog = function(gmapObj, ObjectOrHtml, id, parentElem, width, height, strict_height){
    //this.debug.addEvent("addEventContextMenu", Array("gmapObj: "+gmapObj,"ObjectOrHtml"+ObjectOrHtml), "CREATE CONTEXT MENU IN MAP");	
    
    elem = document.createElement("div");
    elem.id = id;
    elem.className = 'dlg';
    
    var w = (!isNaN(width)  ? width + 'px'  : (width  == "100%" ? "auto" : width));
    var h = (!isNaN(height) ? height + 'px' : height);
    
    // EXCEPTIONS AND ACCOMODATIONS:
    if(width == "100%" && height == "100%") elem.style.borderWidth = 0;    
       
    if(width != null && height != null){	
      elem.width  = w;  elem.style.width  = w;
      elem.height = h;  if(strict_height == true) elem.style.height = h;
    }
    elem.style.visibility = "hidden";	
    elem.style.display = "none";

    if(typeof ObjectOrHtml == "object"){
      elem.appendChild(ObjectOrHtml);
    }
    else{
      elem.innerHTML = (ObjectOrHtml != null ? ObjectOrHtml : "");
    }
    dlg_parent = document.getElementById(parentElem);
    dlg_parent.appendChild(elem);

    return elem;
  }
//--------------------------------------------------------------------------------------------------------------------
// SHOW "ADD MARKER" DIALOG
//--------------------------------------------------------------------------------------------------------------------
  this.showDialog = function(dlgObj, point){
    gmap.debug.addEvent("showDialog(dlgObj)", Array("dlgObj: "+dlgObj, "point.x: "+point.x, "point.y: "+point.y), "CREATE CONTEXT MENU IN MAP");	
    dlgObj.style.left = (point.x) + "px";
    dlgObj.style.top  = (point.y) + "px";
    dlgObj.style.display = "block";
    dlgObj.style.visibility = "visible";
    gmap.debug.print();	
  }
//--------------------------------------------------------------------------------------------------------------------
// CREATE BORDERS ON MAP TO CONTROL MOVEMENT WHEN HOVERING OVER THEM WITH SETINTERVAL OR SETTIMEOUT
//--------------------------------------------------------------------------------------------------------------------
  this.addPanControl = function(type, step, fps){
    this.debug.addEvent("addPanControl(type, step, fps)", Array("type: "+type,"step: "+step,"fps: "+fps), "CREATE BORDERS ON MAP TO CONTROL MOVEMENT WHEN HOVERING OVER THEM WITH SETINTERVAL OR SETTIMEOUT");	
    step = (step != null ? step : 10);
    fps  = (fps  != null ? fps  : 100);	
	
    var intervalID;
    var width = this.map.getContainer().style.width;
    var height = this.map.getContainer().style.height;
    
    var topDiv = document.createElement("div");
    topDiv.setAttribute('id', 'topDiv');
    topDiv.setAttribute('class', 'mapControl');
    topDiv.style.width = width.substring(0,width.length - 2) - 2 + "px";
    var posTop = new GControlPosition(G_ANCHOR_TOP_LEFT, new GSize(0,0));
    posTop.apply(topDiv);
    topDiv.onmouseover = function(){
       if(type == "i"){ 
         intervalID =setInterval('gmap.map.panBy(new GSize(0,'+ step +'))',1000/fps);
       }
       else{ 
         setTimeout('gmap.map.panBy(new GSize(0,'+ step +'))',1000/fps);
       }
    };
    topDiv.onmouseout = function(){
       clearInterval(intervalID);
    };
	  
    var rightDiv = document.createElement("div");
    rightDiv.setAttribute('id', 'rightDiv');
    rightDiv.setAttribute('class', 'mapControl');
    rightDiv.style.height= height.substring(0,height.length - 2) - 2 + "px";
    var posRight = new GControlPosition(G_ANCHOR_BOTTOM_RIGHT, new GSize(0,0));
    posRight.apply(rightDiv);
    rightDiv.onmouseover = function(){
      if(type == "i"){ 
        intervalID =setInterval('gmap.map.panBy(new GSize(-'+ step +',0))',1000/fps);
	    }
	    else{
        setTimeout('gmap.map.panBy(new GSize(-'+ step +',0))',1000/fps);
      }
    };
    rightDiv.onmouseout = function(){
      clearInterval(intervalID);
    };

    var bottomDiv = document.createElement("div");
    bottomDiv.setAttribute('id', 'bottomDiv');
    bottomDiv.setAttribute('class', 'mapControl');
    bottomDiv.style.width = width.substring(0,width.length - 2) - 2 + "px";
    var posBottom = new GControlPosition(G_ANCHOR_BOTTOM_LEFT, new GSize(0,0));
    posBottom.apply(bottomDiv);
    bottomDiv.onmouseover = function(){
      if(type == "i"){ 
        intervalID =setInterval('gmap.map.panBy(new GSize(0,-'+ step +'))',1000/fps);
      }
      else {
        setTimeout('gmap.map.panBy(new GSize(0,-'+ step +'))',1000/fps);
      }
    };
    bottomDiv.onmouseout = function(){
      clearInterval(intervalID);
    };
	  
    var leftDiv = document.createElement("div");
    leftDiv.setAttribute('id', 'leftDiv');
    leftDiv.setAttribute('class', 'mapControl');
    leftDiv.style.height= height.substring(0,height.length - 2) - 2 + "px";
    var posLeft = new GControlPosition(G_ANCHOR_TOP_LEFT, new GSize(0,0));
    posLeft.apply(leftDiv);
    leftDiv.onmouseover = function(){
      if(type == "i"){ 
        intervalID =setInterval('gmap.map.panBy(new GSize('+ step +',0))',1000/fps);
      }
      else {
        setTimeout('gmap.map.panBy(new GSize('+ step +',0))',1000/fps);
      }
    };
    leftDiv.onmouseout = function(){
      clearInterval(intervalID);
    };
	
    this.map.getContainer().appendChild(topDiv);
    this.map.getContainer().appendChild(bottomDiv);
    this.map.getContainer().appendChild(rightDiv);
    this.map.getContainer().appendChild(leftDiv);
  }
//--------------------------------------------------------------------------------------------------------------------
// GET ARRAY OF SOUTHWEST AND NORTHEAST COORDINATES
//--------------------------------------------------------------------------------------------------------------------
  this.getMapCorners = function(){
    this.debug.addEvent("getMapCorners()",Array(), "GET ARRAY OF SOUTHWEST AND NORTHEAST COORDINATES");	
    bounds = this.map.getBounds();
    return Array(bounds.getSouthWest(),	bounds.getNorthEast());
  }  
}



//################################################################################################### CLASS CDebug ###
//# CLASS CDebug - defines the advanced debug control
//--------------------------------------------------------------------------------------------------------------------
function CDebug(targetLayerName, mode, doPause){ 
  this.targetLayerName = targetLayerName				// Layer that display messages

  this.msg = "";							// Holds MESSAGE TEXT
  this.msgno = 0;							// Holds MESSAGE SEQUENCE NUMBER
  this.mode = mode;
  this.doPause = doPause;  
//--------------------------------------------------------------------------------------------------------------------
// PRINTS DEBUG INFORTION
//--------------------------------------------------------------------------------------------------------------------
  this.print = function(returnParam){	
    if(this.msgno > 0){
      if(returnParam instanceof Array){
        this.msg += "RETURN: " + "\n";	
        returnNamesLength = new Array();
        for(var i=0; i<returnParam.length; i++) returnNamesLength[i] = returnParam[i].split(':')[0].length;
        returnNamesMaxLength = Math.max.apply(Math, returnNamesLength);
		
        for(var i=0; i<returnParam.length; i++){
          p = returnParam[i];
          k = p.indexOf(': ');
          returnValue = " " + p.slice(k+2, p.length);
          this.msg += "     " + returnParam[i].split(':')[0] + Helper.String.Pad(' ', returnNamesMaxLength-returnParam[i].split(':')[0].length) + ':' + returnValue + "\n";
        }
	  }
      else{
        if(returnParam!=null) this.msg += "RETURN: " + returnParam + "\n";	
      }	
      
      if(this.mode == 'toMessageBox'){
        alert(this.msg);
        this.msg = "";	 
        this.msgno = 0;	
      }
      else if(this.mode == 'toLayer'){
        strFormated = this.msg.replace(/</gi, '&lt;')
  	    strFormated = strFormated.replace(/>/gi, '&gt;')	 		
        strFormated = strFormated.replace(/\n/g, '<br>');
        strFormated = strFormated.replace(/ /gi, '&nbsp;')
        document.getElementById(this.targetLayerName).innerHTML = strFormated;
        if(this.doPause) alert('(DEBUGGER) Breakpoint found: <ENTER> to continue');
        this.msg = "";
        this.msgno = 0;
      }		
    }
  }
//--------------------------------------------------------------------------------------------------------------------
// ADDS NEW EVENT
//--------------------------------------------------------------------------------------------------------------------
  this.addEvent = function(eventName, param, comment){	
    if(this.msgno > 0) this.msg += "\n";								// Message BODY separator (between two messages)
    this.msg += "EVENT: " + eventName + "\n";							// Message BODY->EVENT (name of event)
    if(comment!=null) this.msg+="COMMENT: "+comment.toLowerCase()+"\n"; // Message BODY->COMMENTS (event description)		
    if(param.length > 0){
      this.msg += "PARAMETERS:" + "\n";									// Message BODY->PARAMETERS (event parameter:value pairs)
      paramNamesLength = new Array();
      for(var i=0; i<param.length; i++) paramNamesLength[i] = param[i].split(':')[0].length;
      paramNamesMaxLength = Math.max.apply(Math, paramNamesLength);

      for(var i=0; i<param.length; i++){
        p = param[i];
        k = p.indexOf(': ');
        paramValue = " " + p.slice(k+2, p.length);
        this.msg += "     " +  param[i].split(':')[0] + Helper.String.Pad(' ', paramNamesMaxLength-param[i].split(':')[0].length) + ':' + paramValue + "\n";
      }
    }
    this.msgno++;							
  }	
//--------------------------------------------------------------------------------------------------------------------
// SETS DEBUG MODE
//--------------------------------------------------------------------------------------------------------------------
  this.setMode = function(mode){	
    this.mode = mode;
  } 
}



//--------------------------------------------------------------------------------------------------------------------
// FUNCTION getMousePoint is used in:
//   user defined HTML (to get relative mouse position at given moment)
//--------------------------------------------------------------------------------------------------------------------
  function gmap_onclick(e){
    if(gmap != null){
      point = Helper.Mouse.GetLocation(e);
      //gmap.debug.addEvent("map mouseup(event)", Array("x: "+gmap.mouseX, "y: "+gmap.mouseY),"EVENT OCCURES WHEN USER RELEASES MOUSE BUTTON ON THE MAP"); 
      gmap.mouseX = point.x; // - (document.getElementById('results').style.width.replace("%", "")/100 * screen.width);
      gmap.mouseY = point.y; // - (document.getElementById('search').style.height.replace("px", "")); 
      //gmap.debug.print();
    }
  } 
//--------------------------------------------------------------------------------------------------------------------
// FUNCTION parseAttribute(name, value) is used in:
//   used in this library (to extract composite data from markers xml field, designated as name)
//--------------------------------------------------------------------------------------------------------------------  
  function parseAttribute(name, value){
    switch(name){
      case "custom":{
        text = value;
        
        attribute = new Array();
        re = new RegExp(/([a-z]+) *: *'(.+?)' *;* */g); // Finds: "points: '1, 3; 45, 55; '" used in custom attribute
        m = re.exec(text);
        for(i=0; m!=null; i++){
          name = m[1];
          attribute[name] = {name: m[1], value: m[2]};   
          m = re.exec(text);
        }
        break;
      }
      default: return -1;
    }
    return attribute;
  }
//--------------------------------------------------------------------------------------------------------------------
// FUNCTION extractInteger(text, delimiter) is used in:
//   used in this library (to extract integer from text by delimiter)
//--------------------------------------------------------------------------------------------------------------------  
  function extractInteger(text, delimiter){
    peaces = text.split(delimiter);
    integer = peaces[0];
    return integer;
  }  
//--------------------------------------------------------------------------------------------------------------------
// FUNCTION makeXML is used in:
//   user defined HTML (to compose XML output for map overlays)
//--------------------------------------------------------------------------------------------------------------------  
  function startXMLTag(tagName, attrName, attrValue){
    var xml = "<"+tagName;
    for(var i=0; i<attrName.length; i++){
      xml += " " + attrName[i] + "=\"" + attrValue[i] + "\"";
	  }	
    xml += ">";		
    return xml;
  }   
  
//--------------------------------------------------------------------------------------------------------------------
// FUNCTION makeXML is used in:
//   user defined HTML (to compose XML output for map overlays)
//--------------------------------------------------------------------------------------------------------------------  
  function endXMLTag(tagName){
    var xml = "</" + tagName + ">";		
    return xml;
  }    
//--------------------------------------------------------------------------------------------------------------------
// FUNCTION makeXML is used in:
//   user defined HTML (to compose XML output for map overlays)
//--------------------------------------------------------------------------------------------------------------------  
  function makeURL(targetName, attrName, attrValue, p_options){
    p_options = (p_options != null ? p_options : "noblanks"); // SET DEFAULT
	  
    url = targetName;
    switch(p_options){ 
      case 'noblanks': {  	
        for(var i=0; i<attrName.length; i++){
          if(i==0) delim = "?";
          else delim = "&";
		      if(attrValue[i] != "") url += delim + attrName[i] + "=" + attrValue[i];
        }		
        return url;
      }
    }
  }
//--------------------------------------------------------------------------------------------------------------------
// FUNCTION makeXML is used in:
//   user defined HTML (to compose XML output for map overlays)
//--------------------------------------------------------------------------------------------------------------------
  function validateAddress(address){
    enc_address = convertBalticToLatin(address)
    var re = new RegExp(VALIDATION.ADDRESS);
    var match = re.exec(enc_address);    
    return (match != null ? true : false);
  }  
//--------------------------------------------------------------------------------------------------------------------
// FUNCTION convertBalticToLatin is used in:
//   user defined HTML (to replace baltic charachters with latin to aplly JavaScript regular expressions)
//--------------------------------------------------------------------------------------------------------------------   
  function convertBalticToLatin(str){  
    esc_str = escape(str);
 
    var lt_small_case = Array('%u0105', '%u010D', '%u0119', '%u0117', '%u012F', '%u0161', '%u0173', '%u016B', '%u017E');
    var lt_big_case   = Array('%u0104', '%u010C', '%u0118', '%u0116', '%u012E', '%u0160', '%u0172', '%u016A', '%u017D');	
    var en_small_case = Array('%u0061', '%u0063', '%u0065', '%u0065', '%u0069', '%u0073', '%u0075', '%u0075', '%u007A');
    var en_big_case   = Array('%u0041', '%u0043', '%u0045', '%u0045', '%u0049', '%u0053', '%u0055', '%u0055', '%u005A');		
    for(i=0; i<lt_small_case.length; i++){
      esc_str = esc_str.replace(lt_small_case[i], en_small_case[i], 'g'); 
      esc_str = esc_str.replace(lt_big_case[i],   en_big_case[i]), 'g';
    }
    str = unescape(esc_str);	  
    return str; 
  }
