package system.util;

import java.sql.*;
import system.util.*;
/**
 * A thread that fills 'wrMarketSum' DB. It is triggered by wrServer.
 * @author: Nikolai Rangelov
 */
public class wr_SumDB_ResolveThread extends Thread 
{
	private static Queue wr_Queue = null;
	private static Connection dbConnection = null;
	private static LogPrinter wrLog = null;
	public static volatile byte State = Constants.NOT_INITED;
/**
 * wr_SumResolveThread constructor. It sets the global parameters.
 */
public wr_SumDB_ResolveThread(Queue wr_q, LogPrinter SwrLog) {
	super();
	State = Constants.NOT_INITED;
	wr_Queue = null;
	dbConnection = null;
	wrLog = null;
	wrLog = SwrLog;
	if (wrLog == null) {
		wrLog.log("wr_SumDB_ResolveThread (constructor) : Error in sent log parameter - null.", LogPrinter.ERROR);
		wrLog.flush();
		State = Constants.INIT_ERROR;
	} else {
		wr_Queue = wr_q;
		if (wr_Queue == null) {
			wrLog.log("wr_SumDB_ResolveThread (constructor) : Error in sent queue parameter - null.", LogPrinter.ERROR);
			wrLog.flush();
			State = Constants.INIT_ERROR;
		}
		if (!wrdbConnect()) {
			wrLog.log("wr_SumDB_ResolveThread (constructor) : Error in getting db connection. Change properties.", LogPrinter.ERROR);
			wrLog.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 wr_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.wrWhichTable(' ', wr_MK.Key) + " (" + dbFields.db_wrKey + "," + dbFields.db_marketKey + "," + dbFields.db_wrCounts + "," + dbFields.db_wrRegDate + "," + dbFields.db_wrLastCount + ") values (?,?,?,?,?)";
		PreparedStatement stmt = dbConnection.prepareStatement(SQLStat);
		stmt.clearParameters();
		stmt.setLong(1, wr_MK.Key);
		stmt.setShort(2, wr_MK.marketKey);
		stmt.setLong(3, wr_MK.Counts);
		stmt.setDate(4, Now);
		stmt.setDate(5, Now);
		stmt.executeUpdate();
		wrLog.log("wr_SumDB_ResolveThread (RegisterRelation) : wrKey " + wr_MK.Key + " info inserted in the DB", LogPrinter.DEBUG);
		return true;		
	} catch (SQLException e) {
		try {
			if (dbConnection == null || dbConnection.isClosed()) {
				if (!wrdbConnect()) {
					wrLog.log("wr_SumDB_ResolveThread (RegisterRelation) : wrdbConnect() failure.", LogPrinter.ERROR);
					wrLog.flush();
					return false;
				}
				wrLog.log("wr_SumDB_ResolveThread (RegisterRelation) : Reconnection to db done.", LogPrinter.INFO);
				wrLog.flush();
				return RegisterRelation(wr_MK);
			} else {
				wrLog.log("wr_SumDB_ResolveThread (RegisterRelation) : SQL Statement error - " + SQLStat + "\n" + e, LogPrinter.ERROR);
				wrLog.flush();
				return false;
			}
		} catch (Exception ex) {
			wrLog.log("wr_SumDB_ResolveThread (RegisterRelation) : Exception in re-connect: " + ex, LogPrinter.ERROR);
			wrLog.flush();
			return false;
		}
	} catch (NumberFormatException e) {
		wrLog.log("wr_SumDB_ResolveThread (RegisterRelation) : error format - " + SQLStat, LogPrinter.ERROR);
		wrLog.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() {
	wrLog.log("wr_SumDB_ResolveThread (run) : wr_SumDB_ResolveThread started with State - " + State, LogPrinter.INFO);
	Key_MarketKey_Relation wr_MK = null;
	if (State != Constants.READY) {
		wrLog.log("wr_SumDB_ResolveThread (run) : Error in the init process. State - " + State, LogPrinter.ERROR);
		wrLog.flush();
		wrdbDisConnect();
		return;
	} else {
		while (true) {
			try {
				yield();
				wr_MK = (Key_MarketKey_Relation) wr_Queue.readObject();
				if (wr_MK.Key == Constants.No_Key) {
					wrLog.log("wr_SumDB_ResolveThread (run) : Error in wrKey (" + wr_MK.Key + ")", LogPrinter.ERROR);
					wrLog.flush();
				} else {
					if (!UpdateRelation(wr_MK)) {
						wrLog.log("wr_SumDB_ResolveThread (run) : Error in UpdateRelation method.", LogPrinter.ERROR);
						wrLog.flush();
					}
				}
				yield();
			} catch (NullPointerException e) {
				wrLog.log("wr_SumDB_ResolveThread (run) : Error in run() method. wr_MK :" + wr_MK + ", Queue :" + wr_Queue + "\n" + e.getMessage(), LogPrinter.ERROR);
				wrLog.flush();
			}
		}
	}
}
/**
 * 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 wr_MK) {
	String SQLStat = null;
	try {
		if (dbConnection == null)
			throw new SQLException();
		if (wr_MK.Counts < 1) {
			wrLog.log("wr_SumDB_ResolveThread (UpdateRelation) : Wr with wrKey = " + wr_MK.Key + " has wrCounts (" + wr_MK.Counts + ") less then 1. Not updated or inserted.", LogPrinter.ERROR);
			wrLog.flush();
			return false;
		}
		SQLStat = "UPDATE " + Constants.wrWhichTable(' ', wr_MK.Key) + " SET " + dbFields.db_wrCounts + " = " + dbFields.db_wrCounts + " + " + String.valueOf(wr_MK.Counts) + "," + dbFields.db_wrLastCount + " = '" + new java.sql.Date(wr_MK.LastCount) + "' WHERE " + dbFields.db_wrKey + " = " + String.valueOf(wr_MK.Key) + " AND " + dbFields.db_marketKey + " = " + String.valueOf(wr_MK.marketKey);
		Statement stmt = dbConnection.createStatement();
		int result = stmt.executeUpdate(SQLStat);
		stmt.close();
		if (result == 1) {
			wrLog.log("wr_SumDB_ResolveThread (UpdateRelation) : wrKey = " + wr_MK.Key + " updated in the DB.", LogPrinter.DEBUG);
		} else {
			if (result > 1) {
				wrLog.log("wr_SumDB_ResolveThread (UpdateRelation) : Res from updating = " + result + ", wrKey = " + wr_MK.Key + " in " + Constants.wrWhichTable(' ', wr_MK.Key) + " table is DUBLICATED.", LogPrinter.ERROR);
				wrLog.flush();
			} else
				if (result == 0) {
					if (!RegisterRelation(wr_MK)) {
						wrLog.log("wr_SumDB_ResolveThread (UpdateRelation) : RegisterRelation method error. Updated records = " + result + ", wrKey = " + wr_MK.Key + ": not updated or inserted.", LogPrinter.ERROR);
						wrLog.flush();
						return false;
					}
				} else {
					wrLog.log("wr_SumDB_ResolveThread (UpdateRelation) : Updated records = " + result + ", wrKey = " + wr_MK.Key + ": not updated or inserted.", LogPrinter.ERROR);
					wrLog.flush();
					return false;
				}
		}
		return true;
	} catch (SQLException e) {
		try {
			if (dbConnection == null || dbConnection.isClosed()) {
				if (!wrdbConnect()) {
					wrLog.log("wr_SumDB_ResolveThread (UpdateRelation) : wrdbConnect() failure.", LogPrinter.ERROR);
					wrLog.flush();
					return false;
				}
				wrLog.log("wr_SumDB_ResolveThread (UpdateRelation) : Reconnection to db done.", LogPrinter.INFO);
				wrLog.flush();
				return UpdateRelation(wr_MK);
			} else {
				wrLog.log("wr_SumDB_ResolveThread (UpdateRelation) : SQL Statement error - " + SQLStat + "\n" + e, LogPrinter.ERROR);
				wrLog.flush();
				return false;
			}
		} catch (Exception ex) {
			wrLog.log("wr_SumDB_ResolveThread (UpdateRelation) : Exception in re-connect: " + ex, LogPrinter.ERROR);
			wrLog.flush();
			return false;
		}
	} catch (NumberFormatException e) {
		wrLog.log("wr_SumDB_ResolveThread (UpdateRelation) : error format - " + SQLStat, LogPrinter.ERROR);
		wrLog.flush();
		return false;
	}
}
/**
 * This method connects the Thread to 'wrMarketSum' 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 wrdbConnect() {
	try {
		Class.forName(rwConf.db_Drivers).newInstance();
		wrLog.log("wr_SumDB_ResolveThread (wrdbConnect) : Got a driver to " + dbFields.db_wrMarketSumDB + " db.", LogPrinter.INFO);
	} catch (Exception E) {
		wrLog.log("wr_SumDB_ResolveThread (wrdbConnect) : Unable to load a driver to " + dbFields.db_wrMarketSumDB + " db. Exception : " + E, LogPrinter.ERROR);
		wrLog.flush();
		return false;
	}
	dbConnection = null;
	try {
		dbConnection = DriverManager.getConnection(wrConf.db_host + dbFields.db_wrMarketSumDB, wrConf.db_user, wrConf.db_password);
		wrLog.log("wr_SumDB_ResolveThread (wrdbConnect) : Conection to " + dbFields.db_wrMarketSumDB + " db Established.", LogPrinter.INFO);
		if (dbConnection == null || dbConnection.isClosed()) {
			wrLog.flush();
			return false;
		}
		wrLog.flush();
		return true;
	} catch (SQLException E) {
		wrLog.log("wr_SumDB_ResolveThread (wrdbConnect) : SQLException in getting Connection to " + dbFields.db_wrMarketSumDB + " db.\n" + E, LogPrinter.ERROR);
		wrLog.log("wr_SumDB_ResolveThread (wrdbConnect) : SQLException: " + E.getMessage(), LogPrinter.ERROR);
		wrLog.log("wr_SumDB_ResolveThread (wrdbConnect) : SQLState:     " + E.getSQLState(), LogPrinter.ERROR);
		wrLog.flush();
		return false;
	}
}
/**
 * This method disconnects the thread from 'wrMarketSum' DB softly. If there is error
 * <br>during disconneting procedure the connection is stoped in hard way (equals null).
 */
public void wrdbDisConnect() {
	try {
		if (dbConnection != null) {
			dbConnection.close();
			wrLog.log("wr_SumDB_ResolveThread (wrdbDisConnect) : " + dbFields.db_wrMarketSumDB + " db closed.", LogPrinter.INFO);
			wrLog.flush();
			dbConnection = null;
		}
		return;
	} catch (Exception e) {
		wrLog.log("wr_SumDB_ResolveThread (wrdbDisConnect) : Cannot close the " + dbFields.db_wrMarketSumDB + " db. \n" + e, LogPrinter.ERROR);
		wrLog.flush();
		return;
	}
}
}

