//   Copyright 2012 Georg-August-Universität Göttingen, Germany
//
//   Licensed under the Apache License, Version 2.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://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in writing, software
//   distributed under the License is distributed on an "AS IS" BASIS,
//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//   See the License for the specific language governing permissions and
//   limitations under the License.

package de.ugoe.cs.autoquest.http;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;

import java.math.BigInteger;

import de.ugoe.cs.autoquest.httpmonitor.exchange.Address;
import de.ugoe.cs.autoquest.httpmonitor.exchange.Content;
import de.ugoe.cs.autoquest.httpmonitor.exchange.Cookie;
import de.ugoe.cs.autoquest.httpmonitor.exchange.Cookies;
import de.ugoe.cs.autoquest.httpmonitor.exchange.Header;
import de.ugoe.cs.autoquest.httpmonitor.exchange.Headers;
import de.ugoe.cs.autoquest.httpmonitor.exchange.HttpExchange;
import de.ugoe.cs.autoquest.httpmonitor.exchange.HttpRequest;
import de.ugoe.cs.autoquest.httpmonitor.exchange.HttpResponse;
import de.ugoe.cs.autoquest.httpmonitor.exchange.Method;
import de.ugoe.cs.autoquest.httpmonitor.exchange.ObjectFactory;
import de.ugoe.cs.autoquest.httpmonitor.exchange.Protocol;
import de.ugoe.cs.autoquest.httpmonitor.exchange.Session;
import de.ugoe.cs.autoquest.httpmonitor.exchange.Status;

/**
 *
 */
public class HTTPTestUtils {

    private static ObjectFactory factory = new ObjectFactory();

    /**
     *
     */
    public static Session createRandomSession(int maxSize) {
        ObjectFactory factory = new ObjectFactory();
        Session session = factory.createSession();
        
        int count = (int) (maxSize * Math.random());
        
        System.out.println("creating a session with " + count + " exchanges");
        for (int i = 0; i < count; i++) {
            session.getHttpExchange().add(createRandomExchange());
        }
        
        return session;
    }

    /**
     *
     */
    public static HttpExchange createRandomExchange() {
        HttpExchange exchange = factory.createHttpExchange();
        
        exchange.setSender(createRandomAddress());
        exchange.setReceiver(createRandomAddress());
        
        HttpRequest request = factory.createHttpRequest();
        request.setAuthType("AUTH_" + Math.random());
        request.setQuery("QUERY_" + Math.random());
        request.setRemoteUser("REMOTE_USER_" + Math.random());
        request.setRequestedSessionId("REQUESTED_SESSION_ID_" + Math.random());
        request.setUrl("URL_" + Math.random());
        request.setContent(createRandomContent());
        request.setCookies(createRandomCookies());
        request.setHeaders(createRandomHeaders());
        request.setMethod(createRandomMethod());
        request.setProtocol(createRandomProtocol());
        exchange.setRequest(request);
        
        HttpResponse response = factory.createHttpResponse();
        response.setContent(createRandomContent());
        response.setHeaders(createRandomHeaders());
        response.setStatus(BigInteger.valueOf((int) (500 * Math.random())));
        exchange.setResponse(response);
        
        exchange.setStatus(createRandomStatus());
        
        return exchange;
    }

    /**
     *
     */
    public static Address createRandomAddress() {
        Address address = factory.createAddress();
        
        int variant = (int) (7 * Math.random());
        
        switch (variant) {
            case 0:
                address.setHost("host");
                address.setIp("123.23.45.5");
                address.setPort(BigInteger.valueOf(2342));
                break;
            case 1:
                address.setIp("123.23.45.5");
                address.setPort(BigInteger.valueOf(2342));
                break;
            case 2:
                address.setHost("host");
                address.setPort(BigInteger.valueOf(2342));
                break;
            case 3:
                address.setHost("host");
                address.setIp("123.23.45.5");
                break;
            case 4:
                address.setIp("123.23.45.5");
                break;
            case 5:
                address.setHost("host");
                break;
            default:
                address.setPort(BigInteger.valueOf(2342));
                break;
        }
        
        return address;
    }

    /**
     *
     */
    public static Cookies createRandomCookies() {
        Cookies cookies = factory.createCookies();
        
        int counter = (int) (5 * Math.random());
        
        for (int i = 0; i < counter; i++) {
            Cookie cookie = factory.createCookie();
            
            cookie.setComment("COMMENT_" + Math.random());
            cookie.setDomain("DOMAIN_" + Math.random());
            cookie.setIsHttpOnly(Math.random() > 0.5);
            cookie.setIsSecure(Math.random() > 0.5);
            cookie.setMaxAge(BigInteger.valueOf((int) (1000 * Math.random())));
            cookie.setName("NAME_" + Math.random());
            cookie.setPath("PATH_" + Math.random());
            cookie.setValue("VALUE_" + Math.random());
            cookie.setVersion(BigInteger.valueOf((int) (1000 * Math.random())));
            
            cookies.getCookie().add(cookie);
        }
        
        return cookies;
    }

    /**
     *
     */
    public static Method createRandomMethod() {
        int variant = (int) (8 * Math.random());
        
        switch (variant) {
            case 0:
                return Method.CONNECT;
            case 1:
                return Method.DELETE;
            case 2:
                return Method.GET;
            case 3:
                return Method.HEAD;
            case 4:
                return Method.OPTIONS;
            case 5:
                return Method.POST;
            case 6:
                return Method.TRACE;
            default:
                return Method.PUT;
        }
    }

