// Основной прототип работы с картой (id - идентификатор div-контейнера, options - JSON-оснастка (для всех объявлений) )

function uMap(id,options) {
 
 this.faceName = 'map';

 extend(this, baseProto);

 this.options = options;

 var ua = navigator.userAgent.toLowerCase();

 this.isProblem =  (ua.indexOf("msie") != -1 && ua.indexOf("opera") == -1 && ua.indexOf("webtv") == -1);
 this.isOpera   =  (ua.indexOf("opera") != -1);
 this.isSafari  =  (ua.indexOf("safari") != -1);

 this.handlers = { drag:[],mousedown:[],mouseup:[],mousemove:[],blur:[],focus:[],click:[],keypress:[],resize:[],ready:[],change:[]}

 this.view = {      width:0,          // ширина вьюпорта
                    height:0,         // высота вьюпорта
                    ground:"#E0E0E0", // фон карты
                    scaler:false,     // хэндлер масштабной линейки
                    zPan:1,           // базовый zIndex панорамной плоскости
                    zElements:60000,  //                элементов управления
                    zField:5000,      //                слоевых полей
                    zImage:100,       //                фрагментов карты 
                    minHeight:300,    // минимальная высота вьюпорта
                    minWidth:300      // минимальная ширина вьюпорта
             };

 this.part = {
                width:256,
                height:256
             }
                               
                this.width      = 0;      // Фактическая ширина карты 
                this.height     = 0;      // Фактическая высота карты
                this.centerX    = 0;      // X точки центровки на карте
                this.centerY    = 0;      // Y точки центровки на карте
                this.scale      = 1;      // Физический масштаб по умолчанию 
                this.scaleIndex = 0;      // Индекс масштаба по умолчанию
                this.mperpix    = 1;      // Количество метров в одном пикселе
                this.transport  = 0;      // Флаг включенных транспортных слоёв
                this.top        = 0;      // Верхняя точка отсчета (backward compatability)
                this.left       = 0;      // Левая точка отсчета (backward compatability)
                                        
 this.mapInfo = {};   // Хранилище загружаемых аспектов карты
 
 this.scaleList = {}; // Информация о масштабах

 this.oName   = options.name;
 
 this.user    = "umap";
 
 this.id      = 30066;

 this.city    = options.city ? options.city : this.id;

 this.partHosts = ["http://91.201.53.228/shard.php","http://91.201.53.227/_mapnew/shard.php"];  // фраг-хосты

 if(document.location.host.match(/www.umap.ru/)) {
   this.baseURL   = "http://www.umap.ru";  // базовый URL 
 } else {
    if(document.location.host.match(/umap.ru/)) {
        this.baseURL   = "http://umap.ru";  // базовый URL 
      } else 
         this.baseURL   = "http://www.umap.ru";  // базовый URL 
 }

 this.infoURL   = this.baseURL+"/assets/map/info.php"; // URL загрузки данных о картах
 this.loaderURL = this.baseURL + "/assets/map/js.php"; // URL загрузки компонент

 if(options.loaderURL) this.loaderURL = options.loaderURL;

 if(options.infoURL) this.infoURL = options.infoURL;

 this.pans      = new Array();
 this.panCount = 0;
 
 this.menu = false;


 if(options.scaleIndex) 
    this.scaleIndex = parseInt(options.scaleIndex);

 if(options.typeHandler)
    this.typeHandler = options.typeHandler;
 else 
    this.load(this.loaderURL,'initialize',{tool:'tHandler',user:this.user});

 if(options.hosts) {
   if(options.hosts.clear) {
    this.partHosts = [];
   }
   if(options.hosts.list) {
    this.partHosts = options.hosts.list;
   }
 } 
 
 /* Инициализация прототипа  */
 this.init = function(jO,self) {

   // загрузка стилей 
    var link = document.createElement('link');

    if(!this.isSafari)
       document.getElementsByTagName("body")[0].appendChild(link);
    else
       document.getElementsByTagName("head")[0].appendChild(link);

    link.rel  = 'stylesheet';
    link.type = 'text/css';
    link.href = self.baseURL+"/assets/map/css/map.css?id=5";
    
   // инциализация основных хэндлеров 
   $(window).bind('resize',function(e) {self.trigger(e,self,'resize');});

   this.offset = this.container.offset();

   if(self.options) {

      if(self.options.partWidth)  self.part.width  = self.options.partWidth;
      if(self.options.partHeight) self.part.height = self.options.partHeight;            

   }
   

   self.view.width = self.container.width();
   self.view.height = self.container.height();
     
     

   if(!self.view.width) { self.view.width = self.options.viewWidth; self.container.css({'width':self.options.viewWidth}); }
   if(!self.view.height) {     self.view.height = self.options.viewHeight;  self.container.css({'height':self.options.viewHeight});  }

   self.register('resize',self.resize);

   if(self.container)  self.prepareView();
                 else  self.trigger(self, "error", { msg:"1001" } );

   if(!self.scaleIndex)
       self.scaleIndex               = jO.root.map.attr.scale;

   self.scaleList = jO.root.map.scaleList.scale;

   for(var i in jO.root.map.scaleList.scale) {
     self.mapInfo[i] = jO.root.map.scaleList.scale[i];
   }

   jO = jO.root;

  // self.top       = parseInt(self.scaleList[self.scaleIndex].attr.top);
  // self.left      = parseInt(self.scaleList[self.scaleIndex].attr.left);

   self.width     = parseInt(self.scaleList[self.scaleIndex].attr.width );
   self.height    = parseInt(self.scaleList[self.scaleIndex].attr.height );

   self.mperpix   = parseFloat(jO.map.attr.mperpix);
   self.scale     = parseFloat(self.scaleList[self.scaleIndex].attr.scale);

   self.ctop  = parseInt(self.scaleList[0].attr.top* self.scaleList[0].attr.scale );
   self.cleft = parseInt(self.scaleList[0].attr.left* self.scaleList[0].attr.scale );
   
   self.top       = Math.round(self.ctop/self.scale);
   self.left      = Math.round(self.cleft/self.scale);


   if(jO.wgs)
   if(typeof(jO.wgs.a) == 'object') 
      self.WGSmap   = [jO.wgs.a];   
    else
      self.WGSmap    = jO.wgs.a;   

   if(self.options.centerX != undefined && self.options.centerY != undefined) {

     self.centerX = self.options.centerX - self.left*self.scale;
     self.centerY = self.options.centerY - self.top*self.scale;
   }


   if(!self.centerX) { self.centerX = jO.map.attr.centerx* self.scaleList[0].attr.scale - self.left*self.scale; 
                       self.options.centerX = jO.map.attr.centerx;
                     }
    
   if(!self.centerY) { self.centerY = jO.map.attr.centery* self.scaleList[0].attr.scale - self.top*self.scale;
                       self.options.centerY = jO.map.attr.centery;
                     }


   if(!self.view.scaler) {
      self.load( this.loaderURL,'initialize',{tool:'scaler_m',user:self.user });
   }

  if(typeof(self.options.handlers) != 'undefined') {
   
    for(var i in self.options.handlers) {
      self.register(i,self.options.handlers[i]);
    }

  }

  self.addPan();

  self.pan.addField('user',{canDraw:true,layersURL:self.baseURL+"/assets/map/load/showMarks.php"});

  if(self.options.interface !='disabled')
     self.pan.addField('show',{layersURL:self.baseURL+"/assets/map/load/showField.php",maxScale:1}).layers = [1];

  self.pan.addField('transport',{layersURL:self.baseURL+"/assets/map/load/showTransport.php"});

  self.pan.addField('layers',{});

//  self.pans[0].addField('marks',{layersURL:self.baseURL+"/assets/map/load/showMarks.php"});

  self.pan.addField('whois',{layersURL:self.baseURL+"/assets/map/load/showUsers.php"}).layers = [1];
 
  
  self.ifaceInit();

  if(!self.options.menu) {
      self.menuInit();
  } else 
      self.menu = self.options.menu;

    self.register("layers_ready",function(){   self.pans[0].redrawLayers(false,self.pans[0]);});

    this.offset = this.container.offset();

    self.trigger('',self,"map_ready");
 }
 // Конец инициализации карты 

 this.addPan = function() {
   var self = this;
   self.pans[self.panCount++] = new uPan(self,self.options);
   self.pan = self.pans[self.panCount-1];
 }
 
 this.getField = function( name ) {
    return self.pan.getField(name);
 }
// Подготовка вьюпорта
 this.prepareView = function() {
// width:this.view.width, height:this.view.height,
   this.container.css( {position:'relative',overflow:"hidden", background: this.view.ground} );
   this.loadGif = $("<img/>").appendTo(this.container).attr({src:'http://www2.umap.ru/i/load.gif'}).css({zIndex:10000,display:'none',position:'absolute',left:10,bottom:10});
 }

// СЕРВИСНЫЕ ФУНКЦИИ 

// преобразование координат на клиенте к сервисным
 this.clientCoords = function(x,y) {

   return {X:(x+this.left)*this.scale,Y:(y+this.top)*this.scale};

 }

 this.eventCoords = function(e,self) {

   return {X:e.clientX-self.map.offset.left+$(document).scrollLeft()-self.map.pan.ocX,
           Y:e.clientY-self.map.offset.top+$(document).scrollTop()-self.map.pan.ocY};

 }


// Изменение масштаба
 this.setScale    = function(scaleIndex) {

  this.scaler.tool.slider("moveTo",this.scaleList.length-scaleIndex-1);

 }
		 
 this.cityChange = function(id,options) {

   if(this.id != id) {
     
     this.id = id;
     this.city = id;

     this.mapInfo={};
     
     var self = this;

   
      this.load(this.infoURL,function(jO) { self.mapInit(jO,self,options); },{t:'map',n:this.id,s:this.scaleIndex,lt:this.transport,lg:0,ws:0,u:this.user,rsid:0});             
   }                                         
  }

 this.mapChange = this.cityChange;
  
 this.scaleChange = function(scaleIndex) {

  if(this.scaleIndex != scaleIndex) {
    
    this.scaleIndex = scaleIndex*1;
 
    if(!this.mapInfo[this.scaleIndex]) {

      this.load(this.infoURL,'scaleInit',{t:'map',n:this.id,s:this.scaleIndex,lt:this.transport,lg:0,ws:0,u:this.user,rsid:0});             
     }
    else {

     this.scaleInit(this.mapInfo[this.scaleIndex],this);

     }
  }
 }

                                
 this.scaleInit = function(jO,self) {


   //self.top       = parseInt(jO.attr.top);
   //self.left      = parseInt(jO.attr.left);

   self.width     = parseInt(jO.attr.width);
   self.height    = parseInt(jO.attr.height);

   self.scale     = parseFloat(jO.attr.scale);

//   var top  = Math.round(parseInt(self.scaleList[0].attr.top)); 
//   var left = Math.round(parseInt(self.scaleList[0].attr.left)) ;

   var d_top  = parseInt(jO.attr.top);
   var d_left = parseInt(jO.attr.left);

       self.ctop  = d_top * self.scale;
       self.cleft = d_left * self.scale;

       self.top       = d_top;  
       self.left      = d_left; 
       
//       console.log('a' + d_top + ":" + d_left);

   if(!self.width)  self.width  = self.view.width;
   if(!self.height) self.height = self.view.height;

   self.menuInit();

   self.pans[0].init({full:true});

   self.trigger("",self,'scalechange');
 }


  this.mapInit = function(jO,self,opts) {

  opts = opts || {};
   self.scaleIndex = opts.scaleIndex || jO.root.map.attr.scale*1;

   self.scaleList  = jO.root.map.scaleList.scale;

   if(self.scaleIndex >= self.scaleList.length) self.scaleIndex = self.scaleList.length - 1;

   for(var i in jO.root.map.scaleList.scale) {
     self.mapInfo[i] = jO.root.map.scaleList.scale[i];
   }

   jO = jO.root;

   self.width     = parseInt(self.scaleList[self.scaleIndex].attr.width* self.scaleList[0].scale);
   self.height    = parseInt(self.scaleList[self.scaleIndex].attr.height* self.scaleList[0].scale);

   self.top       = parseInt(self.scaleList[self.scaleIndex].attr.top);
   self.left      = parseInt(self.scaleList[self.scaleIndex].attr.left);

  // self.width     = parseInt(jO.map.attr.width);
 //  self.height    = parseInt(jO.map.attr.height); 

   self.mperpix   = parseFloat(jO.map.attr.mperpix);
   self.scale     = parseFloat(self.scaleList[self.scaleIndex].attr.scale);


   self.ctop  = parseInt(self.top * self.scale);
   self.cleft = parseInt(self.left * self.scale);

//   self.top       = Math.round(self.ctop/self.scale);
  // self.left      = Math.round(self.cleft/self.scale);


   if(jO.wgs)
   if(typeof(jO.wgs.a) == 'object')
      self.WGSmap    = [jO.wgs.a];   
    else
      self.WGSmap    = jO.wgs.a;   

   if(!self.width)  self.width  = self.view.width;
   if(!self.height) self.height = self.view.height;

   if(opts.centerLat && opts.centerLon) {

     var coord = self.WGS2map(opts.centerLat,opts.centerLon);
         opts.centerY = coord.top;
         opts.centerX = coord.left;
   }

   if(opts.centerY && opts.centerX) {

        self.centerX = opts.centerX - self.left*self.scale;
        self.centerY = opts.centerY - self.top*self.scale;

   } else {
     if(jO.map.attr.centerx && jO.map.attr.centery) {

        self.scaleList[0].scale = self.scaleList[0].scale || self.scaleList[0].attr.scale*1;
	
	
        self.centerX = jO.map.attr.centerx* self.scaleList[0].scale - self.left*self.scaleList[0].scale;
        self.centerY = jO.map.attr.centery* self.scaleList[0].scale - self.top*self.scaleList[0].scale;

      } else {

        self.centerX = Math.round(self.width/2);
        self.centerY = Math.round(self.height/2);   

      }

   }

   self.menuInit();
   
   self.scaler.reinit();

   self.pans[0].init({full:true});

   if(self.interface && self.interface.search) {
  
     self.trigger('',self,"search_ready");

   }

   self.trigger("",self,'mapinit');

   if(opts.scaleIndex) {
  
     self.trigger("",self,'scalechange');

   }

 }

// Изменение размеров 
 this.resize = function(e,self,options) {

   self.offset = self.container.offset();

   self.view.width = self.container.width();
   self.view.height = self.container.height();

   if(!self.view.width) self.view.width = self.options.viewWidth;
   if(!self.view.height) self.view.height = self.options.viewHeight;
   
    for(var i in self.pans) {
      self.pans[i].init({full:true});
    }
 }

 this.menuInit = function(options) {
   var self = this;

  if(!self.menu) { self.menu = new uMenu(self,{pan:self.pans[0]});

        self.menu.clear();
       
        self.menu.addIt('inScale',{label:'<b>+ Ближе</b>',type:'option',callback:function() {self.scaler.tool.slider("moveTo","+=1"); } });
        self.menu.addIt('deScale',{label:'<b>- Дальше</b>',type:'option',callback:function() {self.scaler.tool.slider("moveTo","-=1"); } });

        self.menu.addIt('dash',{label:'',type:'header'});
        self.menu.addIt('addRoute',{label:'Заехать сюда',type:'option',callback:function() {self.interface.search.addRoutePoint(); } });

        self.menu.addIt('dash',{label:'',type:'header'});
        self.menu.addIt('pointAddress',{label:'Ссылка на эту точку',type:'option',callback:function() { self.interface.info.showPointAddress(); } });
     }  

    if(self.scaleIndex>0) 
     self.menu.setData('inScale',{disabled:false} );
    else
     self.menu.setData('inScale',{disabled:true} );
    
    if(self.scaleIndex < self.scaleList.length-1)
     self.menu.setData('deScale',{disabled:false} );
    else
     self.menu.setData('deScale',{disabled:true});

 }

 this.ifaceInit = function() {
  var self = this;
    
  if(!self.options.interface) {
   
    self.load(this.loaderURL,'initialize',{tool:'iface',user:self.user});
  
  } else {
     
     switch(self.options.interface) {

       case "external":

         self.load(this.loaderURL,'initialize',{tool:'ifaceEx',user:self.user});

       break;

       case "hide":
         self.load(this.loaderURL,'initialize',{tool:'ifaceHidden',user:self.user});

       break;

       case "minimized":
         self.load(this.loaderURL,'initialize',{tool:'ifaceMini',user:self.user});

       break;

       case "disabled":
       case "none":
       break;

       default:

         self.load(this.loaderURL,'initialize',{tool:this.options.interface,user:self.user});

       break;

     }

  }

 }

 this.goTo  = function(x_lon, y_lat, mode) {
   
   var self = this;

   switch(mode) {

     case "wgs":
       
       var c = self.WGS2map(y_lat,x_lon);

       self.pan.panTo(c.left,c.top);

     break;

     default:
       self.pan.panTo(self.pans[0],x-self.left*self.scale,y-self.top*self.scale);
     break;
    }

 }


// Предынициализация переменных, вызов функций инициализации
  var self = this;

  if(self.options.id) {
    self.id = self.options.id;

    if(!self.options.city) {
      self.city = self.id;
    }

  }

  this.container = $("#"+id);

  this.container.html("");

  this.container.css({width:self.options.viewWidth,height:self.options.viewHeight});
  
  this.load(this.infoURL,'init',{t:'map',n:this.id,s:this.scaleIndex,lt:this.transport,lg:0,ws:0,u:this.user,rsid:0});

  self.map = self;
}

