/*
 * Scone - The Web Enhancement Framework
 * Copyright (C) 2009 Harald Weinreich, Volkert Buchmann, Frank Wollenweber, Torsten Haß
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 * 
 * This program 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 General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 */
 package scone.netobjects;


import java.net.MalformedURLException;
import java.net.URL;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Vector;
import java.util.regex.Pattern;


/**
 * This implementation tries to be compliant with RFC2396 (it is not by default, see below!). However, there are some exceptions:<br>
 * <ul>
 * <li>All whitespaces are removed from the Uri. This can lead to problems with telnet URIs</li>
 * <li>No distincions between undefined or empty parts are made. Empty parts of the URI will be treated like undefined parts.</li>
 * <li><code>//b</code> with base <code>http://a/b</code> will evaluate to <code>http://a//b</code></li>
 * </ul>
 * implementation of ambiguities:<br>
 * <ul>
 * <li><code>../../../g</code> with base <code>http://a/b</code> evaluates to <code>http://a/g</code></li>
 * <li><code>http:g</code> or <code>http:/g</code> with base <code>http://server/e/f</code> are considered opaque URIs</li>
 * </ul><p>
 * Type <code> java SimpleUri</code> for a reference!<p>
 * URIs are parsed into the components<br>
 * scheme:authority/path?query#fragment<br>
 * URLs are normally interpreted as<br>
 * protocol:host/path?query#fragment<br>
 * therefor this class defines methods to access these field virtually.<p>
 * http - URIs are also parsed into port, file and extension. The port is deleted if it is set to 80, the file is deleted if it starts with "index." "welcome." or "default."<p>
 *
 * Unfortunately, the Netscape Navigator evaluates relative URIs in a different way than described in RFC2396:<br>
 * An empty reference with base <code>http://a/b/c/d;p?q</code> evaluates to <code>http://a/b/c/</code><br>
 * This class mimics the behaviour of the Netscape Navigator/ Internet Explorer by default. If you want to have a clean RFC compliant parsing, set the static variable <code>parseNavigatorLike</code> to false.<p>
 *
 * @author Harald Weinreich
 * @author Volkert Buchmann
 */
public class SimpleUri {

    protected String scheme;
    protected String authority;
    protected String path;
    protected String query;
    protected String fragment;
    protected String opaquePart;

    protected String port;
    protected String file;
    protected String extension;

    protected String originalUriString;  // Original string from constructor
    protected SimpleUri base;

    public static boolean parseNavigatorLike = true;

