/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package com.k_int.webapp.admin;

import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.UriInfo;
import javax.ws.rs.*;
import javax.ws.rs.Path;
import javax.ws.rs.POST;
import javax.ws.rs.core.MultivaluedMap;

import com.sun.jersey.api.view.Viewable;
import com.sun.jersey.api.view.ImplicitProduces;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlTransient;

import com.sun.jersey.spi.resource.Singleton;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

import org.hibernate.SessionFactory;
import org.hibernate.Session;
import org.hibernate.Query;
import org.hibernate.Transaction;
import org.hibernate.HibernateException;

import com.k_int.sql.config.*;
import java.util.List;

import javax.servlet.http.HttpServletRequest;
import org.springframework.orm.hibernate3.SessionFactoryUtils;


/**
 * REST Web Service
 *
 * @author ibbo
 */


@XmlRootElement
@ImplicitProduces("text/html;qs=5")
@XmlAccessorType(XmlAccessType.FIELD)
@Path("/admin/DataSources")
@Component
public class DataSources {

  @XmlTransient
  private static Log log = LogFactory.getLog(DataSources.class);

  @XmlTransient
  @Autowired
  @Qualifier(value="IdentSessionFactory")
  private SessionFactory factory = null;

  @XmlTransient
  @Context
  private UriInfo context;

  @XmlTransient
  @Context
  HttpServletRequest r;

  // This shares the list of data sources with the view (jsp)
  private List<com.k_int.sql.config.JDBCDataSource> sources = null;

  // This object is used to share the data source model for the form on the DataSources page
  private com.k_int.sql.config.JDBCDataSource source = null;

  @XmlTransient
  @Autowired
  private com.k_int.webapp.helpers.ConfigManager config_manager = null;


  public DataSources() {
  }

  public List<com.k_int.sql.config.JDBCDataSource> getSources() {
    return sources;
  }

  public com.k_int.sql.config.JDBCDataSource getSource() {
    log.debug("getSource()");
    return source;
  }

  public com.k_int.webapp.helpers.ConfigManager getConfigManager() {
    return config_manager;
  }

  public void setSources(List<com.k_int.sql.config.JDBCDataSource> sources) {
    this.sources = sources;
  }

  /**
   * Retrieves representation of an instance of info.made4u.made4uws.workorder.Made4UWorkOrderResource
   * @param id resource URI parameter
   * @return an instance of java.lang.String
   */
  @GET
  @Produces({MediaType.TEXT_HTML,MediaType.APPLICATION_XHTML_XML})
  public Viewable getXml() {
    log.debug("getXml "+r.getHeader("Accept"));
    // Set up a blank source for the view
    source = new com.k_int.sql.config.JDBCDataSource();
    return new Viewable("index",this);
  }

  @GET
  @Produces({MediaType.APPLICATION_JSON})
  public com.k_int.webapp.admin.DataSources getJson() {
    log.debug("getJson");
    populateSourcesList();
    return this;
  }

  private void populateSourcesList() {
    log.debug("populateSourcesList()");
    if ( factory != null ) {
      Session sess = null;
      try {
        sess = SessionFactoryUtils.getSession(factory,true);
        org.hibernate.Query q = sess.createQuery("select x from com.k_int.sql.config.JDBCDataSource x");
        sources = q.list();
      } catch (HibernateException he ) {
        log.error("[firstrun:1] Problem with resource action",he);
      } catch (Exception e ) {
        log.error("[firstrun:1]Problem with resource action",e);
      } finally {
        log.debug("Populate sources returned "+sources);
      }
    }
    else {
      log.error("No Factory available");
    }
  }

