/*
 * $Id: PersistentObject.java,v 1.15 2007/10/30 13:45:38 marbobo Exp $
 *
 * Copyright (c) Siemens AG 2008 
 *           (c) Universität Paderborn 2008 
 * Licensed under EUPL 1.1. 
 *
 * $Log: PersistentObject.java,v $
 * Revision 1.15  2007/10/30 13:45:38  marbobo
 * + removed unnecessary statements
 *
 * Revision 1.14  2007/08/16 11:10:53  marbobo
 * + Bugfixes
 * + Refactorings
 *
 * Revision 1.13  2006/07/07 12:32:40  lawern
 * Postgres-Bugfix
 *
 */
package vkc.db.common;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;

import vkc.db.PersistenceManager;
import vkc.db.helper.DBHelper;
import vkc.exception.DBException;
import vkc.misc.VKCLogManager;

/**
 * This class represents
 * 
 * @created 08.01.2004
 * @author koppy
 */
public abstract class PersistentObject {
    protected PersistenceManager pm = null;

    private Integer id = null;

    private String dbUrl = null;

    private String idColumn = null;

    private String table = null;

    /**
     * Only objects associated to a database table are allowed to instatiate.
     */
    private PersistentObject() {
    }

    /**
     * Construct a new PersistentObject
     * 
     */
    public PersistentObject(String table, String idColumn) {
        this();
        this.pm = PersistenceManager.getInstance();
        this.table = table;
        this.idColumn = idColumn;
    }

    /**
     * Associates this persistent object with the given dbUrl
     * 
     * @param dbUrl
     */
    public void associateWithDbUrl(String dbUrl) {
        this.dbUrl = dbUrl;
    }

    /**
     * Returns the url of the associated db
     * 
     * @return
     */
    public String getAssocDbUrl() {
        return dbUrl;
    }

    /**
     * Initializes this object by the values from Database
     * 
     * @param id
     * @throws DBException
     */
    public final void initialize(Integer id) throws DBException {
        Connection conn = null;

        try {
            conn = pm.getConnection(dbUrl);
            initialize(id, conn);
            conn.commit();
        } catch (Exception e) {
            VKCLogManager.errorLog(this, "", e.getMessage(), e);
            DBHelper.rollBack(conn);
            throw new DBException(e);
        } finally {
            DBHelper.close(conn);
        }
    }

    /**
     * Initializes this object by the values from Database.<br>
     * To be implemented by the subclasses.
     * 
     * @param id
     *            the id of the object to be initialized
     * @param conn
     *            reference to the connection object
     */
    public void initialize(Integer id, Connection conn) throws DBException {
        try {
            VKCLogManager.infoLog(this, "Call to unimplemented initialized( " + id + ", " + conn + ")");
            throw new UnsupportedOperationException("initialize(.., .., ..) not yet implemented!");
        } catch (Exception e) {
            throw new DBException(e);
        }
    }

    /**
     * Helper method
     * 
     * @param table
     * @param column
     * @param newValue
     * @param whereIDColumn
     * @param whereIDKey
     * @throws DBException
     */
    protected final void makePersistent(String table, String column, Integer newValue, String whereIDColumn, Integer whereIDKey) throws DBException {
        Connection conn = null;

        try {
            conn = pm.getConnection(dbUrl);
            makePersistent(conn, table, column, newValue, whereIDColumn, whereIDKey);
            conn.commit();
        } catch (Exception e) {
            DBHelper.rollBack(conn);
            throw new DBException(e);
        } finally {
            DBHelper.close(conn);
        }
    }

    /**
     * Helper method
     * 
     * @param conn
     * @param table
     * @param column
     * @param newValue
     * @param whereIDColumn
     * @param whereIDKey
     * @throws DBException
     */
    protected final void makePersistent(Connection conn, String table, String column, Integer newValue, String whereIDColumn, Integer whereIDKey) throws DBException {
        PreparedStatement pStmt = null;

        try {
            pStmt = conn.prepareStatement("UPDATE " + table + " SET " + column + " = ? WHERE " + whereIDColumn + " = ?");
            pStmt.setInt(1, newValue.intValue());
            pStmt.setInt(2, whereIDKey.intValue());
            pStmt.execute();
        } catch (Exception e) {
            throw new DBException(e);
        } finally {
            DBHelper.close(pStmt);
        }
    }

    /**
     * Helper method
     * 
     * @param table
     * @param column
     * @param newValue
     * @param whereIDColumn
     * @param whereIDKey
     * @throws DBException
     */
    protected final void makePersistent(String table, String column, String newValue, String whereIDColumn, Integer whereIDKey) throws DBException {
        Connection conn = null;

        try {
            conn = pm.getConnection(dbUrl);
            makePersistent(conn, table, column, newValue, whereIDColumn, whereIDKey);
            conn.commit();
        } catch (Exception e) {
            DBHelper.rollBack(conn);
            throw new DBException(e);
        } finally {
            DBHelper.close(conn);
        }
    }

