/**
 * Title:
 * @version:    $Id: SearchModel.java,v 1.1 2004/11/15 13:47:50 rob Exp $
 * Copyright:   Copyright (C) 2003 Ian Ibbotson
 * @author:     Ian Ibbotson
 * Company:
 * Description:
 */

package com.k_int.AdminApp.models.Search;


import java.io.*;

import java.util.*;

import com.k_int.QueryDescriptor.*;
import com.k_int.oql.iface.*;

import net.sf.hibernate.*;
import net.sf.hibernate.type.*;

import javax.naming.*;

import java.util.logging.*;

import org.apache.commons.collections.LRUMap;

public class SearchModel
{
    private static Logger cat = Logger.getLogger("com.k_int.AdminApp.models.Search.SearchModel");
  private QueryDescriptor qd;
  private Hashtable values = new Hashtable();
  private Session session = null;
  private int row_count = 0;
  private java.util.List qry_result;
  private LRUMap row_cache = new LRUMap(50); // Cache upto 50 rows of data for the UI.
  private Object[] current_row = null;
  private int current_row_num = -1;

  public SearchModel(String descriptor_id, Session session) throws NamingException
  {
    cat.fine("New SearchModel......");
    Hashtable descriptors;
    Hashtable session_factories;
    Hashtable env = new Hashtable();
  
    env.put( Context.INITIAL_CONTEXT_FACTORY, "tyrex.naming.MemoryContextFactory" );
    env.put( Context.PROVIDER_URL, "XDAdmin" );
    Context ctx = new InitialContext( env );
    descriptors = (Hashtable) ctx.lookup("SearchDescriptors");
    session_factories = (Hashtable) ctx.lookup("SessionFactories");
  
    cat.finest("Descriptors:"+descriptors);
    cat.finest("SessionFactories:"+session_factories);

    cat.finest("Lookup "+descriptor_id);
  
    qd = (QueryDescriptor) descriptors.get(descriptor_id);

    cat.finest("Descriptor "+descriptor_id+"="+qd);

    this.session = session;
  }

  public SearchModel(String descriptor_id, String repository_id) throws NamingException
  {
    try
    {
      cat.fine("New SearchModel......");
      Hashtable descriptors;
      Hashtable session_factories;
      Hashtable env = new Hashtable();
  
      env.put( Context.INITIAL_CONTEXT_FACTORY, "tyrex.naming.MemoryContextFactory" );
      env.put( Context.PROVIDER_URL, "XDAdmin" );
      Context ctx = new InitialContext( env );
      descriptors = (Hashtable) ctx.lookup("SearchDescriptors");
      session_factories = (Hashtable) ctx.lookup("SessionFactories");
  
      cat.finest("Descriptors:"+descriptors);
      cat.finest("SessionFactories:"+session_factories);

      cat.finest("Lookup "+descriptor_id);
  
      qd = (QueryDescriptor) descriptors.get(descriptor_id);

      cat.finest("Descriptor "+descriptor_id+"="+qd);

      SessionFactory sf = (SessionFactory) session_factories.get(repository_id);
      session = sf.openSession();
    }
    catch ( net.sf.hibernate.HibernateException he )
    {
        cat.log(Level.SEVERE,"Error",he);
    //  he.printStackTrace();
    }
  }

  public QueryDescriptor getQueryDescriptor()
  {
    return qd;
  }

  public int evaluate()
  {
    // Step one.. Generate the count query
    row_cache.clear();
    row_count = 0;
    current_row = null;
    current_row_num = -1;

    try
    {
      Vector bind_vars = new Vector();
      Vector bind_types = new Vector();
      OQLSelectStatement s = com.k_int.oql.util.OQLSelectFactory.createStatement(qd,
                                                                                 bind_vars,
                                                                                 bind_types,
                                                                                 values,
                                                                                 "Count");

      // Hmm... we want to count (rootscope.id)

      cat.finest("New statement: "+s);
      cat.finest("bind vars: "+bind_vars);

      Iterator iter = session.iterate(s.toString(), bind_vars.toArray(), (Type[])bind_types.toArray(new Type[0]));
      if ( iter.hasNext() )
      {
        Integer count = (Integer) iter.next();
        row_count = count.intValue();
        cat.finest("Result count: "+row_count);
      }
      else 
      {
        cat.finest("No result count");
      }

      iter = null;

      if ( row_count > 0 )
      {
        cat.finest("Process real search....");
        bind_types.clear();
        bind_vars.clear();

        OQLSelectStatement s2 = com.k_int.oql.util.OQLSelectFactory.createStatement(qd,
                                                                                    bind_vars,
                                                                                    bind_types,
                                                                                    values,
                                                                                    "Default");
        cat.finest("New query is : "+s2);
  
        qry_result = session.find(s2.toString(), bind_vars.toArray(), (Type[])bind_types.toArray(new Type[0]));
      }
    }
    catch ( net.sf.hibernate.HibernateException he )
    {
        cat.log(Level.SEVERE,"Error",he);
     // he.printStackTrace();
    }

    return row_count;
  }

  public void setSearchValue(String name, Object value)
  {
    values.put(name,value);
  }

  public void close()
  {
    try
    {
      cat.finest("Closing....");
      session.close();
    }
    catch ( Exception e )
    { 
        cat.log(Level.SEVERE,"Error",e);
      //e.printStackTrace();
    }
  }

  public int getRowCount()
  {
    return row_count;
  }

  public Object getValueAt(int row_num, int col)
  {
    // Is the requested row the "Current row"
    if ( row_num != current_row_num )
    {
      // try to get the row from the cache
      current_row = (Object[])(row_cache.get(new Integer(row_num)));

      // Check it was found in the cache
      if ( current_row == null )
      {
        // Oops.. not found in the cache.. Better grab it from the database
        current_row = getDataRow(row_num);
        row_cache.put(new Integer(row_num),current_row);
      }

      current_row_num = row_num;
    }

    return current_row[col];
  }

  private Object[] getDataRow(int row)
  {
  	cat.finest("result of getDataRow is"+qry_result.get(row));
    return (Object[])qry_result.get(row);
  }

  public Object getResultSetObject(int row)
  {
    Object o = null;
    try
    {
      cat.finest("getResultSetObject, row="+row+", class="+qd.getBaseClassName());
      Class c = Class.forName(qd.getBaseClassName());
      o = session.load(c, (Serializable) getValueAt(row,0));
    }
    catch ( Exception e )
    {
        cat.log(Level.SEVERE,"Error",e);
      System.exit(1);
    }
    return o;
  }

  public Session getSession()
  {
    return session;
  }

  protected void finalize()
  {
    cat.finest("SearchModel::finalize()");
  }

  public void clearCache()
  {
    row_cache.clear();
  }
  
  public void resetSearchValues()
  {
  	values.clear();
  }
}
