package controllers;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.text.ParseException;
import java.util.AbstractMap.SimpleEntry;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

import com.google.common.base.Strings;
import com.google.common.collect.Lists;

import objects.HorseRaceData;
import objects.UpdateRaceRow;
import parsers.TravsportParser;

public class DatabaseContoller {

	private static final DatabaseContoller instance = new DatabaseContoller();

	private static final String username = "atg";
	private static final String password = "CvWKY34DqtlVgjt_9";
	private static final String database = "atg";
	private static final String url = "jdbc:mysql://nordh.xyz:3306/";
	private static final String timezoneFix = "?useUnicode=true&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=UTC";

	private Connection conn;

	protected DatabaseContoller() {
		getConnection();
	}

	public static DatabaseContoller getInstance() {
		return instance;
	}

	protected Connection getConnection() {
		if (conn == null) {
			try {
				conn = DriverManager.getConnection(url + database + timezoneFix, username, password);
			} catch (final SQLException e) {
				e.printStackTrace();
			}
		}
		return conn;
	}

	public void insertResult(String trackShortCode, String date, int raceNumber, int lane, int distance, int result,
			float time, String timeModifier, int shoes, int sulky, String driver, String trainer, String horseName,
			int travsportIdHorse, int travsportIdTrainer, int travsportIdDriver, String raceType, int raceId) {
		final String sql;
		final boolean raceToday = date.equals(MainController.DATE_FORMAT.format(new Date()));
		horseName = horseName.replaceAll("[^a-zåäöA-ZÅÄÖ0-9 ()\\.']", "");
		driver = driver.replaceAll("[^a-zåäöA-ZÅÄÖ0-9] ()\\.'", "");
		if (raceToday) {
			sql = "INSERT INTO "
					+ "`Results`(`TrackId`, `RaceDate`, `RaceNumber`, `Lane`, `Distance`, `Result`, `Time`, `TimeModifier`, "
					+ "`Shoes`, `Sulky`, `DriverId`, `TrainerId`, `HorseId`, raceId, RaceType) "
					+ "VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?) ON DUPLICATE KEY UPDATE id=id, Result = ?, Time = ?, RaceType = CONCAT(RaceType, ?)";
		} else {
			sql = "INSERT INTO "
					+ "`Results`(`TrackId`, `RaceDate`, `RaceNumber`, `Lane`, `Distance`, `Result`, `Time`, `TimeModifier`, "
					+ "`Shoes`, `Sulky`, `DriverId`, `TrainerId`, `HorseId`, raceId) "
					+ "VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?) ON DUPLICATE KEY UPDATE id=id, Result = ?, Time = ?";
		}

		final int horseId = getHorseId(horseName, travsportIdHorse);
		final int driverId = getDriverId(driver, travsportIdDriver);
		final int trainerId = getTrainerId(trainer, travsportIdTrainer);
		final int trackId = getTrackIdFromShortcode(trackShortCode);

		try {
			final PreparedStatement stat = getConnection().prepareStatement(sql);

			stat.setInt(1, trackId);
			stat.setString(2, date);
			stat.setInt(3, raceNumber);
			stat.setInt(4, lane);
			stat.setInt(5, distance);
			stat.setInt(6, result);
			stat.setFloat(7, time);
			stat.setString(8, timeModifier);
			stat.setInt(9, shoes);
			stat.setInt(10, sulky);
			stat.setInt(11, driverId);
			stat.setInt(12, trainerId);
			stat.setInt(13, horseId);
			stat.setInt(14, raceId);

			if (raceToday) {
				stat.setString(15, raceType);

				stat.setInt(16, result);
				stat.setFloat(17, time);
				stat.setString(18, ", " + raceType);
			} else {
				stat.setInt(15, result);
				stat.setFloat(16, time);
			}
			stat.executeUpdate();

		} catch (final SQLException e) {
			e.printStackTrace();
		}
	}

