import { action } from '@ember/object';
import Modifier from 'ember-modifier';
import Rectangle from 'papermerge/utils/rectangle';



class UISelect {
  /**
    Desktop like select
  **/

  get DRAG_THRESHOLD() {
    /*
      Some mouse clicks are acompanied by slight mouse movements, which
      makes 'clicks' look like mouse drag events. In order the avoid
      this confusion, DRAG_THRESHOLD is introduced. Any rectangle with
      height or width < DRAG_THRESHOLD will be discarded.
    */
    return 5;
  }

  constructor(parent_selector) {
    /***
      x, y coordinates where selection started.
      parent - dom parent element. Selection DOM element
      will be attached to parent and it's coordinates
      will be relative to the parent DOM.
    **/
    // x,y where selection started
    this.start_x = 0;
    this.start_y = 0;
    this.current_x = 0;
    this.current_y = 0;
    this.parent = parent_selector;
    this.select_div = document.getElementById('ui-select');
    this.nodes_arr = Array.from(
      document.getElementsByClassName('node')
    );
  }

  init(x, y) {
    this.start_x = x;
    this.start_y = y;
  }

  show(x, y) {
    this.visibility = 'visible';
    this.top = `${x}px`;
    this.left  = `${y}px`;
  }

  hide() {
    this.visibility = 'hidden';
  }

  update(x, y) {
    let height, width, top, left;


    this.show(x, y);
    this.current_x = x;
    this.current_y = y;

    width = Math.abs(this.current_x - this.start_x);
    height = Math.abs(this.current_y - this.start_y);

    if (this.select_div) {

      if (this.current_y <  this.start_y) {
        this.top = `${this.current_y + 7}px`;
        top = this.current_y + 7;
      } else {
        this.top = `${this.start_y}px`;
        top = this.start_y;
      }
      if (this.current_x <  this.start_x) {
        this.left = `${this.current_x + 7}px`;
        left = this.current_x + 7;
      } else {
        this.left = `${this.start_x}px`;
        left = this.start_x;
      }
      this.width = `${width}px`;
      this.height = `${height}px`;

      const { selected_nodes, unselected_nodes } = this.get_nodes_selection(
        new Rectangle(left, top, width, height)
      );

      if (width < this.DRAG_THRESHOLD && height < this.DRAG_THRESHOLD) {
        console.log('Not passing DRAG_THRESHOLD. Ignored.');
        return;
      }

      this.select_nodes(selected_nodes);
      this.unselect_nodes(unselected_nodes);
    }
  }

  get_nodes_selection(selection_rect) {
    /**
      selection_rect is instance of utils.MgRect
    **/
    let selected_nodes = [], unselected_nodes = [];

    this.nodes_arr.forEach(element => {
      let _r, rect;

      _r = element.getBoundingClientRect();
      rect = new Rectangle(_r.x, _r.y, _r.width, _r.height);

      if (rect.intersect(selection_rect)) {
        selected_nodes.push(element);
      } else {
        unselected_nodes.push(element);
      }
    });

    return {selected_nodes, unselected_nodes};
  }

  select_nodes(elements) {
    let input_el;

    elements.forEach(element => {
      input_el = element.querySelector('input');
      if (input_el && !input_el.checked) {
        input_el.click();
      }
    });
  }

  unselect_nodes(elements) {
    let input_el;

    elements.forEach(element => {
      input_el = element.querySelector('input');
      if (input_el && input_el.checked) {
        input_el.click();
      }
    });
  }

  deselect_all_nodes() {
    let input_el;

    this.nodes_arr.forEach(element => {
      input_el = element.querySelector('input');
      if (input_el && input_el.checked) {
        input_el.click();
      }
    });
  }

  set width(value) {
    if (!this.select_div) {
      return;
    }
    this.select_div.style.width = value;
  }

  set height(value) {
    if (!this.select_div) {
      return;
    }
    this.select_div.style.height = value;
  }

  set top(value) {
    if (!this.select_div) {
      return;
    }
    this.select_div.style.top = value;
  }

  set left(value) {
    if (!this.select_div) {
      return;
    }
    this.select_div.style.left = value;
  }

  set visibility(value) {
    if (!this.select_div) {
      return;
    }
    this.select_div.style.visibility = value;
  }

}


export default class UISelectModifier extends Modifier {

  ui_select = undefined;

  addEventListener() {
    this.element.addEventListener('mousedown', this.onMouseDown);
    this.element.addEventListener('mouseup', this.onMouseUp);
    this.element.addEventListener('mousemove', this.onMouseMove);
  }

  removeEventListener() {
    this.element.removeEventListener('mousedown', this.onMouseDown);
    this.element.removeEventListener('mouseup', this.onMouseUp);
    this.element.removeEventListener('mousemove', this.onMouseMove);
  }

  // lifecycle hooks
  didReceiveArguments() {
    this.removeEventListener();
    this.addEventListener();

    this.ui_select = new UISelect(this.element);
  }

  willDestroy() {
    this.removeEventListener();
  }

  @action
  onMouseMove(event) {
    if (!event.buttons) {
      this.hide();
    } else if (this.ui_select) {
      this.ui_select.update(event.clientX, event.clientY);
    }
  }

  @action
  onMouseUp() {
    this.hide();
  }

  @action
  onMouseDown(event) {
    this.ui_select.init(event.clientX, event.clientY);
  }

  hide() {
    if (this.ui_select) {
      this.ui_select.hide();
    }
  }
}