text: 'use strict';
  
  var util = require('./util'),
      Mustache = require('mustache');
  
  var GridControl = L.Control.extend({
  
      options: {
          pinnable: true,
          follow: false,
          sanitizer: require('sanitize-caja'),
          touchTeaser: true,
          location: true
      },
  
      _currentContent: '',
  
      // pinned means that this control is on a feature and the user has likely
      // clicked. pinned will not become false unless the user clicks off
      // of the feature onto another or clicks x
      _pinned: false,
  
      initialize: function(_, options) {
          L.Util.setOptions(this, options);
          util.strict_instance(_, L.Class, 'L.mapbox.gridLayer');
          this._layer = _;
      },
  
      setTemplate: function(template) {
          util.strict(template, 'string');
          this.options.template = template;
          return this;
      },
  
      _template: function(format, data) {
          if (!data) return;
          var template = this.options.template || this._layer.getTileJSON().template;
          if (template) {
              var d = {};
              d['__' + format + '__'] = true;
              return this.options.sanitizer(
                  Mustache.to_html(template, L.extend(d, data)));
          }
      },
  
      // change the content of the tooltip HTML if it has changed, otherwise
      // noop
      _show: function(content, o) {
          if (content === this._currentContent) return;
  
          this._currentContent = content;
  
          if (this.options.follow) {
              this._popup.setContent(content)
                  .setLatLng(o.latLng);
              if (this._map._popup !== this._popup) this._popup.openOn(this._map);
          } else {
              this._container.style.display = 'block';
              this._contentWrapper.innerHTML = content;
          }
      },
  
      hide: function() {
          this._pinned = false;
          this._currentContent = '';
  
          this._map.closePopup();
          this._container.style.display = 'none';
          this._contentWrapper.innerHTML = '';
  
          L.DomUtil.removeClass(this._container, 'closable');
  
          return this;
      },
  
      _mouseover: function(o) {
          if (o.data) {
              L.DomUtil.addClass(this._map._container, 'map-clickable');
          } else {
              L.DomUtil.removeClass(this._map._container, 'map-clickable');
          }
  
          if (this._pinned) return;
  
          var content = this._template('teaser', o.data);
          if (content) {
              this._show(content, o);
          } else {
              this.hide();
          }
      },
  
      _mousemove: function(o) {
          if (this._pinned) return;
          if (!this.options.follow) return;
  
          this._popup.setLatLng(o.latLng);
      },
  
      _navigateTo: function(url) {
          window.top.location.href = url;
      },
  
      _click: function(o) {
  
          var location_formatted = this._template('location', o.data);
          if (this.options.location && location_formatted &&
              location_formatted.search(/^https?:/) === 0) {
              return this._navigateTo(this._template('location', o.data));
          }
  
          if (!this.options.pinnable) return;
  
          var content = this._template('full', o.data);
  
          if (!content && this.options.touchTeaser && L.Browser.touch) {
              content = this._template('teaser', o.data);
          }
  
          if (content) {
              L.DomUtil.addClass(this._container, 'closable');
              this._pinned = true;
              this._show(content, o);
          } else if (this._pinned) {
              L.DomUtil.removeClass(this._container, 'closable');
              this._pinned = false;
              this.hide();
          }
      },
  
      _onPopupClose: function() {
          this._currentContent = null;
          this._pinned = false;
      },
  
      _createClosebutton: function(container, fn) {
          var link = L.DomUtil.create('a', 'close', container);
  
          link.innerHTML = 'close';
          link.href = '#';
          link.title = 'close';
  
          L.DomEvent
              .on(link, 'click', L.DomEvent.stopPropagation)
              .on(link, 'mousedown', L.DomEvent.stopPropagation)
              .on(link, 'dblclick', L.DomEvent.stopPropagation)
              .on(link, 'click', L.DomEvent.preventDefault)
              .on(link, 'click', fn, this);
  
          return link;
      },
  
      onAdd: function(map) {
          this._map = map;
  
          var className = 'leaflet-control-grid map-tooltip',
              container = L.DomUtil.create('div', className),
              contentWrapper = L.DomUtil.create('div', 'map-tooltip-content');
  
          // hide the container element initially
          container.style.display = 'none';
          this._createClosebutton(container, this.hide);
          container.appendChild(contentWrapper);
  
          this._contentWrapper = contentWrapper;
          this._popup = new L.Popup({ autoPan: false, closeOnClick: false });
  
          map.on('popupclose', this._onPopupClose, this);
  
          L.DomEvent
              .disableClickPropagation(container)
              // allow people to scroll tooltips with mousewheel
              .addListener(container, 'mousewheel', L.DomEvent.stopPropagation);
  
          this._layer
              .on('mouseover', this._mouseover, this)
              .on('mousemove', this._mousemove, this)
              .on('click', this._click, this);
  
          return container;
      },
  
      onRemove: function (map) {
  
          map.off('popupclose', this._onPopupClose, this);
  
          this._layer
              .off('mouseover', this._mouseover, this)
              .off('mousemove', this._mousemove, this)
              .off('click', this._click, this);
      }
  });
  
  module.exports.GridControl = GridControl;
  
  module.exports.gridControl = function(_, options) {
      return new GridControl(_, options);
  };
  