
import javax.swing.table.AbstractTableModel;
import java.util.List;
import java.util.ArrayList;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.ResultSet;
import java.sql.Types;

/**
 * Cette classe encapusle dans un TableModel (cf package javax.swing.table)
 * les donn&eacute;es fournies par un resultSet.
 * @author : Philippe Genoud (Philippe.Genoud@imag.fr) d'apr&egrave;s Philip Milne 
 *           SUN Micro Systems).
 */
public class ResultSetTableModel extends AbstractTableModel {

  
	private static final long serialVersionUID = 860198988699966848L;
/**
   * les noms des colonnes
   */
  protected String[] columnNames = {};
  /**
   * le nombre de colonnes
   */
  protected int columnCount = 0;
  /**
   * la classe correspondant au type Java de chaque colonne.
   */
  protected Class[] columnClasses = {};

  /**
   * Une liste pour stocker chaque ligne de valeur.
   * Chaque ligne sera elle même repr&eacute;sent&eacute;e par un tableau d'Object.
   */
  protected List<Object[]> rowValues = new ArrayList<Object[]>();

  /**
   * les meta donn&eacute;es du resultset repr&eacute;sent&eacute; par ce TableModel
   */
  protected ResultSetMetaData   metaData;

  /**
   * bool&eacute;en idniquant si le mod&egrave;le est &eacute;ditable
   */
  protected boolean editable = false;


  /**
   * modifie ce  ResultSetTableModel pour qu'il corresponde &agrave; un
   * ResultSet donn&eacute;.
   * @param rs le ResultSet
   * @exception SQLException si lors de la construction du mod&egrave;le
   *            une erreur SQL est intervenue.
   */
  public void updateModel(ResultSet rs) throws SQLException {
    // r&eacute;cp&eacute;ration de l'information sur les donn&eacute;es 
    metaData = rs.getMetaData();
      
    columnCount = metaData.getColumnCount();
    
    // allocation des tableaux pour stocker les noms des colonnes
    // et le type (classes) des colonnes
    columnNames = new String[columnCount];
    columnClasses = new Class[columnCount];
      
    for (int i = 1; i <= columnCount;  i++) {
      columnNames[i-1] = metaData.getColumnName(i);
      try {
	columnClasses[i-1] = Class.forName(metaData.getColumnClassName(i));
      }
      catch (ClassNotFoundException clnfe) {
	clnfe.printStackTrace();
	System.exit(0);
      }
    }

    // chargement des donn&eacute;es dans la liste rowValues

    // initialisation de la liste des lignes avec une liste vide
    rowValues = new ArrayList<Object[]>();
    
    // r&eacute;cuperation de chacune des lignes du ResultSet 
    while (rs.next()) {
      //cr&eacute;ation d'un tableau d'objets pour r&eacute;cup&eacute;rer les donn&eacute;es d'une ligne
      Object[] values = new Object[columnCount];
      // recopie des valeurs de la ligne dans le tableau
      for (int i = 1; i <= columnCount; i++)
	values[i-1] = rs.getObject(i);
      // ajout du tableau &agrave; la liste des lignes
      rowValues.add(values);
    }

    // signale au Listener de ce TableModel qu'une nouvelle table a
    // &eacute;t&eacute; constitu&eacute;e
    fireTableChanged(null); 
  }

  /**
   * rends le mod&egrave;le &eacute;ditable ou non.
   * @param edit si true le mod&egrave;le est alors &eacute;ditable, sinon le
   *        mod&egrave;le ne peut être &eacute;dit&eacute;.
   */
  public void setEditable(boolean edit) {
    editable = edit;
  }

  /**
   * retourne le statut du mod&egrave;le par rapport &agrave; l'&eacute;dition.
   * @return true : le mod&egrave;le est &eacute;ditable, false sinon.
   */
  public boolean isEditable() {
    return editable;
  }

  /**
   * retourne une r&eacute;pr&eacute;sentation textuelle au format SQL d'une
   * valeur de la table.
   * @param column le num&eacute;ro de la colonne (dans la JTable et non pas
   *        dans la table SQL) dont est issue la valeur.
   * @param value l'objet repr&eacute;sentant la valeur.
   * @return la cha&icirc;ne repr&eacute;sentant la valeur en SQL.
   */
  public String dbRepresentation(int column, Object value) {
        int type;

        if (value == null) {
            return "null";
        }

        try {
            type = metaData.getColumnType(column+1);
        }
        catch (SQLException e) {
            return value.toString();
        }

        switch(type) {
        case Types.INTEGER:
        case Types.DOUBLE:
        case Types.FLOAT:
            return value.toString();
        case Types.BIT:
            return ((Boolean)value).booleanValue() ? "1" : "0";
        case Types.DATE:
            return value.toString(); // This will need some conversion.
        default:
            return "\""+value.toString()+"\"";
        }

    }


  //-----------------------------------------------------
  // r&eacute;d&eacute;finitions des m&eacute;thodes de l'interface TableModel
  //-----------------------------------------------------

  public int getColumnCount() {
    return columnCount;
  }

  public int getRowCount() {
    return rowValues.size();
  }

  public String getColumnName(int col) {
    return columnNames[col];
  }

  public Class getColumnClass(int col) {
    return columnClasses[col];
  }

  public Object getValueAt(int row, int col) {
    return ((Object[]) (rowValues.get(row)))[col];
  }

  public boolean isCellEditable(int row, int column) {
        try {
            return editable && metaData.isWritable(column+1);
        }
        catch (SQLException e) {
            return false;
        }
  }

  public void setValueAt(Object value, int row, int column) {
        try {
            String tableName = metaData.getTableName(column+1);
            String columnName = columnNames[column];
            String query =
                "update "+tableName+
                " set "+columnName+" = "+dbRepresentation(column, value)+
                " where ";
            // We don't have a model of the schema so we don't know the
            // primary keys or which columns to lock on. To demonstrate
            // that editing is possible, we'll just lock on everything.
            for(int col = 0; col< columnCount; col++) {
                String colName = columnNames[col];
                if (colName.equals("")) {
                    continue;
                }
                if (col != 0) {
                    query = query + " and ";
                }
                query = query + colName +" = "+
                    dbRepresentation(col, getValueAt(row, col));
            }
            System.out.println(query);
            System.out.println("Not sending update to database");
            // statement.executeQuery(query);
        }
        catch (SQLException e) {
            //     e.printStackTrace();
            System.err.println("Update failed");
        }
        Object[] dataRow = (Object []) rowValues.get(row);
        dataRow[column] = value;
    }

}







