//global g_maps maps map_name to hash m
// m.map - YMaps.Map object;  m.map.data == m;
// m.options - options for initMap
var g_maps = {};

// jQuery function
var $Q;

// Zoom factor map when clicking on geopoint
var ZOOM_ON_SHOW = 12;

var g_new_locations_count = 0;

var ROAD_TYPES= ['Асфальт', 'Гравий', 'Бездорожье'];

var EDITABLE_FIELDS = [
  'id', 'title', 'description', 'lat', 'lng',
  'fish', 'paid', 'road_type'
];

var ALL_FIELDS = [
  'id', 'title', 'description', 'lat', 'lng',
  'author', 'items_description',
  'fish', 'paid', 'road_type'
];

function initMap(map_name, options) {
  $Q = YMaps.jQuery;
  var i;
  var m = {};
  g_maps[map_name || 'new'] = m;
  m.options = options;
  m.addable_to_item = !!options.addable_to_item;
  m.name = map_name;
  m.inside_init = true;
  m.network_id = options.network_id;

  if (options.do_not_draw) {
    // map is hidden now
    // we will draw it later
    m.options.do_not_draw = false;
    return;
  }

  m.map = new YMaps.Map(document.getElementById(options.id));
  var map = m.map;
  map.data = m;
  map.name = map_name;

  m.search_closest_geopoint = true;

  map.addCopyright('&copy; myfishstory.ru');

  setBounds(map_name);

  var om = new YMaps.ObjectManager();
  m.om = om;
  map.addOverlay(om);

  var special_controls = {
      TypeControl: new YMaps.TypeControl([YMaps.MapType.MAP, YMaps.MapType.SATELLITE, YMaps.MapType.HYBRID], [0,1,2]),
      MiniMap: new YMaps.MiniMap()
  };

  // Map controls
  for(i = 0 ; i < options.controls.size(); i++) {
    var ctr = options.controls[i];
    map.addControl(special_controls[ctr] || eval('new YMaps.' + ctr + '();'));
  }

  // Init templates
  for(i = 0; i < options.templates.size(); i++) {
    var tmp = options.templates[i];
    //var el = document.getElementById(tmp.id + "_YMapDiv"); //el.innerHTML
    var t = new YMaps.Template(tmp.html);
    YMaps.Templates.add(tmp.id + "#template", t);
    var s = new YMaps.Style();
    s.balloonContentStyle = new YMaps.BalloonContentStyle(tmp.id + "#template");
    YMaps.Styles.add(tmp.id + "#style", s);
    //el.outerHTML = '';

    s.iconStyle = new YMaps.IconStyle();
    s.iconStyle.offset = new YMaps.Point(tmp.style.offset[0], tmp.style.offset[1]);
    s.iconStyle.href = tmp.style.href;
    s.iconStyle.size = new YMaps.Point(tmp.style.size[0], tmp.style.size[1]);
    s.iconStyle.shadow = new YMaps.IconShadowStyle();
    s.iconStyle.shadow.offset = new YMaps.Point(tmp.style.shadow.offset[0], tmp.style.shadow.offset[1]);
    s.iconStyle.shadow.href = tmp.style.shadow.href;
    s.iconStyle.shadow.size = new YMaps.Point(tmp.style.shadow.size[0], tmp.style.shadow.size[1]);
    if (tmp.default_style) {
      m.point_default_style = tmp.id + "#style";
    }
  }
  
  m.locations = [];
  if (options.locations) {
    options.locations.each(function (location) {
      m.locations.push(addLocationToMap(map_name, location));
    });
  }
  
  // Delay load

  for(i = 0; i < options.delay_load.size(); i++) {
    var dl = options.delay_load[i];
    new Ajax.Request(dl, {
      method:'get',
      onSuccess: function(transport){
        var locations = eval(transport.responseText);
        locations.each(function (location) {
          // alert("Adding location " + location.id);
          m.locations.push(addLocationToMap(map_name, location));
        });
        if (m.locations.length() == 1) {
          // showLocationBalloonWait(map_name, last_p.id);
        }
      },
      onFailure: function() {
        alert('Something went wrong while loading locations...');
      }
    });
  }
  
  // Map events
  var map_events = options.events;
  m.map_events = map_events;
  if (map_events && map_events.map_click) {
     eval('YMaps.Events.observe(map, map.Events.Click, ' + map_events.map_click + ');');
  }

  map.buttons = [];
  // Custom buttons
  if (options.buttons) {
    var tool_bar = new YMaps.ToolBar(
      (options.tool_bar_buttons || ['Move', 'Magnifier', 'Ruler']).map(function(name){
        return eval("new YMaps.ToolBar." + name + "Button()");
      })
    );
    for(i = 0; i < options.buttons.size(); i++) {
      var bt = options.buttons[i];
      var button = new YMaps.ToolBarToggleButton({ caption: bt.caption });
      map.buttons[bt.caption] = button;
      button.ondeselect = bt.ondeselect;
      button.onselect = bt.onselect;
      tool_bar.add(button);
      YMaps.Events.observe(button, button.Events.Select, function () {
        map.addCursor(YMaps.Cursor.POINTER);
        eval(this.onselect);
      });
      YMaps.Events.observe(button, button.Events.Deselect, function () {
        map.removeCursor(YMaps.Cursor.POINTER);
        eval(this.ondeselect);
      });
    }
    map.addControl(tool_bar);
  }
  try {
    special_controls.MiniMap.setVisible(false);
  } catch (error) {
    // TODO
  }
  YMaps.load( function() {
    fixMapLogosAndCopyrights.delay(0.5);
    fixMapLogosAndCopyrights.delay(2);
    fixMapLogosAndCopyrights.delay(4);
    fixMapLogosAndCopyrights.delay(8);
    setBounds.delay(0.5, map_name);
    setBounds.delay(2, map_name);
    setBounds.delay(3, map_name);
  });
  if (options.eval) {
    eval(options.eval);
  }
  m.inside_init = false;
  if (!options.no_init_again) {
    initAgainUnlessInitialized(map_name, 6);
  }
}


