package org.jboss.cache;

import org.jboss.cache.annotations.Experimental;

import java.util.Arrays;
import java.util.List;

/**
 * An optimisation of Fqn that does more efficient equals() and hashcode() computations.  This is returned by default when
 * the factory method {@link Fqn#fromString(String)} is used, or when any of the other factory methods on {@link Fqn} are
 * passed only String elements.
 * <p/>
 * <b>Note</b> that the "/" character is illegal in any Fqn String element and if encountered may be used to split Fqn elements.
 * Expect indeterminate behaviour until proper String escaping is in place.
 * <p/>
 *
 * @author Manik Surtani (<a href="mailto:manik@jboss.org">manik@jboss.org</a>)
 * @since 2.2.0
 */
// TODO: 3.0.0: Implement proper String escaping.
@Experimental
public final class StringFqn extends Fqn
{
   // Needs to be public because of NodeData serialization.
   // TODO: Remove in 3.0.0 once we refactor NodeData to go through a cache marshaller instead of it's current serialization.
   public StringFqn()
   {
      super(true);
      stringRepresentation = SEPARATOR;
   }

   protected StringFqn(StringFqn base, List<String> elements)
   {
      super(true, base, elements);
      String elementStringRep = getStringRepresentation(elements);
      stringRepresentation = base.isRoot() ? elementStringRep : base.stringRepresentation + elementStringRep;
   }

   protected StringFqn(StringFqn base, StringFqn relative)
   {
      super(true, base, relative.elements);
      if (base.isRoot())
      {
         if (relative.isRoot())
            stringRepresentation = SEPARATOR;
         else
            stringRepresentation = relative.stringRepresentation;
      }
      else
      {
         if (relative.isRoot())
            stringRepresentation = base.stringRepresentation;
         else
            stringRepresentation = base.stringRepresentation + relative.stringRepresentation;
      }
   }

   protected StringFqn(List<String> stringElements)
   {
      super(true, stringElements, false);
      stringRepresentation = getStringRepresentation(elements);
   }

   protected StringFqn(String stringRep)
   {
      this(Arrays.asList(stringRep.split("/")));
   }

   @Override
   public boolean equals(Object other)
   {
      if (other == this) return true;
      if (other == null) return false;
      if (other.getClass().equals(StringFqn.class))
      {
         return stringRepresentation.equals(((StringFqn) other).stringRepresentation);
      }
      else
      {
         return super.equals(other);
      }
   }

   @Override
   protected int calculateHashCode()
   {
      return stringRepresentation.hashCode();
   }

   @Override
   public boolean isChildOrEquals(Fqn parentFqn)
   {
      if (parentFqn.getClass().equals(StringFqn.class))
      {
         StringFqn stringParentFqn = (StringFqn) parentFqn;
         return stringRepresentation.startsWith(stringParentFqn.stringRepresentation);
      }
      else
      {
         return super.isChildOrEquals(parentFqn);
      }
   }

   public String getStringRepresentation()
   {
      return stringRepresentation;
   }
}