    /**
     * This main method is only for test purposes!
     */
    public static void main(String[] args) {

        System.out.println("base URI");
        SimpleUri uri1 = new SimpleUri(null, "http://a/b/c/d;p?q");

        uri1.print();

        System.out.println("C.1.  Normal Examples");

        // SimpleUri.parseNavigatorLike = false;
        (new SimpleUri(uri1, "g:h")).print();
        (new SimpleUri(uri1, "g")).print();
        (new SimpleUri(uri1, "./g")).print();
        (new SimpleUri(uri1, "g/")).print();
        (new SimpleUri(uri1, "/g")).print();
        (new SimpleUri(uri1, "//g")).print(); // not compliant!
        (new SimpleUri(uri1, "?y")).print();
        (new SimpleUri(uri1, "g?y")).print();
        (new SimpleUri(uri1, "#s")).print();
        (new SimpleUri(uri1, "g#s")).print();
        (new SimpleUri(uri1, "g?y#s")).print();
        (new SimpleUri(uri1, ";x")).print();
        (new SimpleUri(uri1, "g;x")).print();
        (new SimpleUri(uri1, "g;x?y#s")).print();
        (new SimpleUri(uri1, ".")).print();
        (new SimpleUri(uri1, "./")).print();
        (new SimpleUri(uri1, "..")).print();
        (new SimpleUri(uri1, "../")).print();
        (new SimpleUri(uri1, "../g")).print();
        (new SimpleUri(uri1, "../..")).print();
        (new SimpleUri(uri1, "../../")).print();
        (new SimpleUri(uri1, "../../g")).print();
        (new SimpleUri(uri1, "/../g/")).print();
        (new SimpleUri(uri1, "/g/../")).print();

        System.out.println("\nC.2.   Abnormal Examples");
        (new SimpleUri(uri1, "")).print();
        (new SimpleUri(uri1, "../../../g")).print();
        (new SimpleUri(uri1, "../../../../g")).print();
        (new SimpleUri(uri1, "/./g")).print();
        (new SimpleUri(uri1, "/../g")).print();
        (new SimpleUri(uri1, "g.")).print();
        (new SimpleUri(uri1, ".g")).print();
        (new SimpleUri(uri1, "g..")).print();
        (new SimpleUri(uri1, "..g")).print();
        (new SimpleUri(uri1, "./../g")).print();
        (new SimpleUri(uri1, "./g/.")).print();
        (new SimpleUri(uri1, "g/./h")).print();
        (new SimpleUri(uri1, "g/../h")).print();
        (new SimpleUri(uri1, "g;x=1/./y")).print();
        (new SimpleUri(uri1, "g;x=1/../y")).print();
        (new SimpleUri(uri1, "g?y/./x")).print();
        (new SimpleUri(uri1, "g?y/../x")).print();
        (new SimpleUri(uri1, "g#s/./x")).print();
        (new SimpleUri(uri1, "g#s/../x")).print();
        (new SimpleUri(uri1, "http:g")).print();

        (new SimpleUri(null, "http://www.scone.de:80/test/index.html?was")).print();
        (new SimpleUri(null, "http://www.scone.de:81/test/index.html?was")).print();

        System.out.println((new SimpleUri(null, "http://www.scone.de:81/test/index.html?was")).getMainHost());
        System.out.println((new SimpleUri(null, "http://www.ebay.de/")).getMainHost());
        System.out.println((new SimpleUri(null, "http://ebay.de/")).getMainHost());
        System.out.println((new SimpleUri(null, "http://search.ebay.de/")).getMainHost());
        System.out.println((new SimpleUri(null, "http://xxx.search.ebay.de/")).getMainHost());
        System.out.println((new SimpleUri(null, "http://www.ebay.co.uk/")).getMainHost());
        System.out.println((new SimpleUri(null, "http://search.ebay.co.uk/")).getMainHost());
        System.out.println((new SimpleUri(null, "http://ebay.com.hk/")).getMainHost());
        System.out.println((new SimpleUri(null, "http://134.100.11.181/")).getMainHost());
        System.out.println((new SimpleUri(null, "com")).getMainHost());


    }

    /**
     * for test purposes: Print original URI and normalized URI
     */
    protected void print() {
        System.out.println(originalUriString + "      \t = " + toString());
    }


    /** 
     * Create a new SimpleUri to a base URI.
     * @param SimpleUri baseUri
     * @param String uriString
     */
    public SimpleUri(SimpleUri base, String uriString) {
        reset();           // Clear
        this.base = base;  
        this.originalUriString = uriString;
        parseUri();
        normalizeHttpUri();
    }

    /**
     * Create a new SimpleUri from a String. The Uri will be normalized
     */ 
    public SimpleUri(String uriString) {
        this(null, uriString);
    }

    /**
     * Compare this SimpleUri to another normalized URI.<P>
     * Example:
     * <CODE>http://www.scone.de:80/index.html</code> equals <code>http://www.scone.de/</code>
     */
    public boolean equals(String uriString) {
        return this.toString().equals((new SimpleUri(uriString)).toString());
    }

    /**
     * Compare this SimpleUri to another SimpleUri.<P>
     */
    public boolean equals(SimpleUri uri) {
        return this.toString().equals(uri.toString());
    }
    
    /**
     * @return path part or URI without host or filename etc. 
     */
    public String getPath() {
        return path;
    }

    /**
     * @return the query part of the URI without the ``?´´
     */
    public String getQuery() {
        return query;
    }

    /**
     * @return opaque part of URI, like ``webmaster@scone.de´´ in ``mailto:webmaster@scone.de´´
     */
    public String getOpaquePart() {
        return opaquePart;
    }

    /**
     * @return the original URI from which this SimpleUri was created.
     */ 
    public String getOriginalUri() {
        return originalUriString;
    }