function initAgainUnlessInitialized(map_name, rest_attempts) {
  var m = g_maps[map_name];
  var map = m.map;
  var bounds = map.getBounds();
  m.options.no_init_again = true;
  if ( bounds.getLeft() == bounds.getRight() ||  bounds.getTop() == bounds.getBottom() ) {
    m.initialized = false;
    if (!m.inside_init) {
      initMap(map_name, m.options);
    }
    initAgainUnlessInitialized.delay(4, map_name, rest_attempts - 1)
  } else {
    m.initialized = true;
  }
};

function setZoom(map_name) {
  var m = g_maps[map_name];
  var map = m.map;
  var options = m.options;
  if (options.zoom) {
    map.setZoom(options.zoom);
  } else {
    if ( map.getZoom() > ZOOM_ON_SHOW ) {
      map.setZoom(ZOOM_ON_SHOW);
    }
  }
}

function setBounds(map_name) {
  var m = g_maps[map_name];
  var map = m.map;
  var options = m.options;
  var bounds = map.getBounds();
  if (options.bounds[0].lat == options.bounds[1].lat && options.bounds[0].lng == options.bounds[1].lng ) {
    map.setCenter(new YMaps.GeoPoint(options.bounds[0].lat, options.bounds[1].lng), ZOOM_ON_SHOW);
    map.setZoom(ZOOM_ON_SHOW);
  } else {
    map.setBounds(
        new YMaps.GeoBounds(
            new YMaps.GeoPoint(options.bounds[0].lat, options.bounds[0].lng),
            new YMaps.GeoPoint(options.bounds[1].lat, options.bounds[1].lng)
        )
    );
    setZoom(map_name);
  }
}

