/*
  This class makes the canvas droppable
 */

import { on } from 'utils/mixins';
import { bindAll, indexOf } from 'underscore';

export default class Droppable {
  constructor(em) {
    this.em = em;
    const el = em
      .get('DomComponents')
      .getWrapper()
      .getEl();
    this.el = el;
    this.counter = 0;
    bindAll(
      this,
      'handleDragEnter',
      'handleDragOver',
      'handleDrop',
      'handleDragLeave'
    );
    on(el, 'dragenter', this.handleDragEnter);
    on(el, 'dragover', this.handleDragOver);
    on(el, 'drop', this.handleDrop);
    on(el, 'dragleave', this.handleDragLeave);

    return this;
  }

  endDrop(cancel, ev) {
    const { em, dragStop } = this;
    this.counter = 0;
    this.over = 0;
    dragStop && dragStop(cancel);
    em.runDefault();
    em.trigger('canvas:dragend', ev);
  }

  handleDragLeave(ev) {
    this.updateCounter(-1, ev);
  }

  updateCounter(value, ev) {
    this.counter += value;
    this.counter === 0 && this.endDrop(1, ev);
  }

  handleDragEnter(ev) {
    const { em } = this;
    const dt = ev.dataTransfer;
    this.updateCounter(1, ev);
    if (this.over) return;
    this.over = 1;
    const utils = em.get('Utils');
    const canvas = em.get('Canvas');
    // For security reason I can't read the drag data on dragenter, but
    // as I need it for the Sorter context I will use `dragContent` or just
    // any not empty element
    const content = em.get('dragContent') || '<br>';
    const container = canvas.getBody();
    em.stopDefault();
    let dragStop;

    if (em.inAbsoluteMode()) {
      const wrapper = em.get('DomComponents').getWrapper();
      const target = wrapper.append({})[0];
      const dragger = em.get('Commands').run('core:component-drag', {
        event: ev,
        guidesInfo: 1,
        center: 1,
        target,
        onEnd: (ev, dragger, { cancelled }) => {
          if (!cancelled) {
            const comp = wrapper.append(content)[0];
            const { left, top, position } = target.getStyle();
            comp.setStyle({ left, top, position });
            this.handleDragEnd(comp, dt);
          }
          target.remove();
        }
      });
      dragStop = cancel => dragger.stop(ev, { cancel });
    } else {
      const sorter = new utils.Sorter({
        em,
        wmargin: 1,
        nested: 1,
        canvasRelative: 1,
        direction: 'a',
        container,
        placer: canvas.getPlacerEl(),
        containerSel: '*',
        itemSel: '*',
        pfx: 'gjs-',
        onEndMove: model => this.handleDragEnd(model, dt),
        document: canvas.getFrameEl().contentDocument
      });
      sorter.setDropContent(content);
      sorter.startSort();
      this.sorter = sorter;
      dragStop = cancel => {
        cancel && (sorter.moved = 0);
        sorter.endMove();
      };
    }

    this.dragStop = dragStop;
    em.trigger('canvas:dragenter', dt, content);
  }

  handleDragEnd(model, dt) {
    if (!model) return;
    const { em } = this;
    em.set('dragResult', model);
    em.trigger('canvas:drop', dt, model);
  }

  /**
   * Always need to have this handler active for enabling the drop
   * @param {Event} ev
   */
  handleDragOver(ev) {
    ev.preventDefault();
    this.em.trigger('canvas:dragover', ev);
  }

  handleDrop(ev) {
    ev.preventDefault();
    const { sorter } = this;
    const dt = ev.dataTransfer;
    const content = this.getContentByData(dt).content;
    ev.target.style.border = '';

    if (sorter) {
      if (content) {
        sorter.setDropContent(content);
      } else {
        sorter.moved = 0;
      }
    }

    this.endDrop(0, ev);
  }

  getContentByData(dataTransfer) {
    const em = this.em;
    const types = dataTransfer.types;
    const files = dataTransfer.files || [];
    const dragContent = em.get('dragContent');
    let content = dataTransfer.getData('text');

    if (files.length) {
      content = [];
      for (let i = 0; i < files.length; i++) {
        const file = files[i];
        const type = file.type.split('/')[0];

        if (type == 'image') {
          content.push({
            type,
            file,
            attributes: { alt: file.name }
          });
        }
      }
    } else if (dragContent) {
      content = dragContent;
    } else if (indexOf(types, 'text/html') >= 0) {
      content = dataTransfer
        .getData('text/html')
        .replace(/<\/?meta[^>]*>/g, '');
    } else if (indexOf(types, 'text/uri-list') >= 0) {
      content = {
        type: 'link',
        attributes: { href: content },
        content: content
      };
    } else if (indexOf(types, 'text/json') >= 0) {
      const json = dataTransfer.getData('text/json');
      json && (content = JSON.parse(json));
    }

    const result = { content };
    em.trigger('canvas:dragdata', dataTransfer, result);

    return result;
  }
}

@@ -1234,24 +1234,64 @@
 ('Canvas');%0A
+    const container = canvas.getBody();%0A
     // For s
@@ -1350,16 +1350,16 @@
 er, but%0A
-
     // a
@@ -1455,28 +1455,26 @@
 element%0A    
-cons
+le
 t content = 
@@ -1514,42 +1514,33 @@
     
-const container = canvas.getBody()
+let dragStop, dragContent
 ;%0A  
@@ -1562,26 +1562,8 @@
 t();
-%0A    let dragStop;
 %0A%0A  
@@ -2241,24 +2241,68 @@
  cancel %7D);%0A
+      dragContent = cnt =%3E (content = cnt);%0A
     %7D else %7B
@@ -2884,24 +2884,87 @@
 );%0A      %7D;%0A
+      dragContent = content =%3E sorter.setDropContent(content);%0A
     %7D%0A%0A    t
@@ -2988,16 +2988,52 @@
 agStop;%0A
+    this.dragContent = dragContent;%0A
     em.t
@@ -3491,22 +3491,27 @@
 const %7B 
-sorter
+dragContent
  %7D = thi
@@ -3637,143 +3637,59 @@
 '';%0A
-%0A
     
-if (sorter) %7B%0A      if (content) %7B%0A        sorter.setDropContent(content);%0A      %7D else %7B%0A        sorter.moved = 0;%0A      %7D%0A    %7D%0A
+content && dragContent && dragContent(content);
 %0A   
@@ -3702,17 +3702,24 @@
 endDrop(
-0
+!content
 , ev);%0A 

Update content on handleDrop in Droppable