package net.noderunner.amazon.s3;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;

import org.apache.commons.httpclient.Header;

/**
 * HTTP header wrapper.
 * 
 * @author Elias Ross
 */
public class Headers {
	
	public static final String METADATA_PREFIX = "x-amz-meta-";
	
	private Map<String, List<String>> headers;
	
    /**
	 * Constructs a new Headers object.
	 */
	public Headers(Map<String, List<String>> headers) {
		this.headers = headers;
	}
	
	/**
	 * Copy-constructs new Headers.
	 */
	public Headers(Headers headers) {
		this();
        for (Map.Entry<String, List<String>> me : headers.headers.entrySet()) {
        	for (String v : me.getValue())
            	put(me.getKey(), v);
        }
	}

    /**
	 * Constructs a new Headers object.
	 */
	public Headers() {
    	this(new HashMap<String, List<String>>());
    }
	
    /**
	 * Constructs a new Headers object.
	 */
	public Headers(Header[] requestHeaders) {
		this();
		for (Header h : requestHeaders) {
			put(h.getName(), h.getValue());
		}
	}

	/**
	 * Adds a header.
	 */
	public void put(String header, String value) {
        if (headers.containsKey(header)) {
            headers.get(header).add(value);
        } else {
            headers.put(header, new ArrayList<String>(Collections.singletonList(value)));
        }
	}

	/**
	 * Returns headers.
	 */
	public Map<String, List<String>> getHeaders() {
		return headers;
	}
	
	/**
	 * Returns a list of values.
	 */
	public List<String> getValues(String header) {
		return headers.get(header);
	}
	
	public String getValue(String header) {
		List<String> values = getValues(header);
		if (values == null || values.isEmpty())
			return null;
		return values.get(0);
	}

	/**
	 * Returns the number of headers.
	 */
	public int size() {
		return headers.size();
	}

	/**
	 * Returns a new Headers object with metadata from this object.
	 */
	public Headers extractMetadata() {
		TreeMap<String, List<String>> metadata = new TreeMap<String, List<String>>();
		for (Map.Entry<String, List<String>> me : headers.entrySet()) {
			String key = me.getKey();
			if (key == null)
				continue;
			if (key.startsWith(METADATA_PREFIX)) {
				metadata.put(key.substring(METADATA_PREFIX.length()), me.getValue());
			}
		}

		return new Headers(metadata);
	}
	
	/**
	 * Returns new headers with metadata.
	 */
    public Headers mergeMetadata(Headers metadata) {
        if (metadata == null)
        	return this;
        Map<String, List<String>> merged = new TreeMap<String, List<String>>(this.headers);
        for (Map.Entry<String, List<String>> me : metadata.headers.entrySet()) {
            String key = me.getKey();
            String metadataKey = METADATA_PREFIX + key;
            if (merged.containsKey(metadataKey)) {
                merged.get(metadataKey).addAll(me.getValue());
            } else {
                merged.put(metadataKey, me.getValue());
            }
        }
        return new Headers(merged);
    }
    
    /**
     * Returns a debug string.
     */
    @Override
    public String toString() {
       return "headers=" + headers;
    }

}