// find DOM element by element_path inside wrapper_element;
// if wrapper_element is string, then it is treated as element id
function $MM(element_path, wrapper_element) {
  if (wrapper_element && typeof(wrapper_element) == "string") {
    wrapper_element = $Q('#' + wrapper_element)[0];
  }
  if (wrapper_element) {
    return $Q(element_path, wrapper_element)[0];
  } else {
    return $Q(element_path)[0];
  }
}

// find placemark inside map by id
function findLocationByID(map_name, id) {
  var m = g_maps[map_name];
  var map = m.map;
  var found_p = null;
  map.__objectLayer.forEach(function (p) { if (p.id == id) found_p = p; }, map);
  return found_p;
}

// helper for stopping click propagation
function stopEventPropagation(e) {
  if (e.cancelBubble) {
      e.cancelBubble = true;
  } else {
      e.stopPropagation();
  }
}

function setZindex(el, zindex) {
  var s = el.getAttribute('style') || '';
  s = s.replace(/\bstyle\s*:\s*\d+(!important)?;?/i, '');
  s += 'z-index: ' + zindex + ' !important;';
  el.setAttribute('style', s);
  $(el).style.zIndex = zindex;
}

// fix z-index of copyrights && logos (they overlap creator form on items#show)
function fixMapLogosAndCopyrights() {
  [
    '.YMaps-buttons', '.YMaps-scale-line', '.YMaps-copyrights',
    '.YMaps-logo', '.YMaps-buttons', '.YMaps-mini-map', '.YMaps-slider'
  ].each(function(cl) {
    $Q(cl).each(function(idx, el) {
      setZindex(el, 1);
    });
  });
}

/*
  set style for placemark balloon
  style depends on placemark attributes
  basic styles are:
    * show_point
    * show_added_point (same as show_point, but icon is green)
    * new_point
    * edit_point (same as new_point, but has delete action, and different submit action)
    * show_geo_point (has one action -- add_to_item)
*/
function setLocationStyle(p) {
  p.setStyle(YMaps.Styles.get(p.added ?  "show_added_point#style" : "show_point#style"));
}

// switch on flag 'draggable' for given point
function makeDraggable(map_name, id) {
  var m = g_maps[map_name];
  var p = findLocationByID(map_name, id);
  p.setOptions({draggable: true});
  p.closeBalloon();
}

function dragendEvent(p) {
  if (p.editable) {
    var lat = p.getGeoPoint().getX();
    var lng = p.getGeoPoint().getY();
    $Q('#locations_' + p.id + '_lat').val(lat);
	$Q('#locations_' + p.id + '_lng').val(lng);
    if ( !p.is_new && (p.id+'').match(/^\d+$/)) {
      new Ajax.Request(
        '/locations/move', {
          parameters: {
            id: p.id,
            lat: lat,
            lng: lng
          }
        }
      );
    }
  }
}

function showLocationBalloon(map_name, location_id) {
  var m = g_maps[map_name];
  var p = findLocationByID(map_name, location_id);
  if (p) {
    m.map.setZoom(ZOOM_ON_SHOW);
    p.openBalloon();
  }
}

function showLocationBalloonWait(map_name, location_id) {
  var m = g_maps[map_name];
  var map = m.map;
  var p = findLocationByID(map_name, location_id);
  if (p) {
    map.setZoom(ZOOM_ON_SHOW);
    p.openBalloon();
  } else {
    setTimeout('showLocationBalloonWait("' + map_name + '", ' + location_id + ');', 200);
  }
}

function showLocationBalloonAndCenter(map_name, location_id) {
  var m = g_maps[map_name];
  var map = m.map;
  var p = findLocationByID(map_name, location_id);
  if (p) {
    map.panTo(p.getGeoPoint());
    map.setZoom(ZOOM_ON_SHOW);
    p.openBalloon();
  }
  map.panTo(new YMaps.GeoPoint(p.lat, p.lng), {
    flying: false,
    callback: function (state) {
      if (state == YMaps.State.SUCCESS) showLocationBalloonWait(map_name, location_id);
    }
  });
}