    /** 
     * return the URI as String. Same as toString()<P>
     * scheme:authority:port/path/file?query#fragment
     */
    public String getUri() {
        return toString();
    }

    /**
     * @return the protocol (i.e. scheme) of this URI like http, ftp or mailto (without colon)
     */
    public String getProtocol() {
        return scheme;
    }

    /**
     * @return the scheme (i.e. protocol) of this URI like http, ftp or mailto (without colon)
     */
    public String getScheme() {
        return scheme;
    }

    /**
     * @return the host (i.e. authority) part of the URI
     */ 
    public String getHost() {
        return authority;
    }

    /**
     * @return the host (i.e. authority) part of the URI
     */ 
    public String getAuthority() {
        return authority;
    }

    /**
     * @return the main host part of the URI, i.e. ebay.com from search.ebay.com and www.ebay.com, or ebay.co.uk from search.ebay.co.uk and www.ebay.co.uk
     */ 
    public String getMainHost() {
    	// Test if IP-Address!
    	boolean b = Pattern.matches("[\\d]{1,3}\\.[\\d]{1,3}\\.[\\d]{1,3}\\.[\\d]{1,3}", authority);
        if (b)
        	return authority;
        // Domain Name...
    	String mainHost=authority;
        String [] temp = null;
        temp = authority.split("\\.");
	    if (temp.length>2) {
	    	int n = temp.length-2;
	    	String c = temp[n];
	    	// Check if second level domain is part of TLD (e.g. "co.uk")
	    	if (temp.length > 2 &&
	    			(c.equals("com") ||
	    					c.equals("co") || 		
	    					c.equals("edu") || 		
	    					c.equals("ac") || 		
	    					c.equals("gov") || 		
	    					c.equals("gv") || 		
	    					c.equals("org") || 		
	    					c.equals("or") || 		
	    					c.equals("mil") || 		
	    					c.equals("net") || 		
	    					c.equals("com") ) ) {
	    		n=n-1;
	    	}
	    	mainHost="";
	    	for (int i = temp.length-1 ; i >=n  ; i--) {
	    		mainHost=temp[i]+mainHost;
	    		if (n!=i)
	    			mainHost="."+mainHost;
		    }
        }
        return mainHost;
    }
    
    
    /**
     * @return the port number of the URI. Empty if default port is used.
     */ 
    public String getPort() {
        return port;
    }

    public String getFile() {
        return file;
    }

    /**
     * returns the file extension of the URI like html, php or asp. Without the dot.
     */ 
    public String getExtension() {
        return extension;
    }

    
    /**
     * Returns the fragment part of the URI (the string after the # without the #).
     */
    public String getRef() {
        return fragment;
    }

    /**
     * Returns the fragment part of the URI (the string after the # without the #).
     */
    public String getFragment() {
        return fragment;
    }


    /**
     * The complete URI is returned (same as getUri()).<P>
     * scheme:authority:port/path/file?query#fragment
     */
    public String toString() {
        // scheme:authority:port/path/file?query#fragment
        String stringRepr = toDocString();

        if (fragment != null && fragment.length() > 0) {
            stringRepr += "#" + fragment;
        }
        return stringRepr;
    }

    /**
     * This method returns the URI without the fragment (``#´´) identifyer...
     */
    public String toDocString() {
        // scheme:authority:port/path/file?query
        String stringRepr = toHostString();

        stringRepr += path;
        if (file != null && file.length() > 0) {
            stringRepr += file;
        }
        if (query != null && query.length() > 0) {
            stringRepr += "?" + query;
        }

        return stringRepr;
    }

    /**
     * The complete URI is returned.<P>
     * scheme:authority:port/path/file?query#fragment
     * @return returns a Java URL made from this SimpleURI.
     */
    public URL toURL() {
        try {
            return new URL(this.toString());
        } catch (MalformedURLException e) {
            System.out.println("Illegal URL: " + this.toString() + "\n" + e.toString());
            return null;
        }
    }
   
    /**
     * This method returns the URI without the fragment identifyer...
     */
    public URL toDocURL() {
        try {
            return new URL(toDocString());
        } catch (MalformedURLException e) {
            System.out.println("Illegal URL: " + this.toString() + "\n" + e.toString());
            return null;
        }
    }

