package SampleDatabase;
import ModSQL.*;
import java.sql.*;
import java.lang.reflect.*;

/* SampleDatabase/TableTemplate.java
 *
 * Copyright (c) 2003 Chris Studholme <chris.studholme@utoronto.ca>
 *
 * May be copied or modified under the terms of the GNU General Public
 * License.  See COPYING for more information.
 */

/**
 * <p>This is an abstract class that should be extended to create
 * individual tables.  Table classes should be named 'tablename_Class'.
 * The case of the tablename is preserved, but since SQL is 
 * case-insensitive, you should not create two tables with names that
 * only differ in case.  
 *
 * <p>See one of the tables defined in this package for an idea of
 * how to create your own tables.  Decendant classes only need to
 * provided a constructor.  In addition to creating a table class, 
 * you will also need to provide a row class named 'tablename_Row'.
 * This class only needs a list of fields representing columns and
 * a constructor to initialize the row.  See the examples provided
 * for more information.
 *
 * @author chris.studholme@utoronto.ca
 */

abstract class TableTemplate implements DatabaseTable {

  protected int rowid=0;   // 1 to rows.length for row number
  protected String name=null;
  protected Object[] rows=null;
  protected Field[] fields=null;


  //======================================================================
  // Methods for manipulating table
  //======================================================================
    
  public DatabaseIndex openIndex(int column) {
    return null;
  }
  public void close() {
  }
    
    
  //======================================================================
  // Methods for accessing table metadata
  //======================================================================
    
  public boolean isIndexAvailable(int column) {
    return false;
  }
    
  public boolean isReadOnly() {
    return true;
  }
    
  public String getTableName() {
    return name;
  }
    
  public int getColumnCount() {
    return fields!=null ? fields.length : 0;
  }
    
  public long getTableSize() {
    return rows.length;
  }
    
  public long getTableSignature() {
    return 1;
  }

  public long getRowCount() {
    return rows.length;
  }
    
    
  //======================================================================
  // Methods for accessing column metadata
  //======================================================================
    
  public int findColumn(String name) {
    if (fields==null)
      return -1;
    for (int i=0; i<fields.length; ++i)
      if (name.equalsIgnoreCase(fields[i].getName()))
	return i+1;
    return -1;
  }
    
  public int getColumnDisplaySize(int column) throws DatabaseException {
    try {
      if ((fields!=null)&&(column-1<fields.length)&&(column>=1)) {
	if (fields[column-1].getType().
	    equals(Class.forName("java.lang.String"))) {
	  int max=0;
	  for (int i=0; i<rows.length; ++i) {
	    Object s = fields[column-1].get(rows[i]);
	    if ((s!=null)&&(((String)s).length()>max))
	      max=((String)s).length();
	  }
	  return max;
	}
      }
    }
    catch (Exception e) {
      throw new DatabaseException("class exception (was "+e.toString()+")");
    }
    return 0;
  }
    
  public String getColumnName(int column) {
    if ((fields!=null)&&(column-1<fields.length)&&(column>=1))
      return fields[column-1].getName();
    return null;
  }
    
  public String getColumnLabel(int column) {
    return getColumnName(column);
  }
    
  public int getColumnType(int column) throws DatabaseException {
    if ((fields!=null)&&(column-1<fields.length)&&(column>=1)) {
      String c = fields[column-1].getType().getName();
      if (c.equals("java.lang.String")) 
	return Types.VARCHAR;
      else if (c.equals("char")) 
	return Types.CHAR;
      else if (c.equals("byte")) 
	return Types.TINYINT;
      else if (c.equals("short")) 
	return Types.SMALLINT;
      else if (c.equals("int")) 
	return Types.INTEGER;
      else if (c.equals("long")) 
	return Types.BIGINT;
      else if (c.equals("double")) 
	return Types.DOUBLE;
      else if (c.equals("float")) 
	return Types.FLOAT;
      else if (c.equals("bool")) 
	return Types.BIT;
      else
	throw new DatabaseException("unknown field type ("+c+")");
    }
    return Types.NULL;
  }
    
  public void addColumn(String name, int type, int maxlen)
    throws DatabaseException {
    throw new DatabaseException("cannot add column");
  }
    
    
  //======================================================================
  // Methods for changing current row
  //======================================================================
    
  public boolean next() {
    return ++rowid<=rows.length;
  }
    
  public boolean findNext(int column, Object data)
    throws DatabaseException {
    while (next()) {
      Object o = getObject(column);
      if (data==null) {
	if (o==null)
	  return true;
      }
      else if (data.equals(o))
	return true;
    }
    return false;
  }
  
  public void deleteRow() throws DatabaseException {
    throw new DatabaseException("cannot delete row");
  }
    
  public void addRow() throws DatabaseException {
    throw new DatabaseException("cannot add row");
  }
    
  public boolean isBeforeFirst() {
    return (rowid<1);
  }
    
  public boolean isAfterLast() {
    return (rowid>rows.length);
  }
    
  public void beforeFirst() {
    rowid = 0;
  }
    
  public void afterLast() {
    rowid = rows.length+1;
  }
    
  public Object getRowId() {
    return new Integer(rowid);
  }
    
  public boolean absolute(Object id) {
    rowid = ((Number)id).intValue();
    return (rowid>0 && rowid<=rows.length);
  }
    
    
  //======================================================================
  // Methods for accessing column data
  //======================================================================
    
  public Object getObject(int column) throws DatabaseException {
    if ((rowid<1)||(rowid>rows.length))
      return null;
    if ((fields==null)||(column<1)||(column>fields.length))
      return null;
    try {
      return fields[column-1].get(rows[rowid-1]);
    }
    catch (Exception e) {
      throw new DatabaseException("class exception (was "+e.toString()+")");
    }
  }
    
  public void updateObject(int columnIndex, Object x) 
    throws DatabaseException {
    throw new DatabaseException("cannot update row");
  }
  public void commitUpdates() throws DatabaseException {
    throw new DatabaseException("cannot update row");
  }
    
};