function selectLocation(map_name, id) {
  var m = g_maps[map_name];
  var map = m.map;
  var p = findLocationByID(map_name, id);
  if (p) {
    p.added = true;
    setLocationStyle(p);
    map.panTo(p.getGeoPoint());
    p.openBalloon();
    map.setZoom(ZOOM_ON_SHOW);
    var x = p.getGeoPoint().getX();
    var y = p.getGeoPoint().getY();
    map.panTo(new YMaps.GeoPoint(x,y), {
      flying: false,
      callback: function (state) {
        if (state == YMaps.State.SUCCESS) showLocationBalloonWait(m.name, id);
      }
    });
  }
}

function isLocationAlreadyAdded(map_name, p) {
  var m = g_maps[map_name];
  var gp = p.getGeoPoint();
  var fl = false;
  $$('#' + map_name + ' .locations_fields li').each(function (el) {
    if (
      $Q('.location_id', el).val() == p.id || (
        $Q('.location_lat', el).val() == gp.getX() &&
        $Q('.location_lng', el).val() == gp.getY()
      )
    )  {
      if ($Q('.location_remove', el).val() == 'true') {
        $Q('.location_remove', el).val('');
        el.style.display = '';
        var fp = findLocationByID(map_name, $Q('.location_id', el).val());
        fp.added = true;
      }
      fl = true;
    }
  });
  return fl;
}

// add placemark for loaded placemark to map
// with given parameters;
function addLocationToMap(map_name, l) {
  var m = g_maps[map_name];
  if (!m) return null;

  var p = new YMaps.Placemark(new YMaps.GeoPoint(l.lat, l.lng), {draggable: false});
  p.initial_attributes = l;

  ALL_FIELDS.each(function(attr) {
    p[attr] = l[attr]
  })

  // flags used in names of div's classes
  // they should be true or false
  p.paid = !!l.paid;
  p.editable = !!l.editable;
  p.addable = !!m.addable_to_item;
  p.added = !!l.added;
  p.is_new = !!l.is_new;

  
  // calculate full_description and short_description
  setDescriptions(p);

  // style of placemark is defined by its attributes
  setLocationStyle(p);

  m.om.add(p);

  if (m.map_events && m.map_events.point_dragend) {
    YMaps.Events.observe(p, p.Events.DragEnd, eval(m.map_events.point_dragend));
  }
  if (m.map_events && m.map_events.point_click) {
    YMaps.Events.observe(p, p.Events.Click, eval(m.map_events.point_click));
  }

  return p;
}

// search locations (if search_locations_url is given) and geopoints;
// called from _search_form partial
function searchPoints(map_name, form, search_locations_url, results_id) {
  var m = g_maps[map_name];
  var search_query = $MM('#location_s', map_name).value;
  var results = $MM('#' + results_id);
  if (search_query) {
    results.innerHTML = '<div class="search_locations_spinner"></div>';
    if (search_locations_url) {
      new Ajax.Updater(
        results_id,
        search_locations_url, {
          method: 'post',
          parameters: {
            location_s: search_query,
            map_name: map_name,
            network_id: m.network_id
          },
          onComplete: function(transport) {
            var limit = 10 - $Q('a', results).length;
            if (limit > 0) {
              geoCoderRequest(map_name, search_query, limit, results);
            }
          }
        }
      );
    } else {
      geoCoderRequest(map_name, search_query, 10, results);
    }
  }
  return false;
}

