
package rob.servlets.addressbook ;

// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2, or (at your option)
// any later version.<P>
// 
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.<P>
// 
// To obtain a copy of the GNU General Public License write to the Free
// Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. <P>


import java.io.* ;
import java.util.* ;
import java.sql.* ;

import javax.servlet.* ;
import javax.servlet.http.* ;

import org.postgresql.util.UnixCrypt ;

/**
 * <code>AddressBookAppletServlet</code> is the same code as 
 * <code>AddressBookServlet</code> except that it is meant for returning the 
 * information to an applet instead of a browser.  The main difference is that
 * most methods return just a status message, while the search function writes
 * a Java Object to the OutputStream, which is reconstructed by the applet on 
 * the other end.  
 *
 * This extends <code>AddressBookServlet</code> to avoid repeating too much code,
 * and with a little re-writing most of the code here could also be eliminated.
 *
 * Created: Wed Aug 16 14:36:00 2000
 *
 * @author <a href="mailto:rob@corwin">Robert Judd</a>
 * @version 1.0
 * @since 1.0
 * @see AddressBookServlet
 */
public class AddressBookAppletServlet extends AddressBookServlet {

    /**
     * Process a <code>GET</code> request - just return the date.
     *
     * @param req the <code>HttpServletRequest</code> object passed in by the
     *            server
     * @param res the <code>HttpServletResponse</code> object passed in by the
     *            server
     *
     * @exception <code>ServletException</code> if anything goes wrong with the
     *            servlet/server communication
     * @exception <code>IOException</code> if anything goes wrong with the io
     *            streams.
     */
    public void doGet(HttpServletRequest req, HttpServletResponse res)
    	throws ServletException, IOException {
	
	res.setContentType("text/html") ;

	// We no longer call this here
	//PrintWriter out = res.getWriter() ;
	// 
	// In order to print out text (i.e. an HTML page) use the PrintWriter
	// obtained from res.getWriter().  For binary data use the 
	// OutputStream obtained from res.getOutputStream().  Only one
	// of these methods may be called in a single request, so we delay
	// calling them here until we know what type of data we want to 
	// return.
	
	if (!dbClassLoaded) {
	    error(res.getWriter(), "Unable to load database driver.") ;
	    return ;
	}

	Properties p = getParameters(req) ;

	String action = p.getProperty("action") ;

	if (action == null || action.equals(""))
	    login(res.getWriter()) ;
	else if (action.equals("Open"))
	    open(res.getWriter(), p) ;
	else if (action.equals("Add"))
	    add(res.getWriter(), p) ;
	else if (action.equals("Save"))
	    save(res.getWriter(), p) ;
	else if (action.equals("Delete"))
	    delete(res.getWriter(), p) ;
	else if (action.equals("Log Out"))
	    logout(res.getWriter(), p) ;
	else if (action.equals("Search"))
	    search(res.getOutputStream(), p) ;
	else 
	    error(res.getWriter(), "Your command: "+action+" was not understood.") ;
	

    }  

    // ----------- The methods to handle the different requests -------------

    public void login(PrintWriter out) {

	// Nothing to do yet.  Just return the page
	new AppletLoginPage().write(out) ;
	if (out.checkError()) 
	    error(out, "There was an error returning the login page.") ;

    }

    public void open(PrintWriter out, Properties params) {

	// Get the userid (param "userid") and password (param "password")
	// Look the user up in the DB
	// if success, then return the initial page,
	// else return and error message

	String userid = params.getProperty("userid") ;
	String password = params.getProperty("password") ;

	if (userid == null || userid.equals(""))
	    error(out, "Please specify a userid.") ;
	else if (password == null)
	    error(out, "Please specify a password.") ;
	else {

	    try {
		String[][] response = executeQuery
		    ("SELECT password FROM Users WHERE userid = '"+userid+"'");
		if (response == null || response.length == 0)
		    error(out, "No such user id.") ;
		else if (!UnixCrypt.matches(response[0][0], password))
		    error(out, "Invalid user id/password.") ;
		else { // We're in!!!

		    HttpSession session = (HttpSession) params.get("HttpSession") ;
		    session.putValue("IsLoggedIn", Boolean.TRUE) ;
		    session.putValue("userid", userid) ;


		    new AppletPage(userid).write(out) ;

		}
	    } catch (SQLException sqle) {
		error(out, sqle.getMessage()) ;
	    }
	}

    }