	private int insertNewName(String table, String name, int travsportId) { // travsportId inte generell, behövs en bättre lösning
		final String sql = "INSERT INTO " + table + " (name, travsportId) VALUES (?, ?)";
		int last_id = -1;
		try {
			final PreparedStatement stat = getConnection().prepareStatement(sql, PreparedStatement.RETURN_GENERATED_KEYS);
			stat.setString(1, name);
			stat.setInt(2, travsportId);

			stat.executeUpdate();
			final ResultSet generatedId = stat.getGeneratedKeys();
			while (generatedId.next()) {
				last_id = generatedId.getInt(1);
			}

		} catch (final SQLException e) {
			e.printStackTrace();
		}
		return last_id;
	}

	private int getTrackIdFromShortcode(String shortcode) {
		final String trackSql = "SELECT id FROM Track WHERE shortCode = ?";
		int trackId = -1;
		try {
			final PreparedStatement stat = getConnection().prepareStatement(trackSql);
			stat.setString(1, shortcode);

			final ResultSet rs = stat.executeQuery();
			while (rs.next()) {
				trackId = rs.getInt("id");
			}
		} catch (final SQLException e) {
			e.printStackTrace();
		}

		return trackId;
	}

	public int getHorseId(String horseName, int travsportId) {
		horseName = horseName.replaceAll("[^a-zåäöA-ZÅÄÖ0-9 ()\\.']", "");
		final String horseSql = "SELECT id FROM Horse WHERE name = ? OR travsportId = ?";
		int horseId = -1;
		try {
			final PreparedStatement stat = getConnection().prepareStatement(horseSql);
			stat.setString(1, horseName);
			stat.setInt(2, travsportId);

			final ResultSet rs = stat.executeQuery();
			while (rs.next()) {
				horseId = rs.getInt("id");
			}
			if (horseId == -1) {
				horseId = insertNewName("Horse", horseName, travsportId);
			}
		} catch (final SQLException e) {
			e.printStackTrace();
		}

		return horseId;
	}

	public int getHorseTravsportId(String horseName) {
		final String sql = "SELECT travsportId FROM Horse WHERE name = ?";
		int id = -1;

		try {
			final PreparedStatement stat = getConnection().prepareStatement(sql);
			stat.setString(1, horseName);

			final ResultSet rs = stat.executeQuery();

			while (rs.next()) {
				id = rs.getInt("travsportId");
			}
		} catch (final SQLException e) {
			e.printStackTrace();
		}

		return id;
	}

	public int getDriverId(String driverName, int travsportId) {
		driverName = driverName.replaceAll("[^a-zA-Z0-9 ]", "");
		final String driverSql = "SELECT id FROM Driver WHERE name = ? OR travsportId = ?";
		int driverId = -1;
		try {
			final PreparedStatement stat = getConnection().prepareStatement(driverSql);
			stat.setString(1, driverName);
			stat.setInt(2, travsportId);

			final ResultSet rs = stat.executeQuery();
			while (rs.next()) {
				driverId = rs.getInt("id");
			}
			if (driverId == -1) {
				driverId = insertNewName("Driver", driverName, travsportId);
			}
		} catch (final SQLException e) {
			e.printStackTrace();
		}

		return driverId;
	}

	private int getTrainerId(String trainerName, int travsportId) {
		trainerName = trainerName.replaceAll("[^a-zA-Z0-9 ]", "");
		final String trainerSql = "SELECT id FROM Trainer WHERE name = ? OR travsportId = ?";
		int trainerId = -1;
		try {
			final PreparedStatement stat = getConnection().prepareStatement(trainerSql);
			stat.setString(1, trainerName);
			stat.setInt(2, travsportId);

			final ResultSet rs = stat.executeQuery();
			while (rs.next()) {
				trainerId = rs.getInt("id");
			}
			if (trainerId == -1) {
				trainerId = insertNewName("Trainer", trainerName, travsportId);
			}
		} catch (final SQLException e) {
			e.printStackTrace();
		}

		return trainerId;
	}

	public void setHorseTravsportId(int horseId, String horseName) {
		final String sql = "UPDATE Horse SET travsportId = ? WHERE name = ?";

		try {
			final PreparedStatement stat = getConnection().prepareStatement(sql);
			stat.setInt(1, horseId);
			stat.setString(2, horseName);

			stat.executeUpdate();
		} catch (final SQLException e) {
			e.printStackTrace();
		}
	}

