package org.swellrt.beta.model.remote;

import org.waveprotocol.wave.model.id.IdGenerator;
import org.waveprotocol.wave.model.id.InvalidIdException;
import org.waveprotocol.wave.model.id.ModernIdSerialiser;
import org.waveprotocol.wave.model.id.WaveletId;
import org.waveprotocol.wave.model.util.Preconditions;

/**
 * Class representing a SNode substrate id.
 * <p>
 * A substrate has three elements:
 * <ul>
 * <li>type of the non primitive CNode</li>
 * <li>the document id where the CNode</li>
 * <li>the wavelet id where the document is stored</li>  
 * </ul>
 * <p>
 * Example: map => m:data+34js1a:m+3jg39s
 * <p>
 * The document id must contain also the type prefix
 * 
 * @author pablojan@gmail.com (Pablo Ojanguren)
 *
 */
public class SubstrateId {

  private static final String SEPARATOR = ":";
  private static final String MAP_TYPE_PREFIX = "m";
  private static final String LIST_TYPE_PREFIX = "l";
  private static final String TEXT_TYPE_PREFIX = "t";
  private static final String TOKEN_SEPARATOR = "+";

  
  private final String type;
  private final WaveletId containerId;
  private final String documentId;
  
  private final String str; 
  
  
  public static boolean isMap(SubstrateId id) {
    Preconditions.checkArgument(id != null, "Null substrate id");
    return MAP_TYPE_PREFIX.equals(id.type);
  }
  
  public static boolean isText(SubstrateId id) {
    Preconditions.checkArgument(id != null, "Null substrate id");
    return TEXT_TYPE_PREFIX.equals(id.type);
  }
  
  public static boolean isText(String documdentId) {
    Preconditions.checkArgument(documdentId != null, "Null document id"); 
    return documdentId.startsWith(TEXT_TYPE_PREFIX+TOKEN_SEPARATOR);
  }

  
  
  private static SubstrateId of(String type, WaveletId containerId, String substrateId) {
    Preconditions.checkArgument(containerId != null, "Null container id");
    Preconditions.checkArgument(substrateId != null, "Null substrate id");
    return new SubstrateId(type, containerId, substrateId);
  }
  
  public static SubstrateId ofMap(WaveletId containerId, String substrateId) {
    Preconditions.checkArgument(substrateId.startsWith(MAP_TYPE_PREFIX+TOKEN_SEPARATOR), "Bad substrate id format");
    return of(MAP_TYPE_PREFIX, containerId, substrateId);
  }
  
  public static SubstrateId ofList(WaveletId containerId, String substrateId) {
    Preconditions.checkArgument(substrateId.startsWith(LIST_TYPE_PREFIX+TOKEN_SEPARATOR), "Bad substrate id format");
    return of(LIST_TYPE_PREFIX, containerId, substrateId);
  }
  
  public static SubstrateId ofText(WaveletId containerId, String substrateId) {
    Preconditions.checkArgument(substrateId.startsWith(TEXT_TYPE_PREFIX+TOKEN_SEPARATOR), "Bad substrate id format");
    return of(TEXT_TYPE_PREFIX, containerId, substrateId);
  }

  public static SubstrateId deserialize(String s) {
      Preconditions.checkArgument(s != null && !s.isEmpty(), "String is null or empty");
      
      String parts[] = s.split(SEPARATOR);
      if (parts.length != 3)
        return null;
      
      // TODO add list check
      if (!parts[0].equals(MAP_TYPE_PREFIX) &&
          !parts[0].equals(TEXT_TYPE_PREFIX)) 
        return null;

      if (!parts[2].startsWith(MAP_TYPE_PREFIX+TOKEN_SEPARATOR) &&
          !parts[2].startsWith(TEXT_TYPE_PREFIX+TOKEN_SEPARATOR))
        return null;
      
      WaveletId containerId = null;
      try {
        containerId = ModernIdSerialiser.INSTANCE.deserialiseWaveletId(parts[1]);
      } catch (InvalidIdException e) {
        
      }
      
      if (containerId == null)
        return null;
      
      return SubstrateId.of(parts[0], containerId, parts[2]);
  }
  
  public static SubstrateId createForMap(WaveletId containerId, IdGenerator tokenGenerator) {
    return of(MAP_TYPE_PREFIX, containerId, MAP_TYPE_PREFIX+TOKEN_SEPARATOR+tokenGenerator.newUniqueToken());
  }
  
  public static SubstrateId createForList(WaveletId containerId, IdGenerator tokenGenerator) {
    return of(LIST_TYPE_PREFIX, containerId, LIST_TYPE_PREFIX+TOKEN_SEPARATOR+tokenGenerator.newUniqueToken());
  }
  
  public static SubstrateId createForText(WaveletId containerId, IdGenerator tokenGenerator) {
    return of(TEXT_TYPE_PREFIX, containerId, TEXT_TYPE_PREFIX+TOKEN_SEPARATOR+tokenGenerator.newUniqueToken());
  }
  
  protected SubstrateId(String type, WaveletId containerId, String substrateId) {
    this.type = type;
    this.containerId = containerId;
    this.documentId = substrateId;
    this.str = type+SEPARATOR+ModernIdSerialiser.INSTANCE.serialiseWaveletId(containerId)+SEPARATOR+substrateId;            

  }
  
  public boolean isList() {    
    return LIST_TYPE_PREFIX.equals(type);
  }
  
  public boolean isMap() {    
    return MAP_TYPE_PREFIX.equals(type);
  }
  
  public boolean isText() {
    return TEXT_TYPE_PREFIX.equals(type);
  }
  
  public String getType() {
    return type;
  }


  public WaveletId getContainerId() {
    return containerId;
  }


  public String getDocumentId() {
    return documentId;
  }

  public String serialize() {
    return str;
  }

  @Override
  public int hashCode() {
    final int prime = 31;
    int result = 1;
    result = prime * result + ((containerId == null) ? 0 : containerId.hashCode());
    result = prime * result + ((documentId == null) ? 0 : documentId.hashCode());
    result = prime * result + ((type == null) ? 0 : type.hashCode());
    return result;
  }


  @Override
  public boolean equals(Object obj) {
    if (this == obj)
      return true;
    if (obj == null)
      return false;
    if (getClass() != obj.getClass())
      return false;
    SubstrateId other = (SubstrateId) obj;
    if (containerId == null) {
      if (other.containerId != null)
        return false;
    } else if (!containerId.equals(other.containerId))
      return false;
    if (documentId == null) {
      if (other.documentId != null)
        return false;
    } else if (!documentId.equals(other.documentId))
      return false;
    if (type == null) {
      if (other.type != null)
        return false;
    } else if (!type.equals(other.type))
      return false;
    return true;
  }
  
  
  
}

@@ -3046,37 +3046,9 @@
    %0A
-      // TODO add list check
 %0A
+
     
@@ -3086,24 +3086,72 @@
 _PREFIX) &&%0A
+          !parts%5B0%5D.equals(LIST_TYPE_PREFIX) &&%0A
           !p
@@ -3207,16 +3207,16 @@
  null;%0A%0A
-
       if
@@ -3270,24 +3270,92 @@
 PARATOR) &&%0A
+          !parts%5B2%5D.startsWith(LIST_TYPE_PREFIX+TOKEN_SEPARATOR) &&%0A
           !p

Fix deserialization of lists from blips