/*
 * Created on Jan 6, 2005
 *
 * TODO To change the template for this generated file go to
 * Window - Preferences - Java - Code Style - Code Templates
 */
package gov.nasa.jsc.plum.DBManager;

import gov.nasa.jsc.plum.DBManager.Table;

import java.sql.Blob;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Iterator;
import java.util.TreeMap;

/**
 * @author randrews
 *
 * TODO To change the template for this generated type comment go to
 * Window - Preferences - Java - Code Style - Code Templates
 */
/**
 * @author randrews
 *
 * TODO To change the template for this generated type comment go to
 * Window - Preferences - Java - Code Style - Code Templates
 */
public class Row {

    private TreeMap fields;
    private Table table;
    private int status;
    private String index;
    
    public static final int UNCHANGED=0;
    public static final int NEW=1;
    public static final int MODIFIED=2;
    public static final int DELETED=3;
   
    /**
     * @param res The resultset to take data from.
     * Note that this will grab the table from the database as well, so if you're
     * making a lot of these, it's probably better to use another, faster constructor.
     */
    public Row(ResultSet res){
        try {
            status=UNCHANGED;
            index=null;
            fields=new TreeMap();
            ResultSetMetaData md=res.getMetaData();
            table=new Table(md.getTableName(1),res.getStatement().getConnection());

            int count=md.getColumnCount();
            for(int n=1;n<=count;n++)
            {
                String name=md.getColumnLabel(n);
                if(md.getColumnType(n)==java.sql.Types.LONGVARBINARY) // Don't ask me why BLOB doesn't work. MySQL weirdness?
                {
                    Blob b=res.getBlob(n);
                    if(b!=null)
                    {
                        String s=new String(b.getBytes(1,(int) b.length()));
                        fields.put(name,s);
                    }
                    else
                        fields.put(name,null);
                }
                else
                    fields.put(name,res.getObject(n));
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
    
    /**
     * @param table The table this is a row in.
     * Sets all fields null.
     */
    public Row(Table table){
        fields=new TreeMap();
        Iterator i=table.getIterator();
        while(i.hasNext()) // Put null in all the field spots.
            fields.put(i.next(),null);
        status=NEW;
        index=null;
        this.table=table;
    }

    /**
     * @param tblname The name of the table
     * @param conn A connection to pull it from.
     * Sets all fields null.
     */
    public Row(String tblname,Connection conn){
        Table table=new Table(tblname,conn);
        fields=new TreeMap();
        Iterator i=table.getIterator();
        while(i.hasNext())
            fields.put(i.next(),null);
        status=NEW;
        index=null;
        this.table=table;
    }
    
    /**
     * The fastest constructor that initializes things.
     * @param res the resultset to get data from
     * @param table the table that we're getting format from.
     */
    public Row(ResultSet res,Table table){
        fields=new TreeMap();
        this.table=table;
        status=UNCHANGED;
        index=null;
        try{
            ResultSetMetaData md=res.getMetaData();
            
            int count=md.getColumnCount();
            for(int n=1;n<=count;n++)
            {
                String name=md.getColumnLabel(n);
                if(md.getColumnType(n)==java.sql.Types.LONGVARBINARY) // Don't ask me why BLOB doesn't work. MySQL weirdness?
                {
                    Blob b=res.getBlob(n);
                    if(b!=null)
                    {
                        String s=new String(b.getBytes(1,(int) b.length()));
                        fields.put(name,s);
                    }
                    else
                        fields.put(name,null);
                }
                else
                    fields.put(name,res.getObject(n));
            }
        } catch(Exception e){
            e.printStackTrace();
        }
    }
    
    public Iterator getIterator(){
        return fields.keySet().iterator();
    }
    
    public Object get(String field){
        if(fields.containsKey(field))
            return fields.get(field);
        return "";
    }
    
    public void set(String field,Object value){
        if(fields.containsKey(field))
        {
            Object curr=fields.get(field);
            if(status==UNCHANGED)
                if((value==null ^ curr==null) || (value!=null && !(value.equals(curr))))
                    status=MODIFIED;
            fields.put(field,value);
        }
    }
    
    public void save(Connection conn) throws SQLException, NoPrimaryKeyException{
        if(status!=UNCHANGED)
        {
            if(getIndex()==null)throw new NoPrimaryKeyException();
            Statement stmt=conn.createStatement();
//            System.out.println(toString());
            stmt.execute(toString());
            if(status==NEW)
            {
                ResultSet res=stmt.executeQuery("select last_insert_id()");
                res.next();
                set(table.getIndex().getName(),res.getObject(1));
            }
            status=UNCHANGED;
        }
    }
    
    
    
    public String toString(){
        String str=new String();
        if(status==UNCHANGED)return str;
        String index=getIndex();

        if(status==DELETED)
        {
            return "delete from "+table.getName()+" where "+index+"="+get(index);
        }
        if(status==NEW)
        {
            String f=new String();
            String v=new String();
            str="insert into "+table.getName()+" (";
            Iterator currentkey=fields.keySet().iterator();
            boolean comma=false;
            while(currentkey.hasNext())
            {
                String k=(String) currentkey.next();
                if(k.equals(index))continue;
                if(comma){f+=", ";v+=", ";}
                else comma=true;
                f+=k;
                Object val=get(k);
                if(val!=null && val instanceof String)
                    v+="\""+val+"\"";
                else if(val!=null && val instanceof Boolean)
                    v+=(((Boolean)val).booleanValue()?1:0);
                else
                    v+=val;
            }
            return str+f+") values ("+v+")";
        }
        if(status==MODIFIED)
        {
            str="update "+table.getName()+" set ";
            boolean comma=false;
            Iterator currentkey=fields.keySet().iterator();
            while(currentkey.hasNext())
            {
                String k=(String) currentkey.next();
                if(k.equals(index))continue;
                if(comma)str+=", ";
                else comma=true;
                Object v=get(k);
                str+=k+"=";
                if(v!=null && v instanceof String)
                    str+="\""+v+"\"";
                else if(v!=null && v instanceof Boolean)
                    str+=(((Boolean)v).booleanValue()?1:0);
                else
                    str+=v;
            }
            return str+" where "+index+"="+get(index);
        }
        return str;
    }
    
    /**
     * @return Returns the name of the index field.
     */
    public String getIndex() {
        if(index!=null)
            return index;
        Field f=table.getIndex();
        if(f==null)
            return null;
        return f.getName();
    }
    
    public void setIndex(String index){
        this.index=index;
    }
    
    public Table getTable(){
        return table;
    }
    
    /**
     * @return Returns the status.
     */
    public int getStatus() {
        return status;
    }
    /**
     * @param status The status to set.
     */
    public void setStatus(int status) {
        this.status = status;
    }
    
    /**
     * @return the number of fields in the row
     */
    public int size(){
        return fields.size();
    }
    
    public class NoPrimaryKeyException extends Exception{};
}