	// Lane stats SELECT Lane, Count(*) FROM `Results` WHERE Result = 1 AND TimeModifier NOT like "%a%" GROUP BY Lane ORDER BY `Results`.`Lane` ASC
	// SELECT Lane, (Count(*) / SUM(COUNT(*)) OVER()) * 100 AS Percent, Distance FROM `Results` WHERE Result = 1 AND TimeModifier NOT like '%a%' AND Lane > 0 AND Distance IN (2140,2160) GROUP BY Lane, Distance ORDER BY `Results`.`Lane` ASC

	public List<SimpleEntry<Integer, Float>> getAutostartWinPercents(ArrayList<String> distance) {
		final List<SimpleEntry<Integer, Float>> resultList = Lists.newArrayList();
		final String sql = "SELECT Lane, (Count(*) / SUM(COUNT(*)) OVER()) * 100 AS Percent, distance FROM `Results` WHERE Result = 1 AND TimeModifier like '%a%' AND Lane > 0 AND Distance IN (?) GROUP BY Lane, distance ORDER BY `Results`.`Lane` ASC";
		try {
			final PreparedStatement stat = getConnection().prepareStatement(sql);
			stat.setString(1, String.join(",", distance));
			final ResultSet rs = stat.executeQuery();

			while (rs.next()) {
				resultList.add(new SimpleEntry<>(rs.getInt("Lane"), rs.getFloat("Percent")));
			}

		} catch (final SQLException e) {
			e.printStackTrace();
		}

		return resultList;
	}

	public List<SimpleEntry<Integer, Float>> getVoltstartWinPercents(ArrayList<String> distance) {
		final List<SimpleEntry<Integer, Float>> resultList = Lists.newArrayList();
		final String sql = "SELECT Lane, (Count(*) / SUM(COUNT(*)) OVER()) * 100 AS Percent FROM `Results` WHERE Result = 1 AND TimeModifier NOT like '%a%' AND Lane > 0 AND Distance = ? GROUP BY Lane ORDER BY `Results`.`Lane` ASC";
		try {
			final PreparedStatement stat = getConnection().prepareStatement(sql);
			stat.setString(1, String.join(",",distance));
			final ResultSet rs = stat.executeQuery();

			while (rs.next()) {
				resultList.add(new SimpleEntry<>(rs.getInt("Lane"), rs.getFloat("Percent")));
			}

		} catch (final SQLException e) {
			e.printStackTrace();
		}

		return resultList;
	}