uMap.prototype = { 
                  
                  scaleIndexByFactor: function ( factor ) {

                    var self = this;

                    var c_index  = -1;
                    var treshold = false;
                     
                    for(var i in self.scaler.l4) {

                      var scale = self.scaler.l4[i].attr('scale');
                       
                     if (factor > scale ) {
                         treshold = true;
                     }

                     if(treshold && factor < scale) {
                       c_index = i;
                       break;
                     }

                    }

                    if( c_index >= 0 ) {
                      return {level: 'l4', index: c_index };
                    } 

                    treshold = false;

                    for(var i in self.scaler.l6) {

                      var scale = self.scaler.l6[i].attr('scale');

                     if (factor > scale ) {
                        treshold = true;
                     }

                     if(treshold && factor < scale) {
                       c_index = i;
                       break;
                     }

                    }

                    if( c_index < 0 ) {
                      c_index = i;
                    } 
                     
                      return {level: 'l6', index: c_index };
 

                  },

                  map2WGS : function (x,y) {
                      
                      var self = this;
                      
                      var c = {lat:0,lon:0}; 

                      for(var i in self.WGSmap) { 
                      
                      var itm = self.WGSmap[i]; 
                      
                      
                      if( (x >= itm.attr.x1*1) && (lat <= itm.attr.x2*1) && (y >= itm.attr.y1*1) && (lon<= itm.attr.y2*1) ) 
                      
                      { 

                       found = true; 
                      
                      break; 
                      
                      }

                     }

                       c.lon = itm.attr.aka*x+itm.attr.akb*y+itm.attr.akc*1; 
                       c.lat = itm.attr.akd*x+itm.attr.ake*y+itm.attr.akf*1; 

                      return c;
                  },

                  pan2WGS : function (x,y) {
                     
                      var self = this;

                      var c = {lat:0,lon:0}; 
                      x += self.left*self.scale; 
                      y += self.top*self.scale;

                      for(var i in self.WGSmap) { 
                      
                      var itm = self.WGSmap[i]; 
                      
                      if( (x >= itm.attr.x1*1) && (lat <= itm.attr.x2*1) && (y >= itm.attr.y1*1) && (lon<= itm.attr.y2*1) ) 
                      
                      { 

                       found = true; 
                      
                       break; 
                      
                      }
                     
                     }

                  // alert(JSON.stringify(itm));
                      if(itm) {
                       c.lon = itm.attr.aka*x+itm.attr.akb*y+itm.attr.akc*1; 
                       c.lat = itm.attr.akd*x+itm.attr.ake*y+itm.attr.akf*1; 

                       return c; } else {return {};}
                  
                  },

                  WGS2pan : function ( lat, lon ) { 
                  
                  var self = this; 
                  
                  var found = false; 
                  //mia add 
                  var len_min=360*360; 
                  var itm_min; 
                  //mia end add 
                  
                  for(var i in self.WGSmap) { 
                  
                  var itm = self.WGSmap[i]; 
                  
                  if( (lat >= itm.attr.la1*1) && (lat <= itm.attr.la2*1) && (lon >= 
                  
                   itm.attr.lo1*1) && (lon<= itm.attr.lo2*1) ) { 
                   found = true; 
                  
                  break; 
                  
                  } 
                  //mia add 
                  else{ 
                   
                   latx=((itm.attr.la1*1)+(itm.attr.la2*1))/2; 
                   
                   lonx=((itm.attr.lo1*1)+(itm.attr.lo2*1))/2; 
                   
                   len=(latx-lat)*(latx-lat)+(lonx-lon)*(lonx-lon); 

                   if (len<len_min){len_min=len;itm_min=itm}; 
                  } 
                  //mia end add 
                  } 

                  var c = {left:0,top:0}; 
                 
                  if(found) { 
                     c.left = itm.attr.ka*lon+itm.attr.kb*lat+itm.attr.kc*1 - 
                     self.left*self.scale; 

                     c.top = itm.attr.kd*lon+itm.attr.ke*lat+itm.attr.kf*1 - 
                     self.top*self.scale; 
                  } 
                  //mia add 
                  else { 

                  c.left = 
                  itm_min.attr.ka*lon+itm_min.attr.kb*lat+itm_min.attr.kc*1 - 
                  self.left*self.scale; 

                  c.top = 
                  itm_min.attr.kd*lon+itm_min.attr.ke*lat+itm_min.attr.kf*1 - 
                  self.top*self.scale; 

                  } 
                  //mia end add 
                  return c; 
                  }, 

                  WGS2map : function ( lat, lon ) { 

                  var self = this; 
                  var found = false; 
                  //mia add 
                  var len_min=360*360; 
                  var itm_min; 
                  //mia end add 
                  for(var i in self.WGSmap) {
                   
                    var itm = self.WGSmap[i]; 

                    if( (lat >= itm.attr.la1*1) && (lat <= itm.attr.la2*1) && (lon >= itm.attr.lo1*1) && (lon<= itm.attr.lo2*1) ) { 
                     
                     found = true; 

                    break; 
                    
                    } 
                  //mia add 
                  else{ 

                  latx=((itm.attr.la1*1)+(itm.attr.la2*1))/2; 
                  lonx=((itm.attr.lo1*1)+(itm.attr.lo2*1))/2; 
                  len=(latx-lat)*(latx-lat)+(lonx-lon)*(lonx-lon); 

                   if (len<len_min){len_min=len;itm_min=itm}; 

                  } 
                  //mia end add 
                  } 

                  var c = {left:0,top:0}; 

                  if(found) { 
                  
                   c.left = itm.attr.ka*lon+itm.attr.kb*lat+itm.attr.kc*1 ; 
                   c.top = itm.attr.kd*lon+itm.attr.ke*lat+itm.attr.kf*1 ; 

                  } 
                  //mia add 
                  else { 
                   c.left = 
                    itm_min.attr.ka*lon+itm_min.attr.kb*lat+itm_min.attr.kc*1; 
                   c.top = 
                    itm_min.attr.kd*lon+itm_min.attr.ke*lat+itm_min.attr.kf*1; 
                  } 
                  //mia end add 
                  return c; 
                  } 
}; 







