/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package com.smartitengineering.bookstore.ws.server;

import com.smartitengineering.bookstore.domain.Book;
import com.smartitengineering.bookstore.domain.PublicationHouse;
import com.smartitengineering.bookstore.domain.filter.BookFilter;
import com.smartitengineering.bookstore.domain.filter.PublicationHouseFilter;
import com.smartitengineering.bookstore.ws.element.BookElement;
import com.smartitengineering.bookstore.ws.element.BookElements;
import com.smartitengineering.bookstore.ws.element.BookFilterElement;
import com.smartitengineering.bookstore.ws.element.PublicationHouseElement;
import com.smartitengineering.bookstore.ws.element.PublicationHouseElements;
import com.smartitengineering.bookstore.ws.element.PublicationHouseFilterElement;
import com.sun.jersey.api.client.Client;
import com.sun.jersey.api.client.WebResource;
import com.sun.jersey.api.client.WebResource.Builder;
import com.sun.jersey.client.apache.ApacheHttpClient;
import com.sun.jersey.client.apache.config.DefaultApacheHttpClientConfig;
import com.sun.jersey.core.util.MultivaluedMapImpl;
import java.io.File;
import java.net.URI;
import java.util.Collections;
import java.util.Random;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.core.UriBuilder;
import junit.framework.TestCase;
import org.glassfish.embed.GlassFish;
import org.glassfish.embed.ScatteredWar;

/**
 *
 * @author imyousuf
 */
