package system.util;

import java.sql.*;
import system.util.*;
/**
 * A thread that fills 'rwMarketSum' DB. It is triggered by rwServer.
 * @author: Nikolai Rangelov
 */
public class rw_SumDB_ResolveThread extends Thread 
{
	private Queue rw_Queue = null;
	private static Connection dbConnection = null;
	private static LogPrinter rwLog = null;
	public static volatile byte State = Constants.NOT_INITED;
/**
 * rw_SumResolveThread constructor. It sets the global parameters.
 */
public rw_SumDB_ResolveThread(Queue rw_q, LogPrinter slog) {
	super();
	State = Constants.NOT_INITED;
	rw_Queue = null;
	dbConnection = null;
	rwLog = null;
	rwLog = slog;
	if (rwLog == null) {
		rwLog.log("rw_SumDB_ResolveThread (constructor) : Error in sent log parameter - null.", LogPrinter.ERROR);
		rwLog.flush();
		State = Constants.INIT_ERROR;
	} else {
		rw_Queue = rw_q;
		if (rw_Queue == null) {
			rwLog.log("rw_SumDB_ResolveThread (constructor) : Error in sent queue parameter - null.", LogPrinter.ERROR);
			rwLog.flush();
			State = Constants.INIT_ERROR;
		}
		if (!rwdbConnect()) {
			rwLog.log("rw_SumDB_ResolveThread (constructor) : Error in getting db connection. Change properties.", LogPrinter.ERROR);
			rwLog.flush();
			State = Constants.CONN_ERROR;
		} else {
			State = Constants.READY;
		}
	}
}
/**
 * Registers a key-marketKey relation in the DB.
 * @return boolean 
 *	       <br> true  - if the method succeed
 * 		   <br> false - if the method failed
 */
private boolean RegisterRelation(Key_MarketKey_Relation rw_MK) {
	String SQLStat = null;
	try {
		if (dbConnection == null)
			throw new SQLException();
		java.sql.Date Now = new java.sql.Date(System.currentTimeMillis());
		SQLStat = "INSERT INTO " + Constants.rwWhichTable(' ', rw_MK.Key) + " (" + dbFields.db_rwKey + "," + dbFields.db_marketKey + "," + dbFields.db_rwRegDate + ", " + dbFields.db_rwLastCount + ", " + dbFields.db_rwSumCounts + ", " + dbFields.db_rwSumVolatility + ", " + dbFields.db_rwSumVulgarity + ", " + dbFields.db_volatilityUpdate + ", " + dbFields.db_vulgarityUpdate + " ) values (?,?,?,?,?,?,?,?,?)";
		PreparedStatement stmt = dbConnection.prepareStatement(SQLStat);
		stmt.clearParameters();
		stmt.setLong(1, rw_MK.Key);
		stmt.setShort(2, rw_MK.marketKey);
		stmt.setDate(3, Now);
		stmt.setDate(4, Now);
		stmt.setLong(5, rw_MK.Counts);
		stmt.setLong(6, 0);
		stmt.setLong(7, 0);
		stmt.setDate(8, Now);
		stmt.setDate(9, Now);
		stmt.executeUpdate();
		rwLog.log("rw_SumDB_ResolveThread (RegisterRelation) : rwKey " + rw_MK.Key + " info inserted in the DB", LogPrinter.DEBUG);
		return true;
	} catch (SQLException e) {
		try {
			if (dbConnection == null || dbConnection.isClosed()) {
				if (!rwdbConnect()) {
					rwLog.log("rw_SumDB_ResolveThread (RegisterRelation) : rwdbConnect() failure.", LogPrinter.ERROR);
					rwLog.flush();
					return false;
				}
				rwLog.log("rw_SumDB_ResolveThread (RegisterRelation) : Reconnection to db done.", LogPrinter.INFO);
				rwLog.flush();
				return RegisterRelation(rw_MK);
			} else {
				rwLog.log("rw_SumDB_ResolveThread (RegisterRelation) : SQL Statement error - " + SQLStat + "\n" + e, LogPrinter.ERROR);
				rwLog.flush();
				return false;
			}
		} catch (Exception ex) {
			rwLog.log("rw_SumDB_ResolveThread (RegisterRelation) : Exception in re-connect: " + ex, LogPrinter.ERROR);
			rwLog.flush();
			return false;
		}
	} catch (NumberFormatException e) {
		rwLog.log("rw_SumDB_ResolveThread (RegisterRelation) : error format - " + SQLStat, LogPrinter.ERROR);
		rwLog.flush();
		return false;
	}
}
/**
 * This is the main method. It reads from the queue, decides whether this relation is new or familiar
 * <br>and calls the apropriate method.
 */
public void run() {
	rwLog.log("rw_SumDB_ResolveThread (run) : rw_SumDB_ResolveThread started with State - " + State, LogPrinter.INFO);
	Key_MarketKey_Relation rw_MK = null;
	Key_MarketKey_Relation temp = null;
	if (State != Constants.READY) {
		rwLog.log("rw_SumDB_ResolveThread (run) : Error in the init process. State - " + State, LogPrinter.ERROR);
		rwLog.flush();
		rwdbDisConnect();
		return;
	} else {
		while (true) {
			try {
				yield();
				temp = (Key_MarketKey_Relation) rw_Queue.readObject();
				if (temp == null) {
					rwLog.log("rw_SumDB_ResolveThread (run) : Error in run() method. Queue Read element : " + temp + " prevoiuse rw_MK :" + rw_MK + ", Queue :" + rw_Queue, LogPrinter.ERROR);
					rwLog.flush();
				} else {
					rw_MK = temp;
					if (rw_MK.Key == Constants.No_Key) {
						rwLog.log("rw_SumDB_ResolveThread (run) : Error in rwKey (" + rw_MK.Key + ")", LogPrinter.ERROR);
						rwLog.flush();
					} else {
						if (!UpdateRelation(rw_MK)) {
							rwLog.log("rw_SumDB_ResolveThread (run) : Error in UpdateRelation method.", LogPrinter.ERROR);
							rwLog.flush();
						}
					}
					yield();
				}
			} catch (NullPointerException e) {
				rwLog.log("rw_SumDB_ResolveThread (run) : Error in run() method. rw_MK :" + rw_MK + ", Queue :" + rw_Queue + "\n" + e, LogPrinter.ERROR);
				rwLog.flush();
			}
		}
	}
}
/**
 * This method connects the Thread to 'rwMarketSum' DB.
 * @return boolean 
 *	       <br> true  - if the method succeed (we have connections)
 * 		   <br> false - if the method failed (we don't have connections)
 */
private boolean rwdbConnect() {
	try {
		Class.forName(rwConf.db_Drivers).newInstance();
		rwLog.log("rw_SumDB_ResolveThread (rwdbConnect) : Got a driver to " + dbFields.db_rwMarketSumDB + " db.", LogPrinter.INFO);
	} catch (Exception E) {
		rwLog.log("rw_SumDB_ResolveThread (rwdbConnect) : Unable to load a driver to " + dbFields.db_rwMarketSumDB + " DB. Exception : " + E, LogPrinter.ERROR);
		rwLog.flush();
		return false;
	}
	dbConnection = null;
	try {
		dbConnection = DriverManager.getConnection(rwConf.db_host + dbFields.db_rwMarketSumDB, rwConf.db_user, rwConf.db_password);
		rwLog.log("rw_SumDB_ResolveThread (rwdbConnect) : Conection to " + dbFields.db_rwMarketSumDB + " db Established.", LogPrinter.INFO);
		if (dbConnection == null || dbConnection.isClosed()) {
			rwLog.flush();
			return false;
		}
		rwLog.flush();
		return true;
	} catch (SQLException E) {
		rwLog.log("rw_SumDB_ResolveThread (rwdbConnect) : SQLException in getting Connection to " + dbFields.db_rwMarketSumDB + " db.\n" + E, LogPrinter.ERROR);
		rwLog.log("rw_SumDB_ResolveThread (rwdbConnect) : SQLException: " + E.getMessage(), LogPrinter.ERROR);
		rwLog.log("rw_SumDB_ResolveThread (rwdbConnect) : SQLState:     " + E.getSQLState(), LogPrinter.ERROR);
		rwLog.flush();
		return false;
	}
}
/**
 * This method disconnects the thread from 'rwMarketSum' DB softly. If there is error
 * <br>during disconneting procedure the connection is stoped in hard way (equals null).
 */

public void rwdbDisConnect() {
	try {
		if (dbConnection != null) {
			dbConnection.close();
			rwLog.log("rw_SumDB_ResolveThread (rwdbDisConnect) : " + dbFields.db_rwMarketSumDB + " db closed.", LogPrinter.INFO);
			rwLog.flush();
			dbConnection = null;
		}
		return;
	} catch (Exception e) {
		rwLog.log("rw_SumDB_ResolveThread (rwdbDisConnect) : Cannot close the " + dbFields.db_rwMarketSumDB + " db. \n" + e, LogPrinter.ERROR);
		rwLog.flush();
		return;
	}
}
/**
 * Updates a key-marketKey relation in the DB.
 * @return boolean 
 *	       <br> true  - if the method succeed
 * 		   <br> false - if the method failed
 */

private boolean UpdateRelation(Key_MarketKey_Relation rw_MK) {
	String SQLStat = null;
	try {
		if (dbConnection == null)
			throw new SQLException();
		if (rw_MK.Counts < 1) {
			rwLog.log("rw_SumDB_ResolveThread (UpdateRelation) : Rw with rwKey = " + rw_MK.Key + " has rwCounts (" + rw_MK.Counts + ") less then 1. Not updated or inserted.", LogPrinter.ERROR);
			rwLog.flush();
			return false;
		}
		SQLStat = "UPDATE " + Constants.rwWhichTable(' ', rw_MK.Key) + " SET " + dbFields.db_rwSumCounts + " = " + dbFields.db_rwSumCounts + " + " + String.valueOf(rw_MK.Counts) + "," + dbFields.db_rwLastCount + " = '" + new Date(rw_MK.LastCount) + "' WHERE " + dbFields.db_rwKey + " = " + String.valueOf(rw_MK.Key) + " AND " + dbFields.db_marketKey + " = " + String.valueOf(rw_MK.marketKey);
		Statement stmt = dbConnection.createStatement();
		int result = stmt.executeUpdate(SQLStat);
		stmt.close();
		if (result == 1) {
			rwLog.log("rw_SumDB_ResolveThread (UpdateRelation) : rwKey = " + rw_MK.Key + " updated in the DB.", LogPrinter.DEBUG);
		} else {
			if (result > 1) {
				rwLog.log("rw_SumDB_ResolveThread (UpdateRelation) : Res from updating = " + result + ", rwKey = " + rw_MK.Key + " in " + Constants.rwWhichTable(' ', rw_MK.Key) + " table is DUBLICATED.", LogPrinter.ERROR);
				rwLog.flush();
			} else
				if (result == 0) {
					if (!RegisterRelation(rw_MK)) {
						rwLog.log("rw_SumDB_ResolveThread (UpdateRelation) : RegisterRelation method error. Updated records = " + result + ", rwKey = " + rw_MK.Key + ": not updated or inserted.", LogPrinter.ERROR);
						rwLog.flush();
						return false;
					}
				} else {
					rwLog.log("rw_SumDB_ResolveThread (UpdateRelation) : Updated records = " + result + ", rwKey = " + rw_MK.Key + ": not updated or inserted.", LogPrinter.ERROR);
					rwLog.flush();
					return false;
				}
		}
		return true;
	} catch (SQLException e) {
		try {
			if (dbConnection == null || dbConnection.isClosed()) {
				if (!rwdbConnect()) {
					rwLog.log("rw_SumDB_ResolveThread (UpdateRelation) : rwdbConnect() failure.", LogPrinter.ERROR);
					rwLog.flush();
					return false;
				}
				rwLog.log("rw_SumDB_ResolveThread (UpdateRelation) : Reconnection to db done.", LogPrinter.INFO);
				rwLog.flush();
				return UpdateRelation(rw_MK);
			} else {
				rwLog.log("rw_SumDB_ResolveThread (UpdateRelation) : SQL Statement error - " + SQLStat + "\n" + e, LogPrinter.ERROR);
				rwLog.flush();
				return false;
			}
		} catch (Exception ex) {
			rwLog.log("rw_SumDB_ResolveThread (UpdateRelation) : Exception in re-connect: " + ex, LogPrinter.ERROR);
			rwLog.flush();
			return false;
		}
	} catch (NumberFormatException e) {
		rwLog.log("rw_SumDB_ResolveThread (UpdateRelation) : error format - " + SQLStat, LogPrinter.ERROR);
		rwLog.flush();
		return false;
	}
}
}