// search geopoints;
// place search results inside element 'results'
function geoCoderRequest(map_name, search_query, limit, results) {
  var m = g_maps[map_name];
  var map = m.map;
  m.geocoder = new YMaps.Geocoder(search_query, {results: limit, boundedBy: map.getBounds()});

  YMaps.Events.observe(m.geocoder, m.geocoder.Events.Load, function () {
      if (this.length()) {
          //alert("Found :" + this.length());
          if (results) {
            var html = "";
            for(var i = 0; i < this.length(); i++) {
              var p = this.get(i);
              p.title = p.text;
              html += '<a href="javascript: showGeoResult(\'' + map_name + '\', ' + i + ');">' + p.text + '</a>';
            }
            if ( !results.innerHTML.match(/<a /) ) {
              results.innerHTML = '';
            }
            results.innerHTML += html;
          }
          if (this.length() > 0) {
            map.addOverlay(this.get(0));
            map.panTo(this.get(0).getGeoPoint());
          }
          showGeoResult(map_name, 0);
      } else if (results) {
        if ( !results.innerHTML.match(/<a /) ) {
          results.innerHTML = 'По запросу \'' +
            search_query.replace(/</, '&lt;').replace(/>/, '&gt;') +
            '\' ничего не найдено';
        }
      }
  });
  YMaps.Events.observe(m.geocoder, m.geocoder.Events.Fault, function (geocoder, error_message) {
    if (results) results.innerHTML = '<font color="red">Error: ' + error_message + '</font>';
  });
}

var g_m;
function showGeoResult(map_name, i) {
  var m = g_maps[map_name];
  g_m = m;
  var map = m.map;
  if (m.gp) {
    map.removeOverlay(m.gp);
  }
  m.gp = m.geocoder.get(i);
  m.gp.setStyle(YMaps.Styles.get('show_geo_point#style'));
  m.gp.addable = m.addable_to_item;
  map.addOverlay(m.gp);
  map.panTo(m.gp.getGeoPoint());
  map.setZoom(ZOOM_ON_SHOW);
  // m.gp.openBalloon({margin: 8});
  m.gp.openBalloon();

  YMaps.Events.observe(m.gp.getBalloon(), m.gp.getBalloon().Events.CloseButtonClick, function () {
     m.map.removeOverlay(m.gp);
  });
}

// create new location from shown geopoint
// just opens new_point balloon and suggest title for new point
var g_el;
function newLocationFromGeoPoint(map_name) {
  var m = g_maps[map_name];
  var p;
  if (m.new_placemark != null) { try { m.map.removeOverlay(m.new_placemark) } catch (e) {} };

  p = m.new_placemark = new YMaps.Placemark(m.gp.getGeoPoint(), {
    style: YMaps.Styles.get("new_point#style"),
    BalloonOptions: {
      margin: 5
    }
  });
  m.om.add(p);

  YMaps.Events.observe(p, "Click", function(p, e) {
    // hack!!
    // this panTo + second openBalloon show scrolls
    m.map.panTo(p.getGeoPoint());
    p.openBalloon.delay(1);
  })

  YMaps.Events.observe(p, "BalloonOpen", function(p, e) {
    // hack!! kill horizontal scroll
    window.setTimeout(function() {
      var b = p.getBalloon();
      var el = b.getContent()._parentNode;
      g_el = el;
      el.style.width = "310px";
      b.mapAutoPan();
    }, 500);
  })

  p.id = 'new_' + (g_new_locations_count++);
  g_p = p;
  m.map.panTo(p.getGeoPoint());
  m.map.addOverlay(p);
  p.openBalloon();
  $MM("#location_title", map_name).value = m.gp.title;
  $MM("#location_lat", map_name).value = p.getGeoPoint().getX();
  $MM("#location_lng", map_name).value = p.getGeoPoint().getY();
  $MM("#location_id", map_name).value = p.id;

  if (m.gp) { try { m.map.removeOverlay(m.gp) } catch (e) {}; };

  // hack!! close & open, otherwise there is no scrolls
  p.closeBalloon(); p.openBalloon();
}

// add shown geo point to current item;
// same as newLocationsfromGeoPoint, but create button
// will not send create request to server (m.addable_to_item = true)
function addGeoPointToItem(map_name) {
  newLocationFromGeoPoint(map_name);
}

