package com.grm.db.mail;

import java.net.Socket;
import java.io.PrintWriter;
import java.io.BufferedReader;
import java.io.IOException;
import java.net.UnknownHostException;
import java.io.InputStreamReader;
import java.io.PrintStream;

/**
Currently implemented commands:
help                                    display this help
listusers                               display existing accounts
countusers                              display the number of existing accounts
adduser [username] [password]           add a new user
verify [username]                       verify if specified user exist
deluser [username]                      delete existing user
setpassword [username] [password]       sets a user's password
setalias [username] [alias]             sets a user's alias
unsetalias [username]                   removes a user's alias
setforwarding [username] [emailaddress] forwards a user's email to another account
user [repositoryname]                   change to another user repository
shutdown                                kills the current JVM (convenient when James is run as a daemon)
quit                                    close connection

 * Describe class <code>JamesAdmin</code> here.
examples
countusers
   Existing accounts 8
listusers
  Existing accounts 8
  user: bob.hansen
  ...
verify don
  User don exist
verify jack
  User jack does not exist  
 *
 * @author <a href="mailto:dsaxton@GraphicResponseMedia.net">Don Saxton</a>
 */
public class JamesAdmin	{
    private String serverAddress = "emailstation.net";
    private int port = 4555;
    private String userId = "GRM_story"; // administrators userid
    private String password = "hoopla";

    private Socket connectionSocket=null;
    private PrintStream out = System.err;
    private BufferedReader in = null;
    private boolean connectedStatus;
    
    public JamesAdmin()
    {
    }
    public JamesAdmin(String server, int port, String uid, String pwd)
    {
	this.userId = uid;
	this.password= pwd;
	this.serverAddress = server;
	this.port = port;
	
	this.connectedStatus = connect();
    }

    //methods
    public void ensure(String _userid, String _password, String _domain)
	throws IOException 
    {
	if (serverAddress.equalsIgnoreCase(_domain)){
	    if (!isConnected()){
		connect();
	    }
	    if(verifyUser(_userid)){ // user exists in james and changing password
		if (null != _password && 0 < _password.length())
		    changePassword(_userid, _password);
	    }else
		addUser(_userid, _password); // user was not in james and should
	}else{
	    if (!isConnected()){
		connect();
	    }
	    if(verifyUser(_userid)){ // user exists in James and should not
		delUser(_userid);
	    }
	}
    }    

    public boolean isConnected()
    {
	return this.connectedStatus;
    }
    
    private void disconnect()
    {
	try
	    {
		this.out.println("quit");
		this.out.close();
		this.in.close();
		this.connectionSocket.close();
		this.connectedStatus=false;
		return;
	    }
	catch (IOException e) 
	    {
		this.connectedStatus=false;
		log("Couldn't get I/O for "
				   + "the connection to server.");
		return;
	    }
    }
    
    private boolean connect()
    {
	try
	    {
		this.connectionSocket = new Socket(this.serverAddress, this.port);
		this.out = new PrintStream(connectionSocket.getOutputStream(), true);
		this.in = new BufferedReader(new InputStreamReader(
								   connectionSocket.getInputStream()));
				//Login to the server
		String userInput;
		log (in.readLine()); //wait for the connection
		out.println(this.userId);//send userid
		log(in.readLine());//wait for \n
		out.println(this.password);//send the password
				//log (in.readLine()); 
		if ( in.readLine().indexOf("HELP") != -1 )
		    {
			this.connectedStatus=true;
			log("Server accepted connection");
			return true;
		    }
		else
		    {
			this.connectedStatus=false;
			log("Server refused connection");
			return false;
		    }
	    }
	catch (UnknownHostException e) 
	    {
		this.connectedStatus=false;
		log("Unable to connect to the host!");
		return false;
	    } 
	catch (IOException e) 
	    {
		this.connectedStatus=false;
		log("Couldn't get I/O for "
				   + "the connection to server.");
		return false;
	    }
    }		
    
    private String execute(String command)
	throws IOException 
    {
	String serverSays;
	if (connectedStatus==false)
	    connect();
	// now execute the command
	log("executing: -"+command+"-");
	out.println(command);
	out.println("###");
	String returnString="";
	char[] inChars = new char[1];
	serverSays=in.readLine();
	while( serverSays != null && serverSays.endsWith("###")==false ) 
	    {
		returnString += serverSays+"\n";
		serverSays=in.readLine();
	    }
	//			log("returning"+returnString);
	return returnString;
    }

    public boolean verifyUser(String userName)
	throws IOException 
    {
	if (!isConnected())
	    connect();
	if (!isConnected())
	    log("broken"); // do something

	String response =execute("verify "+userName);            //   verify if specified user exist
	boolean exists = false;
	if (null != response && -1 == response.indexOf("does not"))
	    exists = true;
	
	return exists;
    }

    public boolean addUser(String userName, String password)
	throws IOException 
    {
	if (!isConnected())
	    connect();
	if (!isConnected())
	    log("broken: no connection to James"); // do something

	String response = execute("adduser "+userName+" " + password);
	boolean exists = false;
	if (null != response){
	}else if ( 0 <= response.indexOf("added")){
	    exists = true;
	}else if ( 0 <= response.indexOf("already")){
	    exists = true;
	}
	
	return exists;
     }

    public boolean delUser(String _userName, String _domain)
	throws IOException 
    {
	if (serverAddress.equalsIgnoreCase(_domain)){
	    return delUser(_userName);
	}
	return true; // well, he is not here!
    }

    public boolean delUser(String userName)
	throws IOException 
    {
	if (!isConnected())
	    connect();
	if (!isConnected())
	    log("broken"); // do something

	boolean exists = false;

	String response = execute("deluser "+userName+" " + password);
	if (null != response){
	}else if ( 0 <= response.indexOf("deleted")){
	    exists = true;  // was deleted
	}else if ( 0 <= response.indexOf("Error")){
	    exists = true; // didn't exist
	
	}	
	return exists;
    }

    public boolean setPassword(String userName, String password)
	throws IOException 
    {
	if (!isConnected())
	    connect();
	if (!isConnected())
	    log("broken"); // do something

	boolean exists = false;

	String response = execute("setpassword "+userName+" " + password);
	if (null != response){
	}else if ( 0 <= response.indexOf("reset")){
	    exists = true;  // was deleted
	}else if ( 0 <= response.indexOf("Error")){
	    exists = true; // didn't exist
	
	}	
	return exists;
    }

    public boolean changePassword(String userName, String password)
	throws IOException 
    {
	//if (verifyUser(userName))  // james 2 added setpassword
	//    delUser(userName);
	return setPassword(userName,password);
    }


    private void log(String note){
	System.err.println(getClass().getName()+" "+note);
    }
}

