package sklep.baza;

import static org.hamcrest.CoreMatchers.anyOf;
import static org.hamcrest.CoreMatchers.is;

import java.io.FileReader;
import java.math.BigDecimal;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

import org.dbunit.DBTestCase;
import org.dbunit.PropertiesBasedJdbcDatabaseTester;
import org.dbunit.dataset.IDataSet;
import org.dbunit.dataset.xml.XmlDataSet;
import org.junit.Assume;

import sklep.baza.Baza;
import sklep.exn.BladBazyDanych;
import sklep.model.Towar;

public class TestBaza_DBTestCase extends DBTestCase {
	private static final String PRALKA = "Pralka";
	private static final String KREDKA = "Kredka";
	private static final String ODKURZACZ = "Odkurzacz";
	private static final String PISAK = "Pisak";
	private static final String NIEZNANY = "nieznany";
	private static final double ZMIANA = 10.0;
	private Baza baza;

	protected void setUp() throws Exception {
		/* Ustawiamy wlasnosci dla DBUnita. */
		System.setProperty(PropertiesBasedJdbcDatabaseTester.DBUNIT_DRIVER_CLASS, "org.sqlite.JDBC");
		System.setProperty(PropertiesBasedJdbcDatabaseTester.DBUNIT_CONNECTION_URL, Baza.url);
		Class.forName("org.sqlite.JDBC");
		super.setUp();

		/* Nastepnie inicjujemy "nasz" testowany obiekt Baza. */
		baza = Baza.nowaBaza(this.getConnection().getConnection());
	}

	@Override
	protected IDataSet getDataSet() throws Exception {
		return new XmlDataSet(new FileReader("dane.xml"));
	}
	
	public void testWezTowar() throws BladBazyDanych {
		Towar towar = baza.wezTowar(PRALKA);
		assertEquals(PRALKA, towar.getNazwa());
		assertEquals(new BigDecimal("1234.00"), towar.getCenaNetto());
		assertEquals(new BigDecimal("0.23"), towar.getVat());
	}

	public void testWezTowar_Nieistniejacy() throws BladBazyDanych {
		Towar towar = baza.wezTowar(NIEZNANY);
		assertEquals(null, towar);
	}

	public void testZapiszTowarNowy() throws BladBazyDanych {
		Towar nowy = new Towar(PISAK, new BigDecimal("10.00"), new BigDecimal("0.23"));
		baza.zapiszTowar(nowy);
		Towar wczytany = baza.wezTowar(PISAK);
		assertNotNull(wczytany);
		assertEquals(nowy, wczytany);
	}
	
	public void testZapiszTowarIstniejacy() throws BladBazyDanych {
		Towar nowy = new Towar(PRALKA, new BigDecimal("120.00"), new BigDecimal("0.07"));
		baza.zapiszTowar(nowy);
		Towar wczytany = baza.wezTowar(PRALKA);
		assertNotNull(wczytany);
		assertEquals(nowy, wczytany);
	}
/*
	public void testZmienWszystkieCeny() throws BladBazy {
//TODO
	}

	public void testZmienCene() throws BladBazy {
		//TODO
	}
*/	
	/** Test metody znajdzMagazynZTowarem w deterministycznym scenariuszu pozytywnym. */
	public void testZnajdzMagazynZTowarem() throws BladBazyDanych {
		String wynik = baza.znajdzMagazynZTowarem(KREDKA, 5);
		assertNotNull(wynik);
		assertEquals("Opole", wynik);
	}

	/** Test metody znajdzMagazynZTowarem w scenariuszu pozytywnym gdy kilka magazynow spelnia warunek. */
	public void testZnajdzMagazynZTowarem_Wiele() throws BladBazyDanych {
		String wynik = baza.znajdzMagazynZTowarem(KREDKA, 3);
		assertNotNull(wynik);
		//assertTrue("Wynik nie jest Warszawa ani Opole", "Warszawa".equals(wynik) || "Opole".equals(wynik));
		
		org.junit.Assert.assertThat(wynik, anyOf(is("Warszawa"), is("Opole")));
	}

	/** Test metody znajdzMagazynZTowarem w scenariuszu negatywnym (brak magazynu zawierajacego towar). */
	public void testZnajdzMagazynZTowarem_Zero() throws BladBazyDanych {
		String wynik = baza.znajdzMagazynZTowarem(NIEZNANY, 1);
		assertNull(wynik);
	}

	/** Test metody znajdzMagazynZTowarem w scenariuszu negatywnym (za malo towarow w magazynach). */
	public void testZnajdzMagazynZTowarem_ZaMalo() throws BladBazyDanych {
		String wynik = baza.znajdzMagazynZTowarem(KREDKA, 10);
		assertNull(wynik);
	}

	public void testZmienStanMagazynu() throws SQLException, Exception {
		baza.zmienStanMagazynu("Warszawa", KREDKA, -2);

		PreparedStatement stmt = getConnection().getConnection().prepareStatement(
				"SELECT stan FROM stany WHERE towar = ? AND magazyn = ?");
		stmt.setString(1, KREDKA);
		stmt.setString(2, "Warszawa");
		ResultSet rs;
		rs = stmt.executeQuery();
		try {
			boolean next = rs.next();
			Assume.assumeTrue(next);

			int nowyStan = rs.getInt(1);
			assertEquals(1, nowyStan);
		} finally {
			rs.close();
		}
	}
}
