/*	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 {unByKey as ol_Observable_unByKey} from 'ol/Observable.js'
import ol_control_Control from 'ol/control/Control.js'
import ol_ext_getMapCanvas from '../util/getMapCanvas.js'

/** ol_control_Cloud adds an old map effect on a canvas renderer.
* It colors the map, adds a parchment texture and compass onto the map. 
* @constructor
* @param {Object} options
*	@param {_ol_color_} options.hue color to set hue of the map, default #963
*	@param {Number} options.saturation saturation of the hue color, default 0.6
*	@param {Number} options.opacity opacity of the overimpose image, default 0.7
* @todo add effects on pan / zoom change
*/
var ol_control_Cloud = class olcontrolCloud extends ol_control_Control {
  constructor(options) {
    options = options || {};

    var div = document.createElement('div');
    div.className = 'ol-cloud ol-unselectable ol-control';
    super({
      element: div
    });

    // Defaut cloud image
    this.cloud = options.img;
    if (!this.cloud) {
      this.cloud = new Image();
      this.cloud.src = "data:image/png;base64,[encoded data, 16376 characters]";
    }
    this.bird = options.bird;
    if (!this.bird) {
      this.bird = new Image();
      this.bird.src = "data:image/png;base64,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";
    }

    // Parameters
    this.set('opacity', options.opacity || 0.3);
    this.set('density', options.density || 0.5);
    this.setWind(options);

  }
  /**
   * Remove the control from its current map and attach it to the new map.
   * Subclasses may set up event handlers to get notified about changes to
   * the map here.
   * @param {_ol_Map_} map Map.
   * @api stable
   */
  setMap(map) {
    if (this._listener)
      ol_Observable_unByKey(this._listener);
    this._listener = null;

    super.setMap(map);

    if (map) {
      this._listener = map.on('postcompose', this.drawCloud_.bind(this));
    }
  }
  /** Set wind direction / force
  */
  setWind(options) {
    options = options || {};

    var rnd = Math.random;
    var a = options.windAngle || rnd() * Math.PI;
    var speed = options.windSpeed || rnd();
    this.wind = { angle: a, cos: Math.cos(a), sin: Math.sin(a), speed: speed };
  }
  /**
  *	@private
  */
  drawCloud_(event) {
    if (!this.getMap())
      return;
    var ctx = event.context || ol_ext_getMapCanvas(this.getMap()).getContext('2d');
    var canvas = ctx.canvas;
    //	var ratio = event.frameState.pixelRatio;
    //	var m = Math.max(canvas.width, canvas.height);
    //	var res = view.getResolution()/ratio;
    //	var rot = view.getRotation();
    // Not ready !
    if (!this.cloud.width)
      return;

    // Go!
    var p = this.particules;
    var rnd = Math.random;
    var w = this.cloud.width;
    var h = this.cloud.height;
    var w2 = this.cloud.width / 2;
    var h2 = this.cloud.height / 2;
    var d = (this.get('density') * 10 * canvas.width * canvas.height / w / h) << 0;
    var i;

    function addClouds(nb) {
      for (i = 0; i < nb; i++) {
        p.push({ x: rnd() * canvas.width - w2, y: rnd() * canvas.height - h2 });
      }
    }

    // First time: init clouds
    if (!p) {
      p = this.particules = [];
      addClouds(d);
      // Wind
      this.width = canvas.width;
      this.height = canvas.height;
      // Birds
      this.birds = [];
      for (i = 0; i < 5; i++) {
        var b = { angle: rnd() * 2 * Math.PI, x: rnd() * canvas.width, y: rnd() * canvas.height, rot: 0, fly: 0 };
        b.cos = Math.cos(b.angle);
        b.sin = Math.cos(b.angle);
        this.birds.push(b);
      }
    } else if (d != p.length) {
      // Parameters changed
      if (this.width !== canvas.width || this.height !== canvas.height) {
        p = this.particules = [];
        addClouds(d);
        this.width = canvas.width;
        this.height = canvas.height;
      } else if (d > p.length) {
        addClouds(1);
      } else if (d < p.length) {
        p.splice((p.length * rnd()) << 0, 1);
      }
    }

    // Draw clouds
    var dx = this.wind.cos * this.wind.speed;
    var dy = this.wind.sin * this.wind.speed;
    for (i = 0; i < p.length; i++) {
      p[i].x += dx + rnd() * 2 - 1;
      p[i].y += dy + rnd() * 2 - 1;
      // out!
      if (p[i].x < -w) {
        p[i].x = canvas.width;
        p[i].y = rnd() * canvas.height - h2;
      } else if (p[i].x > canvas.width) {
        p[i].x = -w;
        p[i].y = rnd() * canvas.height - h2;
      }
      if (p[i].y < -h) {
        p[i].y = canvas.height;
        p[i].x = rnd() * canvas.width - w2;
      } else if (p[i].y > canvas.height) {
        p[i].y = -h;
        p[i].x = rnd() * canvas.width - w2;
      }
    }

    // Draw clouds
    ctx.globalAlpha = this.get('opacity');
    for (i = 0; i < p.length; i++) {
      ctx.drawImage(this.cloud, p[i].x, p[i].y);
    }
    ctx.globalAlpha = 1;

    // Draw birds
    w = this.bird.width / 2;
    h = this.bird.height / 2;
    var sc = 0.5;
    var dw = canvas.width + w;
    var dh = canvas.height + h;

    for (i = 0; i < this.birds.length; i++) {
      var bi = this.birds[i];

      // Animate birds
      var sx = 0;
      if (bi.fly) {
        bi.fly = (++bi.fly % 5);
        sx = -0.1;
      } else if (rnd() < 0.01)
        bi.fly = 1;

      // Rotate birds
      if (bi.rot) {
        bi.angle += bi.rot;
        bi.cos = Math.cos(bi.angle);
        bi.sin = Math.sin(bi.angle);
      }
      if (rnd() < 0.01) {
        bi.rot = bi.rot ? 0 : rnd() * Math.PI / 200 - Math.PI / 400;
        bi.cos = Math.cos(bi.angle);
        bi.sin = Math.sin(bi.angle);
      }

      // Move birds
      bi.x += bi.sin;
      if (bi.x > dw)
        bi.x = -w;
      if (bi.x < -w)
        bi.x = dw;
      bi.y -= bi.cos;
      if (bi.y > dh)
        bi.y = -h;
      if (bi.y < -h)
        bi.y = dh;

      // Draw birds
      ctx.save();
      ctx.translate(bi.x, bi.y);
      ctx.rotate(bi.angle);
      ctx.scale(sc + sx, sc);
      ctx.drawImage(this.bird, -w, -h);
      ctx.restore();
    }

    // Continue animation
    this.getMap().render();
  }
}

export default ol_control_Cloud