// прототип управления панорамированием (uMap - ссылка на инстанс uMap)
function uPan(umap,options) {

  this.map = umap;

  this.initCount = 0;

  extend(this, baseProto);

  this.fields = {};

  this.handlers = { drag:[],mousedown:[],mouseup:[],mousemove:[],blur:[],focus:[],click:[],keypress:[],resize:[],ready:[],change:[]}

  this.faceName = 'pan';

  this.timeoutHand = false;

  this.dragOn     = false;
  this.dragLock   = false;
  this.wasDragged = false;

  this.clicked  = 0;
  this.down     = false;

  this.panVector  = [];
  this.vectorStep = 0;

  this.previousX  = 0;
  this.previousY  = 0;

  this.dragX  = 0;
  this.dragY  = 0;

  this.parts      = [];
  this.partsCount = 0;

  this.grid   = {cols:0,
                 rows:0,
                 top:0,
                 btm:0,                                                                  
                 left:0,
                 right:0
                 };

  // Инициализация панорамы 
  this.init   = function(jO) {
    
    var self = this;

    if(jO.full) {

      this.ocX = -Math.round(this.map.centerX/this.map.scale - this.map.view.width/2); 
      this.ocY = -Math.round(this.map.centerY/this.map.scale - this.map.view.height/2);

      this.vcX = 0; 
      this.vcY = 0;

      $(this.container).css({ 
                        zIndex:1,
                        position:'relative',
                        width:0,
                        height:0,
                        left:this.vcX,
                        top:this.vcY });

     }

     
    this.deltaCol      = Math.floor(-this.ocX / this.map.part.width) ;
    this.deltaRow      = Math.floor(-this.ocY / this.map.part.height);

    this.grid.cols = Math.ceil(this.map.view.width / this.map.part.width) + 1;
    this.grid.rows = Math.ceil(this.map.view.height / this.map.part.height) + 1;
   
    var part = {};
    
    this.initCount++;

    for( var i=0;i<this.grid.rows;i++)
     for( var j=0;j<this.grid.cols;j++) {

        var pLeft = (j+this.deltaCol)*this.map.part.width + this.ocX ;
        var pTop  = (i+this.deltaRow)*this.map.part.height + this.ocY ;
   
        if(this.parts[i+","+j] == undefined) {
          
            var img = $("<img/>").appendTo(this.container)[0];
   
            part = {img:img,real:this.initCount, 
                    left:'', top:'',
 		    destroy:function() { $(this.img).remove(); } };

            $(img).css({
                      zIndex:1+i*this.grid.cols+j,
                      position:'absolute',
                      display:'block',
                      cursor:'pointer',
                      left:pLeft,
                      top:pTop,
                      width:this.map.part.width,
                      height:this.map.part.height});

            img.id = 'part';

            img.onload=function() {
             this.style.display = 'block';
            }
           
           this.parts[i+","+j] = part;

        } else { 
   
           part      = this.parts[i+","+j];
           part.real = this.initCount;

           img  = part.img;
           $(img).css ({left:pLeft,top:pTop});

        }

        var xs  = pLeft + this.map.left - this.ocX;
        var ys  = pTop  + this.map.top - this.ocY ;

       if(part.left != pLeft ||  part.top != pTop || jO.full) {
       
       if(!self.map.printing)
        $(part.img).css('display','none');

        part.left = pLeft;
        part.top  = pTop;

        $(part.img).attr("src",
                 this.map.partHosts[j%this.map.partHosts.length]+"?t=shard&n="+this.map.id+
                 "&s="+this.map.scaleIndex+"&w="+this.map.part.width+"&h="+this.map.part.height+
                 "&lt="+this.map.transport+"&ws=&u="+this.map.user+"&x="+xs+"&y="+ys+"&ddx=1"
                 );
       }

     }
  
   if(jO.full) {
      for(var d in this.parts) 
          if(this.parts[d].real != this.initCount) { 
             this.parts[d].destroy();
             delete this.parts[d];
          }
   }
   
   this.redrawLayers(false,self);

   this.grid.top   = 0;
   this.grid.left  = 0;
   this.grid.btm   = this.grid.rows-1;
   this.grid.right = this.grid.cols-1;


   if(this.map.options.show) { 
                             this.pointer.left = (this.map.options.centerX - this.map.left*this.map.scale+this.ocX*this.map.scale)/this.map.scale -15;
                             this.pointer.top  = (this.map.options.centerY - this.map.top*this.map.scale+this.ocY*this.map.scale)/this.map.scale  -32;
                             this.pointer.container.css({display:'block',
   							 left:this.pointer.left,
						         top:this.pointer.top});
                             }
  
  }

 
 
  this.dragMe = function(e,self,options) {
  
  if(self.dragOn && !self.dragLock) {


     self.dragX = e.clientX-self.previousX;
     self.dragY = e.clientY-self.previousY;

    self.ocX += self.dragX;
    self.ocY += self.dragY;

    self.vcX += self.dragX;
    self.vcY += self.dragY;

    self.map.centerX-=self.dragX*self.map.scale;
    self.map.centerY-=self.dragY*self.map.scale;

    $(self.container).css({left:self.vcX,top:self.vcY});

    if(!self.timeoutHand)
     self.timeoutHand = setTimeout(function() {self.reformParts();},200);

   }
  
  }

 // Присвоение хэндлеров панорамирования
 this.makeHandlers = function() {
    
   var self = this;

   // Развешивание хэндлеров события панорамирования ******************* 
   if(self.map.isProblem) {
    $(this.pan).bind("dblclick", function(e) { 
 
     if(!self.dragOn) {
      self.clicked = 0;
      self.trigger(e,self,"dblclick");
     }

    });
   }

   $(this.pan).bind("mousedown", function(e) { 
      
      if(e.button != 2) { self.clicked++; }
     
       self.previousX = e.clientX;
       self.previousY = e.clientY;

       self.down      = true;

       if(e.target) var targ = e.target;
       if(e.srcElement) var targ = e.srcElement;

       if(targ.id == 'part' || targ.id == 'canvas') {
      
        self.dragOn    = true;

        e.preventDefault();
        e.cancelBubble = true;
        return false;
       } 

      self.trigger(e,self,"mousedown");
   
    });

   $(this.pan).bind("mousemove",function(e) { 
   

     if(self.clicked == 1 && self.down) {
      
      if(e.target) var targ = e.target;
      if(e.srcElement) var targ = e.srcElement;

      if(targ.className!='toolset' && (Math.abs(self.previousX-e.clientX)+Math.abs(self.previousX-e.clientX))>2)
         self.wasDragged = true;
      
      self.dragMe(e,self);

      self.trigger(e,self,"drag");


       self.previousX = e.clientX;
       self.previousY = e.clientY;

       if(targ.id !='infoContent') {
         e.preventDefault();      
         e.cancelBubble = true;
         return false;
        }
     }

   
   });
   
   $(document).bind("mouseup", function(e) {
     
     self.down = false;
      
    if(self.wasDragged) {self.clicked = 0; self.trigger(e,self,"stopdrag");}
     
     self.dragX = 0;
     self.dragY = 0;

     self.trigger(e,self,"mouseup");

     self.dragOn = false;
     self.wasDragged = false;

   //  $(self.pan).css({cursor:'pointer'});


   });

   $(this.map.container).bind("mouseout",function(e) { 
   
     self.dragX = 0;
     self.dragY = 0;

     self.trigger(e,self,"mouseout");
  
   });

   $(this.pan).bind("click",function(e) { 

   if(!self.map.isProblem) {

      setTimeout(function(){
              
                if(self.clicked==1 ) {     
                  self.trigger(e,self,"click");self.clicked=0; }
                 
                 else if(self.clicked>1 && !self.dragOn) {
                  self.trigger(e,self,"dblclick");
                  self.clicked = 0;
                 }
      },150);

      } else {
            setTimeout(function() {if(self.clicked) {
              self.trigger(e,self,"click");self.clicked=0; } },170);
      }

   });

   if(!this.map.options.nowheel)
     $(this.map.container).bind("mousewheel",function(e,delta) {
       
         if(e.target) var targ = e.target;
         if(e.srcElement) var targ = e.srcElement;

         if(targ.id == 'part' || targ.id == 'canvas') {

            var x = e.clientX-self.map.offset.left-self.ocX;
            var y = e.clientY-self.map.offset.top-self.ocY;

            if(self.map.isOpera) delta = delta*(-1);

            if(delta>0) {
            
            // if(self.map.scaleIndex>0) {

               self.dragX = Math.round((self.map.centerX/self.map.scale - x));
               self.dragY = Math.round((self.map.centerY/self.map.scale - y));

               self.dragMe(e,self);
               self.map.scaler.tool.slider("moveTo","+=1");

            //  }
           
            } else {

             //if(self.map.scaleIndex<self.map.scaleList.length-1) {

                self.map.scaler.tool.slider("moveTo","-=1");
             // }
            }
            e.preventDefault();
            return false;
        }
     });

  // Конец развешивания хэндлеров события панорамирования ****************
 }

  this.reformLayers = function(e,self) {

     if(self.map.interface && self.map.interface.layers)
     for(k in self.fields) {
     
       var field = self.fields[k];

       if(!field.options.maxScale || field.options.maxScale >= self.map.scaleIndex) 
          self.showLayers(k,field.layers,self.map.interface.layers);
       else if(field.options.maxScale) field.clear();

     } 

  }

 // Реформация фрагментов на карте в соответствии с её состоянием
  this.reformParts = function() {
    
    var self = this;

    var cX = this.ocX;
    var cY = this.ocY;

    /* Текущее смещение относительно верхнего левого угла карты */
    var cCol      = Math.floor(-cX / this.map.part.width) ;  
    var cRow      = Math.floor(-cY / this.map.part.height);

    /* Дельта смещения ячеек при перетаскивании */
    var offsetCol = cCol - this.deltaCol;
    var offsetRow = cRow - this.deltaRow;
    
    var updateParts = [];
    
    var part = {};

    // Пан вверх
    if(offsetRow>0) {
      
      for( var i = 0;i < offsetRow;i++ ) {

         for(var j=0;j < this.grid.cols; j++) {
          
          var pTop = (this.grid.rows+i+this.deltaRow)*this.map.part.height+cY-this.vcY;
          
          part = this.parts[this.grid.top+","+j];
          
          $(part.img).css({top:pTop,display:'none' });

          part.top = pTop;

          updateParts[this.grid.top+","+j] = part;
          
          }
            this.grid.top = (this.grid.top+1) % this.grid.rows;
            this.grid.btm = (this.grid.btm+1) % this.grid.rows;
            
        }	
       this.deltaRow = cRow;
    } 
    
    // Пан вниз
    if(offsetRow<0) {   
      for( var i = 0 ;i > offsetRow;i-- ) {

         for(var j=0;j < this.grid.cols; j++) {
          
            var pTop = (i+this.deltaRow-1)*this.map.part.height+cY-this.vcY;

            part = this.parts[this.grid.btm+","+j];

            $(part.img).css({top:pTop,display:'none'});
           
            part.top = pTop;
           
            updateParts[this.grid.btm+","+j] = part;
          }
          
          this.grid.btm--;
          if(this.grid.btm<0) this.grid.btm = this.grid.rows-1;

          this.grid.top--;
          if(this.grid.top<0) this.grid.top = this.grid.rows-1;
        }

       this.deltaRow = cRow;

    }
    
    // Пан влево
     if(offsetCol>0) {
      
      for( var j = 0;j < offsetCol;j++ ) {

         for(var i=0;i < this.grid.rows; i++) {
          
          var pLeft = (this.grid.cols+j+this.deltaCol)*this.map.part.width+cX-this.vcX;

          part = this.parts[i+","+this.grid.left];

          $(part.img).css({left:pLeft,display:'none'});

          part.left = pLeft;
                    
          updateParts[i+","+this.grid.left] = part;
 
          }
            this.grid.left = (this.grid.left+1) % this.grid.cols;
            this.grid.right = (this.grid.right+1) % this.grid.cols;
            
        }	
       this.deltaCol = cCol;
    } 
    
    // Пан вправо
    if(offsetCol<0) {   
      for( var j = 0 ;j > offsetCol;j-- ) {

         for(var i=0; i < this.grid.rows; i++) {
          
            var pLeft = (j+this.deltaCol-1)*this.map.part.width+cX-this.vcX;
            
            part = this.parts[i+","+this.grid.right];

            $(part.img).css({left:pLeft,display:'none'});

            part.left = pLeft;
           
            updateParts[i+","+this.grid.right] = part;
            
          }
          
          this.grid.left--;
          if(this.grid.left<0) this.grid.left = this.grid.cols-1;

          this.grid.right--;
          if(this.grid.right<0) this.grid.right = this.grid.cols-1;
        }

       this.deltaCol = cCol;

    }
   
    // обработка сместившихся фрагментов. 
     j=0;
     for(k in updateParts) {
     
        var xs  = updateParts[k].left + self.map.left - cX + self.vcX;
        var ys  = updateParts[k].top  + self.map.top - cY + self.vcY;
       //console.log(updateParts[k].left + ":" + this.map.left + ":" + cX + ":" + this.vcX);
        $(updateParts[k].img).attr("src",
                 this.map.partHosts[j%this.map.partHosts.length]+"?t=shard&n="+this.map.id+
                 "&s="+this.map.scaleIndex+"&w="+this.map.part.width+"&h="+this.map.part.height+
                 "&lt="+this.map.transport+"&ws=00&u="+this.map.user+"&x="+xs+"&y="+ys
                 ); 
         j++;
       
     }
     
    
    self.timeoutHand = false;
  }

// СЕРВИСНЫЕ ФУНКЦИИ 
  
 this.setMapWindowWGS = function(lat1,lon1,lat2,lon2,bidirectional) {

   bidirectional = bidirectional || false;

   c1 = this.map.WGS2pan(lat1,lon1);
  
   c2 = this.map.WGS2pan(lat2,lon2);   

   this.setMapWindow(c1.left,c1.top,c2.left,c2.top,bidirectional);

 } 


 this.setMapWindow    = function(x1,y1,x2,y2,bidirectional) {

   var self = this;

   if(!self.map.scaler.l6) {

     bidirectional = bidirectional || false;

     self.setMapHandler = self.map.register("scaler_data_ready", function() { self.setMapWindow(x1,y1,x2,y2,bidirectional) } );

     return false;
   }

   if(self.setMapHandler >= 0) {
      self.map.unregister("scaler_data_ready",self.setMapHandler);
   }

   var x_avg = Math.round( (x1+x2)/2 );
   var y_avg = Math.round( (y1+y2)/2 );
 

   var factorX = Math.abs(Math.ceil((x2-x1)/this.map.view.width));
   var factorY = Math.abs(Math.ceil((y2-y1)/this.map.view.height));
   
   var sObj = this.map.scaleIndexByFactor( factorX > factorY ? factorX : factorY );
   
   this.panTo(this,x_avg,y_avg,true);
   
   switch(sObj.level) {

     case "l4":
      this.map.scaler.l4[sObj.index].click();
     break;

     case "l6":
         this.map.scaler.l6[sObj.index].click();
     break;

   }

   //this.map.setScale(level);

 }
// Плавное панорамирование

 this.panTo = function(self,x,y,quick) {
  
  //return false;

   if(quick) {

      var dragX = (self.map.centerX-x)/self.map.scale;
      var dragY = (self.map.centerY-y)/self.map.scale;

      self.map.centerX = x;
      self.map.centerY = y;

      self.ocX += dragX;
      self.ocY += dragY;
      self.vcX += dragX;
      self.vcY += dragY;

      $(self.container).css({left:self.vcX,top:self.vcY});
      
      setTimeout(function() {self.reformParts();},100);

      self.trigger("",self,"drag");

      return false;
   }

   if(!self.panVector.length) {

    var dX = (self.map.centerX-x) ;
    var dY = (self.map.centerY-y) ;

    if(Math.abs(dX)<=1 && Math.abs(dY)<=1) return false;
  
    var distance = Math.round(Math.sqrt(dX*dX+dY*dY)/self.map.scale);

     switch(true) {
      case distance<10:   var step = 2; break;
      case distance<100:  var step = 5; break;
      case distance<200:  var step = 7; break;
      case distance>=200: var step = 10; break;
      case distance>=1000: var step = 100; break;
     }


     self.panVector[0] = {factor:0.15,
                          x:x,
                          y:y,
                          dX:dX/(self.map.scale*step),
                          dY:dY/(self.map.scale*step),
                          distance:distance};

     self.vectorStep   = 0;  

     setTimeout(function() {self.panTo(self);},25);

   } else {
     self.dragOn = true;
     self.dragLock = true;

     self.dragX = self.panVector[0].dX*self.panVector[0].factor; 
     self.dragY = self.panVector[0].dY*self.panVector[0].factor;
     
     if(self.panVector[0].factor<1)
        self.panVector[0].factor+=0.15;
     else 
        self.panVector[0].factor = 1;

     if(Math.abs(self.map.centerX - self.panVector[0].x)<Math.abs(self.dragX*self.map.scale*2) ||
        Math.abs(self.map.centerY - self.panVector[0].y)<Math.abs(self.dragY*self.map.scale*2)) {

        self.dragX =  (self.map.centerX - self.panVector[0].x)/self.map.scale;
        self.dragY =  (self.map.centerY - self.panVector[0].y)/self.map.scale;
      }
     
      self.ocX += self.dragX;
      self.ocY += self.dragY;
      self.vcX += self.dragX;
      self.vcY += self.dragY;

      self.map.centerX-=self.dragX*self.map.scale;
      self.map.centerY-=self.dragY*self.map.scale;

      $(self.container).css({left:self.vcX,top:self.vcY});

      self.trigger("",self,"drag");

     if(!self.timeoutHand)
       self.timeoutHand = setTimeout(function() {self.reformParts();},500);

     if((self.panVector[0].x != self.map.centerX || self.panVector[0].y != self.map.centerY) && (!self.timeoutPan)) {
         
         self.timeoutPan = setTimeout(function() { self.timeoutPan = 0; self.panTo(self)},25);

       }
     else if(!self.timeoutPan){ 
      self.vectorStep = 0; self.panVector=[];
      self.dragOn = false;
      self.dragLock = false;
      self.trigger("",self,"stopdrag");
     }

   }

 }

 // Центрирование на карте. X,Y - координаты сервиса
 this.centerMap = function(x,y) {
  var self = this;

  var left = x-(self.map.left)*self.map.scale;
  var top = y-(self.map.top)*self.map.scale;

  self.panTo(self,left,top);

 }

 this.getField = function(id) {
    return this.fields[id];
 }

 this.addField = function(id,options) {
  this.fields[id] = new uField(this,options);
  return this.fields[id];
 }


 this.redrawLayers = function(e,self,options) {
    
    for(var k in self.fields) {
     var field = self.fields[k];

     if(self.map.interface && self.map.interface.layers && field.layers) {
 
       field.redraw();

      if(self.map.interface && self.map.interface.layers) 
       if(!field.options.maxScale || field.options.maxScale >= self.map.scaleIndex) 
          self.showLayers(k,field.layers,self.map.interface.layers);
       else if(field.options.maxScale)
          field.clear();
      
      }
   }
 }

 this.showLayers = function(fieldName,lrs,tool) {

  var self = this;
  
  var get = [];

  var del = [];

  var field = self.fields[fieldName];

 if(lrs.length) { 
        var cX=Math.round((this.map.left-self.ocX)*self.map.scale)-40,
            cY=Math.round((this.map.top-self.ocY)*self.map.scale)-40;   

        var cR=Math.round(cX+self.map.view.width*self.map.scale)+80,
            cB=Math.round(cY+self.map.view.height*self.map.scale)+80;   

        field.layers = lrs;
        
        var filterSet = "{";
        var i = 0;
        for(var lr in tool.filter) {
         if(i>0)
            filterSet +=",";

            filterSet += '"'+lr+'":{';
   
            var j = 0;
            
            for(var idz in tool.filter[lr]) {
              
              if(j>0) filterSet+=",";

              filterSet +='"'+idz+'":'+'"'+tool.filter[lr][idz]+'"';
              j++;
            }

          filterSet += "}";
          i++;
        }
        filterSet +="}";
        
        tool.load(field.options.layersURL,'execute',{layers_get:field.layers
                                             ,fTop:cY,fLeft:cX,fRight:cR,fBottom:cB,showAll:field.showAll,filters:filterSet});
  } else {
      if(field.layers.length > 0) {
         field.clear(); 
         field.layers = lrs;
        }
  }
 }

// *****************************
  var self = this;
  
  this.pan       = $("<div/>").appendTo(this.map.container)[0];

  $(this.pan).css({ cursor:'pointer', zIndex:1, position:'absolute',left:0,top:0 });
  
  this.pan.id='mapPan';
  
  this.container = $("<div/>").appendTo(this.pan)[0];

  this.pointer = {container:$("<img/>").appendTo(this.container)
                 .attr({src:'http://www.umap.ru/sites/default/i/map/pointer.gif',width:29,height:32})
                 .css({zIndex:10000,position:'absolute'}),
		  left:this.map.view.width/2,
		  top:this.map.view.height/2};

  if(this.map.options.show) this.pointer.container.css({display:'block',left:this.pointer.left-15,top:this.pointer.top-32});
  else this.pointer.container.css({display:'none'});

  this.makeHandlers();

  self.register("stopdrag",function(e){ self.reformLayers(e,self);});

 // this.register('drag',this.dragMe);
 
  this.register('dblclick',function(e,self) {    
       if(e.target) var targ = e.target;
       if(e.srcElement) var targ = e.srcElement;

       if(targ.id == 'part' || targ.id == 'canvas') {
          mc = self.map.eventCoords(e,self.map);
          self.panTo(self,(mc.X)*self.map.scale,(mc.Y)*self.map.scale);
       }

  });

  this.init({full:true});

/// 
}

