package com.approximatrix.draco.io;

import static org.junit.Assert.*;
import static com.approximatrix.draco.io.LoadDracoSQLTest.*;

import java.io.File;
import java.io.IOException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import com.approximatrix.draco.analysis.RunANOVA;
import com.approximatrix.draco.fit.RunLS;
import com.approximatrix.draco.fit.RunNLLS;
import com.approximatrix.draco.fit.RunTSLS;
import com.approximatrix.draco.fit.SimpleMLEFit;
import com.approximatrix.draco.general.ui.InfoWindow;
import com.approximatrix.draco.io.sql.DracoSQLTables;
import com.approximatrix.draco.main.ui.SyntheticMainWindow;
import com.approximatrix.draco.main.ui.WorksheetHandler;

public class SaveDracoSQLTest {

	private static final int EXPECTED_STEP_COUNT = 9;
	
	private SyntheticMainWindow smw = null;
	private SaveDracoSQL saver = null;
	private String filename = null;
	
	@Before
	public void setUp() throws Exception {
		smw = new SyntheticMainWindow();
		loadFile(smw,FULL_LOAD_FILE);
		filename = File.createTempFile("SaveDracoSQLTest", ".sql-draco").getAbsolutePath();
		saver = new SaveDracoSQL(filename,smw);
	}

	@After
	public void tearDown() throws Exception {
		new File(filename).delete();
		smw = null;
	}
	
	@Test
	public void testGetTotalSteps() {
		assertEquals(EXPECTED_STEP_COUNT, saver.getTotalSteps());
	}
	
	@Test
	public void testDoStep() throws SQLException, ClassNotFoundException {
		for(int i=0;i<saver.getTotalSteps();i++) {
			saver.doStep();
			assertTrue("A save failure ocurred on step "+Integer.toString(i),
					saver.stepSuccess());
		}
		validateFile();
	}

	private void loadFile(WorksheetHandler smw, String filename) throws IOException {
		LoadDracoSQL loader = new LoadDracoSQL(filename,smw);
		for(int i=0;i<9;i++) {
			loader.doStep();
			if(i==1)
				smw.setWindowTableModel(loader.getLoadedData());
			if(!loader.stepSuccess())
				throw new IOException("The file failed to load properly...");
		}
		loader = null;
	}

	private void validateFile() throws SQLException, ClassNotFoundException {
		Class.forName("org.sqlite.JDBC");
		Connection conn = null;
		try {
			conn = DriverManager.getConnection("jdbc:sqlite:"+filename);
		
			validateVariables(conn);
			validateConstants(conn);
			validateRegressions(conn);
			validateAnalyses(conn);
			validatePlots(conn);
			validatePlugins(conn);
			validateTexts(conn);
		} finally {
			if(conn != null)
				conn.close();
		}
	}
	
	private void validateVariables(Connection conn) throws SQLException {
		assertCount(smw.getWindowTableModel().getColumnCount(), "SELECT COUNT(*) FROM "+DracoSQLTables.VARIABLES,conn);
		assertCount(smw.getWindowTableModel().getRowCount(), "SELECT COUNT(*) FROM "+DracoSQLTables.DATA,conn);
	}
	
	private void validatePlots(Connection conn) throws SQLException {
		assertCount(PLOT_COUNT, "SELECT COUNT(*) FROM "+DracoSQLTables.PLOT,conn);
	}
	
	private void validatePlugins(Connection conn) throws SQLException {
		assertCount(PLUGIN_COUNT, "SELECT COUNT(*) FROM "+DracoSQLTables.PLUGIN,conn);
		assertCount(REGRESSION_PLUGIN_COUNT, "SELECT COUNT(*) FROM "+DracoSQLTables.REGRESSION_PLUGIN,conn);
	}
	
	private void validateRegressions(Connection conn) throws SQLException {
		assertCount(REGRESSIONS.length+REGRESSION_PLUGIN_COUNT, "SELECT COUNT(*) FROM "+DracoSQLTables.REGRESSION,conn);
	}
	
	private void validateTexts(Connection conn) throws SQLException {
		assertCount(smw.getWindowsByClass(InfoWindow.class).length, "SELECT COUNT(*) FROM "+DracoSQLTables.TEXT,conn);
	}
	
	private void validateAnalyses(Connection conn) throws SQLException {
		assertCount(ANALYSES.length, "SELECT COUNT(*) FROM "+DracoSQLTables.ANALYSIS,conn);
	}
	
	private void validateConstants(Connection conn) throws SQLException {
		assertCount(smw.getWindowTableModel().getConstants().size(), "SELECT COUNT(*) FROM "+DracoSQLTables.PARAMETERS+" WHERE "+
				                                                     DracoSQLTables.PARAM_TYPE+" = "+DracoSQLTables.TYPE_CONSTANT,conn);
	}
	
	private void assertCount(int expected, String query, Connection conn) throws SQLException {
		Statement stat = conn.createStatement(ResultSet.TYPE_FORWARD_ONLY,
					ResultSet.CONCUR_READ_ONLY);
		//System.err.println("Query>> "+query);
		ResultSet rs = stat.executeQuery(query);
		assertEquals(expected,rs.getInt(1));
	}
}
