package hep.aida.ref.root;

import hep.aida.ITuple;
import hep.aida.ref.tuple.AbstractTuple;
import hep.io.root.interfaces.TLeaf;
import hep.io.root.interfaces.TLeafB;
import hep.io.root.interfaces.TLeafD;
import hep.io.root.interfaces.TLeafF;
import hep.io.root.interfaces.TLeafI;
import hep.tuple.Cursor;
import hep.tuple.interfaces.FTuple;

import hep.tuple.interfaces.FTupleColumn;
import hep.tuple.interfaces.FTupleCursor;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;

import java.util.List;
import org.freehep.util.Value;



/**
 *
 * @author tonyj
 */
class TLeafFolderColumn extends TLeafColumn
{
   private TLeafI dim;
   private TLeafColumn[] columns;
   private EmbeddedTuple embedded;
   
   TLeafFolderColumn(TLeafI dim)
   {
      this.dim = dim;
      embedded = new EmbeddedTuple(name());
   }
   void addColumn(TLeaf leaf)
   {
      // Each row represents an array, of which the first dimension is dim
      TLeafColumn col;
      if (leaf instanceof TLeafI)
         col = new TLeafIColumn((TLeafI) leaf);
      else if (leaf instanceof TLeafF)
         col = new TLeafFColumn((TLeafF) leaf);
      else if (leaf instanceof TLeafD)
         col = new TLeafDColumn((TLeafD) leaf);
      else if (leaf instanceof TLeafB)
         col = new TLeafBColumn((TLeafB) leaf);
      else
      {
         System.out.println("Ignored column " + leaf.getName() + " of type " + leaf.getClass());
         return;
      }
      if (columns == null) columns = new TLeafColumn[] { col };
      else
      {
         List x = new ArrayList(Arrays.asList(columns));
         x.add(col);
         columns = new TLeafColumn[x.size()];
         x.toArray(columns);
      }
   }
   
   void getValue(int row, Value value)
   {
      try
      {
         // We need to return an ITuple as our value
         embedded.setGlobalRow(row);
         value.set(embedded);
      }
      catch (IOException x)
      {
         x.printStackTrace();
         value.set((Object) null);
      }
   }
   
   public void defaultValue(Value value)
   {
      System.out.println("getting default value  "+name());
      value.set((Object) null);
   }
   
   public String name()
   {
      return "Folder["+dim.getName()+"]";
   }
   
   public Class type()
   {
      return EmbeddedTuple.class;
   }
   
   void getArrayValue(int row, int dim, Value value)
   {
      throw new UnsupportedOperationException();
   }
   
   private class EmbeddedTuple extends AbstractTuple implements FTuple
   {
      private Cursor cursor;
      private Value theValue = new Value();
      private int nRows;
      private int theRow;
      
      EmbeddedTuple(String name)
      {
         super(name);
      }
      void setGlobalRow(int row) throws IOException
      {
         theRow = row;
         nRows = dim.getValue(row);
         cursor = new Cursor(0, nRows, true);
      }
      
      public boolean getBoolean(int col) throws ClassCastException
      {
         columns[col].getArrayValue(theRow, cursor.row(), theValue);
         return theValue.getBoolean();
      }
      
      public byte getByte(int col) throws ClassCastException
      {
         columns[col].getArrayValue(theRow, cursor.row(), theValue);
         return theValue.getByte();
      }
      
      public char getChar(int col) throws ClassCastException
      {
         columns[col].getArrayValue(theRow, cursor.row(), theValue);
         return theValue.getChar();
      }
      
      public double getDouble(int col) throws ClassCastException
      {
         columns[col].getArrayValue(theRow, cursor.row(), theValue);
         return theValue.getDouble();
      }
      
      public float getFloat(int col) throws ClassCastException
      {
         columns[col].getArrayValue(theRow, cursor.row(), theValue);
         return theValue.getFloat();
      }
      
      public boolean isInMemory()
      {
         return false;
      }
      
      public int getInt(int col) throws ClassCastException
      {
         columns[col].getArrayValue(theRow, cursor.row(), theValue);
         return theValue.getInt();
      }
      
