package industries.doublehelix.furrynotemanager.siteImporters;

//Original from: http://java.sun.com/developer/JDCTechTips/2005/tt0913.html
//Corrected by Klaue

import java.net.CookieHandler;
import java.net.URI;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

public class ListCookieHandler extends CookieHandler {

	// "Long" term storage for cookies, not serialized so only
	// for current JVM instance
	private List<Cookie> cache = Collections.synchronizedList(new ArrayList<Cookie>());

	/**
	 * Saves all applicable cookies present in the response headers into cache.
	 * 
	 * @param uri
	 *            URI source of cookies
	 * @param responseHeaders
	 *            Immutable map from field names to lists of field values
	 *            representing the response header fields returned
	 */
	@Override
	public synchronized void put(URI uri, Map<String, List<String>> responseHeaders) {
		List<String> setCookieList = responseHeaders.get("Set-Cookie");
		if (setCookieList != null) {
			for (String item : setCookieList) {
				Cookie cookie = null;
				try {
					cookie = new Cookie(uri, item);
				} catch (Exception e) {
					//System.err.println("Ignoring cookie: " + e.getLocalizedMessage());
					continue;
				}
				// Remove cookie if it already exists
				// New one will replace
				synchronized(this.cache) {
					Iterator<Cookie> iter = this.cache.iterator();
					while (iter.hasNext()) {
						Cookie existingCookie = iter.next(); 
						if ((cookie.domain.equals(existingCookie.domain))
								&& (cookie.getName().equals(existingCookie.getName()))) {
							this.cache.remove(existingCookie);
							break;
						}
					}
					this.cache.add(cookie);
				}
			}
		}
	}

	/**
	 * Gets all the applicable cookies from a cookie cache for the specified uri
	 * in the request header.
	 * 
	 * @param uri
	 *            URI to send cookies to in a request
	 * @param requestHeaders
	 *            Map from request header field names to lists of field values
	 *            representing the current request headers
	 * @return Immutable map, with field name "Cookie" to a list of cookies
	 */
	@Override
	public synchronized Map<String, List<String>> get(URI uri,
			Map<String, List<String>> requestHeaders) {

		// Retrieve all the cookies for matching URI
		// Put in semicolon-separated list
		StringBuilder cookies = new StringBuilder();
		synchronized(this.cache) {
			ArrayList<Cookie> expiredCookies = new ArrayList<Cookie>();
			
			Iterator<Cookie> iter = this.cache.iterator();
			while (iter.hasNext()) {
				Cookie cookie = iter.next(); 
				if (cookie.hasExpired()) {
					expiredCookies.add(cookie);
				} else if (cookie.matches(uri)) {
					if (cookies.length() > 0) {
						cookies.append("; ");
					}
					cookies.append(cookie.toString());
				}
			}
			// Remove cookies that have expired
			for (Cookie c : expiredCookies) {
				this.cache.remove(c);
			}
		}

		// Map to return
		Map<String, List<String>> cookieMap = new HashMap<String, List<String>>(requestHeaders);

		// Convert StringBuilder to List, store in map
		if (cookies.length() > 0) {
			List<String> list = Collections.singletonList(cookies.toString());
			cookieMap.put("Cookie", list);
		}
		// System.out.println("Cookies: " + cookieMap);
		return Collections.unmodifiableMap(cookieMap);
	}
}
