/*
 * 
 * Copyright 2004 Sun Microsystems, Inc. All Rights Reserved.
 * 
 * The contents of this file are subject to the Sun Community Source
 * License v3.0/Jini Technology Specific Attachment v 1.0 (the
 * "License"). You may not use this file except in compliance with the
 * License. You may obtain a copy of the License at
 * http://wwws.sun.com/software/jini/licensing/SCSL3_JiniTSA1.html.
 * Software distributed under the License is distributed on an "AS IS"
 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
 * the License for the specific language governing rights and limitations
 * under the License.
 * 
 * The Reference Code is Jini Technology Core Platform code, v2.0. The
 * Developer of the Reference Code is Sun Microsystems, Inc.
 * 
 * Contributor(s): Sun Microsystems, Inc.
 * 
 * The contents of this file comply with the Jini Technology Core
 * Platform Compatibility Kit, v2.0A.
 * 
 * Tester(s): Sun Microsystems, Inc.
 * 
 * Test Platform(s):
 * Java 2 SDK, Standard Edition, Version 1.4.2_03 for Solaris(TM)SPARC/x86
 * Java 2 SDK, Standard Edition, Version 1.4.2_03 for Linux (Intel x86)
 * Java 2 SDK, Standard Edition, Version 1.4.2_03 for Windows (Intel Platform)
 * 
 */

package com.sun.jini.jeri.internal.http;

import java.lang.ref.SoftReference;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import java.util.StringTokenizer;
import java.util.regex.Pattern;


/**
 * Utility class for querying HTTP-related system properties.
 *
 * @author Sun Microsystems, Inc.
 * 
 */
public class HttpSettings {
    
    private static final Object lastNonProxyLock = new Object();
    private static String lastNonProxyHosts = null;
    private static SoftReference lastNonProxyPatterns = null;

    private final Properties props;

    /**
     * Samples the current values of HTTP-related system properties, returning
     * an HttpSettings instance which can be used to query property values.
     * Changes to property values that occur after the call to getHttpSettings
     * may or may not be reflected in the returned HttpSettings instance.
     * Calling this method will cause the checkPropertiesAccess method of the
     * current security manager (if any) to be invoked.
     */
    public static HttpSettings getHttpSettings() {
	return new HttpSettings(System.getProperties());
    }
    
    /**
     * Creates new HttpSettings instance which returns values from the given
     * system properties list.
     */
    private HttpSettings(Properties props) {
	this.props = props;
    }

    /**
     * Returns http.proxyHost system property value if set; else returns
     * proxyHost system property value if set; else returns provided default
     * value.
     */
    public String getHttpProxyHost(String def) {
	String str;
	return ((str = props.getProperty("http.proxyHost")) != null ||
		(str = props.getProperty("proxyHost")) != null) ? str : def;
    }
    
    /**
     * Returns http.proxyPort system property value if set; else returns
     * proxyPort system property value if set; else returns provided default
     * value.
     */
    public int getHttpProxyPort(int def) {
	String str;
	if ((str = props.getProperty("http.proxyPort")) != null) {
	    try { return Integer.parseInt(str); } catch (Exception ex) {}
	}
	if ((str = props.getProperty("proxyPort")) != null) {
	    try { return Integer.parseInt(str); } catch (Exception ex) {}
	}
	return def;
    }

    /**
     * Returns https.proxyHost system property value if set; otherwise returns
     * provided default value.
     */
    public String getHttpsProxyHost(String def) {
	return props.getProperty("https.proxyHost", def);
    }
    
    /**
     * Returns https.proxyPort system property value if set; otherwise returns
     * provided default value.
     */
    public int getHttpsProxyPort(int def) {
	String str = props.getProperty("https.proxyPort");
	if (str != null) {
	    try { return Integer.parseInt(str); } catch (Exception ex) {}
	}
	return def;
    }

    /**
     * Returns com.sun.jini.jeri.http.responseAckTimeout system
     * property value if set; otherwise returns provided default value.
     */
    public long getResponseAckTimeout(long def) {
	String str = props.getProperty(
	    "com.sun.jini.jeri.http.responseAckTimeout");
	if (str != null) {
	    try { return Long.parseLong(str); } catch (Exception ex) {}
	}
	return def;
    }
    
    /**
     * Returns com.sun.jini.jeri.http.idleConnectionTimeout
     * system property value if set; otherwise returns provided default value.
     */
    public long getConnectionTimeout(long def) {
	String str = props.getProperty(
	    "com.sun.jini.jeri.http.idleConnectionTimeout");
	if (str != null) {
	    try { return Long.parseLong(str); } catch (Exception ex) {}
	}
	return def;
    }

    /**
     * Returns com.sun.jini.jeri.http.idleServerConnectionTimeout
     * system property value if set; otherwise returns provided default value.
     */
    public long getServerConnectionTimeout(long def) {
	String str = props.getProperty(
	    "com.sun.jini.jeri.http.idleServerConnectionTimeout");
	if (str != null) {
	    try { return Long.parseLong(str); } catch (Exception ex) {}
	}
	return def;
    }

    /**
     * If http.nonProxyHosts system property value is set, returns true iff
     * given host matches any regular expressions contained in value; if
     * http.nonProxyHosts is unset, returns provided default value.
     */
    public boolean nonProxied(String host, boolean def) {
	String str = props.getProperty("http.nonProxyHosts");
	if (str == null) {
	    return def;
	}
	synchronized (lastNonProxyLock) {
	    Pattern[] patterns;
	    if (!str.equalsIgnoreCase(lastNonProxyHosts) ||
		(patterns = (Pattern[]) lastNonProxyPatterns.get()) == null)
	    {
		StringTokenizer tok = new StringTokenizer(str, "|");
		List plist = new ArrayList();
		while (tok.hasMoreTokens()) {
		    try {
			plist.add(Pattern.compile(
				      convertToRegex(tok.nextToken()), 
				      Pattern.CASE_INSENSITIVE));
		    } catch (IllegalArgumentException ex) {
			// ignore pattern
		    }
		}
		patterns = (Pattern[]) 
		    plist.toArray(new Pattern[plist.size()]);
		lastNonProxyPatterns = new SoftReference(patterns);
		lastNonProxyHosts = str;
	    }
	    for (int i = 0; i < patterns.length; i++) {
		if (patterns[i].matcher(host).matches()) {
		    return true;
		}
	    }
	    return false;
	}
    }
    
    /**
     * Converts host pattern obtained from http.nonProxyHosts property to
     * java.util.regex-style regular expression.  Throws
     * IllegalArgumentException if given host pattern is invalid.
     */
    private static String convertToRegex(String hostPattern) {
	int len = hostPattern.length();
	StringBuffer sbuf = new StringBuffer(len);
	for (int i = 0; i < len; i++) {
	    char c = hostPattern.charAt(i);
	    if (Character.isLetter(c) || Character.isDigit(c)) {
		sbuf.append(c);
	    } else if (c == '.') {
		sbuf.append("\\.");
	    } else if (c == '*') {
		sbuf.append(".*");
	    } else {
		throw new IllegalArgumentException("illegal char: " + c);
	    }
	}
	return sbuf.toString();
    }
}