uPan.prototype = {};


// прототип управления полями (слоями) в панорамах.

function uField(pan,options) {

   extend(this,baseProto);

   var self = this;

   self.pan      = pan;
   self.map      = pan.map;
   
   self.showAll  = 0;

   self.faceName = 'field';

   self.handlers = { drag:[],mousedown:[],mouseup:[],mousemove:[],blur:[],focus:[],click:[],keypress:[],resize:[],ready:[],change:[]}
   
   self.layers            = [];
   self.options 	  = {layersURL:self.pan.map.baseURL+'/assets/map/load/showLayers.php',
                             axisSnapURL:self.pan.map.baseURL+'/assets/map/axissnap2.php'
                            }; 
   
   self.points      = {};
   self.pointsIndex = [];

   self.shapes      = {};
   self.shapeIndex  = [];

   self.canvas       = false;

   for(var i in options) 
     self.options[i] = options[i];


   self.container = $("<div/>").appendTo(self.pan.container);
   self.container.css({position:'absolute',left:0,top:0,zIndex:self.pan.map.view.zField});

   self.pointContainer = $("<div/>").appendTo(self.container);
   self.pointContainer.css({position:'absolute',left:0,top:0,zIndex:self.pan.map.view.zElements});

   self.pan.register("drag",function(e){  self.dragMe(e,self);});
   self.pan.register("mousedown",function(e){ self.down(e,self);});
   self.pan.register("mouseup",function(e){ self.up(e,self);});

   if(self.options.canDraw) {

      self.canvas = new uCanvas(self);

   }

//   self.pan.map.register("resize",function(e,self) {self.redraw()});
 }