	public List<HorseRaceData> getTodaysRaces(String type, String date) {
		final String sql;
		Date date2 = new Date();
		try {
			date2 = MainController.DATE_FORMAT.parse(date);
		} catch (final ParseException e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		}
		final Calendar c = Calendar.getInstance();
		c.setTime(date2);
		c.add(Calendar.YEAR, -2);
		final String twoYearsAgo = MainController.DATE_FORMAT.format(c.getTime());

		if (Strings.isNullOrEmpty(type)) {
			sql = "SELECT r1.*, driver.name as DriverName, horse.name as HorseName, track.name as TrackName, "
					+ "ROUND(AVG(if (horseResults.time > 0 AND horseResults.RaceDate > ?, horseResults.time,null)),4) horseAvg, "
					+ "ROUND(AVG(IF(driverResults.time > 0 AND driverResults.RaceDate > ?, driverResults.time, null)),4) driverAvg, "
					+ "ROUND(AVG(IF((horseResults.Distance = r1.Distance AND horseResults.Time > 0 AND horseResults.RaceDate > ?), horseResults.time, null)),4) horseAvgByDistance, "
					+ "ROUND(AVG(IF((driverResults.Distance = r1.Distance AND driverResults.Time > 0 AND driverResults.RaceDate > ?), driverResults.time, null)),4) driverAvgByDistance "
					+ "FROM Results r1 "
					+ "				INNER JOIN Driver as driver ON driverId = driver.id "
					+ "				INNER JOIN Horse as horse ON HorseId = horse.id "
					+ "				INNER JOIN Track as track ON TrackId = track.id "
					+ " INNER JOIN Results horseResults ON r1.RaceDate > horseResults.RaceDate AND r1.HorseId = horseResults.HorseId "
					+ " INNER JOIN Results driverResults ON r1.RaceDate > driverResults.RaceDate AND r1.DriverId = driverResults.DriverId "
					/*+ " WHERE r1.RaceDate = ? AND r1.RaceNumber IN (9,10)"*/
					+ " WHERE r1.RaceDate = ? "
					+ " GROUP BY r1.horseId "
					+ "ORDER BY `r1`.`RaceNumber` ASC";
		} else {
			sql = "SELECT r1.*, driver.name as DriverName, horse.name as HorseName, track.name as TrackName, "
					+ "ROUND(AVG(if (horseResults.time > 0 AND horseResults.RaceDate > ?, horseResults.time,null)),4) horseAvg, "
					+ "ROUND(AVG(IF(driverResults.time > 0 AND driverResults.RaceDate > ?, driverResults.time, null)),4) driverAvg, "
					+ "ROUND(AVG(IF((horseResults.Distance = r1.Distance AND horseResults.Time > 0 AND horseResults.RaceDate > ?), horseResults.time, null)),4) horseAvgByDistance, "
					+ "ROUND(AVG(IF((driverResults.Distance = r1.Distance AND driverResults.Time > 0 AND driverResults.RaceDate > ?), driverResults.time, null)),4) driverAvgByDistance "
					+ "FROM Results r1 "
					+ "				INNER JOIN Driver as driver ON driverId = driver.id "
					+ "				INNER JOIN Horse as horse ON HorseId = horse.id "
					+ "				INNER JOIN Track as track ON TrackId = track.id "
					+ " INNER JOIN Results horseResults ON r1.RaceDate > horseResults.RaceDate AND r1.HorseId = horseResults.HorseId "
					+ " INNER JOIN Results driverResults ON r1.RaceDate > driverResults.RaceDate AND r1.DriverId = driverResults.DriverId "
					+ " WHERE r1.RaceDate = ? "
					+ " AND r1.RaceType LIKE ? "
					+ " GROUP BY r1.horseId "
					+ "ORDER BY `r1`.`RaceNumber` ASC";
		}


		final List<HorseRaceData> results = new ArrayList<>();
		try {
			final PreparedStatement stat = getConnection().prepareStatement(sql);
			stat.setString(1, twoYearsAgo);
			stat.setString(2, twoYearsAgo);
			stat.setString(3, twoYearsAgo);
			stat.setString(4, twoYearsAgo);
			if (Strings.isNullOrEmpty(type)) {
				stat.setString(5, date);
				//				MainController.DATE_FORMAT.format(c.getTime())
			} else {
				stat.setString(5, date);
				stat.setString(6, "%" + type + "%");
			}

			final ResultSet rs = stat.executeQuery();
			while (rs.next()) {
				final HorseRaceData rd = new HorseRaceData();
				rd.setDistance(rs.getInt("Distance"));
				rd.setDriverId(rs.getInt("DriverId"));
				rd.setDriverName(rs.getString("DriverName"));
				rd.setHorseName(rs.getString("HorseName"));
				rd.setHorseId(rs.getInt("HorseId"));
				rd.setTrainerId(rs.getInt("TrainerId"));
				rd.setRaceNumber(rs.getInt("RaceNumber"));
				rd.setTrackName(rs.getString("TrackName"));
				rd.setRaceDate(rs.getString("RaceDate"));
				rd.setLane(rs.getInt("Lane"));
				rd.setResult(rs.getInt("Result"));
				rd.setTime(rs.getFloat("Time"));
				rd.setTimeModifier(rs.getString("TimeModifier"));
				rd.setShoes(rs.getInt("Shoes"));
				rd.setSulky(rs.getInt("Sulky"));

				rd.setAvgHorseTime(rs.getFloat("horseAvg"), getHorseRaceCount(rd.getHorseId(), 0));
				rd.setAvgDriverTime(rs.getFloat("driverAvg"), getDriverRaceCount(rd.getDriverId(), 0));
				rd.setAvgHorseTimeByDistance(rs.getFloat("horseAvgByDistance"), getHorseRaceCount(rd.getHorseId(), rd.getDistance()));
				rd.setAvgDriverTimeByDistance(rs.getFloat("driverAvgByDistance"), getDriverRaceCount(rd.getDriverId(), rd.getDistance()));

				if (rd.getAvgDriverTimeCount() < 10) {
					System.out.println("Uppdating driver " + rd.getDriverName() + "(" + rd.getDriverId() + ") travsport id: " +
							getDriverTravsportId(rd.getDriverName()) + "because race count was " + rd.getAvgDriverTimeCount());
					TravsportParser.getInstance().getDriverStatById(getDriverTravsportId(rd.getDriverName()), rd.getDriverName());
				}

				if (rd.getAvgHorseTimeCount() < 2) {
					System.out.println("Uppdating horse " + rd.getHorseName() + "( " + rd.getHorseId() + ") travsport id: " +
							getHorseTravsportId(rd.getHorseName()) + " because race count was " + rd.getAvgHorseTimeCount());
					TravsportParser.getInstance().getHorseStatByIdJson(getHorseTravsportId(rd.getHorseName()), rd.getHorseName(), "");
				}

				results.add(rd);
			}
		} catch (final SQLException e) {
			e.printStackTrace();
		}

		return results;
	}

