package org.apache.cactus.client.authentication;

import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLEncoder;
import java.util.StringTokenizer;

import org.apache.cactus.WebRequest;
import org.apache.cactus.client.HttpClientConnectionHelper;
import org.apache.cactus.util.Configuration;

public class FormAuthentication extends AbstractAuthentication
{
    private URL securityCheckURL = null;
    private String sessionIdCookieName = null;
    private String sessionId = null;
   
    public FormAuthentication(String theName, String thePassword)
    {
        super(theName, thePassword);
    }
    
    protected void validateName(String theName)
    {
        name = URLEncoder.encode(theName);
    }
    
    protected void validatePassword(String thePassword)
    {
        password = URLEncoder.encode(thePassword);
    }

    /**
     * @see AbstractAuthentication#configure(WebRequest)
     */
    public void configure(WebRequest theRequest)
    {
        if (sessionId == null)
        {
           authenticate();
        }
      
        if ((sessionId != null) && (! sessionId.equals("")))
        {
            theRequest.addCookie(sessionIdCookieName, sessionId);
        }
    }
    
    public void setSecurityCheckURL(URL theUrl)
    {
       securityCheckURL = theUrl;
    }
    
    public URL getSecurityCheckURL()
    {
       return securityCheckURL;
    }
    
    public void authenticate()
    {
        try
        {
            String url = Configuration.getContextURL() + "/j_security_check";

            HttpClientConnectionHelper helper = new HttpClientConnectionHelper(url);
            WebRequest request = new WebRequest();
            request.addParameter("j_username", getName(), WebRequest.POST_METHOD);
            request.addParameter("j_password", getPassword(), WebRequest.POST_METHOD);
            HttpURLConnection connection = helper.connect(request);
        
            sessionId = null;
            String cookies = connection.getHeaderField("Set-Cookie");
            if (cookies != null)
            {
                StringTokenizer st = new StringTokenizer(cookies, "&");
                while (st.hasMoreTokens())
                {
                    String cookie = st.nextToken();
                    StringTokenizer st2 = new StringTokenizer(cookie, ";");
                    String nameValue = st2.nextToken();
                    StringTokenizer st3 = new StringTokenizer(nameValue, "=");
                    String name = st3.nextToken();
                    if (name.equalsIgnoreCase("JSESSIONID"))
                    {
                        sessionIdCookieName = name;
                        sessionId = st3.nextToken();
                        break;
                    }
                }
            }
            else
            {
                // ???
                System.out.println("No Cookies Returned!");
            }

//System.out.println("Response code: " + connection.getResponseCode());
//print(connection);

            if (connection.getResponseCode() != 302)
            {
                throw new IllegalArgumentException("Unable to login, probably due to bad username/password.");
            }
            
/*
            String location = connection.getHeaderField("Location");
            if (location != null)
            {
                int index = location.indexOf(";");
                if (index != -1) location = location.substring(0, index);
                if (! location.equals(Configuration.getContextURL()))
                {
                    throw new IllegalArgumentException("Unable to login, probably due to bad username/password.");
                }
            }
            else
            {
                int i = 0;
                String key = connection.getHeaderFieldKey(i++);
                while (key != null)
                {
                    System.out.println(key + ": " + connection.getHeaderField(key));
                    key = connection.getHeaderFieldKey(i++);
                }
            }
*/
        }
        catch (Throwable e)
        {
            // This is to deal with some weirdness with the HttpURLConnection impl,
            // because the compiler complains the connect call above throws a "Throwable"
            // and must be caught. If anything happends we'll just turn it into
            // a runtime exception.
            throw new IllegalStateException(e.getClass() + ": " + e.getMessage());
        }
    }
    
    private void print(HttpURLConnection connection)
    {
        try
        {
            java.io.InputStream in = connection.getInputStream();
            
            byte[] buf = new byte[1000];
            int num = in.read(buf);
            while (num != -1)
            {
                System.out.println(new String(buf, 0, num));
                num = in.read(buf);
            }
        }
        catch (java.io.IOException e)
        {
            System.out.println(e);
        }
    }
}