uField.prototype.addBeacon = function(id,options) {
   
   options.id = id;

   this.points[id] = new uPoint(this,options);
   this.pointsIndex[this.pointsIndex.length] = id;

   return this.points[id];
 }

uField.prototype.addBeaconMap = function(id,options) {
   
   var self = this;

   options.id = id;
   
   if(options.left && options.top) {
      var left = options.left;
      var top  = options.top;

      options.left -= self.map.left*self.map.scale;
      options.top  -= self.map.top*self.map.scale;
      

    } else 
        if(options.leftPan && options.topPan) {
          var left = options.leftPan + self.map.left*self.map.scale;
          var top  = options.topPan + self.map.top*self.map.scale;

           options.left = options.leftPan;
           options.top  = options.topPan;
        } 


   self.points[id] = new uPoint(this,options);
   self.pointsIndex[self.pointsIndex.length] = id;

   return this.points[id];
 }

uField.prototype.snapPoint2Axis = function(jO,point) {
  
  var self = this;

  var map = self.pan.map;
  point.setData({left:jO.root.p.attr.x - map.left*map.scale, top: jO.root.p.attr.y - map.top*map.scale});

}

uField.prototype.removeBeacon = function(id) {
   
   if(this.points[id]) {   
     this.points[id].destroy();
     delete this.points[id];
   }

 }

uField.prototype.addShape = function(id,options) {
  this.shapes[id] = new uShape(this,options);

  this.shapeIndex[this.shapeIndex.length] = id;

  return this.shapes[id];
}

uField.prototype.removeShape = function(id) {
   if(this.shapes[id]) {   
     this.shapes[id].destroy();
     delete this.shapes[id];
   
     var j=0;
      var sm = this.shapesIndex;
      
      this.shapesIndex = [];

     for(var i in this.shapesIndex) {

      if(this.shapesIndex[i] != id) { 
          this.shapesIndex[j] = sm[i]; 
          j++;
        }

     }

   }


}

uField.prototype.dragMe = function(e,self) {
       self.trigger(e,self,"drag");
}

uField.prototype.down = function(e,self) {
       self.trigger(e,this,"mousedown");
}

uField.prototype.up = function(e,self) {  
       self.trigger(e,self,"mouseup");
}

uField.prototype.redraw  = function() {

   if(this.canvas)  this.canvas.clear();
        
   for(var k in this.points) {
    this.points[k].redraw();
   }

   for(var k in this.shapes) {
    this.shapes[k].redraw();
   }

}

uField.prototype.clear   = function() {
          

          this.pointContainer.html("");
        
          if(this.canvas) this.canvas.clear();
          
          this.points      = {};
          this.pointsIndex = [];

          for(i in this.shapes) {
            this.shapes[i].clear();
           }

          this.shapes      = {};
          this.shapeIndex = [];


          this.redraw();

}

// прототип управления фигурами в полях 
function uShape(field,options) {
/*
   type is definintion of methods of beacons interconnection:
     - lineConnected
     - clusterConnected
     - standAlone
*/  
 extend(this, baseProto);

 var self = this;

 self._trackPointTreshold = 30;

 self.handlers = { drag:[],mousedown:[],mouseup:[],mousemove:[],blur:[],focus:[],click:[],keypress:[],resize:[],ready:[],change:[]}

 self.field = field;
 self.pan   = field.pan;
 self.map   = field.pan.map;

 self._lineColor =  "#e63518";

     try {

       var typeD = eval("_shape_"+options.type);

     } catch(e) {

     }

 if(typeof(typeD) == "function") {
    extend(this,typeD);
 }
 
 self.faceName = 'shape';
 
 self.options = options;
 
 self.container = $("<div/>").appendTo(self.field.container);
 self.container.css({position:'absolute',left:0,top:0,zIndex:self.pan.map.view.zField});

 self.pointContainer = $("<div/>").appendTo(self.container);
 self.pointContainer.css({position:'absolute',left:0,top:0,zIndex:self.pan.map.view.zElements});

 self.points        = {};
 self.pointsIndex   = [];

 self.pan.register("drag",function(e){  self.dragMe(e,self);});
 self.pan.register("mousedown",function(e){ self.down(e,self);});
 self.pan.register("mouseup",function(e){ self.up(e,self);});


 this.init = function(options) {
   
   var self = this;                                        	
   
   if(typeof(self.init_) == "function") 
      self.init_(self);
 }

 this.init();

}

uShape.prototype.setColor = function(color) {
   this.field.canvas.setColor(color);
}


uShape.prototype.addVertex = function(id,options) {
   
   var self = this;

   if(!id) id = this.pointsIndex.length;

   options.id = id;

   if(options.left && options.top) {
      options.left -= self.map.cleft; //self.map.left*self.map.scale;
      options.top  -= self.map.ctop; //self.map.top*self.map.scale;
      
    } else 
        if(options.leftPan && options.topPan) {
           options.left = options.leftPan;
           options.top  = options.topPan;
        } else
           if(options.lat && options.lon) {
              
              var coord = self.map.WGS2pan(options.lat,options.lon);

              options.left = coord.left;
              options.top  = coord.top;
           }          



   self.pointsIndex.push(id);

   self.points[id] = new uPoint(self,options);

   return self.points[id];
 }


uShape.prototype.addPoint = function(id,options) {
   
   options.id = id;

   this.pointsIndex.push(id);

   this.points[id] = new uPoint(this,options);

   return this.points[id];
 }