  // public Viewable processPost(@FormParam("datasource_name") String datasource_name,
  //                             @FormParam("datasource_identifier") String datasource_identifier,
  //                             @FormParam("jdbc_driver") String data_source_class_name,
  //                             @FormParam("jdbc_url") String jdbc_url,
  //                             @FormParam("jdbc_user") String jdbc_user,
  //                             @FormParam("jdbc_pass") String jdbc_pass) {
  @POST
  @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
  public Viewable processPost(MultivaluedMap<String,String> params) {
    log.debug("Process post");
    java.util.Map<String, java.lang.Class> type_map = new java.util.HashMap<String, java.lang.Class>();
    type_map.put("root",com.k_int.sql.config.JDBCDataSource.class);

    Session sess = null;
    try {
      sess = SessionFactoryUtils.getSession(factory,true);

      log.debug("Applying changeset: "+params);

      com.k_int.cb4.cbhib.CBHibProcessor hib_processor = new com.k_int.cb4.cbhib.CBHibProcessor();

      java.util.Map changeset = new java.util.HashMap();
      for ( java.util.Iterator i = params.keySet().iterator(); i.hasNext(); ) {
        String key = (String) i.next();
        String value = params.getFirst(key);
        changeset.put(key,value);
      }

      com.k_int.cb4.cbhib.CBHibProcessor.ApplyAction apply_action = com.k_int.cb4.cbhib.CBHibProcessor.ApplyAction.ACTION_MERGE;

      // Figure out what the action is
      String form_action = (String) changeset.get("FormAction");
      log.debug("Form action is "+ form_action);
      String[] action_components = null;
      if ( form_action != null ) {
        action_components = form_action.split(":");
        if ( action_components.length > 0 ) {
          if ( action_components[0].equalsIgnoreCase("save") ) {
            log.debug("SAVE action");
            apply_action = com.k_int.cb4.cbhib.CBHibProcessor.ApplyAction.ACTION_SAVE;
          }
        }
      }
    
      source = (com.k_int.sql.config.JDBCDataSource) hib_processor.applyChangeset(sess, changeset, null, type_map, apply_action);

      if ( action_components[0].equalsIgnoreCase("AddPropEntry") ) {
        String props_object_path = action_components[1];
        String prop_name_attr = action_components[2];
        String prop_name = (String) changeset.get(prop_name_attr);
        log.debug("Add prop entry "+props_object_path+","+prop_name_attr+","+prop_name);
        java.util.Map<String,String> props_object = (java.util.Map<String,String>) org.apache.commons.beanutils.PropertyUtils.getProperty(source,props_object_path);
        props_object.put(prop_name,"");
      }

      log.debug("Saving new datasource");
      org.hibernate.Transaction tx = sess.beginTransaction();
      sess.flush();
      tx.commit();

      log.debug("Result of apply changeset is "+source);
      if ( apply_action == com.k_int.cb4.cbhib.CBHibProcessor.ApplyAction.ACTION_SAVE ) {
        log.debug("Asked to save record. All completed OK, so creating a clean new source for view");
        source = new com.k_int.sql.config.JDBCDataSource();
      }

    } catch (HibernateException he ) {
      log.error("[firstrun:1] Problem with resource action",he);
    } catch (Exception e ) {
      log.error("[firstrun:1]Problem with resource action",e);
    } finally {
      // Use open session in view
      // if (sess !=null) try { sess.close(); } catch (Exception e) {  }
    }

    return new Viewable("index",this);
  }

  private void createNewDataSource(String datasource_name,
                                   String datasource_identifier,
                                   String data_source_class_name,
                                   String jdbc_user,
                                   String jdbc_pass) {
    try {
      // Step 1 - Validate the connection
      log.debug("Validate connection");
      String jdbc_url = null;
  
      if ( data_source_class_name != null ) {
        Class data_source_class = Class.forName(data_source_class_name);
        Object datasource = data_source_class.newInstance();
  
        if ( datasource != null ) {
          Class partypes[] = new Class[1];
          partypes[0] = java.lang.String.class;
          java.lang.reflect.Method meth = data_source_class.getMethod( "setUrl", partypes);
  
          if ( meth != null ) {
            Object arglist[] = new Object[1];
            arglist[0] = jdbc_url;
        
            log.debug("Invoking set url");
            Object retobj = meth.invoke(datasource, arglist);

            log.debug("Attempting to get connection from datasource");
            java.sql.Connection c = ((javax.sql.DataSource)datasource).getConnection(jdbc_user,jdbc_pass);

            if ( c != null ) {
              // Step 2 - Set up source
              if ( factory != null ) {
                Session sess = null;
                try {
                  sess = SessionFactoryUtils.getSession(factory,true);
                  // sess = factory.openSession();
                  log.debug("Got session factory");
                  Transaction tx = sess.beginTransaction();
                  java.util.Map<String,String> props = new java.util.HashMap<String,String>();
                  props.put("jdbc_url",jdbc_url);
                  com.k_int.sql.config.JDBCDataSource new_ds = new com.k_int.sql.config.JDBCDataSource(datasource_name,
                                                                                                       datasource_identifier,
                                                                                                       data_source_class_name,
                                                                                                       jdbc_user,
                                                                                                       jdbc_pass,
                                                                                                       props);
                  sess.persist(new_ds);
                  sess.flush();
                  tx.commit();
        
                  sess.clear();
                } catch (HibernateException he ) {
                  log.error("[firstrun:1] Problem with resource action",he);
                } catch (Exception e ) {
                  log.error("[firstrun:1]Problem with resource action",e);
                } finally {
                  // Use open session in view
                  // if (sess !=null) try { sess.close(); } catch (Exception e) {  }
                }
              }
              else {
                log.error("Unable to get connection from datasource");
              }
            }
            else {
              log.error("NO Factory available");
            }
          }
          else {
            log.error("Unable to find setUrl methof");
          }
        }
        else {
          log.error("Unable to create instance of datasource class");
        }
      }
      else {
        log.error("No datasource class");
      }
    }
    catch ( java.sql.SQLException sqle ) {
      log.error("Problem with datasource ",sqle);
    }
    catch ( java.lang.ClassNotFoundException cnfe ) {
      log.error("Problem with datasource class name",cnfe);
    }
    catch ( java.lang.InstantiationException ie ) {
      log.error("Problem with datasource class name",ie);
    }
    catch ( java.lang.NoSuchMethodException nsme ) {
      log.error("Problem with datasource class name",nsme);
    }
    catch ( java.lang.IllegalAccessException iae ) {
      log.error("Problem with datasource class name",iae);
    }
    catch ( java.lang.reflect.InvocationTargetException ite ) {
      log.error("Problem with datasource class name",ite);
    }
  }
}