    public String toHostString() {
        // scheme:authority:port
        String stringRepr = scheme + ":";

        if (opaquePart != null && opaquePart.length() > 0) {
            stringRepr += opaquePart;
            return stringRepr;
        }

        if (authority != null && authority.length() > 0) {
            stringRepr += "//" + authority;
        }
        if (port != null && port.length() > 0) {
            stringRepr += ":" + port;
        }
        return stringRepr;
    }

    /**
     * Returns a hashcode hex String to this SimpleUri.
     */
    public String getHexHashCode() {
        return getHexHashCode(toDocString());
    }

    /**
     * Returns a hashcode hex String to the "scheme:authority:port"-part of the SimpleUri.
     */
    public String getHexHashCodeofHost() {
        return getHexHashCode(toHostString());
    }
    
    /**
     * Returns a hashcode hex String to a SimpleUri String. The hashcode for a 
     * <code>String</code> object is computed as
     * <blockquote><pre> 
     * s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1]
     * </pre></blockquote>
     * using <code>long</code> arithmetic, where <code>s[i]</code> is the 
     * <i>i</i>th character of the SimpleUri, <code>n</code> is the length of 
     * the Uri, and <code>^</code> indicates exponentiation. 
     *
     * @return  a hash code value for this object. 
     */
    public static String getHexHashCode(String uriString) {
        long h = 0;
        int len = uriString.length();
        char value[] = new char[len];

        uriString.getChars(0, len, value, 0);

        for (int i = 0; i < len; i++) {
            h = 137 * h + value[i];
        }   // Prim has to be bigger than 128, otherwise similar URLs cause same Hash codes -> 31: ...000p.html ~ 0022.html

        String hexString = Long.toHexString(h).toUpperCase();

        while (hexString.length() < 16) {
            hexString = "0" + hexString;
        }  // Fill up leading Zeros to aalways get a 16 character hashString.
        return hexString;
    }

    /**
     * This method returns the mime-type of this URI.
     * @return extension the extension of this SimpleUri
     */
    public String getMimeType() {
        String mimeType = "";

        mimeType = (String) mimeTypeTable.get(extension.toLowerCase());
        if (mimeType == null) {
            mimeType = "";
        }
        // System.out.println(mimeType);
        return mimeType;
    }

    /**
     * This static method returns the appropiete mime-type to a file extension.
     * @param extension the extension of the file or Url
     */
	
    public static String getMimeTypeFromExtension(String extension) {
        String mimeType = "";

        mimeType = (String) mimeTypeTable.get(extension.toLowerCase());
        if (mimeType == null) {
            mimeType = "";
        }
        // System.out.println(mimeType);
        return mimeType;
    }


    // ------------------------------ Internal methods... -----------------
    
    /**
     * clear SimpleURI
     */
    protected void reset() {
        scheme = "";
        authority = "";
        opaquePart = "";
        path = "";
        query = "";
        fragment = "";

        port = "";
        file = "";
        extension = "";

        base = null;
        originalUriString = "";
    }

    protected void parseUri() {
        StringBuffer schemeBuf = new StringBuffer();
        StringBuffer work = new StringBuffer();
        StringBuffer fragBuf = new StringBuffer();
        String s = "";
        int l, i, pos;

        l = originalUriString.length();
        char c;

        // remove whitespaces
        for (i = 0; i < l; i++) {
            c = originalUriString.charAt(i);
            // stop at fragment
            if (c == '#') {
                i++; // skip #
                break;
            }
            if (c > ' ') {
                work.append(c);
            }
        }
        s = work.toString();

        // save fragment without whitespaces
        for (; i < l; i++) {
            c = originalUriString.charAt(i);
            if (c > ' ') {
                fragBuf.append(c);
            }
        }
        fragment = fragBuf.toString();

        i = 0;	// parse s from the beginning

        // skip "uri:" (old spec)
        if (s.toLowerCase().startsWith("uri:")) {
            i += 4;
        }

        // find out scheme, if any
        l = s.length();
        for (; ((i < l) && ((c = s.charAt(i)) != '/')); i++) {
            if (c == ':') { // yes, we found a scheme
                scheme = s.substring(0, i).toLowerCase();
                i++;
                break;
            }
        }

        if ((scheme.length() == 0)) {
            parseRelativeUri(s);
        } else {
            parseNetPath(s, i);
        }
    }