    public void add(PrintWriter out, Properties params) {

	String userid = validate(params) ;
	if (userid == null)
	    login(out) ;
	else {
	    StringBuffer sql = new StringBuffer("INSERT INTO Addresses ( ") ;
	    sql.append("userid") ;
	    for (int i=0, max=fields.length; i<max; ++i) 
		sql.append(", ").append(fields[i]) ;
	    sql.append(") VALUES ('").append(userid).append('\'') ;
	    
	    for (int i=0, max=fields.length; i<max; ++i) {
		sql.append(", '") ;
		String value = params.getProperty(fields[i]) ;
		if (value != null) sql.append(value) ;
		sql.append('\'') ;
	    }
	    sql.append(')') ;
	    String msg = "" ;
	    try {
		int count = executeUpdate(sql.toString()) ;
		if (count >= 1) msg = "Address added." ;
		else msg = "Strange error: nothing added." ;
	    } catch (SQLException sqle) {
		msg = sqle.getMessage() ;
	    }
	    out.println(msg);
	    out.flush() ;
	    out.close() ;
	}
    }

    public void save(PrintWriter out, Properties params) {

	String userid = validate(params) ;
	String addressid = params.getProperty("addressid", "") ;
	String msg = "" ;
	if (userid == null)
	    msg = "No userid." ;
	else if (addressid.equals("")) 
	    msg = "No address given." ;
	else {
	    StringBuffer sql = new StringBuffer("UPDATE Addresses SET ") ;

	    String sep = "" ;
	    for (int i=0, max=fields.length; i<max; ++i) {
		sql.append(sep).append(fields[i]).append(" = '") ;
		String value = params.getProperty(fields[i], "") ;
		sql.append(value).append('\'') ;
		sep = ", " ;
	    }
		
	    sql.append(" WHERE userid = '").append(userid)
		.append("' AND addressid = '").append(addressid).append('\'') ;
	    try {
		int count = executeUpdate(sql.toString()) ;
		if (count >= 1) msg = "Address saved." ;
		else msg = "Strange error: nothing saved." ;
	    } catch (SQLException sqle) {
		msg = sqle.getMessage() ;
	    }
	}
    
	out.println(msg);
	out.flush() ;
	out.close() ;

    }

    public void delete(PrintWriter out, Properties params) {

	String userid = validate(params) ;
	String addressid = params.getProperty("addressid", "") ;
	String msg = "" ;
	if (userid == null)
	    msg = "No userid." ;
	else if (addressid.equals("")) 
	    msg = "No address given." ;
	else {
	    try {
		int count = executeUpdate
		    ("DELETE FROM Addresses WHERE userid = '"+userid+
		     "' AND addressid = '"+addressid+"' ") ;
		if (count >= 1) msg = "Address deleted." ;
		else msg = "No records match" ;
	    } catch (SQLException sqle) {
		msg = sqle.getMessage() ;
	    }
	}
	out.println(msg);
	out.flush() ;
	out.close() ;
	
    }

    /**
     * This is the only method that differs from <code>AddressBookServlet</code> 
     * in any major way.  Once we have the list of addresses, as a double array
     * object we create an ObjectOutputStream that we can use to write the 
     * Object.  The applet the other end reads it with an ObjectInputStream
     * and can decode the original array.
     *
     * @param out an <code>OutputStream</code> value
     * @param params a <code>Properties</code> value
     */
    public void search(OutputStream out, Properties params) {

	String userid = validate(params) ;
	String msg = "" ;
	if (userid == null)
	    msg = "No userid." ;
	else {
	    StringBuffer sql = 
		new StringBuffer("SELECT ") ;
	    String sep = "" ;
	    for (int j=0, max=fields.length; j<max; ++j) {
		sql.append(sep).append(fields[j]) ;
		sep = ", " ;
	    }
	    sql.append(", addressid") ;
	    sql.append(" FROM Addresses WHERE userid = '") ;
	    sql.append(userid).append('\'') ;
	    
	    String search = params.getProperty("search") ;
	    String field = params.getProperty("field") ;
	    if (search != null && !search.equals("") && field != null) {
		if (field.equals("all")) {
		    sep = "" ;
		    sql.append(" AND ( ") ;
		    for (int j=0, max=fields.length; j<max; ++j) {
			sql.append(sep).append(fields[j]).append(" ~* '")
			    .append(search).append('\'') ;
			sep = " OR " ;
		    }
		    sql.append(')') ;
		} else 
		    sql.append(" AND ").append(field).append(" ~* '")
			.append(search).append('\'') ;
	    }

	    try {
		log("SQL: "+sql.toString()) ;
		String[][] response = executeQuery(sql.toString()) ;
		log(""+response) ;
		if (response == null) response = new String[0][0] ;

		// Serialise and send the array
		ObjectOutputStream objout = new ObjectOutputStream(out) ;
		objout.writeObject(response) ;
		objout.flush() ;
		objout.close() ;
		return ;

	    } catch (SQLException sqle) {
		msg = sqle.getMessage() ;
	    } catch (IOException ioe) {
		msg = ioe.getMessage() ;
	    }
	}

	log(msg) ;
	PrintWriter pout = new PrintWriter(out) ;
	pout.println(msg);
	pout.flush() ;
	pout.close() ;
    }

}
