/*	Copyright (c) 2016 Jean-Marc VIGLINO, 
  released under the CeCILL-B license (French BSD license)
  (http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.txt).
*/

import ol_Overlay from 'ol/Overlay.js'
import ol_ext_element from '../util/element.js'

/**
 * @classdesc
 * A popup element to be displayed over the map and attached to a single map
 * location. The popup are customized using CSS.
 *
 * @example
var popup = new ol_Overlay_Popup();
map.addOverlay(popup);
popup.show(coordinate, "Hello!");
popup.hide();
*
* @constructor
* @extends {ol_Overlay}
* @fires show
* @fires hide
* @param {} options Extend Overlay options 
*	 @param {String} [options.popupClass] the a class of the overlay to style the popup.
*	 @param {boolean} [options.anim Animate=false] the popup the popup, default false.
*	 @param {bool} [options.closeBox=false] popup has a close box, default false.
*	 @param {function|undefined} [options.onclose] callback function when popup is closed
*	 @param {function|undefined} [options.onshow] callback function when popup is shown
*	 @param {Number|Array<number>} [options.offsetBox] an offset box
*	 @param {ol.OverlayPositioning | string | undefined} options.positioning 
*		the 'auto' positioning var the popup choose its positioning to stay on the map.
*	 @param {boolean} [options.minibar=false] add a mini vertical bar
* @api stable
*/
var ol_Overlay_Popup = class olOverlayPopup extends ol_Overlay {
  constructor(options) {
    options = options || {};
    // Popup div
    var element = document.createElement("div");
    //element.classList.add('ol-overlaycontainer-stopevent');
    options.element = element;
    super(options);

    if (typeof (options.offsetBox) === 'number') {
      this.offsetBox = [options.offsetBox, options.offsetBox, options.offsetBox, options.offsetBox];
    } else {
      this.offsetBox = options.offsetBox;
    }

    // Closebox
    this.closeBox = options.closeBox;
    this.onclose = options.onclose;
    this.onshow = options.onshow;
    ol_ext_element.create('BUTTON', {
      className: 'closeBox' + (options.closeBox ? ' hasclosebox' : ''),
      type: 'button',
      click: function () {
        this.hide();
      }.bind(this),
      parent: element
    });
    // Anchor div
    if (options.anchor !== false) {
      ol_ext_element.create('DIV', {
        className: 'anchor',
        parent: element
      });
    }

    // Content
    this.content = ol_ext_element.create('DIV', {
      html: options.html || '',
      className: "ol-popup-content",
      parent: element
    });
    if (options.minibar) {
      ol_ext_element.scrollDiv(this.content, {
        vertical: true,
        mousewheel: true,
        minibar: true
      });
    }

    // Stop event
    if (options.stopEvent) {
      element.addEventListener("mousedown", function (e) { e.stopPropagation(); });
      element.addEventListener("touchstart", function (e) { e.stopPropagation(); });
    }

    this._elt = element;

    // call setPositioning first in constructor so getClassPositioning is called only once
    this.setPositioning(options.positioning || 'auto');
    this.setPopupClass(options.popupClass || options.className || 'default');
    if (options.anim)
      this.addPopupClass('anim');

    // Show popup on timeout (for animation purposes)
    if (options.position) {
      setTimeout(function () { this.show(options.position); }.bind(this));
    }
  }
  /**
   * Get CSS class of the popup according to its positioning.
   * @private
   */
  getClassPositioning() {
    var c = "";
    var pos = this.getPositioning();
    if (/bottom/.test(pos))
      c += "ol-popup-bottom ";
    if (/top/.test(pos))
      c += "ol-popup-top ";
    if (/left/.test(pos))
      c += "ol-popup-left ";
    if (/right/.test(pos))
      c += "ol-popup-right ";
    if (/^center/.test(pos))
      c += "ol-popup-middle ";
    if (/center$/.test(pos))
      c += "ol-popup-center ";
    return c;
  }
  /**
   * Set a close box to the popup.
   * @param {bool} b
   * @api stable
   */
  setClosebox(b) {
    this.closeBox = b;
    if (b)
      this.element.classList.add("hasclosebox");
    else
      this.element.classList.remove("hasclosebox");
  }
  /**
   * Set the CSS class of the popup.
   * @param {string} c class name.
   * @api stable
   */
  setPopupClass(c) {
    var classes = ["ol-popup"];
    if (this.getVisible())
      classes.push('visible');
    this.element.className = "";
    var classesPositioning = this.getClassPositioning().split(' ')
      .filter(function (className) {
        return className.length > 0;
      });
    if (c) {
      c.split(' ').filter(function (className) {
        return className.length > 0;
      })
        .forEach(function (className) {
          classes.push(className);
        });
    } else {
      classes.push("default");
    }
    classesPositioning.forEach(function (className) {
      classes.push(className);
    });
    if (this.closeBox) {
      classes.push("hasclosebox");
    }
    this.element.classList.add.apply(this.element.classList, classes);
  }
  /**
   * Add a CSS class to the popup.
   * @param {string} c class name.
   * @api stable
   */
  addPopupClass(c) {
    this.element.classList.add(c);
  }
  /**
   * Remove a CSS class to the popup.
   * @param {string} c class name.
   * @api stable
   */
  removePopupClass(c) {
    this.element.classList.remove(c);
  }
  /**
   * Set positionning of the popup
   * @param {ol.OverlayPositioning | string | undefined} pos an ol.OverlayPositioning
   * 		or 'auto' to var the popup choose the best position
   * @api stable
   */
  setPositioning(pos) {
    if (pos === undefined)
      return;
    if (/auto/.test(pos)) {
      this.autoPositioning = pos.split('-');
      if (this.autoPositioning.length == 1)
        this.autoPositioning[1] = "auto";
    } else {
      this.autoPositioning = false;
    }
    pos = pos.replace(/auto/g, "center");
    if (pos == "center")
      pos = "bottom-center";
    this.setPositioning_(pos);
  }
  /** @private
   * @param {ol.OverlayPositioning | string | undefined} pos
   */
  setPositioning_(pos) {
    if (this.element) {
      super.setPositioning(pos);
      this.element.classList.remove("ol-popup-top", "ol-popup-bottom", "ol-popup-left", "ol-popup-right", "ol-popup-center", "ol-popup-middle");
      var classes = this.getClassPositioning().split(' ')
        .filter(function (className) {
          return className.length > 0;
        });
      this.element.classList.add.apply(this.element.classList, classes);
    }
  }
  /** Check if popup is visible
  * @return {boolean}
  */
  getVisible() {
    return this.element.classList.contains("visible");
  }
  /**
   * Set the position and the content of the popup.
   * @param {ol.Coordinate|string} coordinate the coordinate of the popup or the HTML content.
   * @param {string|undefined} html the HTML content (undefined = previous content).
   * @example
  var popup = new ol_Overlay_Popup();
  // Show popup
  popup.show([166000, 5992000], "Hello world!");
  // Move popup at coord with the same info
  popup.show([167000, 5990000]);
  // set new info
  popup.show("New informations");
  * @api stable
  */
  show(coordinate, html) {
    if (!html && typeof (coordinate) == 'string') {
      html = coordinate;
      coordinate = null;
    }
    if (coordinate === true) {
      coordinate = this.getPosition();
    }

    var self = this;
    var map = this.getMap();
    if (!map)
      return;

    if (html && html !== this.prevHTML) {
      // Prevent flickering effect
      this.prevHTML = html;
      this.content.innerHTML = '';
      if (html instanceof Element) {
        this.content.appendChild(html);
      } else {
        ol_ext_element.create('DIV', {
          html: html,
          parent: this.content
        });
      }
      // Refresh when loaded (img)
      Array.prototype.slice.call(this.content.querySelectorAll('img'))
        .forEach(function (image) {
          image.addEventListener('load', function () {
            try { map.renderSync(); } catch (e) { /* ok */ }
            self.content.dispatchEvent(new Event('scroll'));
          });
        });
    }

    if (coordinate) {
      // Auto positionning
      if (this.autoPositioning) {
        var p = map.getPixelFromCoordinate(coordinate);
        var s = map.getSize();
        var pos = [];
        if (this.autoPositioning[0] == 'auto') {
          pos[0] = (p[1] < s[1] / 3) ? "top" : "bottom";
        }
        else
          pos[0] = this.autoPositioning[0];
        pos[1] = (p[0] < 2 * s[0] / 3) ? "left" : "right";
        this.setPositioning_(pos[0] + "-" + pos[1]);
        if (this.offsetBox) {
          this.setOffset([this.offsetBox[pos[1] == "left" ? 2 : 0], this.offsetBox[pos[0] == "top" ? 3 : 1]]);
        }
      } else {
        if (this.offsetBox) {
          this.setOffset(this.offsetBox);
        }
      }
      // Show
      this.setPosition(coordinate);
      // Set visible class (wait to compute the size/position first)
      this.element.parentElement.style.display = '';
      if (typeof (this.onshow) == 'function')
        this.onshow();
      this.dispatchEvent({ type: 'show' });
      this._tout = setTimeout(function () {
        self.element.classList.add('visible');
      }, 0);
    }
  }
  /**
   * Hide the popup
   * @api stable
   */
  hide() {
    if (this.getPosition() == undefined)
      return;
    if (typeof (this.onclose) == 'function')
      this.onclose();
    this.setPosition(undefined);
    if (this._tout)
      clearTimeout(this._tout);
    this.element.classList.remove("visible");
    this.dispatchEvent({ type: 'hide' });
  }
}

export  default ol_Overlay_Popup
