/**
 * JOnAS: Java(TM) Open Application Server
 * Copyright (C) 2010 Bull S.A.S.
 * Contact: jonas-team@ow2.org
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or any later version.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
 * USA
 *
 * --------------------------------------------------------------------------
 * $Id$
 * --------------------------------------------------------------------------
 */
package org.ow2.jonas.itests.cargo.jrmp;

import java.io.IOException;
import java.net.URLConnection;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * HTTP cookie manager.
 * 
 * @author S. Ali Tokmen
 */
public class CookieManager {

    private static final String DATE_FORMAT = "EEE, dd-MMM-yyyy hh:mm:ss z";

    private static final DateFormat dateFormat = new SimpleDateFormat(DATE_FORMAT);

    private List<String> cookies;

    /**
     * Constructs a cookie manager with no cookies.
     */
    public CookieManager() {
        this.cookies = new ArrayList<String>();
    }

    /**
     * Constructs a cookie manager with no cookies.
     * 
     * @param copy CookieManager to copy cookies from.
     */
    public CookieManager(CookieManager copy) {
        if (copy != null) {
            this.cookies = new ArrayList<String>(copy.cookies);
        } else {
            this.cookies = new ArrayList<String>();
        }
    }

    /**
     * Adds a cookie to the cookies list.
     * 
     * @param cookie Cookie string to add.
     */
    private void addCookie(String cookie) {
        String key = cookie.substring(0, cookie.indexOf('='));
        for (String c : this.cookies) {
            String k = c.substring(0, c.indexOf('='));
            if (k.equals(key)) {
                this.cookies.remove(cookie);
                break;
            }
        }
        this.cookies.add(cookie);
    }

    /**
     * Retrieves and stores cookies returned by the host on the other side of
     * the the open java.net.URLConnection. The connection MUST have been opened
     * using the <i>connect()</i> method or a IOException will be thrown.
     * 
     * @param conn A URLConnection - must be open, or IOException will be thrown
     * @throws IOException Thrown if <i>conn</i> is not open.
     */
    public void storeCookies(URLConnection conn) throws IOException {
        String headerName = null;
        for (int i = 1; (headerName = conn.getHeaderFieldKey(i)) != null; i++) {
            if ("Set-Cookie".equals(headerName)) {
                addCookie(conn.getHeaderField(i));
            }
        }
    }

    /**
     * Prior to opening a URLConnection, calling this method will set all
     * unexpired cookies that match the path or subpaths for thi underlying URL.
     * The connection MUST NOT have been opened method or an IOException will be
     * thrown.
     * 
     * @param conn A URLConnection - must NOT be open, or IOException will be
     *        thrown
     * @throws IOException Thrown if <i>conn</i> has already been opened.
     * @throws ParseException Thrown if the "expires" field of the cookie is not
     *         a valid date.
     */
    public void setCookies(URLConnection conn) throws IOException, ParseException {
        StringBuilder cookies = new StringBuilder();
        for (String cookie : this.cookies) {
            String c = null;
            String domain = "";
            String path = "";
            Date expires = null;
            for (String part : cookie.split(";")) {
                if (c == null) {
                    c = part;
                }
                String[] parts = part.trim().split("=");
                if (parts.length == 2) {
                    if ("domain".equals(parts[0])) {
                        domain = parts[1];
                    } else if ("path".equals(parts[0])) {
                        path = parts[1];
                    } else if ("expires".equals(parts[0])) {
                        expires = dateFormat.parse(parts[1]);
                    }
                }
            }
            if (c == null) {
                break;
            }
            if (expires != null) {
                if ((new Date()).after(expires)) {
                    break;
                }
            }
            if (!conn.getURL().getHost().endsWith(domain)) {
                break;
            }
            if (!conn.getURL().getPath().startsWith(path)) {
                break;
            }
            if (cookies.length() > 0) {
                cookies.append("; ");
            }
            cookies.append(c);
        }
        if (cookies.length() > 0) {
            conn.setRequestProperty("Cookie", cookies.toString());
        }
    }

    @Override
    public String toString() {
        return super.toString() + this.cookies;
    }
}