public class BookStoreResourcesTest
        extends TestCase {

    private static int getPort(int defaultPort) {
        String port = System.getenv("JERSEY_HTTP_PORT");
        if (null != port) {
            try {
                return Integer.parseInt(port);
            } catch (NumberFormatException e) {
            }
        }
        return defaultPort;
    }

    private static URI getBaseURI() {
        return UriBuilder.fromUri("http://localhost/").port(getPort(9998)).path(
                "bookstore").build();
    }
    private static final URI BASE_URI = getBaseURI();
    private GlassFish glassfish;
    private WebResource webResource;
    private Client client;

    public BookStoreResourcesTest(String testName) {
        super(testName);
    }

    @Override
    protected void setUp()
            throws Exception {
        super.setUp();
        // Start Glassfish
        glassfish = new GlassFish(BASE_URI.getPort());
        // Deploy Glassfish referencing the web.xml
        ScatteredWar war = new ScatteredWar(BASE_URI.getRawPath(),
                new File("src/test/webapp"),
                new File("src/test/webapp/WEB-INF/unitTestWeb.xml"),
                Collections.singleton(new File("target/classes").toURI().toURL()));
        glassfish.deploy(war);
        DefaultApacheHttpClientConfig clientConfig = new DefaultApacheHttpClientConfig();
        clientConfig.getState().setCredentials(null, null, -1, "modhu", "modhu");
        client = ApacheHttpClient.create(clientConfig);
        webResource = client.resource(BASE_URI);
    }

    @Override
    protected void tearDown()
            throws Exception {
        super.tearDown();
        glassfish.stop();
    }

    public void testResources() {
        doTestPublicationServices();
        doTestBookServices();
    }
    
    private void doTestBookServices(){
        doTestBookCreate();
        doTestBookUpdate();
        doTestBookGetByISBN();
        doTestBookDelete();
        doTestBookSearchGet();
        doTestBookSearchPost();        
    }
    
    private void doTestPublicationServices() {
        doTestPublicationHouseCreate();
        doTestPublicationHouseUpdate();
        doTestPublicationHouseGetByUniqueShortName();
        doTestPublicationHouseDelete();
        doTestPublicationHouseSearchGet();
        doTestPublicationHouseSearchPost();        
    }

    
    public void doTestBookCreate() {
        int count = Math.abs(new Random().nextInt()) + 1;
        if (count > 10) {
            count = 10;
        }
        System.out.println("Total creation iteration number: " + count);
        BookElement bookElement = new BookElement();
        Book book = new Book();
        bookElement.setBook(book);

        for (int j = 0; j < count; ++j) {
            for (int i = 0; i < 2; ++i) {
                final Builder type =
                        webResource.path("book").type("application/xml");
                type.post(bookElement);
            }
            try {
                final Builder type =
                        webResource.path("book").type("application/xml");
                type.post(bookElement);
                fail("Should not succeed!");
            } catch (Exception ex) {
                
            }
        }
    }

    public void doTestBookDelete() {
        String isbn = "testA";
        final String baseUri = "book";
        webResource.path(baseUri + "/" + isbn).delete();
    }
    
    private void doTestBookUpdate() {
        String isbn = "testA";
        WebResource resource = webResource.path("book/" + isbn);
        assertEquals(200, resource.head().getStatus());
        final BookElement element = resource.get(BookElement.class);
        assertNotNull(element);
        final Builder type = webResource.path("book").type("application/xml");
        type.put(element);
    }
    
    private void doTestBookGetByISBN() {
        String isbn = "testA";
        WebResource resource = webResource.path("book/" + isbn);
        assertEquals(200, resource.head().getStatus());
        final BookElement element = resource.get(BookElement.class);
        assertNotNull(element);
        final Book book = element.getBook();
        assertNotNull(book);
        assertEquals(isbn, book.getIsbn());
        assertEquals("No Name", book.getName());
    }
    
      private void doTestBookSearchGet() {
        MultivaluedMap<String, String> map = new MultivaluedMapImpl();
        final String name = "Muktomon";
        final String isbn = "000-0000-000";
        map.add("name", name);
        map.add("isbn", isbn);
        WebResource resource =
                webResource.path("book").queryParams(map);
        BookElements elements = resource.get(BookElements.class);         
        verifyBookElements(elements, name, isbn);
        final String nameDefault = "NO NAME";
        final String isbnDefault = "NO ISBN";
        resource = webResource.path("book");
        //elements = resource.get(BookElements.class);
        //verifyBookElements(elements, nameDefault, isbnDefault);
    }

    private void doTestBookSearchPost() {
        BookFilterElement filter = new BookFilterElement();
        BookFilter bookFilter = new BookFilter();
        filter.setBookFilter(bookFilter);
        final String name = "Muktomon";
        final String isbn = "000-0000-000";
        bookFilter.setName(name);
        bookFilter.setIsbn(isbn);
        final Builder type = webResource.path("book/search").type("application/xml");
        final BookElements elements = type.post(BookElements.class, filter);
        verifyBookElements(elements, name, isbn);
    }

    
    private void doTestPublicationHouseDelete() {
        String uniqueShortName = "testA";
        final String baseUri = "pub-house";
        webResource.path(baseUri + "/" + uniqueShortName).delete();
    }

    private void doTestPublicationHouseGetByUniqueShortName() {
        String uniqueShortName = "testA";
        WebResource resource = webResource.path("pub-house/" +
                uniqueShortName);
        assertEquals(200, resource.head().getStatus());
        final PublicationHouseElement element = resource.get(
                PublicationHouseElement.class);
        assertNotNull(element);
        final PublicationHouse publicationHouse = element.getPublicationHouse();
        assertNotNull(publicationHouse);
        assertEquals(uniqueShortName, publicationHouse.getUniqueShortName());
        assertEquals("No Name", publicationHouse.getName());
        assertEquals("NONE@NONE", publicationHouse.getContactEmailAddress());
    }

    private void doTestPublicationHouseSearchGet() {
        MultivaluedMap<String, String> map = new MultivaluedMapImpl();
        final String name = "Sheba Prokashoni";
        final String uniqueName = "sheba-prok";
        map.add("name", name);
        map.add("shortName", uniqueName);
        WebResource resource =
                webResource.path("pub-house").queryParams(map);
        PublicationHouseElements elements = resource.get(
                PublicationHouseElements.class);
        verifyPublicationHouseElements(elements, name, uniqueName);
        final String nameDefault = "NO NAME";
        final String uniqueNameDefault = "NO SHORT NAME";
        resource =
                webResource.path("pub-house");
        elements = resource.get(
                PublicationHouseElements.class);
        verifyPublicationHouseElements(elements, nameDefault, uniqueNameDefault);
    }

    private void doTestPublicationHouseSearchPost() {
        PublicationHouseFilterElement filter =
                new PublicationHouseFilterElement();
        PublicationHouseFilter publicationHouseFilter =
                new PublicationHouseFilter();
        filter.setPublicationHouseFilter(publicationHouseFilter);
        final String name = "Sheba Prokashoni";
        final String uniqueName = "sheba-prok";
        publicationHouseFilter.setName(name);
        publicationHouseFilter.setUniqueShortString(uniqueName);
        final Builder type =
                webResource.path("pub-house/search").type("application/xml");
        final PublicationHouseElements elements = type.post(
                PublicationHouseElements.class, filter);
        verifyPublicationHouseElements(elements, name, uniqueName);
    }

    private void doTestPublicationHouseCreate() {
        int count = Math.abs(new Random().nextInt()) + 1;
        if (count > 10) {
            count = 10;
        }
        System.out.println("Total creation iteration number: " + count);
        PublicationHouseElement houseElement = new PublicationHouseElement();
        PublicationHouse house = new PublicationHouse();
        houseElement.setPublicationHouse(house);
      
        for (int j = 0; j < count; ++j) {
            for (int i = 0; i < 2; ++i) {
                final Builder type =
                        webResource.path("pub-house").type("application/xml");
                type.post(houseElement);
            }
            try {
                final Builder type =
                        webResource.path("pub-house").type("application/xml");
                type.post(houseElement);
                fail("Should not succeed!");
            } catch (Exception ex) {
            
            }
        }
    }

    private void doTestPublicationHouseUpdate() {
        String uniqueShortName = "testA";
        WebResource resource = webResource.path("pub-house/" +
                uniqueShortName);
        assertEquals(200, resource.head().getStatus());
        final PublicationHouseElement element = resource.get(
                PublicationHouseElement.class);
        assertNotNull(element);
        final Builder type =
                webResource.path("pub-house").type("application/xml");
        type.put(element);
    }

    private void verifyBookElements(final BookElements elements, final String name, final String isbn) {        
        assertTrue(elements.getBooks().size() > 0);
        for (Book book : elements.getBooks()) {
            System.out.println(book.getName());
            System.out.println(book.getIsbn());
            assertTrue(book.getName().startsWith(name));
            assertTrue(book.getIsbn().startsWith(isbn));
        }
    }

    private void verifyPublicationHouseElements(final PublicationHouseElements elements,
            final String name,
            final String uniqueName) {
        assertTrue(elements.getPublicationHouses().size() > 0);
        for (PublicationHouse house : elements.getPublicationHouses()) {
            assertTrue(house.getName().startsWith(name));
            assertTrue(house.getUniqueShortName().startsWith(uniqueName));
        }
    }
}