package hep.aida.ref.tuple;

import hep.aida.IBaseTupleColumn;
import hep.aida.ITuple;
import hep.aida.ref.AidaUtils;

import java.util.ArrayList;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Map;
import java.util.StringTokenizer;

import org.freehep.util.Value;

/**
 *
 * @author  The FreeHEP team @ SLAC.
 *
 */
public class Tuple extends AbstractTuple {
    
    protected static final int COLUMN_ROWS = 1000;
    private int columnLength;
    private int columnMaxLength;
    
    private String tupColumnsString = "";
    
    private int startRow = 0;
    private int endRow = -1;
    private int filledRows = 0;
    
    private Map optionMap;
    
    private String[] columnDefaultValues;
    
    private ArrayList tupleColumns = new ArrayList();
    private ArrayList folderList = new ArrayList();
    private Hashtable columnCounters = new Hashtable();
    
    private Value tupleValue = new Value();
    
    public Tuple(String name, String title, String[] columnName, Class[] columnType, String options) {
        super(name, title, options);
        initTuple(name, title,columnName,columnType,options);
    }
    
    public Tuple(String name, String title, String columnsString, String options) {
        super(name, title, options);
        initTuple(name, title,columnsString,options);
    }
    
    private int numberOf(String str, String s) {
        int n = 0;
        int i = str.indexOf(s);
        if ( i <0 )
            return n;
        else {
            n++;
            n += numberOf(str.substring(i+1),s);
        }
        return n;
    }
    