uShape.prototype.removePoint = function(id) {
   
   if(this.points[id]) {   
     
     this.points[id].destroy();
     
     delete this.points[id];

     var j=0;
     var sm = this.pointsIndex;
     
     this.pointsIndex = [];

    for(var i in this.pointsIndex) {

     if(this.pointsIndex[i] != id) { 
         this.pointsIndex[j] = sm[i]; 
         j++;
       }

    }

   }

 }

uShape.prototype.snapTrack = function( invert ) {

     invert = invert || false;

     var left,top,pps=[], self = this,i,k;

     var map = self.map;

     if (! invert ) {

        if(self._trackPoint == undefined) self._trackPoint = 0;
        
        k = 0;

        for( i = self._trackPoint ; i<self.pointsIndex.length ;i++ ) {
          var itm  = self.points[self.pointsIndex[i]];

              lat = itm.lat; //Math.round(itm.left +map.left*map.scale);
              lon  = itm.lon; //Math.round(itm.top +map.top*map.scale);
              pps.push(lon+","+lat);

              k++;

              if(k > self._trackPointTreshold) { 

                break;
              }

        }
     
     } else {

        if(self._trackPoint == undefined) self._trackPoint = self.pointsIndex.length ;
        
        k = 0;

        for( i = self._trackPoint - 1 ; i > 0 ; i-- ) {

          var itm  = self.points[self.pointsIndex[i]];
              lat = itm.lat; //Math.round(itm.left +map.left*map.scale);
              lon = itm.lon; //Math.round(itm.top +map.top*map.scale);
        
              pps.push(lon+","+lat);

              k++;

              if(k > self._trackPointTreshold) { 
                break;
              }

        }


     }

     self._trackPointLength = k;

     self._trackPoint = i;

     self.load(self.field.options.axisSnapURL,function(jO) { self.snapPoints2Axis(jO, invert); }, { n:map.city,pp:pps.join(";")});

}

uShape.prototype.snapPoints2Axis = function(jO, invert) {
     var i,itm,t,k;
     var self = this;
     var map  = self.map;

     //if(typeof(jO.root.p) == 'object') jO.root.p = [ jO.root.p ];
     
     if(!invert) {

       k  = self._trackPoint > 0 ? self._trackPoint - self._trackPointLength : 0;

       if( self._trackPoint > self._trackPointTreshold) k++;

       for(i in jO.root.p) {

           itm  = self.points[self.pointsIndex[k+i*1]];
           
           if(itm == undefined) continue;
           t    = jO.root.p[i].attr;

           itm.setData({lon: t.lon*1, lat: t.lat*1});
       }

       if(self._trackPoint > 0 && self._trackPoint < self.pointsIndex.length) {
          self.snapTrack(invert);
       }
      
     } else {

       k  = self._trackPoint < self.pointsIndex.length - 1 ? self._trackPoint + self._trackPointLength : self.pointsIndex.length - 1 ;

       var len = jO.root.p.length - 1;

       for(i in jO.root.p) {
           itm  = self.points[self.pointsIndex[k - i*1]];
           
           if(itm == undefined) continue;

           t    = jO.root.p[i].attr;
           itm.setData({lon: t.lon,lat: t.lat});
       }

       if(self._trackPoint > 0 && self._trackPoint < self.pointsIndex.length) {
          self.snapTrack(invert);
       }


     }
     self.field.redraw();


}

uShape.prototype.destroy  = function() {
   this.clear();
   $(this.container).remove();

 }

uShape.prototype.dragMe = function(e,self) {
       self.trigger(e,self,"drag");
}

uShape.prototype.down = function(e,self) {
       self.trigger(e,this,"mousedown");
}

uShape.prototype.up = function(e,self) {  
       self.trigger(e,self,"mouseup");
}

uShape.prototype.calcDistance = function(i,j) {
  var self = this;

  var pointA = self.points[self.pointsIndex[i]];
  var pointB = self.points[self.pointsIndex[j]];
   if(i>=0 && j>=0) {
    return Math.sqrt( (pointA.left-pointB.left)
                      *(pointA.left-pointB.left) +
                      (pointA.top-pointB.top)
                      *(pointA.top-pointB.top)) * self.pan.map.mperpix;


   } else 
    return false;

}


/*  ПРОТОТИПЫ ФИГУР */

// Тип фигуры "Линия" (прототип с отрисовкой линии по точкам)
function _shape_line() { } 

 _shape_line.prototype = {

       init_:function(self) {
       },

       redraw:function() {
        for(var k in this.points) {
         this.points[k].redraw();
        }
        this.redrawLines();
       },
       
       clear:function() {
          this.pointContainer.html("");
          
          this.points = {};
          this.pointsIndex = [];

          for(i in this.handlers) 
             this.handlers[i] = [];
       },

       redrawLines:function() {
         
         if(!this.options.color) {
           this.setColor("#e63518");
         } else {
           this.setColor(this.options.color);
         }

          if(this.pointsIndex.length>1) {

             this.field.canvas.beginLine();
          
             var curr   = this.points[this.pointsIndex[0]];
             var length = this.pointsIndex.length;

            this.field.canvas.moveTo(curr.cleft+curr.offsetX,curr.ctop+curr.offsetY);

            for(var k=1;k<length;k++)   {

               curr = this.points[this.pointsIndex[k]];
              
              this.field.canvas.lineTo(curr.cleft+curr.offsetX,curr.ctop+curr.offsetY);
             }
              this.field.canvas.paintLine();
          } 
        
       }

 }


function _shape_route() { } 

 _shape_route.prototype = {

       init_:function(self) {

         self.loadURL = self.map.baseURL + "/assets/map/load/routeShape.php";
         self._dirty  = false;
         self.__addVertex = self.addVertex;
         self.addVertex = self._addVertex;

         self._beforeColor = self.options.beforeColor || self._lineColor;
         self._afterColor  = self.options.afterColor  || self._lineColor;
         self._keyPoints = [];
       },

       _addVertex:function(id,opts) {

         var self = this;
         if(self.map.typeHandler[opts.type] && opts.canMove) {
            self.map.typeHandler[opts.type].canSaveMove = 1;
         }

         var z = self.__addVertex(id,opts);

         z.linkURL = self.loadURL;

         z.save =  function(e,d,options) {

                   if(e.target) var targ = e.target;
                   if(e.srcElement) var targ = e.srcElement;
                   
                   if(targ.tag == d.id) {

                     self.makeRouted();
                   }

                 }

         z.key = true;

         self._keyPoints.push(z);
         
         if(opts.current) self.currentVertex = z.id;

         return z;
       },
       
       vxMakeCurrent:function(id) {
         this.currentVertex = id;
         this.redraw();
       },

       makeRouted:function() {

         var curr = [],
             self = this, 
             params = {},
             left,top;


         params['s_map']   = self.map.oName;
         params['s_city']  = self.map.city;
         params['s_scale'] = self.map.scale;
         params['s_scaleI'] = self.map.scaleIndex;

         
         for(var i in self.pointsIndex) {

          if(self.points[ self.pointsIndex[i] ].key) {
            left = self.points[ self.pointsIndex[i] ].left+self.map.left*self.map.scale;
            top  = self.points[ self.pointsIndex[i] ].top+self.map.top*self.map.scale;
            curr.push( left + "," + top); 
           }
         }

         params['s_pts'] = curr.join(";");4

         self.load(self.loadURL,function(jO) { self.loadData(jO); },params);
       },

       loadData: function(jO) {

         var self = this,j,left,top;

         var sPoints = [],
             p_ptr   = 0,
             it,itm,idz;
          
         for(j in self.points) {
            if(!self.points[j].key) {
             self.points[j].destroy();
             delete self.points[j];
            }
         }
         
         if(jO.marks.length>1) {

             for(j in jO.marks) {

               itm = jO.marks[j];

               left = itm.x-self.map.left*self.map.scale;
               top  = itm.y-self.map.top*self.map.scale;

               if(itm.node != 'routeNode') {
                  self._keyPoints[p_ptr]._distance = itm.dist;
                  sPoints.push(self._keyPoints[p_ptr].id);
                  p_ptr++;
                  self._distance = itm.dist;
               } else {
                 idz = self._keyPoints[p_ptr].id + "_" + itm.id;
                  sPoints.push(idz);

                  self.points[idz] =  new uPoint(self,{id:idz,
                                                  left:left,
                                                  top:top,
                                                  virtual:true,
                                                  type:'markUp',
                                                  entity:'routeNode'
                                                 } );  	
               }
               
             }
           
             self.pointsIndex = sPoints;
             self.field.canvas.clear();
             self.redraw();
         }

         self.trigger(false,self,'dataLoaded');
       
       },
       getDistance:function(id) {
          if(id)
            return this.points[id]._distance;
          else 
            return this._distance;
       },
       redraw:function() {

        for(var k in this.points) {
         this.points[k].redraw();
        }
        this.redrawLines(); 
       },

       clear:function() {
          this.pointContainer.html("");
          
          this.points = {};
          this.pointsIndex = [];

          for(i in this.handlers) 
             this.handlers[i] = [];
       },

       redrawLines:function() {

          this.setColor(this._beforeColor);

          if(this.pointsIndex.length>1) {

             //this.field.canvas.beginLine();
          
             var c_curr   = this.points[this.pointsIndex[0]];
             
             var length = this.pointsIndex.length;

             if(this.currentVertex && this.currentVertex == c_curr.id) {
               this.setColor(this._afterColor);
             }
             
           // this.field.canvas.moveTo(curr.cleft+curr.offsetX,curr.ctop+curr.offsetY);

            for(var k=1;k<length;k++)   {
                   	
              curr = this.points[this.pointsIndex[k]];

              if(this.currentVertex && this.currentVertex == curr.id) {
                 this.setColor(this._afterColor);
              }
              
              this.field.canvas.drawLine(c_curr.cleft+c_curr.offsetX,
                                         c_curr.ctop+c_curr.offsetY,
                                         curr.cleft+curr.offsetX,
                                         curr.ctop+curr.offsetY);

                 c_curr = curr;
             }


          } 



       } ,
        removePoint:function(id) {
    
          if(this.points[id]) {   
            
            this.points[id].destroy();
            
            delete this.points[id];

            var j=0;
            var sm = this._keyPoints;
            
            this.pointsIndex = [];

            for(var i in this._keyPoints) {

             if(this._keyPoints[i] != id) { 
                 this._keyPoints[j] = sm[i]; 
                 j++;
               }

            }

          }

        }

 }


