package hep.io.root.reps;

import hep.io.root.*;
import hep.io.root.core.*;
import hep.io.root.interfaces.*;

import java.io.*;
import java.lang.ref.SoftReference;


/**
 * @author Tony Johnson (tonyj@slac.stanford.edu)
 * @version $Id: TKeyRep.java,v 1.3 2003/05/23 20:59:15 duns Exp $
 */
public abstract class TKeyRep extends AbstractRootObject implements TKey
{
   private AbstractRootObject object;
   private java.util.Date fDatime;
   private RootInput rin;
   private SoftReference soft;
   private String fClassName;
   private String fName;
   private String fTitle;
   private int fNbytes; // number of bytes for the compressed object+key       //
   private int fObjlen; // Length of uncompressed object                       //
   private int fSeekKey; // Address of the object on file (points to fNbytes)   //
   private int fSeekPdir;
   private short fCycle;
   private short fKeylen; // number of bytes for the key structure               //

   /**
    * Get the object corresonding to this key
    */
   public RootObject getObject() throws RootClassNotFound, IOException
   {
      // Use of a soft reference allows the object to be cleared
      // from memory if not in use, and if memory is short.
      // Proxies are messing this up?? --- Does the proxy not hold a reference to the object??
      // AbstractRootObject object = soft == null ? null : (AbstractRootObject) soft.get();
      if (object == null)
      {
         object = createObject(getObjectClass());
         rin.setPosition(fSeekKey + fKeylen);
         if (fObjlen > (fNbytes - fKeylen)) // We need to decompress
         {
            RootInput in = getData();
            object.read(in);
         }
         else
         {
            rin.setMap(fKeylen);
            object.read(rin);
            rin.clearMap();
         }
         soft = new SoftReference(object);
      }
      return object;
   }

   public RootClass getObjectClass() throws RootClassNotFound, IOException
   {
      return rin.getFactory().create(fClassName);
   }

   public void readMembers(RootInput in) throws IOException
   {
      fNbytes = in.readInt();

      int v = in.readVersion();
      fObjlen = in.readInt();
      fDatime = ((hep.io.root.interfaces.TDatime) in.readObject("TDatime")).getDate();
      fKeylen = in.readShort();
      fCycle = in.readShort();
      fSeekKey = in.readInt();
      fSeekPdir = in.readInt();
      fClassName = in.readObject("TString").toString();
      fName = in.readObject("TString").toString();
      fTitle = in.readObject("TString").toString();
      rin = in.getTop();
   }

   RootInput getData() throws IOException
   {
      if ((fNbytes - fKeylen) < fObjlen)
      {
         RootInput slice = rin.slice(fNbytes - fKeylen, fObjlen);
         slice.setMap(fKeylen);
         return slice;
      }
      else
      {
         RootInput slice = rin.slice(fObjlen);
         slice.setMap(fKeylen);
         return slice;
      }
   }

   private AbstractRootObject createObject(RootClass k) throws RootClassNotFound
   {
      return ((GenericRootClass) k).newInstance();
   }
}
