package com.myapp.castor;

import java.util.Hashtable;
import java.util.Vector;
import java.util.Enumeration;
import java.util.Date;
import java.io.PrintWriter;
import java.io.InputStreamReader;
import java.io.Serializable;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.DriverManager;
import org.exolab.castor.jdo.JDO;
import org.exolab.castor.jdo.Database;
import org.exolab.castor.jdo.OQLQuery;
import org.exolab.castor.jdo.QueryResults;
import org.exolab.castor.persist.spi.Complex;
import org.exolab.castor.mapping.Mapping;
import org.xml.sax.InputSource;
import java.util.*;
import java.net.*;
import com.myapp.exceptions.*;
import com.myapp.common.*;
import com.myapp.util.LogWrapper;
/**
 * Implementation of PersistenceManager
 * interface that uses Castor
 * @author  Marco Mistroni
 * @version 1.0
 */
 
class CastorPersistenceManager implements PersistenceManager {
	
	private Mapping  _mapping;
	private JDO      _jdo;
	private LogWrapper log = new LogWrapper(this.getClass().getName());
	private Hashtable queries = new Hashtable();	


	/**
	 * Constructor
	 */
	CastorPersistenceManager() {
		log.debug("Creating CastorPM..");
			
	}
	
	/**
	 * Initializes Castor Persitence Manager.
	 * @param mapping fully qualified name of
	 *	  the mapping file
	 * @param databas fully qualified name of
	 *        the database file
	 * @param queries queries 
	 * @throws an exception if something went wrong
	 */
	 void init(String mapping, 
	 	   String database,
		   Hashtable queries) throws Exception {
		try {
		System.err.println("Initializing.. with:" + mapping);
		
		_mapping = new Mapping( getClass().getClassLoader() );
		_mapping.setLogWriter(new PrintWriter(System.out) );
		System.err.println("CastorPM. Loading mapping file....!!");
		InputStream stream = this.getClass().getResourceAsStream(mapping);
		_mapping.loadMapping(new InputSource( stream ) );
 		System.err.println("Creating JDO...");
		_jdo = new JDO();
                System.err.println("JDO created...");
		_jdo.setLogWriter(new PrintWriter(System.out));
		System.err.println("loading URL classloader...");
		URL url = this.getClass().getClassLoader().getResource("/database.xml");
		System.err.println("URL LOADED,AND IT IS:" + url.toString());
		_jdo.loadConfiguration(url.toString());
		System.err.println("setting dbname.");
                _jdo.setDatabaseName( "test" );

		this.queries = queries;


		System.err.println("Initialization completed..");
		} catch(Throwable e) {
			System.err.println("--- error in initializing\n" +  e);
			throw new Exception("Error in initializing cpmgr!" + e.toString());
		}
	 }
		
	
	public void insert(Entry data) throws PersistenceException {
		try {
			Database db = null;
			db = _jdo.getDatabase();
			if(db == null)
				System.err.println("db isnull");
			else
				System.err.println("db is NOT null!!");
			System.err.println("before beginning....");
			db.begin();
			CastorEntry entry = (CastorEntry)data;
			db.create(data);
			db.commit();
			System.err.println("Entry created..");
			db.close();
		} catch(Exception e) {
			log.error("Exception in creating CastorEntry\n" + e);
			throw  new PersistenceException(e);
		}
	}
	
	public void update(Entry entry) throws PersistenceException{}
	
	public void delete(Entry data) throws PersistenceException{
		try {
			// Only way to delete with Castor is to
			// load the object again since load and delete
			// have to be in same transaction/
			Database db = null;
			db = _jdo.getDatabase();
			db.begin();
			CastorEntry tmp = (CastorEntry)data;
			CastorEntry entry = (CastorEntry)db.load(tmp.getClass(), new Integer(tmp.getId()));
			db.remove((CastorEntry)entry);
			db.commit();
			db.close();
			System.err.println("Entry deleted..");
		} catch(Exception e) {
			log.error("Exception in creating Deleting CastorEntry\n" + e);
			throw  new PersistenceException(e);
		}	
	}
	
	public Collection query(String query, Object[] paramValues) throws PersistenceException{
				
		Collection returnResults = new Vector();
		OQLQuery      entryQuery;
		QueryResults results = null;
		try {
			System.err.println("Test Start..");
			Database db = _jdo.getDatabase();
			entryQuery = getQuery(query,paramValues,db);
			db.begin();
			results = entryQuery.execute();
			while(results.hasMore()) {
				returnResults.add(results.next());
			}
			db.commit();
			db.close();
			System.err.println("Query successful!!");
	        } catch(Exception e) {
			log.error("Exception in querying CastorEntry\n" + e);
			throw  new PersistenceException(e);
		}
	
		return returnResults;
	
	}
					
	OQLQuery getQuery(String query,
				  Object[] paramValues,
				  Database db) throws Exception{
		
		OQLQuery oQlquery = null;
		      
	      
		String _query = (String)queries.get(query);

		log.debug("-------- CPM. gettingquery:" + _query);
		oQlquery = db.getOQLQuery(_query);
		log.debug("-------- we got query");

		if(paramValues != null) {
			for(int i=0; i  < paramValues.length; i++) {
				Object value = paramValues[i];
				log.debug("CPMgr.binding" + value);
				oQlquery.bind(value);
			}
		}
		
		return oQlquery;
	}


	/**
       * This method allows us to fetch a
       * predefined query given its name.
       */
      void populateQueries() {

		log.debug("************************** CMP.POPULATE");	

		String userSql = "SELECT u from com.myapp.castor.CastorUser u " +
				     "WHERE u.username = $1 and u.password=$2";

		String typesSql = "SELECT t from com.myapp.castor.CastorExpenseType t";

		String dateQuery = "SELECT e from com.myapp.castor.CastorEntry e " +
					 " WHERE e.date >= $1 and e.date <= $2";

		String typeQuery = "SELECT e from com.myapp.castor.CastorEntry e " +
					 " WHERE e.type = $1 ";

		String dateTypeQuery = "SELECT e from com.myapp.castor.CastorEntry e " +
					 " WHERE e.type = $1 and e.date >= $2 and e.date <= $3";
			      
		String genericQuery = "SELECT e from com.myapp.castor.CastorEntry e WHERE ";
		queries.put("User", userSql);
		queries.put("Types", typesSql);
		queries.put("TypeQuery", typeQuery);
		queries.put("DateQuery", dateQuery);
		queries.put("DateTypeQuery", dateTypeQuery);

		System.err.println("------- queries =" + queries);
		
	
	}

	public Entry getEmptyEntry() {
		return new CastorEntry();
	}
}