// Тип фигуры "Область" (расширение прототипа "линия" с отрисовкой полигона
// по точкам с замыканием области)
function _shape_area() { } 

 _shape_area.prototype = {
     
       init_:function(self) {
        self.canvas = new uCanvas(self);
       },

       redraw:function() {
        for(var k in this.points) {
         this.points[k].redraw();
        }
        this.redrawLines();
       },

       clear:function() {
          this.pointContainer.html("");
        
          this.points = {};
          this.pointsIndex = [];

          for(i in this.handlers) 
             this.handlers[i] = [];


       },
      
      redrawPolys:function() {
         if(!this.options.color) {
           this.setColor("#e63518");
         } else {
           this.setColor(this.options.color);
         }

         this.field.canvas.drawPoly(this.points,this.field.pan);
       },                             
      
       redrawLines:function() {
       
        if(this.pointsIndex.length>2) {
          this.redrawPolys();
        } else if(this.pointsIndex.length==2) {

             this.field.canvas.beginLine();
          
             var curr = this.points[this.pointsIndex[0]];

             this.field.canvas.moveTo(curr.cleft+curr.offsetX,curr.ctop+curr.offsetY);

             if(curr == this.currentVertex) {
               this.setColor(this._afterColor);
             }

             var length = this.pointsIndex.length;

            for(var k=1;k<length;k++)   {

               curr = this.points[this.pointsIndex[k]];
              
               if(curr == this.currentVertex) {
                 this.setColor(this._afterColor);
               }

              this.field.canvas.lineTo(curr.cleft+curr.offsetX,curr.ctop+curr.offsetY);
             }
              this.field.canvas.paintLine();
          }   

       }
 }






// прототип управления объектами на карте
function uPoint(u,options) {

 var self = this;

 this.u   = u;
 this.map = u.pan.map;

 this.options = options;

 if(options.left && options.top) {
   
   this.left    = options.left;
   this.top     = options.top;

  } else 
         if(options.lat && options.lon) {
            
            var coord = self.map.WGS2pan(options.lat,options.lon);

            this.left = coord.left;
            this.top  = coord.top;

         }

  if(options.lat && options.lon) {
            this.lat  = options.lat;
            this.lon  = options.lon;

  }                 

 
 this.linkURL = this.u.map.baseURL+"/assets/map/operate.php";

 if(options.url) this.linkURL = options.url;

 if(!this.options.virtual) {
   
   extend(this, baseProto);

   this.timeHandle = false;

   this.handlers = { drag:[],mousedown:[],mouseup:[],mousemove:[],blur:[],focus:[],click:[],keypress:[],resize:[],ready:[],change:[]},

   this.dragOn     = false;
   this.wasDragged = false;

   if(!options.typeHandler) {
   
    this.typeHandler =  clone( this.u.pan.map.typeHandler[ this.options.type ] );
   
   } else {
    
    this.typeHandler = options.typeHandler;
   }
 
   this.container = $("<div/>").appendTo(this.u.pointContainer)[0];

 }

 this.init();

}


uPoint.prototype.init = function() {

   var self = this;
       self._dhandlers = [];

   if(!self.options.virtual) {
    var $container = $(this.container);
    
    if(self.options.glyph) {
     
      $container.css(self.options.glyph.css);

      self.typeHandler.offsetX = self.options.glyph.offsetX;
      self.typeHandler.offsetY = self.options.glyph.offsetY;

     } else {

         $container.css(self.typeHandler.container.css);

     }
     self.offsetX = self.typeHandler.offsetX;
     self.offsetY = self.typeHandler.offsetY;
   } else {
     self.offsetX = 0;
     self.offsetY = 0;
   }

   self.cleft = Math.round(self.left/self.u.pan.map.scale-self.offsetX+this.u.pan.ocX-this.u.pan.vcX);
   self.ctop  = Math.round(self.top/self.u.pan.map.scale-self.offsetY+this.u.pan.ocY-this.u.pan.vcY) ;    
   
   if(!self.options.virtual)  {

      $container.css({overflow:'visible',
                          
                          zIndex:self.u.pan.map.view.zElements+self.u.pointsIndex.length,
                          
                          position:'absolute',
                          
                          left:self.cleft,

                          top:self.ctop,
                          cursor:'pointer'  });

      self.label = $("<span/>").appendTo(self.container)[0];
     
      $(self.label).css(self.typeHandler.label.css);

      if(self.options.label) {
        $(self.label).html(self.options.label);
      }

      if(self.typeHandler.content) {
     
        self.content = $("<div/>").appendTo(self.container)[0];
     
        $(self.content).css(self.typeHandler.content.css);

       if(self.options.content)
        $(self.content).html(self.options.content);
      }

      if(self.options.title) {
        $container.attr('title',self.options.title);
      }

      if(self.options.entity) {
        $container[0].id = self.options.entity;
        self.label.id = self.options.entity;
      }

      if(self.options.url) {
        
        $container[0].href = self.options.url;
        self.label.href = self.options.url;
      }

      if(self.options.id) {
        
        self.id = self.options.id;

        $container[0].tag = self.id;
        self.label.tag = self.id;
      }

     if(self.options.behavior != undefined) {
       self.typeHandler.behavior = self.options.behavior;
     }

     if(self.typeHandler.behavior) {

       for(var i in self.typeHandler.behavior) {

         if(self[i] != undefined)
            self[i](self.typeHandler.behavior[i]);
       }

     } 
   }
   
   if(self.options.autoStreetSnap) {
      var left = self.left + self.u.pan.map.left*self.u.pan.map.scale;
      var top  = self.top  + self.u.pan.map.top*self.u.pan.map.scale;

      var pnt = left + ',' + top;
      
      var field = self.u.field ? self.u.field : self.u;

      self.load(field.options.axisSnapURL,function(jO) { field.snapPoint2Axis(jO,self); },{n:self.u.pan.map.city,pp:pnt});
   }
 
 }

uPoint.prototype.redraw  = function() {

   var pan = this.u.pan;

   var self = this;

   if(self.lat && self.lon) {
     var coord = self.map.WGS2pan(self.lat,self.lon);
     self.left = coord.left;
     self.top  = coord.top;
   }

   self.cleft = Math.round(self.left/pan.map.scale-self.offsetX+pan.ocX-pan.vcX);
   self.ctop  = Math.round(self.top/pan.map.scale-self.offsetY+pan.ocY-pan.vcY ) ;    

   if(!self.options.virtual) {
           
           $(self.container).css({left:self.cleft,top:self.ctop + 'px'});



         }   
 }

uPoint.prototype.setData = function(options) {
  
  var self = this;

  var map = self.u.pan.map;

  if(!self.options.virtual) {
    var container = $(self.container);

   if(options.glyph) {
    
     container.css(options.glyph.css);

     self.typeHandler.offsetX = options.glyph.offsetX;
     self.typeHandler.offsetY = options.glyph.offsetY;

     self.offsetX = self.typeHandler.offsetX;
     self.offsetY = self.typeHandler.offsetY;

    } 

   if(options.lat && options.lon) {
      
      var coord = self.map.WGS2pan(options.lat,options.lon);
      
      self.left = coord.left;
      self.top  = coord.top;

      self.lat  = options.lat;
      self.lon  = options.lon;

      var left  = coord.left + map.cleft; //map.left*map.scale;
      var top   = coord.top  + map.ctop;  //map.top*map.scale;

   }

   if(options.left) {
     var left = options.left + map.cleft;//map.left*map.scale;
     self.left = options.left;
   }

   if(options.top) {
     var top = options.top + map.ctop;//map.left*map.scale;
     self.top = options.top;
   }

   if( ( options.top || options.left ) && (self.lat && self.lon) ) {

      var coord = self.map.pan2WGS(self.left,self.top);

      self.lat = coord.lat;
      self.lon = coord.lon;

   }

   if(options.mapLeft) {
     var left  = options.mapLeft;
     self.left = options.mapLeft - map.cleft;//map.left*map.scale;;
   }

   if(options.mapTop) {
     var top  = options.mapTop; 
     self.top = options.mapTop - map.ctop;//map.top*map.scale;;
   }

   
                
   if(options.label) {
     $(self.label).html(options.label);
   }

   if(options.title) {
     container.attr('title',options.title);
   }

   if(options.content)
    $(self.content).html(options.content);
   }

   if(options.autoStreetSnap) {
      var pnt = left + ',' + top;
      
      var field = self.u.field ? self.u.field : self.u;

      self.load(field.options.axisSnapURL,function(jO) { field.snapPoint2Axis(jO,self); },{n:self.u.pan.map.city,pp:pnt});
    return true;
   }

   if(options.recalc == undefined || options.recalc) {

    self.cleft = Math.round(self.left/self.u.pan.map.scale-self.offsetX +self.u.pan.ocX-self.u.pan.vcX);
    self.ctop  = Math.round(self.top/self.u.pan.map.scale-self.offsetY +self.u.pan.ocY-self.u.pan.vcY) ;    

    if(!self.options.virtual) {   

    
    container.css({ left:self.cleft, top:self.ctop  });




    				                 }
   }

 }
 
uPoint.prototype.destroy = function() {

  for(var j in this._dhandlers) {
     self.u.unregister(this._dhandlers[j]);
  }

  if(typeof(this.container) == "object" && typeof(this.container.remove) == "function")
     this.container.remove();

 }

uPoint.prototype.canTip = function(options) {
}

uPoint.prototype.canMove = function(options) {
   
   var self = this;
   
   self._dhandlers.push( self.u.register("drag",function(e){ self.dragMe(e,self,options);}) );
   self._dhandlers.push( self.u.register("mousedown",function(e){self.down(e,self,options);}) );
   self._dhandlers.push( self.u.register("mouseup",function(e){self.up(e,self,options);}) ); 

}

uPoint.prototype.canSaveMove = function(options) {
   
   var self = this;

   self.canMove();

   self.u.register("mouseup",function(e){self.save(e,self,options);}); 

}


uPoint.prototype.dragMe = function(e,self,options) {
   if(self.dragOn) {      
    
    self.grabObject.left += (e.clientX-self.u.pan.previousX)*self.u.pan.map.scale;
    self.grabObject.top  += (e.clientY-self.u.pan.previousY)*self.u.pan.map.scale;

    if(self.lat && self.lon) {

      var coord = self.map.pan2WGS(self.grabObject.left,self.grabObject.top);
      self.lat = coord.lat;
      self.lon = coord.lon;
    }
    	
    self.grabObject.setData({recalc:true});

    self.wasDragged = true;
 
   if(!self.timeHandle)
      self.timeHandle = setTimeout(function() {self.timeHandle = false;
                                               
                                               if(self.u.field)
                                                 self.u.field.redraw();

                                               self.trigger(e,self,"drag")},5);
   }

}