function editLocation(map_name, location_id) {
  var m = g_maps[map_name];
  var p = findLocationByID(map_name, location_id);
  if (p) {
    m.edited_placemark = p;
    p.setStyle(YMaps.Styles.get("edit_point#style"));
    YMaps.Events.observe(p.getBalloon(), p.getBalloon().Events.CloseButtonClick, function () {
      cancelUpdateLocation(map_name, location_id);
    });
    p.openBalloon();
    setFormFields(map_name, p);
  }
}

function cancelUpdateLocation(map_name, location_id) {
  var m = g_maps[map_name];
  var p = findLocationByID(map_name, location_id);
  if (p) {
    p.closeBalloon();
    setLocationStyle(p);
    p.setOptions({draggable: false});
    m.edited_placemark = null;
  }
}

function updateLocation(map_name, form, location_id) {
  try {
  var m = g_maps[map_name];
  var map = m.map;
  var p = findLocationByID(map_name, location_id);

  /// geopoint coordinates to form
  $MM("#location_lat", map_name).value = p.getGeoPoint().getX();
  $MM("#location_lng", map_name).value = p.getGeoPoint().getY();

  // update-form fields to location attributes
  setLocationAttributes(map_name, p);

  // geopoint coordinates to location attributes
  p.lat = p.getGeoPoint().getX();
  p.lng = p.getGeoPoint().getY();

  p.setOptions({draggable: false});
  m.edited_placemark = null;

  if ( p.added && m.addable_to_item ) {
    // location attributes to locations form fields
    updateLocationFields(map_name, p);
  }

  if (!p.is_new) {
    // send update request to server;
    // update form to server
    // alert(Form.serialize(form,true) );
    var params = Form.serialize(form, true);
    params.network_id = m.network_id;

    new Ajax.Request('/locations/update', {
      asynchronous: true,
      evalScripts: true,
      method: 'post',
      parameters: params
    });
  }
  setLocationStyle(p);
  map.closeBalloon();
  } catch(e) {
    alert(e);
  }
}

/*
  updates hidden fields for given placemark
  real update will have place only after submitting form
*/
function updateLocationFields(map_name, p) {
  if (p.editable) {
    EDITABLE_FIELDS.each(function(attr) {
      $Q('#locations_' + p.id + '_' + attr).val(p[attr]);
    })
  }
}

/*
  function for handling clicks at locations#index page;
  opens baloon with new_point form
*/
function newLocation(map, e) {
  var m = map.data;
  if (!m.add_button_selected || map.rulerEnabled() || map.magnifierEnabled()) return;
  if (m.new_placemark != null) map.removeOverlay(m.new_placemark);
  var gp = e.getGeoPoint();
  var p = new YMaps.Placemark(gp, {style: YMaps.Styles.get("new_point#style")} );
  map.panTo(gp);
  map.addOverlay(p);
  p.is_new = true;
  p.id = 'new_' + g_new_locations_count++;
  p.editable = true;
  p.openBalloon();
  p.title = p.description = '';
  p.fish = '';
  p.lat = gp.getX();
  p.lng = gp.getY();
  m.new_placemark = p;
  // m.new_placemark.getBalloon().setOptions({hasCloseButton: false});
  YMaps.Events.observe(p.getBalloon(), p.getBalloon().Events.CloseButtonClick, function () {
     if (p.getBalloon() != null) map.removeOverlay(p);
  });

  YMaps.Events.observe(p, p.Events.DragEnd, dragendEvent);

  if (m.search_closest_geopoint) {
    geocoder = new YMaps.Geocoder(gp, {results: 1, boundedBy: map.getBounds(), strictBounds: true });
    YMaps.Events.observe(geocoder, geocoder.Events.Load, function () {
      if (this.length()) {
        // suggest name for new point from closest geopoint
        var found_gp = this.get(0);
        p.title = found_gp.text;
      }
      setFormFields(map.name, p);
    })
  } else  {
    setFormFields(map.name, p);
  }
}