    protected void parseNetPath(String s, int i) {

        // is there an authority (host)?
        if (s.length() <= (i + 2) || !s.substring(i, i + 2).equals("//")) {
            // no, just an opaque part (like mailto:me@somewhere)
            opaquePart = s.substring(i);
            return;
        }
        i += 2;

        // find end of authority
        int j = s.indexOf("/", i);

        // no path found, we are done!
        if (j == -1) {
            authority = s.substring(i);
            path = "/";
            query = "";
        } else { // there is a path, so continue!
            authority = s.substring(i, j);
            findPathAndQuery(s, j);
        }
    }

    protected void parseRelativeUri(String s) {

        if (base == null) {
            // better throw an exception!
            return;
        }

        int i = 0;

        // is there a query (``?´´) in the URI?
        findPathAndQuery(s, i);

        scheme = base.getScheme();
        authority = base.getAuthority();

        while (true) {

            // step 2
            // same document
            if (path.length() == 0) {
                path = base.getPath();

                // if base is a http-uri we do not want to lose the file
                if ((query.length() == 0)
                        && (!parseNavigatorLike
                                || (parseNavigatorLike && fragment.length() > 0))) {
                    path += base.getFile();
                }

                if (base.getQuery().length() > 0 && query.length() == 0
                        && !parseNavigatorLike) {
                    query = base.getQuery();
                }

                break;
            }

            // step 3 already done!
            // loophole not implemented!

            // step 4 already done!

            // step 5
            // absolute-path?
            Vector basePath = null;

            if (path.charAt(0) == '/') {          // if path starts with "/" it's absolute
                basePath = parseBase("/");
            }      // -> start with no path
            else {
                basePath = parseBase(base.getPath());
            } // start with base path...

            // step 6 merging pathes
            StringBuffer segBuf = new StringBuffer();
            String segment = "";
            int length = path.length();
            char c;

            // now parse this (relative) path...
            for (i = 0; i < length; i++) {  // separate the segments of the path...
                c = path.charAt(i);  // every character
                segBuf.append(c);    // added to this segment...
                if ((c == '/') || (i == length - 1)) {     // found an "/" -> segment over... or path over (length-1)
                    segment = segBuf.toString();  // get segment...
                    segBuf.setLength(0);          // prepare for next segment
                    // ignore leading or separate "/"
                    if (segment.equals("/")) {
                        continue;
                    }  
                    // Shorten path if ".."					   
                    if (segment.equals("..") || segment.equals("../")) {
                        if (basePath.size() > 0) {                       // if possible:
                            basePath.setSize(basePath.size() - 1);
                        }      // shorten path
                        continue;
                    }
                    // ignore ".", otherwise add segment.
                    if (!segment.equals(".") && !segment.equals("./")) { 
                        basePath.addElement(segment);
                    }
                }
            }

            path = "/";
            for (Enumeration e = basePath.elements(); e.hasMoreElements();) {
                path += (String) e.nextElement();
            }

            break;
        }

    }

    protected Vector parseBase(String path) {
        Vector vec = new Vector();
        StringBuffer store = new StringBuffer();
        int length = path.length();
        char c;

        for (int i = 1; i < length; i++) {
            c = path.charAt(i);
            store.append(c);
            if (c == '/') {
                vec.addElement(new String(store));
                store.setLength(0);
            }
        }

        return vec;
    }

    protected void findPathAndQuery(String s, int j) {
        // search for query
        if (j < s.length()) {
            int i = s.indexOf("?", j);

            if (i == -1) { // not found, we are done!
                path = s.substring(j);
                query = "";
            } else { // yes, there is a query!
                path = s.substring(j, i);
                if ((i + 1) < s.length()) {
                    query = s.substring(i + 1);
                } else {
                    query = "";
                }
            }
        }
    }

