package org.swellrt.beta.client.js.editor.annotation;

import org.swellrt.beta.client.js.editor.SEditorHelper;
import org.waveprotocol.wave.client.doodad.annotation.GeneralAnnotationHandler;
import org.waveprotocol.wave.client.editor.content.CMutableDocument;
import org.waveprotocol.wave.client.editor.content.ContentElement;
import org.waveprotocol.wave.client.editor.content.ContentNode;
import org.waveprotocol.wave.client.editor.content.misc.AnnotationPaint;
import org.waveprotocol.wave.client.editor.content.misc.CaretAnnotations;
import org.waveprotocol.wave.client.editor.util.EditorAnnotationUtil;
import org.waveprotocol.wave.model.document.MutableAnnotationSet;
import org.waveprotocol.wave.model.document.indexed.LocationMapper;
import org.waveprotocol.wave.model.document.util.Range;
import org.waveprotocol.wave.model.util.ReadableStringSet;

import com.google.gwt.user.client.Event;

/**
 * Convenience wrapper of (non-paragraph) annotations.
 * <p>
 * More info at {@link GeneralAnnotationHandler} and {@link AnnotationPaint} 
 *  
 * @author pablojan@gmail.com (Pablo Ojanguren)
 *
 */
public class TextAnnotation implements Annotation, Annotation.Listenable, AnnotationPaint.EventHandler, AnnotationPaint.MutationHandler {

  
  public static void clearRange(MutableAnnotationSet<String> doc,
      CaretAnnotations caret, ReadableStringSet keys, int start, int end) {
    
    EditorAnnotationUtil.clearAnnotationsOverRange(doc, caret, keys, start, end);
  }
  
  private final String name;
  private AnnotationInstance.Handler handler; 
  
  private final String contentNodeAttributeName;
  
  public TextAnnotation(String name) {
    super();
    this.name = name;
    this.contentNodeAttributeName = AnnotationPaint.VALUE_ATTR_PREFIX + GeneralAnnotationHandler.getSafeKey(name);
  }

  public String getName() {
    return name;
  }
  
  @Override
  public void set(CMutableDocument doc, LocationMapper<ContentNode> mapper, MutableAnnotationSet<Object> localAnnotations, CaretAnnotations caret, Range range, String value) {     
    if (Annotation.isLocal(name)) {
      localAnnotations.setAnnotation(range.getStart(), range.getEnd(), name, value);
    } else {
      EditorAnnotationUtil.setAnnotationOverRange(doc, caret, name, value, range.getStart(), range.getEnd());
    }   
  }

  @Override
  public void reset(CMutableDocument doc, LocationMapper<ContentNode> mapper, MutableAnnotationSet<Object> localAnnotations, CaretAnnotations caret, Range range) {
    if (Annotation.isLocal(name)) { 
      localAnnotations.setAnnotation(range.getStart(), range.getEnd(), name, null);
    } else {
      EditorAnnotationUtil.clearAnnotationsOverRange(doc, caret, new String[]{ name }, range.getStart(), range.getEnd());
    }
  }
  

  @Override
  public void update(CMutableDocument doc, LocationMapper<ContentNode> mapper, MutableAnnotationSet<Object> localAnnotations, CaretAnnotations caret, Range range, String value) {
    set(doc, mapper, localAnnotations, caret, range, value);

    
  }

  @Override
  public Range mutate(CMutableDocument doc, LocationMapper<ContentNode> mapper, MutableAnnotationSet<Object> localAnnotations, CaretAnnotations caret, Range range, String text, String value) {
    reset(doc, mapper, localAnnotations, caret, range);    
    Range mutatedRange = SEditorHelper.replaceText(doc, range, text); 
    set(doc, mapper, localAnnotations, caret, mutatedRange, value);
    return mutatedRange;
  }

  
  @Override
  public void setHandler(AnnotationInstance.Handler h) {    
    this.handler = h;
    if (handler != null) {
      AnnotationPaint.registerEventHandler(name, this);
      AnnotationPaint.setMutationHandler(name, this);
    } else {
      // clear event handler?
      AnnotationPaint.clearMutationHandler(name);
    }
  }
  
  

     
  @Override
  public void onAdded(ContentElement node) {
    if (handler != null && !AnnotationRegistry.muteHandlers) {      
      String value = node.getAttribute(this.contentNodeAttributeName);          
      handler.exec(AnnotationInstance.EVENT_ADDED, AnnotationInstance.create(name, value, node), null);
    }    
  }

  @Override
  public void onMutation(ContentElement node) {
    if (handler != null && !AnnotationRegistry.muteHandlers) {
      String value = node.getAttribute(this.contentNodeAttributeName);
      handler.exec(AnnotationInstance.EVENT_MUTATED, AnnotationInstance.create(name, value, node), null);
    }   
  }

  @Override
  public void onRemoved(ContentElement node) {
    if (handler != null && !AnnotationRegistry.muteHandlers) {
      String value = node.getAttribute(this.contentNodeAttributeName);
      handler.exec(AnnotationInstance.EVENT_REMOVED, AnnotationInstance.create(name, value, node), null);
    }   
  }

  @Override
  public void onEvent(ContentElement node, Event event) {
    if (handler != null && !AnnotationRegistry.muteHandlers) {
      String value = node.getAttribute(this.contentNodeAttributeName);
      handler.exec(AnnotationInstance.EVENT_MOUSE, AnnotationInstance.create(name, value, node), event);
    }   
  }

  
}

@@ -788,63 +788,297 @@
 til.
-Range;%0Aimport org.waveprotocol.wave.model.util.Readable
+Annotations;%0Aimport org.waveprotocol.wave.model.document.util.Range;%0Aimport org.waveprotocol.wave.model.util.CollectionUtils;%0Aimport org.waveprotocol.wave.model.util.ReadableStringSet;%0Aimport org.waveprotocol.wave.model.util.ReadableStringSet.Proc;%0Aimport org.waveprotocol.wave.model.util.
 Stri
@@ -1538,16 +1538,63 @@
 ng%3E doc,
+ MutableAnnotationSet%3CObject%3E localAnnotations,
 %0A      C
@@ -1661,16 +1661,340 @@
 t end) %7B
+%0A%0A    StringSet nonLocalKeys = CollectionUtils.newStringSet();%0A    keys.each(new Proc()%7B%0A%0A      @Override%0A      public void apply(String key) %7B%0A        if (Annotations.isLocal(key))%0A          localAnnotations.setAnnotation(start, end, key, null);%0A        else%0A          nonLocalKeys.add(key);          %0A      %7D      %0A    %7D);
 %0A    %0A  
@@ -2054,17 +2054,25 @@
  caret, 
-k
+nonLocalK
 eys, sta

Fix local annotations reset