/*
  copy location attributes to location_form fields
*/
function setFormFields(map_name, p) {
  ['title', 'fish', 'description', 'lat', 'lng', 'id'].each(function(attr) {
    $MM("#location_" + attr, map_name).value = p[attr] || '';
  });
  $MM("#location_paid", map_name).checked = !!p.paid;
  setRoadType($MM("#road_type_field", map_name), p.road_type);
}

function setRoadType(wrapper_element, road_type) {
  road_type = parseInt(road_type) || 0;
  $Q('input:radio', wrapper_element).each(function(ids, input) {
    if (input.value == road_type) {
      input.checked = true;
    }
  });
}

/*
  copy location_form fields to location attributes
*/
function setLocationAttributes(map_name, p) {
  EDITABLE_FIELDS.each(function(attr) {
    var e = $MM("#location_" + attr, map_name);
    p[attr] = e && e.value;
  });
  p.paid = $MM("#location_paid", map_name).checked;
  p.road_type = $MM("#road_type_field input:checked", map_name).value;
  setDescriptions(p);
  return p;
}
  
function isBlank(o) {
  return o === null || o === undefined || o == "" || o == {} || o == [];
}

// calculate short- and full-descriptions of the location
var g_pp;
function setDescriptions(p) {
  g_pp = p;
  p.description = p.description || '';
  p.short_description = truncate(p.description);
  p.has_full_description = !(p.description.length < 60 && isBlank(p.fish) && isBlank(p.items_description) && isBlank(p.road_type));
  p.full_description =
    '<span class="p_description">' + p.description + '</span>' +
    (isBlank(p.author) ?    '' : '<br><b>Добавил:</b> ' + p.author) +
    (isBlank(p.fish) ?      '' : '<br><b>Кого ловим:</b> ' + p.fish) +
    (isBlank(p.road_type) ? '' : '<br><b>Тип дороги:</b> ' + (ROAD_TYPES[p.road_type]||'')) +
    ((p.paid) ? '<br><b>Платный водоём:</b> Да' : '') +
    (isBlank(p.items_description) ? '' : p.items_description)
  ;
}

