

import java.io.IOException;
import java.net.URISyntaxException;
import java.rmi.RemoteException;
import java.util.NoSuchElementException;
import java.util.StringTokenizer;

import javax.servlet.http.HttpServletResponse;
import javax.xml.rpc.ServiceException;

import org.apache.axis.encoding.Base64;
import org.apache.commons.httpclient.Cookie;
import org.apache.commons.httpclient.Header;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpException;
import org.apache.commons.httpclient.cookie.CookiePolicy;
import org.apache.commons.httpclient.cookie.CookieSpec;
import org.apache.commons.httpclient.methods.PostMethod;

import de.escidoc.core.common.exceptions.application.security.AuthenticationException;
import de.escidoc.core.common.exceptions.system.SqlDatabaseSystemException;
import de.escidoc.core.common.exceptions.system.WebserverSystemException;
import de.mpg.escidoc.services.framework.PropertyReader;
import de.mpg.escidoc.services.framework.ServiceLocator;

/**
 * TODO Description.
 * 
 * @author frank (initial creation)
 * @author $Author$ (last modification)
 * @version $Revision$ $LastChangedDate$
 */
public class Login
{
    protected String userHandle;
    private static final int NUMBER_OF_URL_TOKENS = 2;

    /**
     * Logs in the given user with the given password.
     * 
     * @param userid The id of the user to log in.
     * @param password The password of the user to log in.
     * @return The handle for the logged in user.
     * @throws HttpException
     * @throws IOException
     * @throws ServiceException
     * @throws URISyntaxException
     */
    protected String login(String userid, String password) throws HttpException, IOException, ServiceException,
            URISyntaxException
    {
        String frameworkUrl = ServiceLocator.getFrameworkUrl();
        StringTokenizer tokens = new StringTokenizer(frameworkUrl, "//");
        if (tokens.countTokens() != NUMBER_OF_URL_TOKENS)
        {
            throw new IOException("Url in the config file is in the wrong format, needs to be http://<host>:<port>");
        }
        tokens.nextToken();
        StringTokenizer hostPort = new StringTokenizer(tokens.nextToken(), ":");
        /*if (hostPort.countTokens() != NUMBER_OF_URL_TOKENS)
        {
            throw new IOException("Url in the config file is in the wrong format, needs to be http://<host>:<port>");
        }*/
        String host = hostPort.nextToken();
        int port;
        try
        {
            port = Integer.parseInt(hostPort.nextToken());
        }
        catch (NoSuchElementException e)
        {
            port = 8080;
        }
        HttpClient client = new HttpClient();
        client.getHostConfiguration().setHost(host, port, "http");
        client.getParams().setCookiePolicy(CookiePolicy.BROWSER_COMPATIBILITY);
        PostMethod login = new PostMethod(frameworkUrl + "/aa/j_spring_security_check");
        login.addParameter("j_username", userid);
        login.addParameter("j_password", password);
        client.executeMethod(login);
        // System.out.println("Login form post: " + login.getStatusLine().toString());
        login.releaseConnection();
        CookieSpec cookiespec = CookiePolicy.getDefaultSpec();
        Cookie[] logoncookies = cookiespec.match(host, port, "/", false, client.getState().getCookies());
        // System.out.println("Logon cookies:");
        Cookie sessionCookie = logoncookies[0];
        /*
         * if (logoncookies.length == 0) { System.out.println("None"); } else { for (int i = 0; i < logoncookies.length;
         * i++) { System.out.println("- " + logoncookies[i].toString()); } }
         */
        PostMethod postMethod = new PostMethod("/aa/login");
        postMethod.addParameter("target", frameworkUrl);
        client.getState().addCookie(sessionCookie);
        client.executeMethod(postMethod);
        // System.out.println("Login second post: " + postMethod.getStatusLine().toString());
        if (HttpServletResponse.SC_SEE_OTHER != postMethod.getStatusCode())
        {
            throw new HttpException("Wrong status code: " + login.getStatusCode());
        }
        userHandle = null;
        Header[] headers = postMethod.getResponseHeaders();
        for (int i = 0; i < headers.length; ++i)
        {
            if ("Location".equals(headers[i].getName()))
            {
                String location = headers[i].getValue();
                int index = location.indexOf('=');
                userHandle = new String(Base64.decode(location.substring(index + 1, location.length())));
            }
        }
        if (userHandle == null)
        {
            throw new ServiceException("User not logged in.");
        }
        return userHandle;
    }

    public String loginPubManUser() throws Exception
    {
        if (this.userHandle == null)
        {
            return login("siedersleben", "pubman"); //TODO
        }
        else
        {
            return this.userHandle;
        }
    }
    
    /**
     * Logs the user roland in and returns the corresponding user handle.
     * 
     * @return userhandle
     * @throws ServiceException
     * @throws HttpException
     * @throws IOException
     */
    protected  String loginSystemAdministrator() throws ServiceException, HttpException, IOException, URISyntaxException
    {
        return login(PropertyReader.getProperty("framework.admin.username"), PropertyReader.getProperty("framework.admin.password"));
    }
    
    public void logout(String handle) throws WebserverSystemException, SqlDatabaseSystemException,
    AuthenticationException, RemoteException, ServiceException, URISyntaxException
    {
        ServiceLocator.getUserManagementWrapper(handle).logout();
    }
 
    public String getUserHandle()
    {
        return userHandle;
    }

    public void setUserHandle(String userHandle)
    {
        this.userHandle = userHandle;
    }
}