      public long getLong(int col) throws ClassCastException
      {
         columns[col].getArrayValue(theRow, cursor.row(), theValue);
         return theValue.getLong();
      }
      
      public Object getObject(int col) throws ClassCastException
      {
         columns[col].getArrayValue(theRow, cursor.row(), theValue);
         return theValue.getObject();
      }
      
      public void setRow(int row) throws IllegalArgumentException
      {
         cursor.setRow(row);
      }
      
      public short getShort(int col) throws ClassCastException
      {
         columns[col].getArrayValue(theRow, cursor.row(), theValue);
         return theValue.getShort();
      }
      
      public String getString(int col) throws ClassCastException
      {
         columns[col].getArrayValue(theRow, cursor.row(), theValue);
         return theValue.getString();
      }
      
      public ITuple getTuple(int param)
      {
         return null;
      }
      
      public void close(){}
      
      public FTupleColumn column(int index)
      {
         return columns[index];
      }
      
      public FTupleColumn columnByName(String name)
      {
         int n = columnIndexByName(name);
         if (n < 0)
            return null;
         return column(n);
      }
      
      public int columnIndexByName(String name)
      {
         for (int i = 0; i < columns.length; i++)
         {
            if (columns[i].name().equals(name))
               return i;
         }
         return -1;
      }
      
      public double columnMax(int index) throws IllegalArgumentException
      {
         columns[index].maxValue(theValue);
         return theValue.getDouble();
      }
      
      public void columnMaxValue(int column, Value value)
      {
         value.set(columnMax(column));
      }
      
      public double columnMean(int index) throws IllegalArgumentException
      {
         columns[index].meanValue(theValue);
         return theValue.getDouble();
      }
      
      public void columnMeanValue(int column, Value value)
      {
         value.set(columnMean(column));
      }
      
      public double columnMin(int index) throws IllegalArgumentException
      {
         columns[index].minValue(theValue);
         return theValue.getDouble();
      }
      
      public void columnMinValue(int column, Value value)
      {
         value.set(columnMin(column));
      }
      
      public String columnName(int index) throws IllegalArgumentException
      {
         return columns[index].name();
      }

      public String[] columnNames() throws java.lang.IllegalArgumentException {
          String[] names = new String[columns.length];
          for ( int i = 0; i < names.length; i++ )
              names[i] = columns[i].name();
          return names;
      }

      public double columnRms(int index) throws IllegalArgumentException
      {
         columns[index].rmsValue(theValue);
         return theValue.getDouble();
      }
      
      public void columnRmsValue(int column, Value value)
      {
         value.set(columnRms(column));
      }
      
      public Class columnType(int index) throws IllegalArgumentException
      {
         return columns[index].type();
      }

      public Class[] columnTypes() throws java.lang.IllegalArgumentException {
          Class[] types = new Class[columns.length];
          for ( int i = 0; i < types.length; i++ )
              types[i] = columns[i].type();
          return types;
      }
      
      public void columnValue(int index, FTupleCursor cursor, Value value)
      {
         columns[index].getArrayValue(theRow, cursor.row(), value);
      }
      
      public int columns()
      {
         return columns.length;
      }
      
      public FTupleCursor cursor() throws IllegalStateException
      {
         return new Cursor(0, nRows, true);
      }
      
      public int findColumn(String name) throws IllegalArgumentException
      {
         int n = columnIndexByName(name);
         if (n < 0)
            throw new IllegalArgumentException("Unknown column " + name);
         return n;
      }
      
      public boolean next()
      {
         return cursor.next();
      }
      
      public int rows()
      {
         return nRows;
      }
      
      public void skip(int n) throws IllegalArgumentException
      {
         cursor.skip(n);
      }
      
      public void start()
      {
         cursor.start();
      }
      
      public boolean supportsMultipleCursors()
      {
         return true;
      }
      
      public boolean supportsRandomAccess()
      {
         return true;
      }
      
      public FTuple tuple(int index)
      {
         return null;
      }
   }
}