    /**
     * Shorten the URI as much as useful
     */
    protected void normalizeHttpUri() {
        if (!scheme.equals("http")
                || (opaquePart != null && opaquePart.length() > 0)) {
            return;
        }

        // try to find port
        int i = authority.lastIndexOf(':');

        // extract port
        if (i >= 0 && i <= authority.length()) {
            port = authority.substring(i + 1);
        }
        // clean authority from :port
        if (i >= 0) {
            authority = authority.substring(0, i);
        }

        // try to find file
        i = path.lastIndexOf('/') + 1;
        if (i >= 1 && i < path.length()) {
            file = path.substring(i);
            path = path.substring(0, i);
            // try to find extension
            i = file.lastIndexOf('.') + 1;
            if (i >= 1 && i < file.length()) {
                extension = file.substring(i);
            }
        }
        // delete index-files
        String fs = file.toLowerCase();

        if (fs.startsWith("index.") || fs.startsWith("welcome.")
                || fs.startsWith("default.")) {
            file = "";
        }

        // delete standard ports
        if (scheme.equals("http") && port.equals("80")) {
            port = "";
        }
        // else if(scheme.equals("ftp") && port.equals("21")) port="";
        
        // normalizing finished
        // now set the uriString
        
    }

    // Associate file extensions to mime types
    // --------------------------------------- 

