(function(){
  // -*- coding: utf-8 -*-
  YMaps.jQuery(function() {
    var $, add_mark, bounds, checklocations, citychange, cityinput, cleanup, clip, content, currentinput, currentmark, georesults, get_cookie, getlocations, hash, link, map, mapelem, name, newheight, query, range, search, set_cookie, setcurrent, setlocations, sliceby, spinner, ta;
    $ = YMaps.jQuery;
    mapelem = $('#map');
    cityinput = $('input[name=city]');
    currentinput = $('input[name=current]');
    georesults = [];
    bounds = null;
    currentmark = null;
    sliceby = 20;
    spinner = $('#spinner');
    link = $('input[name=link]');
    ta = $('#temp');
    content = $('#content');
    range = null;
    // attach colorizers
    content.cleanup = function cleanup() {
      return $('div', content).removeClass('changed').removeClass('error').removeClass('success');
    };
    content.node = function node(i) {
      return $("div.line." + (i), content);
    };
    content.changed = function changed(i) {
      return content.node(i).addClass('changed').removeClass('error').removeClass('success');
    };
    content.success = function success(i) {
      return content.node(i).removeClass('changed').removeClass('error').addClass('success');
    };
    content.error = function error(i) {
      return content.node(i).removeClass('changed').addClass('error').removeClass('success');
    };
    // init map
    map = new YMaps.Map(mapelem[0]);
    map.enableRightButtonMagnifier();
    map.enableHotKeys();
    map.addControl(new YMaps.ToolBar());
    map.addControl(new YMaps.Zoom());
    map.addControl(new YMaps.ScaleLine());
    // resize map if there is any free space
    newheight = $(window).height() - $('html').height() + mapelem.height();
    if (newheight > mapelem.height()) {
      mapelem.height(newheight);
    }
    // location container handlers
    getlocations = function getlocations() {
      var text;
      text = content.html().replace(/<\/?div[^>]*>/g, '\n').replace(/<br[^>]*>/g, '\n').split('\n');
      text = $.grep(text, function(item) {
        return $.trim(item);
      });
      setlocations(text);
      return text;
    };
    setlocations = function setlocations(locs) {
      if (!(locs instanceof Array)) {
        throw new Error('wtf');
      }
      return content.html($.map(locs, function(item, i) {
        return "<div class='line " + (i) + "'>" + (item) + "</div>";
      }).join(''));
    };
    // handle paste
    content.bind('paste', function(e) {
      var runchange;
      range = document.getSelection().getRangeAt(0);
      ta.val('').focus();
      runchange = function runchange() {
        return ta.change();
      };
      return setTimeout(runchange, 10);
    });
    ta.change(function(e) {
      var _a, _b, _c, item, node;
      content.focus();
      range.deleteContents();
      _a = ta.val().split('\n');
      for (_b = 0, _c = _a.length; _b < _c; _b++) {
        item = _a[_b];
        node = $('<div>' + item + '</div>');
        range.insertNode(node[0]);
        range.collapse(false);
      }
      content.scrollTop(node.offset().top - content.offset().top);
      document.getSelection().collapse(range.endContainer, range.endOffset);
      return ta.val('');
    });
    // city processing
    citychange = function citychange(city, callback) {
      city = new YMaps.Geocoder(city, {
        results: 1
      });
      return YMaps.Events.observe(city, city.Events.Load, function() {
        if (this.length()) {
          map.setCenter(this.get(0).getGeoPoint());
          map.setBounds(this.get(0).getBounds());
          map.setZoom(map.getZoom() + 1);
          // rely on stored bounds instead of relying on visible area
          bounds = this.get(0).getBounds();
          return callback();
        }
      });
    };
    // current location processing
    setcurrent = function setcurrent(current) {
      return query(current, function(mark) {
        return mark.setOptions({
          style: "default#houseIcon"
        });
      });
    };
    // cookie helpers
    set_cookie = function set_cookie(name, city) {
      var year;
      year = new Date();
      year.setTime(year.getTime() + 365 * 24 * 60 * 60 * 1000);
      return document.cookie = '' + (name) + "=" + (encodeURIComponent(city)) + "; \
expires=" + (year.toUTCString());
    };
    get_cookie = function get_cookie(name) {
      var _a, _b, _c, cookie;
      _a = document.cookie.split(';');
      for (_b = 0, _c = _a.length; _b < _c; _b++) {
        cookie = _a[_b];
        cookie = $.trim(cookie);
        if (cookie.substr(0, name.length + 1) === '' + (name) + "=") {
          return decodeURIComponent(cookie.substr(name.length + 1));
        }
      }
      return null;
    };
    // address cleanup
    cleanup = function cleanup(location) {
      var prefix, ulloc;
      location = $.trim(location);
      // replace "B.Khmelnitskogo" with "Khmelnitskogo",
      // replace curly aphostrophe
      location = location.replace(/([^\wа-яА-Я])[^.]\./g, '$1').replace(/’/g, "'").replace(/&\w+;/g, '');
      // if there is less than 4 symbols or 3 consecutive letters
      // before ul|pr, then this is garbage, strip it
      if (/ул\.|пр\./.test(location)) {
        ulloc = location.indexOf(/ул\.|пр\./.exec(location)[0]);
        prefix = location.slice(0, ulloc);
        prefix.length < 4 || !/[\wа-яА-Я]{3}/.test(prefix) ? (location = location.slice(ulloc)) : null;
      }
      // slash is often separator of two different street names
      if (location.indexOf('/') !== -1) {
        location = location.replace(/([^,]+)\/[^,]+/g, '$1');
        // colon is usually some definition before address
      }
      location.indexOf(':') !== -1 ? (location = $.trim(location.replace(/[^:]+:/, ''))) : null;
      return location;
    };
    // submit handlers
    $('#locsubmit').click(function() {
      var run;
      run = function run() {
        location.hash = encodeURIComponent(getlocations().join('\n'));
        return search(getlocations());
      };
      return setTimeout(run, 50);
    });
    $('#locclear').click(function() {
      location.hash = '';
      setlocations([]);
      return content.focus();
    });
    $('form#city').submit(function() {
      try {
        citychange(cityinput.val());
        return set_cookie('city', cityinput.val());
      } finally {
        return false;
      }
    });
    $('form#current').submit(function() {
      try {
        setcurrent(currentinput.val());
        return set_cookie('current', currentinput.val());
      } finally {
        return false;
      }
    });
    // generate name, maps.ya.ru specific
    name = function name(geo) {
      var prefix, suffix;
      prefix = geo.AddressDetails == undefined ? undefined : geo.AddressDetails.Country == undefined ? undefined : geo.AddressDetails.Country.Locality == undefined ? undefined : geo.AddressDetails.Country.Locality.Thoroughfare == undefined ? undefined : geo.AddressDetails.Country.Locality.Thoroughfare.ThoroughfareName;
      if (!prefix) {
        return geo.text;
      }
      suffix = geo.AddressDetails == undefined ? undefined : geo.AddressDetails.Country == undefined ? undefined : geo.AddressDetails.Country.Locality == undefined ? undefined : geo.AddressDetails.Country.Locality.Thoroughfare == undefined ? undefined : geo.AddressDetails.Country.Locality.Thoroughfare.Premise == undefined ? undefined : geo.AddressDetails.Country.Locality.Thoroughfare.Premise.PremiseNumber;
      return suffix ? '' + prefix + ", " + suffix : prefix;
    };
    // set mark on map
    add_mark = function add_mark(location, callback, errback) {
      var args;
      args = Array.prototype.slice.call(arguments, 3);
      return (function() {
        var mark;
        query.stop();
        if (this.length()) {
          mark = this.get(0);
          mark.text = name(mark);
          map.addOverlay(mark);
          if (callback) {
            return callback.apply(this, [mark].concat(args));
          }
        } else if (errback) {
          return errback.apply(this, args);
        }
      });
    };
    // send query to geocoder
    query = function query(location, callback, errback) {
      var args, geo;
      args = Array.prototype.slice.call(arguments, 3);
      query.start();
      geo = new YMaps.Geocoder(location, {
        results: 1,
        boundedBy: bounds,
        strictBounds: 1
      });
      // FIXME: somewhat hardcoded :(
      if (args) {
        content.changed(args[0]);
      }
      return YMaps.Events.observe(geo, geo.Events.Load, add_mark.apply(this, [location].concat([callback]).concat([errback]).concat(args)));
    };
    query.count = 0;
    query.start = function start() {
      query.count++;
      return spinner.show();
    };
    query.stop = function stop() {
      query.count--;
      if (!query.count) {
        spinner.hide();
        return content.trigger('query-stop');
      }
    };
    // initiate a search
    search = function search(locations, start) {
      var _a, _b, _c, _d, _e, _f, callback, errback, geo, i, location;
      if (!locations.length) {
        return null;
      }
      if (!start) {
        content.cleanup();
        start = 0;
        _a = georesults;
        for (_b = 0, _c = _a.length; _b < _c; _b++) {
          geo = _a[_b];
          map.removeOverlay(geo);
        }
      }
      locations.length > sliceby ? content.bind('query-stop', function(e) {
        content.unbind(e);
        return search(locations.slice(sliceby), start + sliceby);
      }) : null;
      callback = function callback(mark, i) {
        georesults.push(mark);
        content.success(i);
        return content.node(i).click(function() {
          currentmark ? currentmark.setOptions({
            style: 'default#lightbluePoint'
          }) : null;
          mark.setOptions({
            style: 'default#redPoint'
          });
          return currentmark = mark;
        });
      };
      errback = function errback(i) {
        return content.error(i);
      };
      _d = []; _e = locations.slice(0, sliceby);
      for (i = 0, _f = _e.length; i < _f; i++) {
        location = _e[i];
        location = cleanup(location);
        if (!location) {
          continue;
        }
        query(location, callback, errback, i + start);
      }
      return _d;
    };
    // make actions
    // hash checker
    hash = null;
    checklocations = function checklocations() {
      var locs;
      if (hash !== location.href.split('#')[1]) {
        link.val(location);
        hash = location.href.split('#')[1];
        locs = decodeURIComponent(hash).split('\n');
        if (hash && locs !== getlocations()) {
          setlocations(locs);
          return $('#locsubmit').click();
        }
      }
    };
    // set city and current location
    try {
      cityinput.val(get_cookie('city') || 'Киев');
      cityinput.change();
    } catch (e) {
      cityinput.val('Киев');
      cityinput.change();
    }
    citychange(cityinput.val(), function() {
      var current;
      current = get_cookie('current');
      if (current) {
        try {
          currentinput.val(current);
          currentinput.change();
          setcurrent(current);
        } catch (e) {
          // pass
        }
      }
      // initiate hash check
      return setInterval(checklocations, 50);
    });
    // hotkey handler
    $(document).keydown(function(e) {
      if (e.ctrlKey && e.keyCode === 13) {
        $('#locsubmit').click();
        return e.preventDefault();
      }
    });
    // clipboard
    clip = new ZeroClipboard.Client();
    clip.glue('copylink', 'copycontainer');
    clip.addEventListener('mouseDown', function(client) {
      return clip.setText(document.getElementById('link').value);
    });
    return $(window).resize(function() {
      return clip.reposition();
    });
  });
})();