    /**
     * Helper method
     * 
     * @param conn
     * @param table
     * @param column
     * @param newValue
     * @param whereIDColumn
     * @param whereIDKey
     * @throws DBException
     */
    protected final void makePersistent(Connection conn, String table, String column, String newValue, String whereIDColumn, Integer whereIDKey) throws DBException {
        PreparedStatement pStmt = null;

        try {
            pStmt = conn.prepareStatement("UPDATE " + table + " SET " + column + " = ? WHERE " + whereIDColumn + " = ?");
            pStmt.setString(1, newValue);
            pStmt.setInt(2, whereIDKey.intValue());
            pStmt.execute();
        } catch (Exception e) {
            throw new DBException(e);
        } finally {
            DBHelper.close(pStmt);
        }
    }

    /**
     * Helper method
     * 
     * @param table
     * @param column
     * @param value
     * @throws DBException
     */
    protected final void deletePersistent(String table, String column, Object value) throws DBException {
        Connection conn = null;

        try {
            conn = pm.getConnection(dbUrl);
            deletePersistent(conn, table, column, value);
            conn.commit();
        } catch (Exception e) {
            DBHelper.rollBack(conn);
            throw new DBException(e);
        } finally {
            DBHelper.close(conn);
        }
    }

    /**
     * 
     * @param conn
     * @param table
     * @param column
     * @param value
     * @throws SQLException
     */
    protected void deletePersistent(Connection conn, String table, String column, Object value) throws DBException {
        PreparedStatement pStmt = null;

        try {
            pStmt = conn.prepareStatement("DELETE FROM " + table + " WHERE " + column + " = ?");
            pStmt.setString(1, value.toString());
            pStmt.execute();
        } catch (Exception e) {
            throw new DBException(e);
        } finally {
            DBHelper.close(pStmt);
        }
    }

    /**
     * Makes this object persistent.
     * 
     * @throws DBException
     */
    public final void makePersistent() throws DBException {
        Connection conn = null;

        try {
            conn = pm.getConnection(dbUrl);
            makePersistent(conn);
            conn.commit();
        } catch (Exception e) {
            VKCLogManager.errorLog(this, "", e.getMessage(), e);
            DBHelper.rollBack(conn);
            throw new DBException(e);
        } finally {
            DBHelper.close(conn);
        }
    }

    /**
     * Makes this object persistent.<br>
     * To be implemented by the subclasses.
     * 
     * @param conn
     *            reference to the connection object
     */
    public void makePersistent(Connection conn) throws DBException {
        try {
            VKCLogManager.infoLog(this, "Call to unimplemented makePersistent( " + conn + ")");
            throw new UnsupportedOperationException("makePersistent( Connection ) not yet implemented!");
        } catch (Exception e) {
            throw new DBException(e);
        }
    }

    /**
     * Refreshes this object due to Database content
     * 
     * @throws DBException
     */
    public final void refresh() throws DBException {
        initialize(getId());
    }

    /**
     * Refreshes this object due to Database content
     * 
     * @param conn
     * @throws DBException
     */
    public final void refresh(Connection conn) throws DBException {
        initialize(getId(), conn);
    }

    /**
     * Deletes the persitent object from the database.<br>
     * Should be overriden, if the default deletion by <code>this.getId()</code>
     * not satisfies your needs.
     * 
     * @throws DBException
     */
    public final void deletePersistent() throws DBException {
        deletePersistent(getTable(), getIdColumn(), getId());
    }

    /**
     * Deletes this persistent object from the database.<br>
     * Should be overriden, if the default deletion by <code>this.getId()</code>
     * not satisfies your needs.
     * 
     * @param conn
     * @throws SQLException
     */
    public final void deletePersistent(Connection conn) throws DBException {
        deletePersistent(conn, getTable(), getIdColumn(), getId());
    }

    /**
     * Existiert dieses Objekt bereits in der DB?
     * 
     * @param conn
     * @return
     */
    public final boolean exists(Connection conn) throws SQLException {
        return DBHelper.existsEntry(conn, getTable(), getIdColumn(), getId());
    }

    /**
     * Gibt eine neue ID zurück
     * 
     * @return
     * @throws SQLException
     */
    public final Integer newId() throws DBException {
        return new Integer((int) pm.getNewId(dbUrl, getTable(), getIdColumn()));
    }

    /**
     * Returns the id of this object
     * 
     * @return null, if not yet set
     */
    public final Integer getId() {
        return id;
    }

    /**
     * Sets the id of this object
     * 
     * @param integer
     */
    public final void setId(Integer integer) {
        id = integer;
    }

    /**
     * Returns the associated table(name)
     * 
     * @return the name of the associated table
     */
    public final String getTable() {
        return table;
    }

    public final String getIdColumn() {
        return idColumn;
    }
}