	private int getHorseRaceCount(int horseId, int distance) {
		int returnValue = 0;
		final String sql;
		if (distance > 0) {
			sql = "SELECT Count(*) as c FROM Results WHERE HorseId = ? AND Distance = ? AND Time > 0";
		} else {
			sql = "SELECT Count(*) as c FROM Results WHERE HorseId = ? AND Time > 0";
		}
		try {
			final PreparedStatement stat = getConnection().prepareStatement(sql);
			if (distance > 0) {
				stat.setInt(1, horseId);
				stat.setInt(2, distance);
			} else {
				stat.setInt(1, horseId);
			}
			final ResultSet rs = stat.executeQuery();
			while (rs.next()) {
				returnValue = rs.getInt("c");
			}
		} catch (final SQLException e) {
			e.printStackTrace();
		}
		return returnValue;
	}

	private int getDriverRaceCount(int driverId, int distance) {
		int returnValue = 0;
		final String sql;
		if (distance > 0) {
			sql = "SELECT Count(*) as c FROM Results WHERE DriverId = ? AND Distance = ? AND Time > 0";
		} else {
			sql = "SELECT Count(*) as c FROM Results WHERE DriverId = ? AND Time > 0";
		}
		try {
			final PreparedStatement stat = getConnection().prepareStatement(sql);
			if (distance > 0) {
				stat.setInt(1, driverId);
				stat.setInt(2, distance);
			} else {
				stat.setInt(1, driverId);
			}
			final ResultSet rs = stat.executeQuery();
			while (rs.next()) {
				returnValue = rs.getInt("c");
			}
		} catch (final SQLException e) {
			e.printStackTrace();
		}
		return returnValue;
	}

	// Hämta statistik för häst, förare, kombinationen av dessa två, distans....
	public SimpleEntry<Integer, Integer> getNumHorseGallop(int horseId) {
		final String sql = "SELECT COUNT(*) as total, SUM(IF(TimeModifier LIKE '%g%', 1, 0)) as gallop FROM `Results` WHERE HorseId = ?";
		SimpleEntry<Integer, Integer> returnValue = null;

		try {
			final PreparedStatement stat = getConnection().prepareStatement(sql);
			stat.setInt(1, horseId);

			final ResultSet rs = stat.executeQuery();
			while (rs.next()) {
				returnValue = new SimpleEntry<>(rs.getInt("total"), rs.getInt("gallop"));
			}
		} catch (final SQLException e) {
			e.printStackTrace();
		}

		return returnValue;
	}

	// Hämta statistik för häst, förare, kombinationen av dessa två, distans....
	public SimpleEntry<Integer, Integer> getNumDriverGallop(int driverId) {
		final String sql = "SELECT COUNT(*) as total, SUM(IF(TimeModifier LIKE '%g%', 1, 0)) as gallop FROM `Results` WHERE DriverId = ?";
		SimpleEntry<Integer, Integer> returnValue = null;

		try {
			final PreparedStatement stat = getConnection().prepareStatement(sql);
			stat.setInt(1, driverId);

			final ResultSet rs = stat.executeQuery();
			while (rs.next()) {
				returnValue = new SimpleEntry<>(rs.getInt("total"), rs.getInt("gallop"));
			}
		} catch (final SQLException e) {
			e.printStackTrace();
		}

		return returnValue;
	}