    private void initTuple( String name, String title, String columnsString, String options) {
        setTitle(title);
        
        this.tupColumnsString = columnsString;
        
        optionMap = AidaUtils.parseOptions(options);
        
        StringTokenizer strT = new StringTokenizer( columnsString,",;");
        int bracketCounter = 0;
        int nCol = 0;
        while( strT.hasMoreTokens() ) {
            String token = strT.nextToken();
            if ( bracketCounter == 0 ) nCol++;
            bracketCounter += numberOf(token,"{");
            bracketCounter -= numberOf(token,"}");
        }
        if ( nCol < 1 ) throw new IllegalArgumentException("Cannot build Tuple with no columns\n");
        
        StringTokenizer st = new StringTokenizer(columnsString,",;");
        
        int columnIndex = 0;
        bracketCounter = 0;
        String iTupleColString = "";
        String type = "";
        
        int colDefCount = 0;
        columnDefaultValues = new String[nCol];
        
        while( st.hasMoreTokens() ) {
            String token = st.nextToken();
            token.trim();
            
            bracketCounter += numberOf(token,"{");
            bracketCounter -= numberOf(token,"}");
            
            iTupleColString += token;
            
            if ( st.hasMoreTokens() ) iTupleColString += ";";
            
            if ( bracketCounter == 0 ) {
                String colName;
                String defaultValue = "";
                
                iTupleColString = iTupleColString.trim();
                int brPos = iTupleColString.indexOf("{");
                if ( brPos > 0 ) {
                    iTupleColString.trim();
                    int pos = iTupleColString.indexOf("(");
                    if ( pos > 0 && pos < brPos ) {
                        type = iTupleColString.substring(0,pos).trim();
                        colName = iTupleColString.substring( iTupleColString.indexOf(")")+1, brPos).trim();
                        if ( colName.endsWith("=") ) colName = colName.substring(0,colName.length()-1).trim();
                        defaultValue += iTupleColString.substring( pos+1, iTupleColString.indexOf(")") ).trim();
                        defaultValue += iTupleColString.substring( brPos );
                    } else {
                        int spPos = iTupleColString.indexOf(" ");
                        int eqPos = iTupleColString.indexOf("=");
                        type = iTupleColString.substring(0,spPos).trim();
                        colName = iTupleColString.substring(spPos+1,eqPos).trim();
                        defaultValue = iTupleColString.substring( brPos ).trim();
                    }
                } else {
                    StringTokenizer t = new StringTokenizer( token, "=");
                    int tokens = t.countTokens();
                    
                    String nameAndType = t.nextToken().trim();
                    
                    if ( tokens == 2 ) defaultValue = t.nextToken().trim();
                    else if ( tokens != 1 ) throw new IllegalArgumentException("Wrong format "+token+"\n");
                    
                    StringTokenizer tt = new StringTokenizer( nameAndType, " " );
                    if ( tt.countTokens() == 2 ) type = tt.nextToken().trim();
                    colName = tt.nextToken().trim();
                }
                
                Value value = new Value();
                
                Class colType = null;
                if ( type.endsWith("ITuple") ) {
                    String defVal = defaultValue.substring(defaultValue.indexOf("{")+1,defaultValue.lastIndexOf("}"));
                    Tuple tup = new Tuple( colName, "", defVal, options);
                    addTuple( tup );
                    columnDefaultValues[colDefCount++] = defVal;
                } else {
                    if ( type.equals("int") )          colType = Integer.TYPE;
                    else if ( type.equals("short") )   colType = Short.TYPE;
                    else if ( type.equals("long") )    colType = Long.TYPE;
                    else if ( type.equals("float") )   colType = Float.TYPE;
                    else if ( type.equals("double") )  colType = Double.TYPE;
                    else if ( type.equals("boolean") ) colType = Boolean.TYPE;
                    else if ( type.equals("byte") )    colType = Byte.TYPE;
                    else if ( type.equals("char") )    colType = Character.TYPE;
                    else if ( type.equals("string") )  colType = String.class;
                    else {
                        try {
                            colType = Class.forName( type );
                        } catch ( ClassNotFoundException cnfe ) {
                            throw new IllegalArgumentException("Unsupported type "+type);
                        }
                    }
                    
                    fillDefaultValue(colType, defaultValue,value);
                    TupleColumn fcolumn = TupleColumnFactory.createTupleColumn(colName, colType, value, options, this);
                    addColumn( fcolumn );
                    columnDefaultValues[colDefCount++] = defaultValue;
                }
                iTupleColString = "";
            }
        }
        
        start();
    }
    
    
    private void initTuple(String name, String title, String[] columnName, Class[] columnType, String options){
        
        setTitle(title);
        
        optionMap = AidaUtils.parseOptions(options);
        
        int colNames = columnName.length;
        int colTypes = columnType.length;
        
        if ( colNames < 1 ) throw new IllegalArgumentException("columnName cannot be empty\n");
        if ( colTypes < 1 ) throw new IllegalArgumentException("columnType cannot be empty\n");
        if ( colNames != colTypes ) throw new IllegalArgumentException("The number of column names "
                +colNames+" is different than the number of column types "+colTypes+"\n");
        
        int colDefCount = 0;
        columnDefaultValues = new String[colNames];
        
        for (int i=0; i 0 ) {
                    colName = iTupleString.substring(pos+1,iTupleString.indexOf("{")).trim();
                    if ( colName.endsWith("=") ) colName = colName.substring(0,colName.length()-1).trim();
                    defaultValue += iTupleString.substring(iTupleString.indexOf("(")+1,pos);
                } else {
                    if (iTupleString.indexOf("=") > 0)
                        colName = iTupleString.substring(0,iTupleString.indexOf("=")).trim();
                    else colName = iTupleString.trim();
                }
                if (iTupleString.indexOf("{") > 0)
                    defaultValue += iTupleString.substring(iTupleString.indexOf("{"),iTupleString.lastIndexOf("}")+1).trim();
                
                String defVal = defaultValue.substring(defaultValue.indexOf("{")+1,defaultValue.lastIndexOf("}"));
                
                Tuple tup = new Tuple( colName, "", defVal, options);
                addTuple( tup );
                columnDefaultValues[colDefCount++] = defVal;
                
            } else {
                colName = columnName[i];
                StringTokenizer st = new StringTokenizer(colName,"=");
                colName = st.nextToken().trim();
                if ( st.hasMoreTokens() ) defaultValue = st.nextToken().trim();
                
                fillDefaultValue(colType, defaultValue,value);
                TupleColumn fcolumn = TupleColumnFactory.createTupleColumn(colName, colType, value, options, this);
                addColumn( fcolumn );
                columnDefaultValues[colDefCount++] = defaultValue;
            }
            
        }
        
        start();
    }
    
    // FIXME is this needed?
    private String getColString() {
        return tupColumnsString;
    }
    
    private void fillDefaultValue( Class type, String defaultValue, Value value ) {
        if ( type == Integer.TYPE )
            value.set( defaultValue.equals("") ? (int)0 : Integer.parseInt(defaultValue) );
        else if ( type == Short.TYPE )
            value.set( defaultValue.equals("") ? (short)0 : Short.parseShort(defaultValue) );
        else if ( type == Long.TYPE )
            value.set( defaultValue.equals("") ? (long)0 : Long.parseLong(defaultValue) );
        else if ( type == Float.TYPE )
            value.set( defaultValue.equals("") ? (float)0 : Float.parseFloat(defaultValue) );
        else if ( type == Double.TYPE )
            value.set( defaultValue.equals("") ? (double)0 : Double.parseDouble(defaultValue) );
        else if ( type == Boolean.TYPE )
            value.set( defaultValue.equals("") ? false : Boolean.valueOf(defaultValue).booleanValue() );
        else if ( type == Byte.TYPE )
            value.set( defaultValue.equals("") ? (byte)0 : Byte.parseByte(defaultValue) );
        else if ( type == Character.TYPE )
            value.set( defaultValue.equals("") ? (char)0 : defaultValue.charAt(0) );
        else value.set( defaultValue );
    }
    
    
    public String columnDefaultString( int column ) {
        if ( columnType( column ) != ITuple.class )
            return columnDefaultValues[column];
        else {
            Tuple tup = (Tuple) findTuple(column);
            if ( tup != null )
                return tup.name()+" = {"+tup.getColString()+"}";
            else
                return "null";
        }
    }
    
    
    
    
    
    
    
    
    
    
    
    public boolean providesColumnDefaultValues() {
        return true;
    }
    
    
    /**
     * Get Folder at the current cursor position.
     * @param index The column's index of the Folder.
     * @return The folder.
     *
     */
    public ITuple findTuple(int index) {
        return getFolder( index, filledRows );
    }
    
    public void fill(int column, Value value) {
        tupleColumn(column).fill( value );
    }
    
    public void columnValue(int column, FTupleCursor cursor, Value value) {
        if ( columnType( column ) != ITuple.class )
            tupleColumn(column).value(cursor, value);
        else
            value.set( getFolder( column, cursor.row() ) );
    }
    
    public void columnValue(int column, Value value) {
        if ( columnType( column ) != ITuple.class )
            tupleColumn(column).value(internalCursor(), value);
        else
            value.set( getFolder( column, internalCursor().row() ) );
    }
    
    public boolean isInMemory() {
        return true;
    }
    
    public boolean supportsMultipleCursors() {
        return true;
    }
    
    public boolean supportsRandomAccess() {
        return true;
    }
    
    public void addRow() {
        for ( int i = 0; i < columns(); i++ )
            tupleColumn(i).addRow();
        
        for ( Enumeration keys = columnCounters.keys(); keys.hasMoreElements(); ) {
            String folderName = (String)keys.nextElement();
            Tuple folder = (Tuple) getFolder( findColumn( folderName ), filledRows );
            
            TupleColumn tc = (TupleColumn)columnCounters.get( folderName );
            tc.fill( tupleValue.set( folder.startRow()+folder.rows() ) );
            tc.addRow();
        }
        filledRows++;
        newInternalCursor();
    }
    
    public void resetRow() {
        for ( int i = 0; i 0 ) {
                cf--;
                Tuple folder = (Tuple) getFolder( findColumn( folderName ), cf );
                TupleColumn tc = (TupleColumn)columnCounters.get( folder.name() );
                
                tc.value(numberOfRows, tupleValue);
                int end =  tupleValue.getInt();
                int start = 0;
                if ( numberOfRows > 0 ) {
                    tc.value(numberOfRows-1, tupleValue);
                    start =  tupleValue.getInt();
                }
                folder.setStartEndRow(start,end);
                folder.resetRows( folder.rows() );
                
                tc.resetRows(1);
            }
        }
    }
    
    /**
     * Get a Folder in a given configuration.
     * @param index The column's index for this Folder.
     * @param cursor The cursor position for the Folder.
     *
     */
    private Tuple getFolder( int index, int cursor ) {
        Tuple tup = (Tuple)((TupleColumn)tupleColumns.get( index )).getDefaultValue().getObject();
        TupleColumn tc = (TupleColumn)columnCounters.get( tup.name() );
        if ( cursor > -1 && cursor < filledRows ) {
            tc.value(cursor, tupleValue);
            int end = tupleValue.getInt();
            int start = 0;
            if ( cursor > 0 ) {
                tc.value(cursor-1, tupleValue);
                start = tupleValue.getInt();
            }
            tup.setStartEndRow( start, end );
        } else if ( cursor == filledRows && cursor > 0 ) {
            tc.value(cursor-1, tupleValue);
            int start = tupleValue.getInt();
            tup.setStartEndRow( start, -1 );
        }
        tup.newInternalCursor();
        return (Tuple) tup;
    }
    
    public IBaseTupleColumn column( int column ) {
        return (IBaseTupleColumn)tupleColumns.get( column );
    }
    
    public IBaseTupleColumn column( String name ) {
        return column( findColumn( name ) );
    }
    
    private TupleColumn tupleColumn(int column) {
        return (TupleColumn) column(column);
    }
    
    
    public abstract static class TupleColumnFactory {
        
        public static TupleColumn createTupleColumn(String name, Class type, Value value, Tuple tuple) {
            return createTupleColumn(name, type, value, "", tuple);
        }
        
        public static TupleColumn createFolderColumn(String name, Tuple folderTuple, String options, Tuple parentTuple) {
            return new TupleColumn.TupleColumnFolder( name, folderTuple, options, parentTuple);
        }
        
        public static TupleColumn createTupleColumn(String name, Class type, Value value, String options, Tuple tuple) {
            if ( type == ITuple.class )
                throw new RuntimeException("Cannot create Folder tuple. Use createFolderColumn method instead.");
            if ( type == Integer.TYPE ) return new TupleColumn.TupleColumnInt( name, value, options, tuple);
            else if ( type == Short.TYPE ) return new TupleColumn.TupleColumnShort( name, value, options, tuple);
            else if ( type == Long.TYPE ) return new TupleColumn.TupleColumnLong( name, value, options, tuple);
            else if ( type == Float.TYPE ) return new TupleColumn.TupleColumnFloat( name, value, options, tuple);
            else if ( type == Double.TYPE ) return new TupleColumn.TupleColumnDouble( name, value, options, tuple);
            else if ( type == Boolean.TYPE ) return new TupleColumn.TupleColumnBoolean( name, value, options, tuple);
            else if ( type == Byte.TYPE ) return new TupleColumn.TupleColumnByte( name, value, options, tuple);
            else if ( type == Character.TYPE ) return new TupleColumn.TupleColumnChar( name, value, options, tuple);
            else if ( type == String.class ) return new TupleColumn.TupleColumnString( name, value, options, tuple);
            else return new TupleColumn.TupleColumnObject( name, type, value, options, tuple);
        }
    }
    
    
}

 

Ads help maintain this website.