/*
 * JBoss, Home of Professional Open Source
 *
 * Distributable under LGPL license.
 * See terms of license at gnu.org.
 */
package org.jboss.cache.optimistic;

/**
 * The default implementation of a DataVersion, uses a <code>long</code> to
 * compare versions.
 * This class is immutable.
 * <p/>
 * Also note that this is meant to control implicit, internal versioning.  Do not attempt to instantiate or use instances
 * of this class explicitly, via the {@link org.jboss.cache.config.Option#setDataVersion(DataVersion)} API, as it WILL
 * break things.
 *
 * @author <a href="mailto:manik@jboss.org">Manik Surtani (manik@jboss.org)</a>
 */
public class DefaultDataVersion implements DataVersion
{
   private static final long serialVersionUID = -6896315742831861046L;
   /**
    * Version zero.
    * Assign this as the first version to your data.
    */
   public static final DataVersion ZERO = new DefaultDataVersion(0L);

   /**
    * Version one.
    */
   private static final DataVersion ONE = new DefaultDataVersion(1L);

   /**
    * Version two.
    */
   private static final DataVersion TWO = new DefaultDataVersion(2L);

   private long version;

   /**
    * Constructs with version 0.
    */
   public DefaultDataVersion()
   {
   }

   /**
    * Constructs with a version number.
    */
   public DefaultDataVersion(long version)
   {
      this.version = version;
   }

   /**
    * Returns a new DataVersion with a newer version number.
    */
   public DataVersion increment()
   {
      if (this == ZERO)
      {
         return ONE;
      }
      if (this == ONE)
      {
         return TWO;
      }
      return new DefaultDataVersion(version + 1);
   }

   public boolean newerThan(DataVersion other)
   {
      if (other instanceof DefaultDataVersion)
      {
         DefaultDataVersion dvOther = (DefaultDataVersion) other;
         return version > dvOther.version;
      }
      else
      {
         // now try and swap things around to see if the other implementation knows how to compare against DefaultDataVersion.
         // could cause a problem if 'this' and 'other' have the same value, in which case other.newerThan() will return false
         // and this will return true, which is not strictly true at all.  So we try calling other.equals() first to test
         // this, assuming that other will be able to effectively test equality if they are equal.

         return !other.equals(this) && !other.newerThan(this);
      }
   }

   @Override
   public String toString()
   {
      return "Ver=" + version;
   }

   @Override
   public boolean equals(Object other)
   {
      if (other instanceof DefaultDataVersion)
      {
         return version == ((DefaultDataVersion) other).version;
      }
      return false;
   }

   @Override
   public int hashCode()
   {
      return (int) version;
   }

   public long getRawVersion()
   {
      return version;
   }
}