    /**
     *
     */
    public static Protocol createRandomProtocol() {
        int variant = (int) (3 * Math.random());
        
        switch (variant) {
            case 0:
                return Protocol.HTTP_1_0;
            default:
                return Protocol.HTTP_1_1;
        }
    }

    /**
     *
     */
    public static Content createRandomContent() {
        Content content = factory.createContent();
        
        content.setEncoding("ENVODING_" + Math.random());
        content.setType("TYPE_" + Math.random());
        
        int length = (int) (1000 * Math.random());

        StringBuffer data = new StringBuffer();
        for (int i = 0; i < length; i++) {
            data.append((char) (33 + (1000 * Math.random())));
        }
        
        content.setLength(data.length());
        content.setData(data.toString());
        
        return content;
    }

    /**
     *
     */
    public static Headers createRandomHeaders() {
        Headers headers = factory.createHeaders();
        
        int counter = (int) (5 * Math.random());
        
        for (int i = 0; i < counter; i++) {
            Header header = factory.createHeader();
            header.setKey("KEY_" + Math.random());
            header.setValue("VALUE_" + Math.random());
            headers.getHeader().add(header);
        }
        
        return headers;
    }

    /**
     *
     */
    public static Status createRandomStatus() {
        int variant = (int) (3 * Math.random());
        
        switch (variant) {
            case 0:
                return Status.SUCCESS;
            case 1:
                return Status.FAILURE;
            default:
                return Status.TIMEOUT;
        }
    }
    
    /**
     * 
     */
    public static void assertExchangeEquals(HttpExchange exchange1, HttpExchange exchange2) {
        assertAddressEquals(exchange1.getSender(), exchange2.getSender());
        assertAddressEquals(exchange1.getReceiver(), exchange2.getReceiver());
        assertRequestEquals(exchange1.getRequest(), exchange2.getRequest());
        assertResponseEquals(exchange1.getResponse(), exchange2.getResponse());
        
        assertEquals(exchange1.getStatus(), exchange2.getStatus());
    }

    /**
     *
     */
    public static void assertAddressEquals(Address address1, Address address2) {
        if (address1 == null) {
            assertNull(address2);
        }
        else {
            assertEquals(address1.getHost(), address2.getHost());
            assertEquals(address1.getIp(), address2.getIp());
            assertEquals(address1.getPort(), address2.getPort());
        }
    }

    /**
     *
     */
    public static void assertRequestEquals(HttpRequest request1, HttpRequest request2) {
        assertEquals(request1.getAuthType(), request2.getAuthType());
        assertEquals(request1.getContent().getData(), request2.getContent().getData());
        assertEquals(request1.getContent().getEncoding(), request2.getContent().getEncoding());
        assertEquals(request1.getContent().getLength(), request2.getContent().getLength());
        assertEquals(request1.getContent().getType(), request2.getContent().getType());
        assertEquals(request1.getMethod(), request2.getMethod());
        assertEquals(request1.getProtocol(), request2.getProtocol());
        assertEquals(request1.getQuery(), request2.getQuery());
        assertEquals(request1.getRemoteUser(), request2.getRemoteUser());
        assertEquals(request1.getRequestedSessionId(), request2.getRequestedSessionId());
        assertEquals(request1.getUrl(), request2.getUrl());
        
        assertCookiesEqual(request1.getCookies(), request2.getCookies());
        assertHeadersEqual(request1.getHeaders(), request2.getHeaders());
    }

    /**
     *
     */
    public static void assertCookiesEqual(Cookies cookies1, Cookies cookies2) {
        if (cookies1 == null) {
            assertNull(cookies2);
        }
        else {
            assertEquals(cookies1.getCookie().size(), cookies2.getCookie().size());
            
            for (int i = 0; i < cookies1.getCookie().size(); i++) {
                Cookie cookie1 = cookies1.getCookie().get(i);
                Cookie cookie2 = cookies2.getCookie().get(i);
                assertEquals(cookie1.getComment(), cookie2.getComment());
                assertEquals(cookie1.getDomain(), cookie2.getDomain());
                assertEquals(cookie1.getMaxAge(), cookie2.getMaxAge());
                assertEquals(cookie1.getName(), cookie2.getName());
                assertEquals(cookie1.getPath(), cookie2.getPath());
                assertEquals(cookie1.getValue(), cookie2.getValue());
                assertEquals(cookie1.getVersion(), cookie2.getVersion());
            }
        }
    }

    /**
     *
     */
    public static void assertHeadersEqual(Headers headers1, Headers headers2) {
        if (headers1 == null) {
            assertNull(headers2);
        }
        else {
            assertEquals(headers1.getHeader().size(), headers2.getHeader().size());
            
            for (int i = 0; i < headers1.getHeader().size(); i++) {
                Header header1 = headers1.getHeader().get(i);
                Header header2 = headers2.getHeader().get(i);
                assertEquals(header1.getKey(), header2.getKey());
                assertEquals(header1.getValue(), header2.getValue());
            }
        }
    }

    /**
     *
     */
    public static void assertResponseEquals(HttpResponse response1, HttpResponse response2) {
        assertEquals(response1.getStatus(), response2.getStatus());
        assertEquals(response1.getContent().getData(), response2.getContent().getData());
        assertEquals(response1.getContent().getEncoding(), response2.getContent().getEncoding());
        assertEquals(response1.getContent().getLength(), response2.getContent().getLength());
        assertEquals(response1.getContent().getType(), response2.getContent().getType());
        
        assertHeadersEqual(response1.getHeaders(), response2.getHeaders());
    }

    /**
     * 
     */
    private HTTPTestUtils() {
        // prevent instantiation
    }
}
