package nz.co.nil.base.collections;

import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;

import org.apache.commons.collections.AbstractObjectArrayTrie;
import org.apache.commons.collections.AbstractTransitionMapTrie;

/**
 * A {@link org.apache.commons.collections.Trie} for storing objects indexed by
 * {@link java.net.URI}.
 * 
 * A simplified version of the URI is stored. The URI is split into components
 * with the query and fragment and empty parts of the path removed. Trailing
 * slashes are ignored too. Here are some examples:
 * 
 * <pre>
 * http://jakarta.apache.org/ -> {"http", "jakarta.apache.org"}
 * 
 * http://jakarta.apache.org:8080/ -> {"http", "jakarta.apache.org:8080"}
 * 
 * http://jakarta.apache.org/hello -> {"http", "jakarta.apache. org", "hello"}
 * 
 * http://jakarta.apache.org/hello/ -> {"http", "jakarta.apache.org", "hello"}
 * 
 * http://jakarta.apache.org/hello/there?name=timothy -> {"http", "jakarta.
 * apache.org", "hello", "there"}
 * 
 * https://jakarta.apache.org/view/page?id=24#section3 -> {"https", "jakarta.
 * apache.org", "view", "page"}
 * </pre>
 * 
 * @author <a href="mailto:rich@nil.co.nz">Rich Dougherty</a>
 */
public class SimplifiedURITrie extends AbstractTransitionMapTrie {

    private static final String URI_PATH_SEP = "/";
    public SimplifiedURITrie() {
        super();
    }

    public SimplifiedURITrie(Map map) {
        super(map);
    }

    protected AbstractObjectArrayTrie createTrie() {
        return new SimplifiedURITrie();
    }

    protected Object[] convertKeyToObjectArray(Object key)
        throws IllegalArgumentException, NullPointerException {
        if (!(key instanceof URI)) {
        	throw new IllegalArgumentException("Key must be a java.net.URI: got a " + key.getClass());
        }
        URI uri = (URI) key;
	    List objectList = new ArrayList();
        objectList.add(uri.getScheme());
        objectList.add(uri.getAuthority());
        StringTokenizer tokenizer = new StringTokenizer(uri.getPath(), URI_PATH_SEP);
        while (tokenizer.hasMoreTokens()) {
        	String pathElement = tokenizer.nextToken();
        	if (pathElement.length() != 0) {
        		objectList.add(pathElement);
        	}
        }
        return objectList.toArray();
    }

    protected Object convertObjectArrayToKey(Object[] objectArray) {
    	String scheme = (String) objectArray[0];
    	String authority = (String) objectArray[1];
        StringBuffer pathStringBuffer = new StringBuffer();
        for (int i = 2; i < objectArray.length; i++) {
        	String pathElement = (String) objectArray[i];
            pathStringBuffer.append(pathElement);
        }
        String path = pathStringBuffer.toString();
        URI uri;
        try {
            uri = new URI(scheme, authority, path, "", "");
        } catch (URISyntaxException e) {
        	throw (IllegalArgumentException) new IllegalArgumentException("Couldn't create the URI.").initCause(e);
        }
        return uri;
    }

}