package com.sptci.jdo;

import java.io.Serializable;
import java.util.Collection;
import java.util.HashSet;
import javax.jdo.InstanceCallbacks;

import com.thoughtworks.xstream.XStream;

/**
 * A base object from which all the <code>JDO Object</code> 
 * classes will be derived.  Provides default implementations for 
 * common methods.
 *
 * @author Rakesh Vidyadharan 05<sup><small>th</small></sup> February, 2006
 * <p>Copyright 2006, Sans Pareil Technologies, Inc.</p>
 *
 * @version $Id: JDOObject.java,v 1.2 2006/02/15 00:48:26 rakesh Exp $
 */
public abstract class JDOObject 
  implements Cloneable, Comparable<JDOObject>, Serializable, InstanceCallbacks
{
  /**
   * The default value to use for {@link #hash}.
   */
  protected static final int HASH = 7;

  /**
   * The integer that represents the hash code for this object.
   */
  protected int hash = HASH;

  /**
   * A collection of words used to perform whole-word search across
   * each <code>Extent</code> in the database.
   */
  protected transient Collection<String> words = new HashSet<String>();

  /**
   * A collection of metaphone words used to perform a search across
   * each <code>Extent</code> in the database for similar sounding
   * words.
   */
  protected transient Collection<String> metaphones = new HashSet<String>();

  /**
   * Default constructor.  Initialise {@link #words} and {@link #metaphones}
   * with empty collections.  Cannot be instantiated.
   */
  protected JDOObject()
  {
    words = new HashSet<String>();
    metaphones = new HashSet<String>();
  }

  /**
   * Return a string representation of this object.  Return an XML
   * representation of the data-fields.
   *
   * @see #toXML
   * @return String The xml representation of this class.
   */
  @Override
  public String toString()
  {
    return toXML();
  }

  /**
   * Return a hash code for this object.
   */
  @Override
  public abstract int hashCode();

  /**
   * Compare the specified object with this object for equality.  
   * Returns <code>true</code> if the specified object is of the
   * same type as this  object, and the values of {@link #hashCode}
   * match.
   *
   * @param object The object that is to compared with this object.
   * @return boolean Returns <code>true</code> if the objects have
   *   the same hash code.
   */
  @Override
  public abstract boolean equals( Object object );

  /**
   * Creates and returns a copy of this object.  Implementation of
   * the <code>Cloneable</code> interface.  No special actions are
   * performed.  This method simply allows public access to the
   * <code>Object.clone</code> method.
   *
   * @return Object A clone of this instance.
   * @throws CloneNotSupportedException If the super-class implementation
   *   throws an error.
   */
  @Override
  public Object clone() throws CloneNotSupportedException
  {
    return super.clone();
  }

  /**
   * Compares this object with the specified object for order. Returns 
   * a negative integer, zero, or a positive integer as this object is 
   * less than, equal to, or greater than the specified object.
   *
   * <p><b>Note:</b> The default implementation just compares the
   * {@link #hashCode} values.  It is recommended that sub-classes
   * over-ride this method for appropriate sort order.</p>
   *
   * @param object The object that is to be compared with this object.
   * @return int A negative integer, zero, or a positive integer as 
   *   this object is less than, equal to, or greater than the 
   *   specified object.
   */
  public int compareTo( JDOObject object )
  {
    return ( hashCode() - object.hashCode() );
  }

  /**
   * Return the utility used to convert the object to and from XML 
   * representation.  This method must be used by the {@link #toXML}
   * and {@link #fromXML} methods to initialise the serialiser in a
   * standard manner.
   */
  protected static XStream createXStream()
  {
    XStream xstream = new XStream();
    xstream.alias( "JDOObject", JDOObject.class );
    return xstream;
  }

  /**
   * Return an XML representation of the fields of this object.
   * It is recommended that sub-classes over-ride this method to
   * specify good aliases for fully qualified class names to make
   * the XML for readable.
   *
   * <p><b>Note:</b> Currently this method uses the 
   * <a href='http://xstream.codehaus.org/'>XStream</a> API to
   * convert the object into XML.  This may be modified at a later
   * date to convert into a TMS standard XML format.</p>
   *
   * @see #createXStream
   * @see #fromXML
   * @return String - The string representation of this object.
   */
  public String toXML()
  {
    return createXStream().toXML( this );
  }

  /**
   * Parse the object out of the XML representation of this object.
   * It is recommended that sub-classes over-ride this method to
   * specify good aliases for fully qualified class names to make
   * the XML for readable.
   *
   * @see #createXStream
   * @see #toXML
   * @param xml The XML representation of this object.
   * @return Program The object parsed out of the XML representation.
   */
  public static JDOObject fromXML( String xml )
  {
    return (JDOObject) createXStream().fromXML( xml );
  }

  /**
   * Reset the {@link #hash} value.
   */
  public final void resetHash()
  {
    hash = HASH;
  }

  /**
   * Copy constructor equivalent.  Update the fields of the class 
   * from the specified instance.
   *
   * @param object The instance from which the fields of this object
   *   are to be updated.
   */
  protected abstract <E extends JDOObject> void copy( E object );

  /**
   * InstanceCallbacks method implementation.  No actions required
   * by default.
   */
  public void jdoPostLoad() {}

  /**
   * InstanceCallbacks method implementation.  No actions required.
   */
  public void jdoPreStore() {}

  /**
   * InstanceCallbacks method implementation.  No actions required.
   */
  public void jdoPreClear() {}

  /**
   * InstanceCallbacks method implementation.  No actions required.
   */
  public void jdoPreDelete() {}
}