uPoint.prototype.down = function(e,self,options) {
    
          if(e.target) var targ = e.target;
          if(e.srcElement) var targ = e.srcElement;

          if(targ.tag == self.id) {
            
            self.grabObject = self;
            self.dragOn = true;
          }
        self.trigger(e,self,"down");
}

uPoint.prototype.up = function(e,self,options) {
    
          if(e.target) var targ = e.target;
          if(e.srcElement) var targ = e.srcElement;

          if(targ.tag == self.id) {

            if(self.wasDragged) {
               self.trigger(e,self,"dragStop"); 
              } else {
                self.trigger(e,self,"up");
              }
              self.wasDragged = false;
           }

    self.dragOn = false;
}

uPoint.prototype.save = function(e,self,options) {

  if(e.target) var targ = e.target;
  if(e.srcElement) var targ = e.srcElement;

  if(targ.tag == self.id) {

    self.load(self.linkURL,"execute",{s_left:Math.round(self.left+self.u.map.left*self.u.map.scale),
  				    s_top:Math.round(self.top+self.u.map.top*self.u.map.scale),
  				    s_city:self.u.pan.map.city,
  				    s_map:self.u.pan.map.oName,
  				    s_id:self.id,
  				    s_scale:self.u.pan.map.scale,
  				    s_scaleI:self.u.pan.map.scaleIndex,
  				    s_entity:self.options.entity,
  				    s_type:'save'});
  }

}

// прототип управления слоем векторной графики VML(IE) / Canvas(FF,WebKit,Opera)
function uCanvas(ufield,options) {
  
  this.field  = ufield;
  this.status = true;

  this.init_ = function() {
   
   var self = this;

    if(self.field.pan.map.isProblem) {

       var params = {tool:'vmlCanvas'};

    } else {

       var params = {tool:'standardCanvas'};
    
    }
    $.ajax({type:'GET',url:this.field.pan.map.loaderURL,data:params,dataType:'jsonp',success:function(jO) {self.make(jO,self);}});	
  
  }
  
  this.make = function(jO,self) {
      for (var property in jO) {
      if (typeof (self[property]) == "undefined")
        self[property] = jO[property];
    }

    self.init();

    self.setColor("#e63518");
    self.setStroke(6);

  }

  this.init_();
}



// прототип управления кэшем (должен же быть кэш?)


// прототип контекстного меню
function uMenu(u,options) {
  
  this.clear = function() {
    this.container.html('');
    this.items={};
  }
  
  this.show=function (e,self) {

  self.pan.map.offset = self.pan.map.container.offset();
 
  self.xPos=e.clientX - self.pan.map.offset.left + $(document).scrollLeft() - self.pan.vcX;
  self.yPos=e.clientY - self.pan.map.offset.top  + $(document).scrollTop() - self.pan.vcY;

     var dY = 0;
     var dX = 0;

     dX = self.xPos+self.pan.vcX-self.pan.map.view.width+170>0?self.xPos+self.pan.vcX-self.pan.map.view.width+170:0;
     dY = self.yPos+self.pan.vcY-self.pan.map.view.height+150>0?self.yPos+self.pan.vcY-self.pan.map.view.height+150:0;
     
  self.container.css({left:self.xPos,top:self.yPos,visibility:'visible'});

      if(dY || dX) {
       self.pan.panTo(self.pan,self.pan.map.centerX+dX*self.pan.map.scale,self.pan.map.centerY+dY*self.pan.map.scale);
     }


 }

 this.addIt=function(id,options) {

  switch(options.type) {
  
   case "header":
    this.items[id] = $("<span/>").appendTo(this.container);
    this.items[id].addClass('menuheader');
    this.items[id].html(options.label);
   break;
   
   case "option":
     this.items[id] = $("<a/>").appendTo(this.container);
     this.items[id].html(options.label);
     
     this.items[id].bind('mouseup',options.callback);

//     this.items[id].attr("href","#");
     this.items[id].css("cursor","pointer");
   break;
   
   case "submenu":
   break;
  
  }
 
 }
 
 this.setData = function(id,options) {

  var it = this.items[id];

  if(options.disabled)
    it.attr("id",'disabled');
  else
    it.attr("id",'');

 }

 this.fade = function (self) { 
  self.fadeHandle=setTimeout(function(){self.hide(self);},self.timeout);
  
 }
 
 this.stopFade = function (self) { 
  clearTimeout(self.fadeHandle);
 }

 this.hide = function(self) {  
   self.container.css("visibility","hidden");
 } 
 
 var self   = this;

 self.pan   = options.pan;
 
 self.context = u;

 self.items = {};
 
 self.container = $("<div/>").appendTo(self.pan.container);
 
 self.container.addClass("menuDiv");

 self.hide(self);

 self.container.hover(function() { self.stopFade(self); },function() { self.fade(self); });

 self.container.bind('click',function() { self.hide(self); });

 self.pan.pan.oncontextmenu = function(e) {
      if(!e) e = event;
      
      if(e.target) var targ = e.target;
      if(e.srcElement) var targ = e.srcElement;

      if(targ.id == 'part' || targ.id == 'canvas' || targ.className == "menuDiv") {
        if(e.preventDefault) e.preventDefault(); 
        e.cancelBubble = true;
        return false; 
      }
  };

 self.pan.register("mouseup",function(e,targ) { 
                                     if(e.button == 2) {
                                    
                                     if(e.target) var targ = e.target;
                                     if(e.srcElement) var targ = e.srcElement;
  
                                     if(targ.id == 'part' || targ.id == 'canvas') {
                                       self.show(e,self); 
                                     }
                                    }
                                   });
 self.fadeHandle=0;
 self.target='';
 self.xPos=0;
 self.yPos=0;
 self.timeout=600;
}



/* Вспомогательные методы, декораторы */

// Прототип для загружаемого инструментария ( REM: все инструменты загружаются через map.interface )
function baseProto() {

}

baseProto.prototype = {
       
        initialize: function(jO) {
           var self          = this;
           
           self[jO.faceName] = jO.init(self);
           
           self.trigger(false,self,jO.faceName+"_ready");

        },
       
        register: function(command,handler,override) {
         
          if(override) command += '_override';

          if(!this.handlers[command]) this.handlers[command]=[];

          this.handlers[command][this.handlers[command].length] = handler;

          return this.handlers[command].length-1;
        
        },
        unregister:function(command,id,override) {
          
          if(override) command += '_override';
            
           this.handlers[command][id] = false;

        },

        trigger: function(e,self,command,options){
          
           try {
            if(options == undefined) options = "";

            if(self.handlers[command+'_override'] && this.handlers[command+'_override'].length) {
              for(j in self.handlers[command+'_override']) {
                 if(self.handlers[command+'_override'][j]) { command += '_override'; break; }
              }
            }
             
             var func;
             
             for(j in self.handlers[command]) {
                
               if(func = self.handlers[command][j]) {
                  func(e,self,options);
                 }
             
             }
          
          } catch(ex) {
          
         }
                
        },
        load: function(url,method,params) {
          var self = this;

          if((document.location.host.indexOf('umap.ru')>=0) && $.cookie)
             params['PHPSESSID'] = $.cookie('PHPSESSID');

           if(self.map && self.map.loadGif)
            self.map.loadGif.css({display:'block'});

           switch(typeof(method)) {

            case "function":
              var callFunc = method;
            break;

            case "string":
               var callFunc = function(jO) { if(self.map && self.map.loadGif) self.map.loadGif.css({display:'none'});
                          self[method](jO,self)}
            break;
           }

          $.ajax({type:'GET',cache:true,url:url,data:params,dataType:'jsonp',success: callFunc } );	
        },
        execute: function(jO,self) {
  
           var it = {};

           for( i in jO ) {

             it = jO[i];

            switch( it.type ) {

             case "content":

                switch( it.behavior ) {
                 
                  case "refresh":
                    $( "#"+it.target ).html( it.content );
                    
                    self.map.trigger(false,self.map,it.target+"_ready");
                  break;
                }

             break;

             case "command":
                switch( it.command ) {
                
                  case "value":
                   $( "#"+it.target ).val( it.parameter );
                  break;
                  
                  case "call":
                   if( !it.data ) {
                      eval(it.parameter);
                    } else { 
                      
                      eval( it.parameter+"(it.data)" );
                     }
                  break;
                }
             break;

            case "data":
              eval( it.varn+"="+it.data );
            break;
            }
         }

        }
}

function toolProto() {

}

toolProto.prototype = {

        load:function(url,method,params) {
             var self = this;
             
             params['s_map']   = self.map.oName;
             params['s_city']  = self.map.city;
             params['s_scale'] = self.map.scale;
             params['s_scaleI'] = self.map.scaleIndex;
             
             if(document.location.host.indexOf('umap.ru') && $.cookie)
                params['PHPSESSID'] = $.cookie('PHPSESSID');

            
             self.map.loadGif.css({display:'block'});

             $.ajax({type:'GET',url:url,cache:true,data:params,dataType:'jsonp',success:function(jO) {
                                                                      self.map.loadGif.css({display:'none'});
                                                                      self[method](jO,self)}});	
 
        },        
        execute:function(jO,self) {
           
           var it = {};

           for( i in jO ) {

             it = jO[i];

            switch( it.type ) {

             case "content":

                switch( it.behavior ) {
                 
                  case "refresh":
                    $( "#"+it.target ).html( it.content );
                    
                    self.map.trigger(false,self.map,it.target+"_ready");
                  break;
                }

             break;

             case "command":
                switch( it.command ) {
                
                  case "value":
                   $( "#"+it.target ).val( it.parameter );
                  break;
                  
                  case "call":
                   if( !it.data ) {
                      eval(it.parameter);
                    } else { 
                      
                      eval( it.parameter+"(it.data)" );
                     }
                  break;
                }
             break;

            case "data":
              eval( it.varn+"="+it.data );
            break;
            }
         }
       }, 

       initialize: function(jO) {
        var self          = this;

        self[jO.faceName] = jO.init(self);
        
         self.map.trigger(false,self.map,jO.faceName+"_ready");
       }

}

function extend(child_, super_)
{

  for (var property in super_.prototype) {
    if (typeof (child_[property]) == "undefined")
      child_[property] = super_.prototype[property];
  }
  return child_;
}


function voidOp() {

}                      

function clone(o) {
 if(!o || 'object' !== typeof o)  {
   return o;
 }
 var c = 'function' === typeof o.pop ? [] : {};
 var p, v;
 for(p in o) {
 if(o.hasOwnProperty(p)) {
  v = o[p];
  if(v && 'object' === typeof v) {
    c[p] = clone(v);
  }
  else {
    c[p] = v;
  }
 }
}
 return c;
}



