import Parchment from 'parchment';
import Embed from './embed';
import Emitter from '../core/emitter';


class Cursor extends Embed {
  static value(domNode) {
    return undefined;
  }

  constructor(domNode, selection) {
    super(domNode);
    this.selection = selection;
    this.textNode = document.createTextNode(Cursor.CONTENTS);
    this.domNode.appendChild(this.textNode);
    this._length = 0;
  }

  detach() {
    // super.detach() will also clear domNode.__blot
    if (this.parent != null) this.parent.removeChild(this);
  }

  format(name, value) {
    if (this._length !== 0) {
      return super.format(name, value);
    }
    let target = this, index = 0;
    while (target != null && target.statics.scope !== Parchment.Scope.BLOCK_BLOT) {
      index += target.offset(target.parent);
      target = target.parent;
    }
    if (target != null) {
      this._length = Cursor.CONTENTS.length;
      target.optimize();
      target.formatAt(index, Cursor.CONTENTS.length, name, value);
      this._length = 0;
    }
  }

  index(node, offset) {
    if (node === this.textNode) return 0;
    return super.index(node, offset);
  }

  length() {
    return this._length;
  }

  position(index) {
    return [this.textNode, this.textNode.data.length];
  }

  remove() {
    super.remove();
    this.parent = null;
  }

  restore() {
    if (this.selection.composing) return;
    if (this.parent == null) return;
    let textNode = this.textNode;
    let range = this.selection.getNativeRange();
    // Link format will insert text outside of anchor tag
    while (this.domNode.lastChild != null && this.domNode.lastChild !== this.textNode) {
      this.domNode.parentNode.insertBefore(this.domNode.lastChild, this.domNode);
    }
    if (this.textNode.data !== Cursor.CONTENTS) {
      this.textNode.data = this.textNode.data.split(Cursor.CONTENTS).join('');
      this.parent.insertBefore(Parchment.create(this.textNode), this);
      this.textNode = document.createTextNode(Cursor.CONTENTS);
      this.domNode.appendChild(this.textNode);
    }
    this.remove();
    if (range != null && range.start.node === textNode && range.end.node === textNode) {
      this.selection.emitter.once(Emitter.events.SCROLL_OPTIMIZE, () => {
        let [start, end] = [range.start.offset, range.end.offset].map(function(offset) {
          return Math.max(0, Math.min(textNode.data.length, offset - 1));
        });
        this.selection.setNativeRange(textNode, start, textNode, end);
      });
    }
  }

  update(mutations) {
    mutations.forEach((mutation) => {
      if (mutation.type === 'characterData' && mutation.target === this.textNode) {
        this.restore();
      }
    });
  }

  value() {
    return '';
  }
}
Cursor.blotName = 'cursor';
Cursor.className = 'ql-cursor';
Cursor.tagName = 'span';
Cursor.CONTENTS = "\uFEFF";   // Zero width no break space


export default Cursor;

@@ -57,16 +57,47 @@
 embed';%0A
+import TextBlot from './text';%0A
 import E
@@ -1527,24 +1527,236 @@
 iveRange();%0A
+    let restoreText, start, end;%0A    if (range != null && range.start.node === textNode && range.end.node === textNode) %7B%0A      %5BrestoreText, start, end%5D = %5BtextNode, range.start.offset, range.end.offset%5D;%0A    %7D%0A
     // Link 
@@ -2034,34 +2034,24 @@
 %7B%0A      
-this.textNode.data
+let text
  = this.
@@ -2097,16 +2097,235 @@
 in('');%0A
+      if (this.next instanceof TextBlot) %7B%0A        restoreText = this.next.domNode;%0A        this.next.insertAt(0, text);%0A        this.textNode.data = Cursor.CONTENTS;%0A      %7D else %7B%0A        this.textNode.data = text;%0A  
       th
@@ -2389,24 +2389,26 @@
 his);%0A      
+  
 this.textNod
@@ -2455,24 +2455,26 @@
 NTS);%0A      
+  
 this.domNode
@@ -2498,24 +2498,32 @@
 .textNode);%0A
+      %7D%0A
     %7D%0A    th
@@ -2547,91 +2547,31 @@
 if (
-range != null && range.start.node === textNode && range.end.node === textNode) %7B%0A  
+start == null) return;%0A
     
@@ -2644,22 +2644,16 @@
 %7B%0A      
-  let 
 %5Bstart, 
@@ -2664,44 +2664,18 @@
  = %5B
-range.start.offset, range.end.offset
+start, end
 %5D.ma
@@ -2699,26 +2699,24 @@
 ) %7B%0A        
-  
 return Math.
@@ -2731,24 +2731,27 @@
 ath.min(
-textNode
+restoreText
 .data.le
@@ -2776,24 +2776,20 @@
 ;%0A      
- 
- 
 %7D);%0A
-  
       th
@@ -2820,33 +2820,39 @@
 nge(
-textNode, start, textNode
+restoreText, start, restoreText
 , en
@@ -2863,20 +2863,12 @@
     
-  
 %7D);%0A
-    %7D%0A
   %7D%0A

Fix #1019