function truncate(text) {
  text = text || '';
  if (text.length > 60) {
    text = text.replace(/[\s\n][\s\n]+|\&nbsp;/, ' ');
    if (text.length > 60) {
      text = text.replace(/^(.{50,60} |.{60,60}).+/, '$1') + '&#133;';
      text = text.replace(/\s*\.+\s*\&#133;$/, ' &#133;');
    }
  }
  return text;
}

/*
  called on new_point form submit;
*/
var g_l_id;
function createLocation(map_name, form) {
  var m = g_maps[map_name];
  var map = m.map;
  // current fake id
  var location_id = g_l_id = $MM("#location_id", map_name).value;
  if (m.addable_to_item) {
    var l = {};
    setLocationAttributes(map_name, l);
    var p = afterCreateLocation(map_name, location_id, l);
    p.is_new = true; // not yet created on server side
    p.addable = true;
    // add fields for new location to form
    addLocationToItem(map_name, p);
  } else {
    // send update request to server
    var params = Form.serialize(form, true);
    params.network_id = m.network_id;
    new Ajax.Request('/locations/create', {
      asynchronous: true,
      method: 'post',
      onSuccess: function(transport) {
        // responseText is array with single element - attributes hash
        var l = eval(transport.responseText);
        afterCreateLocation(map_name, location_id, l[0]);
      },
      onFailure: function(transport) {
        alert("Не получается создать точку на карте");
      },
      parameters: params
    });
  }
}

/*
  add point to map
*/
function afterCreateLocation(map_name, old_location_id, created_location) {
  var m = g_maps[map_name];
  var map = m.map;
  var p = created_location;

  p.editable = true;
  
  map.closeBalloon();
  if (m.new_placemark) map.removeOverlay(m.new_placemark);
  m.new_placemark = null;

  return addLocationToMap(map_name, p);
}

function cancelCreateLocation(map_name, event) {
  var m = g_maps[map_name];
  m.map.removeOverlay(m.new_placemark);
  m.new_placemark = null;
  stopEventPropagation(event);
}

function deleteLocation(map_name, location_id, url) {
  var m = g_maps[map_name];
  var p = findLocationByID(map_name, location_id);
  if (confirm('Вы действительно хотите удалить из базы рыбное место "' + p.title + '"' )) {
    p.closeBalloon();
    new Ajax.Request(url, { method: 'post' });
    m.om.remove(p);
    p = null;
  }
}

// create fields for new potential location
// associated with current item
// assign new location_id
function addLocationToItem(map_name, p) {
  var m = g_maps[map_name];

  var lf = $MM(".locations_fields", map_name);
  var lr = $MM(".location_row", map_name);
  var l = lf.childNodes.length;
  $Q(lf).append( ('<li>' + lr.innerHTML + '</li>').replace(/NN/g, p.id));
  var el = lf.childNodes[l];
  EDITABLE_FIELDS.each(function(attr) {
    $Q('.location_' + attr, el).val(p[attr]);
  });
  p.added = true;
  setLocationStyle(p);
  p.closeBalloon();
}


// add existing point to item
function addExistingLocationToItem(map_name, location_id) {
  var p = findLocationByID(map_name, location_id);
  if (p) {
    addLocationToItem(map_name, p);
  }
}

function deleteLocationFromItem(map_name, location_id) {
  var el = $MM('#locations_' + location_id + '_remove', map_name);
  if (el) {
    el.value = "true";
    el.parentNode.style.display = 'none';
  }
  var p = findLocationByID(map_name, location_id);
  if (p) {
    p.added = false;
    setLocationStyle(p);
    p.closeBalloon();
  }
}

function onSelectNewLocationButton(map_name) {
  var m = g_maps[map_name];
  if (!m.my_map_click_listner) {
    m.my_map_click_listner = YMaps.Events.observe(m.map, m.map.Events.Click, newLocation);
  }
  m.add_button_selected = true;
}

function onDeselectNewLocationButton(map_name) {
  var m = g_maps[map_name];
  m.add_button_selected = false;
}


function onCloseSearchSidebar(map_name) {
  var m = g_maps[map_name];
  if (!m) return;
  var b = m.map.buttons['Поиск места'] || m.map.buttons['Искать на карте'] ;
  b.deselect();
}

function onSelectSearchSidebar(map_name) {
  var m = g_maps[map_name];
  if (!m) return;
  var map_id = '#YMapsID_' + map_name;
  $Q(map_id).width((m.options.width - 189) + 'px');
  m.sidebar = true;
  m.map.redraw(true);
  b = m.map.buttons['+ Добавить место'];
  if (b.isSelected()) {
    b.deselect();
  }
}

function onDeselectSearchSidebar(map_name) {
  var m = g_maps[map_name];
  if (!m) return;
  var map_id = '#YMapsID_' + map_name;
  $Q(map_id).width(m.options.width + 'px');
  m.sidebar = false;
  m.map.redraw(true);
}

function toggleShow(path_show, path_hide, wrapper_element) {
  $Q(path_show, wrapper_element)[0].style.display = 'block';
  $Q(path_hide, wrapper_element)[0].style.display = 'none';
}

function showFullDescription(map_name, location_id, wrapper_element) {
  wrapper_element = wrapper_element || $Q('#balloon_' + location_id);
  toggleShow('.p_full_description', '.p_short_description', wrapper_element);
  var p = findLocationByID(map_name, location_id);
  if (p) {
    p.openBalloon();
  }
}

function showShortDescription(map_name, location_id, wrapper_element) {
  wrapper_element = wrapper_element || $Q('#balloon_' + location_id);
  toggleShow('.p_short_description', '.p_full_description', wrapper_element);
  var p = findLocationByID(map_name, location_id);
  if (p) {
    p.openBalloon();
  }
}