	public int getDriverTravsportId(String driverFirstName, String driverLastName) {
		int returnValue = -1;
		final String sql = "SELECT travsportId FROM Driver WHERE name = ?";
		try {
			final PreparedStatement stat = getConnection().prepareStatement(sql);
			stat.setString(1, driverLastName + " " + driverFirstName);

			final ResultSet rs = stat.executeQuery();

			while (rs.next()) {
				returnValue = rs.getInt("travsportId");
			}
		} catch (final SQLException e) {
			e.printStackTrace();
		}
		return returnValue;
	}

	public int getDriverTravsportId(String driverName) {
		int returnValue = -1;
		final String sql = "SELECT travsportId FROM Driver WHERE name = ?";
		try {
			final PreparedStatement stat = getConnection().prepareStatement(sql);
			stat.setString(1, driverName);

			final ResultSet rs = stat.executeQuery();

			while (rs.next()) {
				returnValue = rs.getInt("travsportId");
			}
		} catch (final SQLException e) {
			e.printStackTrace();
		}
		return returnValue;
	}

	public void setDriverTravsportId(int driverId, String firstName, String lastName) {
		final String sql = "UPDATE Driver SET travsportId = ? WHERE name = ?";
		try {
			final PreparedStatement stat = getConnection().prepareStatement(sql);
			stat.setInt(1, driverId);
			stat.setString(2, lastName + " " + firstName);

			stat.executeUpdate();
		} catch (final SQLException e) {
			e.printStackTrace();
		}
	}

