package hep.io.root.reps;

import hep.io.root.core.AbstractRootObject;
import hep.io.root.core.RootInput;
import hep.io.root.interfaces.TBranch;
import hep.io.root.interfaces.TLeafD;
import hep.io.root.interfaces.TLeafI;

import java.io.IOException;

import org.apache.bcel.Constants;
import org.apache.bcel.generic.ConstantPoolGen;
import org.apache.bcel.generic.InstructionFactory;
import org.apache.bcel.generic.InstructionList;
import org.apache.bcel.generic.Type;


/**
 * @author Tony Johnson
 * @version $Id: TLeafDRep.java,v 1.5 2004/07/26 18:40:22 tonyj Exp $
 */
public abstract class TLeafDRep extends AbstractRootObject implements TLeafD, Constants
{
   private Object lastValue;
   private TBranch branch;
   private double lastDouble;
   private int lastDoubleIndex;
   private int lastValueIndex;
   
   public void setBranch(TBranch branch)
   {
      this.branch = branch;
      lastValueIndex = -1;
      lastDoubleIndex = -1;
   }

   public double getValue(int index) throws IOException
   {
      try
      {
         if (index == lastDoubleIndex)
            return lastDouble;

         RootInput in = branch.setPosition(this, lastDoubleIndex = index);
         return lastDouble = in.readDouble();
      }
      catch (IOException x)
      {
         lastDoubleIndex = -1;
         throw x;
      }
   }

   public Object getWrappedValue(int index) throws IOException
   {
      try
      {
         if (index == lastValueIndex)
            return lastValue;
         lastValueIndex = index;

         RootInput in = branch.setPosition(this, index);
         int arrayDim = getArrayDim();
         if (arrayDim == 0)
         {
            return lastValue = new Double(in.readDouble());
         }
         else if (arrayDim == 1)
         {
            TLeafI count = (TLeafI) getLeafCount();
            int len = (count == null) ? getLen() : count.getValue(index);
            double[] array = new double[len];
            in.readFixedArray(array);
            return lastValue = array;
         }
         else
         {
            return lastValue = readMultiArray(in, Double.TYPE, index);
         }
      }
      catch (IOException x)
      {
         lastValueIndex = -1;
         throw x;
      }
   }

   public void generateReadCode(InstructionList il, InstructionFactory factory, ConstantPoolGen cp, String className)
   {
      String leafClassName = getClass().getName();
      int arrayDim = getArrayDim();
      if (arrayDim == 0)
         il.append(factory.createInvoke(leafClassName, "getValue", Type.DOUBLE, new Type[]
               {
                  Type.INT
               }, INVOKEVIRTUAL));
      else
         il.append(factory.createInvoke(leafClassName, "getWrappedValue", Type.OBJECT, new Type[]
               {
                  Type.INT
               }, INVOKEVIRTUAL));
   }

   abstract Object[] readMultiArray(RootInput in, Class type, int index);
}
