package jp.sf.amateras.mirage;

import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

import java.sql.Connection;
import java.sql.DriverManager;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import jp.sf.amateras.mirage.annotation.PrimaryKey;
import jp.sf.amateras.mirage.provider.ConnectionProvider;
import junit.framework.TestCase;

public class SqlManagerImplTest extends TestCase {

	private static final String SQL_PREFIX = "jp/sf/amateras/mirage/";

	private SqlManager sqlManager = new SqlManagerImpl();
	private Connection conn;

	@Override
	protected void setUp() throws Exception {
		super.setUp();
		Class.forName("org.h2.Driver");
		conn = DriverManager.getConnection("jdbc:h2:~/mirage_test", "sa", "");

		ConnectionProvider connectionProvider = mock(ConnectionProvider.class);
		when(connectionProvider.getConnection()).thenReturn(conn);

		sqlManager.setConnectionProvider(connectionProvider);
		sqlManager.executeUpdate(SQL_PREFIX + "SqlManagerImplTest_setUp.sql");
	}

	@Override
	protected void tearDown() throws Exception {
		super.tearDown();
		sqlManager.executeUpdate(SQL_PREFIX + "SqlManagerImplTest_tearDown.sql");
		conn.close();
	}

	public void testGetSingleResultByMap() throws Exception {
		Book book = new Book();
		book.bookName = "Mirage in Action";
		book.author = "Naoki Takezoe";
		book.price = 20;

		sqlManager.insertEntity(book);

		Map<String, String> param = new HashMap<String, String>();
		param.put("bookName", "Mirage in Action");

		@SuppressWarnings("unchecked")
		Map map = sqlManager.getSingleResult(
				Map.class,
				SQL_PREFIX + "SqlManagerImplTest_selectByBookName.sql",
				param);

		assertEquals("Mirage in Action", map.get("bookName"));
		assertEquals("Naoki Takezoe", map.get("author"));
		assertEquals("20", map.get("price"));
	}

	public void testGetSingleResultByInteger() throws Exception {
		Book book = new Book();
		book.bookName = "Mirage in Action";
		book.author = "Naoki Takezoe";
		book.price = 20;

		sqlManager.insertEntity(book);
		sqlManager.insertEntity(book);

		Integer count = sqlManager.getSingleResult(
				Integer.class,
				SQL_PREFIX + "SqlManagerImplTest_countBook.sql");

		assertEquals(2, count.intValue());
	}

	public void testGetCount() throws Exception {
		Book book = new Book();
		book.bookName = "Mirage in Action";
		book.author = "Naoki Takezoe";
		book.price = 20;

		sqlManager.insertEntity(book);
		sqlManager.insertEntity(book);

		Map<String, String> param = new HashMap<String, String>();
		param.put("bookName", "Mirage in Action");

		int count = sqlManager.getCount(
				SQL_PREFIX + "SqlManagerImplTest_selectByBookName.sql",
				param);

		assertEquals(2, count);
	}

	public void testInsertEntity() throws Exception {
		Book book = new Book();
		book.bookName = "Mirage in Action";
		book.author = "Naoki Takezoe";
		book.price = 20;

		sqlManager.insertEntity(book);

		BookParam param = new BookParam();
		param.bookName = "Mirage in Action";

		List<Book> bookList = sqlManager.getResultList(
				Book.class,
				SQL_PREFIX + "SqlManagerImplTest_selectByBookName.sql",
				param);

		assertEquals(1, bookList.size());
		assertEquals("Mirage in Action", bookList.get(0).bookName);
		assertEquals("Naoki Takezoe", bookList.get(0).author);
		assertEquals(new Integer(20), bookList.get(0).price);
	}

	public void testUpdateEntity() throws Exception {
		Book book = new Book();
		book.bookName = "Mirage in Action";
		book.author = "Naoki Takezoe";
		book.price = 20;

		sqlManager.insertEntity(book);

		BookParam param = new BookParam();
		param.bookName = "Mirage in Action";

		book = sqlManager.getSingleResult(
				Book.class,
				SQL_PREFIX + "SqlManagerImplTest_selectByBookName.sql",
				param);

		book.price = 100;
		sqlManager.updateEntity(book);

		List<Book> bookList = sqlManager.getResultList(
				Book.class,
				SQL_PREFIX + "SqlManagerImplTest_selectByBookName.sql");

		assertEquals(1, bookList.size());
		assertEquals("Mirage in Action", bookList.get(0).bookName);
		assertEquals("Naoki Takezoe", bookList.get(0).author);
		assertEquals(new Integer(100), bookList.get(0).price);
	}

	public void testDeleteEntity() throws Exception {
		Book book = new Book();
		book.bookName = "Mirage in Action";
		book.author = "Naoki Takezoe";
		book.price = 20;

		sqlManager.insertEntity(book);

		BookParam param = new BookParam();
		param.bookName = "Mirage in Action";

		book = sqlManager.getSingleResult(
				Book.class,
				SQL_PREFIX + "SqlManagerImplTest_selectByBookName.sql",
				param);

		sqlManager.deleteEntity(book);

		book = sqlManager.getSingleResult(
				Book.class,
				SQL_PREFIX + "SqlManagerImplTest_selectByBookName.sql",
				param);

		assertNull(book);
	}

	public void testFindEntity(){
		Book book = new Book();
		book.bookName = "Mirage in Action";
		book.author = "Naoki Takezoe";
		book.price = 20;

		sqlManager.insertEntity(book);

		book = sqlManager.findEntity(Book.class, 1);
		assertEquals("Mirage in Action", book.bookName);
		assertEquals("Naoki Takezoe", book.author);
		assertEquals(new Integer(20), book.price);

		book = sqlManager.findEntity(Book.class, 0);
		assertNull(book);
	}

	public void testIterate() throws Exception {
		{
			Book book = new Book();
			book.bookName = "Mirage in Action";
			book.author = "Naoki Takezoe";
			book.price = 20;
	
			sqlManager.insertEntity(book);
		}
		{
			Book book = new Book();
			book.bookName = "Click in Action";
			book.author = "Bob Schellink";
			book.price = 30;
	
			sqlManager.insertEntity(book);
		}

		Integer result = sqlManager.iterate(
				Book.class,
				new IterationCallback<Book, Integer>() {
					
					private int result;
					
					@Override
					public Integer iterate(Book entity) {
						result = result + entity.price;
						return result;
					}
				},
				SQL_PREFIX + "SqlManagerImplTest_selectByBookName.sql");

		assertEquals(50, result.intValue());
	}

	
	public static class BookParam {
		public String bookName;
	}

	public static class Book {
		@PrimaryKey
		public Long bookId;
		public String bookName;
		public String author;
		public Integer price;
	}

}