    protected static Hashtable mimeTypeTable = new Hashtable();
    static {
        // mimeTypeTable.put(new String(""), new String("text/html"));  // No extension -> propably html
        mimeTypeTable.put(new String("html"), new String("text/html"));
        mimeTypeTable.put(new String("htm"), new String("text/html"));
        mimeTypeTable.put(new String("shtml"), new String("text/html"));
        mimeTypeTable.put(new String("phtml"), new String("text/html"));
        mimeTypeTable.put(new String("pht"), new String("text/html"));
        mimeTypeTable.put(new String("php"), new String("text/html"));
        mimeTypeTable.put(new String("php3"), new String("text/html"));
        mimeTypeTable.put(new String("php4"), new String("text/html"));
        mimeTypeTable.put(new String("asp"), new String("text/html"));

        mimeTypeTable.put(new String("asc"), new String("text/plain"));
        mimeTypeTable.put(new String("txt"), new String("text/plain"));
        mimeTypeTable.put(new String("c"), new String("text/plain"));
        mimeTypeTable.put(new String("cc"), new String("text/plain"));
        mimeTypeTable.put(new String("h"), new String("text/plain"));
        mimeTypeTable.put(new String("hh"), new String("text/plain"));
        mimeTypeTable.put(new String("cpp"), new String("text/plain"));
        mimeTypeTable.put(new String("hpp"), new String("text/plain"));
        mimeTypeTable.put(new String("rtx"), new String("text/richtext"));

        mimeTypeTable.put(new String("css"), new String("text/css"));
        mimeTypeTable.put(new String("tsv"), new String("text/tab-separated-values"));
        mimeTypeTable.put(new String("etx"), new String("text/x-setext"));
        mimeTypeTable.put(new String("sgml"), new String("text/x-sgml"));
        mimeTypeTable.put(new String("sgm"), new String("text/x-sgml"));
        mimeTypeTable.put(new String("vcs"), new String("text/x-vCalendar"));
        mimeTypeTable.put(new String("vcf"), new String("text/x-vCard"));
        mimeTypeTable.put(new String("xml"), new String("text/xml"));
        mimeTypeTable.put(new String("dtd"), new String("text/xml"));

        mimeTypeTable.put(new String("gif"), new String("image/gif"));
        mimeTypeTable.put(new String("jpeg"), new String("image/jpeg"));
        mimeTypeTable.put(new String("jpg"), new String("image/jpeg"));
        mimeTypeTable.put(new String("jpe"), new String("image/jpeg"));
        mimeTypeTable.put(new String("png"), new String("image/png"));

        mimeTypeTable.put(new String("ief"), new String("image/ief"));
        mimeTypeTable.put(new String("tiff"), new String("image/tiff"));
        mimeTypeTable.put(new String("tif"), new String("image/tiff"));
        mimeTypeTable.put(new String("ras"), new String("image/x-cmu-raster"));
        mimeTypeTable.put(new String("pnm"), new String("image/x-portable-anymap"));
        mimeTypeTable.put(new String("pbm"), new String("image/x-portable-bitmap"));
        mimeTypeTable.put(new String("pgm"), new String("image/x-portable-graymap"));
        mimeTypeTable.put(new String("ppm"), new String("image/x-portable-pixmap"));
        mimeTypeTable.put(new String("rgb"), new String("image/x-rgb"));
        mimeTypeTable.put(new String("xbm"), new String("image/x-xbitmap"));
        mimeTypeTable.put(new String("xpm"), new String("image/x-xpixmap"));
        mimeTypeTable.put(new String("xwd"), new String("image/x-xwindowdump"));

        mimeTypeTable.put(new String("bin"), new String("application/octet-stream"));
        mimeTypeTable.put(new String("dms"), new String("application/octet-stream"));
        mimeTypeTable.put(new String("lha"), new String("application/octet-stream"));
        mimeTypeTable.put(new String("lzh"), new String("application/octet-stream"));

        mimeTypeTable.put(new String("class"), new String("application/java-vm"));		
        mimeTypeTable.put(new String("jar"), new String("application/java-vm"));		
        mimeTypeTable.put(new String("pgp"), new String("application/pgp"));
        mimeTypeTable.put(new String("ai"), new String("application/postscript"));
        mimeTypeTable.put(new String("eps"), new String("application/postscript"));
        mimeTypeTable.put(new String("ps"), new String("application/postscript"));
        mimeTypeTable.put(new String("ppt"), new String("application/powerpoint"));
        mimeTypeTable.put(new String("rtf"), new String("application/rtf"));
        mimeTypeTable.put(new String("xls"), new String("application/excel"));
        mimeTypeTable.put(new String("hqx"), new String("application/mac-binhex40"));
        mimeTypeTable.put(new String("pdf"), new String("application/pdf"));
        mimeTypeTable.put(new String("zip"), new String("application/zip"));
        mimeTypeTable.put(new String("doc"), new String("application/msword"));
        mimeTypeTable.put(new String("dot"), new String("application/msword"));
        mimeTypeTable.put(new String("wrd"), new String("application/msword"));
        mimeTypeTable.put(new String("wp5"), new String("application/wordperfect5.1"));

        mimeTypeTable.put(new String("vcd"), new String("application/x-cdlink"));
        mimeTypeTable.put(new String("z"), new String("application/x-compress"));
        mimeTypeTable.put(new String("cpio"), new String("application/x-cpio"));
        mimeTypeTable.put(new String("csh"), new String("application/x-csh"));
        mimeTypeTable.put(new String("deb"), new String("application/x-debian-package"));
        mimeTypeTable.put(new String("dcr"), new String("application/x-director"));
        mimeTypeTable.put(new String("dir"), new String("application/x-director"));
        mimeTypeTable.put(new String("dxr"), new String("application/x-director"));
        mimeTypeTable.put(new String("swf"), new String("application/x-shockwave-flash"));
        mimeTypeTable.put(new String("spl"), new String("application/futuresplash"));
        mimeTypeTable.put(new String("dvi"), new String("application/x-dvi"));
        mimeTypeTable.put(new String("gtar"), new String("application/x-gtar"));
        mimeTypeTable.put(new String("tgz"), new String("application/x-gtar"));
        mimeTypeTable.put(new String("gz"), new String("application/x-gzip"));
        mimeTypeTable.put(new String("hdf"), new String("application/x-hdf"));
        // mimeTypeTable.put(new String("phtml"), new String("application/x-httpd-php"));	// now text/html!
        // mimeTypeTable.put(new String("pht"), new String("application/x-httpd-php"));
        // mimeTypeTable.put(new String("php"), new String("application/x-httpd-php"));
        mimeTypeTable.put(new String("js"), new String("application/x-javascript"));
        mimeTypeTable.put(new String("latex"), new String("application/x-latex"));
        // mimeTypeTable.put(new String("frm maker frame fm fb book fbdoc"), new String("application/x-maker"));
        mimeTypeTable.put(new String("mif"), new String("application/x-mif"));
        mimeTypeTable.put(new String("com"), new String("application/x-msdos-program"));
        mimeTypeTable.put(new String("exe"), new String("application/x-msdos-program"));
        mimeTypeTable.put(new String("bat"), new String("application/x-msdos-program"));
        mimeTypeTable.put(new String("nc"), new String("application/x-netcdf"));
        mimeTypeTable.put(new String("cdf"), new String("application/x-netcdf"));
        mimeTypeTable.put(new String("pl"), new String("application/x-perl"));
        mimeTypeTable.put(new String("pm"), new String("application/x-perl"));
        mimeTypeTable.put(new String("sh"), new String("application/x-sh"));
        // mimeTypeTable.put(new String("shar"), new String("application/x-shar"));
        mimeTypeTable.put(new String("sit"), new String("application/x-stuffit"));
        // mimeTypeTable.put(new String("sv4cpio"), new String("application/x-sv4cpio"));
        // mimeTypeTable.put(new String("sv4crc"), new String("application/x-sv4crc"));
        mimeTypeTable.put(new String("tar"), new String("application/x-tar"));
        mimeTypeTable.put(new String("tcl"), new String("application/x-tcl"));
        mimeTypeTable.put(new String("tex"), new String("application/x-tex"));
        mimeTypeTable.put(new String("texinfo"), new String("application/x-texinfo"));
        mimeTypeTable.put(new String("texi"), new String("application/x-texinfo"));
        // mimeTypeTable.put(new String("t tr roff"), new String("application/x-troff"));
        mimeTypeTable.put(new String("man"), new String("application/x-troff-man"));
        mimeTypeTable.put(new String("me"), new String("application/x-troff-me"));
        mimeTypeTable.put(new String("ms"), new String("application/x-troff-ms"));
        mimeTypeTable.put(new String("ustar"), new String("application/x-ustar"));
        mimeTypeTable.put(new String("src"), new String("application/x-wais-source"));

        mimeTypeTable.put(new String("au"), new String("audio/basic"));
        mimeTypeTable.put(new String("snd"), new String("audio/basic"));
        mimeTypeTable.put(new String("mid"), new String("audio/midi"));
        mimeTypeTable.put(new String("midi"), new String("audio/midi"));
        mimeTypeTable.put(new String("kar"), new String("audio/midi"));
        mimeTypeTable.put(new String("mpga"), new String("audio/mpeg"));
        mimeTypeTable.put(new String("mp3"), new String("audio/mpeg"));
        mimeTypeTable.put(new String("aif"), new String("audio/x-aiff"));
        mimeTypeTable.put(new String("aifc"), new String("audio/x-aiff"));
        mimeTypeTable.put(new String("aiff"), new String("audio/x-aiff"));
        mimeTypeTable.put(new String("ra"), new String("audio/x-pn-realaudio"));
        mimeTypeTable.put(new String("ram"), new String("audio/x-pn-realaudio"));
        mimeTypeTable.put(new String("wav"), new String("audio/x-wav"));

        mimeTypeTable.put(new String("igs"), new String("model/iges"));
        mimeTypeTable.put(new String("iges"), new String("model/iges"));
        mimeTypeTable.put(new String("msh"), new String("model/mesh"));
        mimeTypeTable.put(new String("mesh"), new String("model/mesh"));
        mimeTypeTable.put(new String("silo"), new String("model/mesh"));
        mimeTypeTable.put(new String("wrl"), new String("model/vrml"));
        mimeTypeTable.put(new String("vrml"), new String("model/vrml"));

        mimeTypeTable.put(new String("dl"), new String("video/dl"));
        mimeTypeTable.put(new String("fli"), new String("video/fli"));
        mimeTypeTable.put(new String("gl"), new String("video/gl"));
        mimeTypeTable.put(new String("mp2"), new String("video/mpeg"));
        mimeTypeTable.put(new String("mpe"), new String("video/mpeg"));
        mimeTypeTable.put(new String("mpeg"), new String("video/mpeg"));
        mimeTypeTable.put(new String("mpg"), new String("video/mpeg"));
        mimeTypeTable.put(new String("qt"), new String("video/quicktime"));
        mimeTypeTable.put(new String("mov"), new String("video/quicktime"));
        mimeTypeTable.put(new String("avi"), new String("video/x-msvideo"));
        mimeTypeTable.put(new String("movie"), new String("video/x-sgi-movie"));

        mimeTypeTable.put(new String("ice"), new String("x-conference/x-cooltalk"));

    }
}
