package market.market_util;

import market.market_util.*;
import java.io.*;
import java.net.*;
import java.sql.*;

/**
 * This thread saves the market wr Cache Table in the Market_wr DB
 * @author: Nikolai Rangelov
 */
 
public class market_wrSaver extends Thread 
{
	static private wrCachTableField CachTable[] = null;
  	private static int MarketKey = Constants.No_MarketKey;
 	private static short MaxFields = 0;
 	private static byte  DownloadMinutes = 0;
	private static Connection dbConnect = null;
 	private static LogPrinter market_wrLog = null;
	public static volatile byte State = Constants.NOT_INITED;
	public static volatile boolean IsSaving = false;
/**
 * market_wrSaver constructor. Loads global parameters for the Thread and sets its state.
 */
public market_wrSaver(wrCachTableField CT[], short MF, int MK, LogPrinter SwrLog) {
	super();
	State = Constants.NOT_INITED;
	IsSaving = false;
	MaxFields = 0;
	MarketKey = Constants.No_MarketKey;
	DownloadMinutes = 0;
	dbConnect = null;
	CachTable = null;
	market_wrLog = null;
	market_wrLog = SwrLog;
	if (market_wrLog == null) {
		State = Constants.LOG_ERROR;
	} else {
		try {
			MarketKey = MK;
			DownloadMinutes = market_wrConf.cb_Minutes_to_Download;
			MaxFields = MF;
			if (MaxFields < 1 || MarketKey < 1 || DownloadMinutes < 1) {
				State = Constants.INIT_ERROR;
				market_wrLog.log("market_wrSaver (constructor) : Error in sent max fields or market key or Download Minutes parameters.", LogPrinter.ERROR);
				market_wrLog.flush();
			} else {
				CachTable = CT;
				if (CachTable == null) {
					State = Constants.CACHE_ERROR;
					market_wrLog.log("market_wrSaver (constructor) : Error in sent Cache Table pointer - null.", LogPrinter.ERROR);
					market_wrLog.flush();
				} else {
					if (!wrSaverdbConnect()) {
						market_wrLog.log("market_wrSaver (constructor) : Error in getting db connection.", LogPrinter.ERROR);
						market_wrLog.flush();
						State = Constants.CONN_ERROR;
					} else {
						State = Constants.READY;
					}
				}
			}
		} catch (Exception e) {
			market_wrLog.log("market_wrSaver (constructor) : Exception during init. Par. are log - " + market_wrLog + ", MaxFields - " + MaxFields + ", MarketKey - " + MarketKey + ", Cache - " + CachTable + ", dbConn - " + dbConnect, LogPrinter.ERROR);
			market_wrLog.flush();
			State = Constants.INIT_ERROR;
		}
	}
}
/**
 * This is the main function of the thread that controls it. Thread sleeps for 'DownloadMinutes' minutes and <br>
 * then saves the Cache Table in the DB by calling UpdateWr() function.
 */
public void run() {
	market_wrLog.log("market_wrSaver (run) : market_wrSaver thread started with State - " + State, LogPrinter.INFO);
	market_wrLog.flush();
	if (State == Constants.READY) {
		while (true) {
			try {
				yield();
				sleep(DownloadMinutes * 60000);
			} catch (InterruptedException e) {
				market_wrLog.log("market_wrSaver (run) : InterruptedException during sleeping.", LogPrinter.ERROR);
				market_wrLog.flush();
				yield();
			}
			IsSaving = true;
			if (!SaveWrCache()) {
				market_wrLog.log("market_wrSaver (run) : Error during downloading cache table. Cache Table not downloaded to the end.", LogPrinter.ERROR);
				market_wrLog.flush();
			}
			IsSaving = false;
			yield();
		}
	} else {
		market_wrLog.log("market_wrSaver (run) : Error in Thread State - " + State, LogPrinter.ERROR);
		market_wrLog.flush();
		wrSaverdbDisConnect();
		return;
	}
}
/**
 * Saves the market wr Cache Table in the Market_wr DB
 *	       <br> true  - if the method succeed 
 * 		   <br> false - if the method failed 
 */
public boolean SaveWrCache() {
	short Count = 0;
	String SQLStat = null;
	wrCachTableField Field = null;
	boolean HasSaved = false;
	for (Count = 1; Count <= MaxFields; Count++) {
		Field = CachTable[Count];
		yield();
		if (Field.cf_wrKey != Constants.No_Key)
			if (Field.cf_wrCounts != 0) {
				do {
					synchronized (Field) {
						if (!Field.cf_NA) {
							Field.cf_NA = true;
							break;
						}
					} // sinchronized	
					try {
						yield();
						Thread.sleep(20);
					} catch (Exception e) {
						market_wrLog.log("market_rwSaver (UpdateWr) : Error on Getting NA!", LogPrinter.ERROR);						
						market_wrLog.flush();
						return false;
					}
				} while (true);
				if (Field.cf_wrKey != Constants.No_Key)
					if (Field.cf_wrCounts != 0) {
						if (!wrWriteInDB(Field)) {
							Field.cf_NA = false;
							market_wrLog.log("market_wrSaver (UpdateWr) : Error in saving wr : wrKey - " + Field.cf_wrKey + ", wrString - " + Field.cf_wrString + ", langKey - " + Field.cf_langKey + ", wrCounts - " + Field.cf_wrCounts + ", wrLastCount - " + Field.cf_wrLastCount, LogPrinter.ERROR);
							market_wrLog.flush();						
							return false;
						}						
						Field.cf_wrCounts = 0;
						HasSaved = true;
					} //if
				Field.cf_NA = false;
			} //if
	} //for
	yield();
	if (HasSaved)
		market_wrLog.log("market_wrSaver (UpdateWr) : market wrCache Table downloaded.", LogPrinter.INFO);
	else
		market_wrLog.log("market_wrSaver (UpdateWr) : market wrCache Table had already been downloaded.", LogPrinter.INFO);
	market_wrLog.flush();
	return true;
}
/**
 * This method connects the market_wrSaver to Market_wr DB
 * @return boolean 
 *	       <br> true  - if the method succeed (we have connection)
 * 		   <br> false - if the method failed (we don't have connection)
 */

private boolean wrSaverdbConnect() {
	try {
		Class.forName(market_wrConf.db_Drivers).newInstance();
		market_wrLog.log("market_wrSaver (wrSaverdbConnect) : Got a driver to " + dbFields.db_market_wrServerDB + " db.", LogPrinter.INFO);
	} catch (Exception E) {
		market_wrLog.log("market_wrSaver (wrSaverdbConnect) : Unable to load a driver to " + dbFields.db_market_wrServerDB + " db. Exception : " + E, LogPrinter.ERROR);
		market_wrLog.flush();
		return false;
	}
	dbConnect = null;
	try {
		dbConnect = DriverManager.getConnection(market_wrConf.db_host + dbFields.db_market_wrServerDB, market_wrConf.db_user, market_wrConf.db_password);
		market_wrLog.log("market_wrSaver (wrSaverdbConnect) : Conection to " + dbFields.db_market_wrServerDB + " db Established.", LogPrinter.INFO);
		if (dbConnect == null || dbConnect.isClosed()) {
			market_wrLog.flush();
			return false;
		}
		market_wrLog.flush();
		return true;
	} catch (SQLException E) {
		market_wrLog.log("market_wrSaver (wrSaverdbConnect) : SQLException in getting Connection to " + dbFields.db_market_wrServerDB + " db : " + E, LogPrinter.ERROR);
		market_wrLog.log("market_wrSaver (wrSaverdbConnect) : SQLException: " + E.getMessage(), LogPrinter.ERROR);
		market_wrLog.log("market_wrSaver (wrSaverdbConnect) : SQLState:     " + E.getSQLState(), LogPrinter.ERROR);
		market_wrLog.flush();
		return false;
	}
}
/**
 * This method disconnects the market_wrSaver from Market_wr DB softly. If there is error during 
 * <br> disconneting procedure the connection is disconnected hard way (equals null).
 */

public void wrSaverdbDisConnect() {
	try {
		if (dbConnect != null) {
			dbConnect.close();
			market_wrLog.log("market_wrSaver (wrSaverdbDisConnect) : " + dbFields.db_market_wrServerDB + " db closed.", LogPrinter.INFO);
			market_wrLog.flush();
			dbConnect = null;
		}
		return;
	} catch (Exception e) {
		market_wrLog.log("market_wrSaver (wrSaverdbDisConnect) : Cannot close the " + dbFields.db_market_wrServerDB + " db.\n" + e, LogPrinter.ERROR);
		market_wrLog.flush();
		return;
	}
}
/**
 * Finds in which table is/to be/ strored the info for specific wr
 * @return String
*/

private String wrWhichTable(char p) {
	StringBuffer result_wrTable = new StringBuffer("wr_");
	result_wrTable.append(String.valueOf(MarketKey));
	result_wrTable.append('_');
	if ((p >= 'a') && (p <= 'z'))
		result_wrTable.append(p);
	else
		if (p >= '0' && p <= '9')
			result_wrTable.append(Constants.cs_EndNumberTable);
		else
			result_wrTable.append(Constants.cs_EndSpecialTable);
	return result_wrTable.toString();
}
/**
 * Updates the wrCounts and wrLastCounted properties of wr CacheTableField in the Market_wr DB.
 * @return boolean
 *	       <br> true  - if the method succeed
 * 		   <br> false - if the method failed
 */
private boolean wrWriteInDB(wrCachTableField Field) {
	String SQLStat = null;
	try {
		if (dbConnect == null)
			throw new SQLException();
		if (Field.cf_wrCounts != 0) {
			SQLStat = "UPDATE " + Constants.market_wrWhichTable(Field.cf_wrString.charAt(0), MarketKey) + " SET " + dbFields.db_wrCounts + " = " + dbFields.db_wrCounts + " + " + String.valueOf(Field.cf_wrCounts) + "," + dbFields.db_wrLastCount + " = '" + (new java.sql.Date(Field.cf_wrLastCount)) + "' WHERE " + dbFields.db_wrKey + " = " + String.valueOf(Field.cf_wrKey);
			Statement stmt = dbConnect.createStatement();
			int result = stmt.executeUpdate(SQLStat);
			if (result == 1) {
				market_wrLog.log("market_wrSaver (wrWriteInDB) : wrString = " + Field.cf_wrString + " updated in the DB.", LogPrinter.DEBUG);
			} else {
				market_wrLog.log("market_wrSaver (wrWriteInDB) : Res from updating = " + result + ", wrKey = " + Field.cf_wrKey + ", wrCounts = " + Field.cf_wrCounts + ", wrString :" + Field.cf_wrString + ": not updated.", LogPrinter.ERROR);
			}
			stmt.close();
		}
		return true;
	} catch (SQLException e) {
		try {
			if (dbConnect == null || dbConnect.isClosed()) {
				if (!wrSaverdbConnect()) {
					market_wrLog.log("market_wrSaver (wrWriteInDB) : market_wrdbConnect() failure.", LogPrinter.ERROR);
					market_wrLog.flush();
					yield();
					return false;
				}
				market_wrLog.log("market_wrSaver (wrWriteInDB) : Reconnection to db is done.", LogPrinter.INFO);
				market_wrLog.flush();
				return wrWriteInDB(Field);
			} else {
				market_wrLog.log("market_wrSaver (wrWriteInDB) : SQL Statement error - " + SQLStat + "\n" + e, LogPrinter.ERROR);
				market_wrLog.flush();
				yield();
				return false;
			}
		} catch (Exception ex) {
			market_wrLog.log("market_wrSaver (wrWriteInDB) : Exception in re-connect: " + ex, LogPrinter.ERROR);
			market_wrLog.flush();
			yield();
			return false;
		}
	} catch (NumberFormatException e) {
		market_wrLog.log("market_wrSaver (wrWriteInDB) : error format " + SQLStat, LogPrinter.ERROR);
		market_wrLog.flush();
		yield();
		return false;
	} catch (Exception e) {
		market_wrLog.log("market_wrSaver (wrWriteInDB) : Exception " + SQLStat, LogPrinter.ERROR);
		market_wrLog.flush();
		yield();
		return false;
	}
}
}