	public float getTrendLast5(HorseRaceData horseRaceData) {
		final String combinedTrendSql = "SELECT Time, (SELECT AVG(Time) FROM Results WHERE HorseId = ? AND DriverId = ? AND Distance = ?) as avgTime FROM Results WHERE HorseId = ? AND DriverId = ? AND Distance = ? AND Time > -1 ORDER BY RaceDate ASC limit 5";
		final String DriverTrendSql = "SELECT Time, (SELECT AVG(Time) FROM Results WHERE DriverId = ? AND Distance = ?) as avgTime FROM Results WHERE DriverId = ? AND Distance = ? AND Time > -1 ORDER BY RaceDate ASC limit 5";
		final String horseTrendSql = "SELECT Time, (SELECT AVG(Time) FROM Results WHERE HorseId = ? AND Distance = ?) as avgTime FROM Results WHERE HorseId = ? AND Distance = ? AND Time > -1  ORDER BY RaceDate ASC limit 5";

		final int horseId = horseRaceData.getHorseId();
		final int driverId = horseRaceData.getDriverId();
		final int distance = horseRaceData.getDistance();

		float avgHorseTime = -1f;
		float avgDriverTime = -1f;
		float avgCombinedTime = -1f;
		float startHorseAvgTime = -1;
		float startDriverAvgTime = -1;
		float startCombinedAvgTime = -1;
		try {
			final PreparedStatement horseStat = getConnection().prepareStatement(horseTrendSql, ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
			horseStat.setInt(1, horseId);
			horseStat.setInt(2, distance);
			horseStat.setInt(3, horseId);
			horseStat.setInt(4, distance);

			final ResultSet horseRs = horseStat.executeQuery();
			if (horseRs.next()) {
				startHorseAvgTime = horseRs.getFloat("avgTime");;
				horseRs.beforeFirst();
				avgHorseTime = getTrendAvgTime(horseRs);
				// This should be the return value for horse
				System.out.println("Horse trend is " + (avgHorseTime - startHorseAvgTime));
			} else {
				System.out.println("No Horse trend found");
			}

			horseRs.close();
			horseStat.close();

			final PreparedStatement driverStat = conn.prepareStatement(DriverTrendSql, ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
			driverStat.setInt(1, driverId);
			driverStat.setInt(2, distance);
			driverStat.setInt(3, driverId);
			driverStat.setInt(4, distance);
			final ResultSet driverRs = driverStat.executeQuery();

			if (driverRs.next()) {
				startDriverAvgTime = driverRs.getFloat("avgTime");;
				driverRs.beforeFirst();
				avgDriverTime = getTrendAvgTime(driverRs);
				System.out.println("Driver trend is " + (avgDriverTime - startDriverAvgTime));
			} else {
				System.out.println("No driver trend found");
			}

			final PreparedStatement combinedStat = conn.prepareStatement(combinedTrendSql, ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);

			combinedStat.setInt(1, horseId);
			combinedStat.setInt(2, driverId);
			combinedStat.setInt(3, distance);
			combinedStat.setInt(4, horseId);
			combinedStat.setInt(5, driverId);
			combinedStat.setInt(6, distance);
			final ResultSet combinedRs = combinedStat.executeQuery();


			if (combinedRs.next()) {
				startCombinedAvgTime = combinedRs.getFloat("avgTime");;
				combinedRs.beforeFirst();
				avgCombinedTime = getTrendAvgTime(combinedRs);
				System.out.println("Combined trend is " + (avgCombinedTime - startCombinedAvgTime));
			} else {
				System.out.println("No combined trend available");
			}

			if (avgHorseTime > -1 && avgDriverTime > -1) {
				System.out.println("Combination of horse and driver: " + ((avgHorseTime - startHorseAvgTime) + (avgDriverTime - startDriverAvgTime)));
			}
			System.out.println("------");

		} catch (final SQLException e) {
			e.printStackTrace();
		}

		return ((avgHorseTime - startHorseAvgTime) + (avgDriverTime - startDriverAvgTime)) / 2f;
	}

	private float getTrendAvgTime(final ResultSet rs) throws SQLException {
		float returnValue = 0.0f;
		while (rs.next()) {
			if (returnValue == 0.0f) {
				returnValue = rs.getFloat("avgTime");
			}

			if (returnValue == 0f) {
				returnValue = rs.getFloat("Time");
			}
			final float diff = -(returnValue - rs.getFloat("Time"));
			returnValue = returnValue + diff;
		}
		return returnValue;
	}

	public void updateResult(String horseName, String driverName, int result, String timeModifier, float timeValue,
			String date, String type) {
		final String sql = "UPDATE Results "
				+ "SET "
				+ "Result = ?, Time = ?, TimeModifier = ?"
				+ "WHERE "
				+ "HorseId = (SELECT id FROM Horse WHERE name = ?) AND "
				+ "DriverId = (SELECT id FROM Driver WHERE name = ?) AND"
				+ "RaceDate = ?";
		try {
			final PreparedStatement stat = getConnection().prepareStatement(sql);
			stat.setInt(1, result);
			stat.setFloat(2, timeValue);
			stat.setString(3, timeModifier);
			stat.setString(4, horseName);
			stat.setString(5, driverName);
			stat.setString(6, date);

			final int res = stat.executeUpdate();

			if (res != 1) {
				System.out.println("Updated " + res + " results for horse " + horseName + " and driver " + driverName + " at date " + date);
			}

		} catch (final SQLException e) {
			e.printStackTrace();
		}

	}

	public String getTrackShortCodeByName(String trackName) {
		final String sql = "SELECT shortcode FROM Track WHERE name = ?";
		String trackcode = null;
		try {
			final PreparedStatement stat = getConnection().prepareStatement(sql);
			stat.setString(1, trackName);

			final ResultSet rs = stat.executeQuery();
			while (rs.next()) {
				trackcode = rs.getString("shortcode");
			}
		} catch (final SQLException e) {
			e.printStackTrace();
		}
		return trackcode;
	}

	public int getRaceCount(String what, int id) {
		int returnValue = 0;
		final String sql;
		if (what.equals("Horse")) {
			sql = "SELECT Count(*) as count FROM Results WHERE HorseId = ?";
		} else if (what.equals("Driver")) {
			sql = "SELECT Count(*) as count FROM Results WHERE DriverId = ?";
		} else {
			sql = "";
		}

		if (!Strings.isNullOrEmpty(sql)) {
			try {
				final PreparedStatement stat = getConnection().prepareStatement(sql);
				stat.setInt(1, id);

				final ResultSet rs = stat.executeQuery();
				while (rs.next()) {
					returnValue = rs.getInt("count");
				}

			} catch (final SQLException e) {
				e.printStackTrace();
			}
		}
		return returnValue;
	}

	public int getRaceId() {
		final String sql = "SELECT raceId FROM Results where raceId > -1 AND RaceDate < DATE(NOW()) ORDER BY RaceDate ASC LIMIT 1";
		int returnValue = -1;
		try {
			final PreparedStatement stat = getConnection().prepareStatement(sql);
			final ResultSet rs = stat.executeQuery();
			while (rs.next()) {
				returnValue = rs.getInt("raceId");
			}
		} catch (final SQLException e) {
			e.printStackTrace();
		}

		return returnValue;

	}

	public List<UpdateRaceRow> getRacesToUpdate(String date) {
		final List<UpdateRaceRow> racesToUpdate = Lists.newArrayList();
		final String sql = "SELECT r.*, t.name as TrackName FROM Results r INNER JOIN Track t ON r.trackId = t.id WHERE r.RaceDate = ? GROUP BY r.RaceDate, t.name, r.RaceNumber";

		try {
			final PreparedStatement stat = getConnection().prepareStatement(sql);
			stat.setString(1, date);

			final ResultSet rs = stat.executeQuery();

			while (rs.next()) {
				racesToUpdate.add(new UpdateRaceRow(rs.getInt("RaceId"), rs.getString("RaceDate"), rs.getString("RaceType"),
						rs.getString("TimeModifier"), rs.getInt("RaceNumber"), rs.getString("TrackName")));
			}
		} catch (final SQLException e) {
			e.printStackTrace();
		}

		return racesToUpdate;

	}

	public void updateRaceInfo(int raceId, String timeModifier, String raceType, int raceNumber) {
		final String sql = "UPDATE Results SET RaceType = ?, TimeModifier = ? WHERE RaceId = ? AND RaceNumber = ?";

		try {
			final PreparedStatement stat = getConnection().prepareStatement(sql);
			stat.setString(1, raceType);
			stat.setString(2, timeModifier);
			stat.setInt(3, raceId);
			stat.setInt(4, raceNumber);

			stat.executeUpdate();
		} catch (final SQLException e) {
			e.printStackTrace();
		}

	}

	public void updateFromRaceResults(int raceId, int result, float time, String timeModifier, int lane, int distance,
			int horseTravsportId, int driverTravsportId, String raceDate, int raceNumber) {
		final String sql = "UPDATE Results SET Result = ?, Time = ?, TimeModifier = ?, raceId = -1 WHERE RaceDate = ? AND RaceId = ? AND RaceNumber = ? AND Lane = ?";

		try {
			final PreparedStatement stat = getConnection().prepareStatement(sql);
			stat.setInt(1, result);
			stat.setFloat(2, time);
			stat.setString(3, timeModifier);
			stat.setString(4, raceDate);
			stat.setInt(5, raceId);
			stat.setInt(6, raceNumber);
			stat.setInt(7, lane);

			stat.executeUpdate();

		} catch (final SQLException e) {
			e.printStackTrace();
		}


	}

	public void removeRaceIds(int raceId) {
		final String sql = "UPDATE Results SET raceId = -1 WHERE RaceId = ?";
		try {
			final PreparedStatement statement = getConnection().prepareStatement(sql);
			statement.setInt(1, raceId);

			statement.executeUpdate();
		} catch (final SQLException e) {
			e.printStackTrace();
		}

	}

	public void setSetting(String name, String value) {
		final String sql = "INSERT INTO Settings (name, value) VALUES (?, ?) ON DUPLICATE KEY UPDATE value = ?";
		try {
			final PreparedStatement stat = getConnection().prepareStatement(sql);
			stat.setString(1, name);
			stat.setString(2, value);
			stat.setString(3, value);

			stat.execute();
		} catch (final SQLException e) {
			e.printStackTrace();
		}
	}

	public String getSetting(String name) {
		final String sql = "SELECT value FROM Settings WHERE name = ?";

		String returnValue = "";
		try {
			final PreparedStatement stat = getConnection().prepareStatement(sql);
			stat.setString(1, name);

			final ResultSet rs = stat.executeQuery();
			while(rs.next()) {
				returnValue = rs.getString("value");
			}
		} catch (final SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		return returnValue;
	}
}
