package org.apache.synapse.transport.http.conn;

import org.apache.http.HttpRequest;
import org.apache.http.HttpRequestFactory;
import org.apache.http.MethodNotSupportedException;
import org.apache.http.RequestLine;
import org.apache.http.message.BasicHttpEntityEnclosingRequest;
import org.apache.http.message.BasicHttpRequest;

public class SynapseHTTPRequestFactory implements HttpRequestFactory {

    private static final String[] RFC2616_COMMON_METHODS = {
            "GET"
    };

    private static final String[] RFC2616_ENTITY_ENC_METHODS = {
            "POST",
            "PUT",
            "PATCH"
    };

    private static final String[] RFC2616_SPECIAL_METHODS = {
            "HEAD",
            "OPTIONS",
            "TRACE",
            "CONNECT"
    };

    /**
     * To provide payload support for HTTP DELETE requests
     * Since DELETE may/may not contain payload, consider as possible enclosing method
    **/
    private static final String[] RFC2616_POSSIBLE_ENTITY_ENC_METHODS = {
            "DELETE"
    };

    public static final String ENDPOINT_URL = "endPointURI";

    public SynapseHTTPRequestFactory() {
        super();
    }

    private static boolean isOneOf(final String[] methods, final String method) {
        for (int i = 0; i < methods.length; i++) {
            if (methods[i].equalsIgnoreCase(method)) {
                return true;
            }
        }
        return false;
    }

    public HttpRequest newHttpRequest(final RequestLine requestline)
            throws MethodNotSupportedException {
        if (requestline == null) {
            throw new IllegalArgumentException("Request line may not be null");
        }
        String method = requestline.getMethod();
        if (isOneOf(RFC2616_COMMON_METHODS, method)) {
            return new BasicHttpRequest(requestline);
        } else if (isOneOf(RFC2616_POSSIBLE_ENTITY_ENC_METHODS, method)) {
            return new BasicHttpEntityPossibleEnclosingRequest(requestline);
        } else if (isOneOf(RFC2616_ENTITY_ENC_METHODS, method)) {
            return new BasicHttpEntityEnclosingRequest(requestline);
        } else if (isOneOf(RFC2616_SPECIAL_METHODS, method)) {
            return new BasicHttpRequest(requestline);
        } else {
            throw new MethodNotSupportedException(method +  " method not supported");
        }
    }

    public HttpRequest newHttpRequest(final String method, final String uri)
            throws MethodNotSupportedException {
        if (isOneOf(RFC2616_COMMON_METHODS, method)) {
            return new BasicHttpRequest(method, uri);
        } else if (isOneOf(RFC2616_POSSIBLE_ENTITY_ENC_METHODS, method)) {
            return new BasicHttpEntityPossibleEnclosingRequest(method, uri);
        } else if (isOneOf(RFC2616_ENTITY_ENC_METHODS, method)) {
            return new BasicHttpEntityEnclosingRequest(method, uri);
        } else if (isOneOf(RFC2616_SPECIAL_METHODS, method)) {
            return new BasicHttpRequest(method, uri);
        } else {
            throw new MethodNotSupportedException(method
                    + " method not supported");
        }
    }

}