package system.util;

import java.io.*;
import java.net.*;
import java.sql.*;
import system.util.*;

/**
 * This class creates and control rw Cache Table. It also creates and start Save Thread 
 * @author: Nikolai Rangelov
 */

// IMPORTANT : Masivite rabotiat v obhvata na short chislata!!!
public class rwCacher {
	private static short MaxFields = 0;
	private static volatile short FieldsInUse = 0;
	private static byte CleaningFactor = 0;
	private static rwCachTableField rwCachTable[] = null;
	private static short IndexesOf[][] = null;
	private static short Numbers[] = null;
	private static short Others[] = null;
	private static int AllUsedCounts = 0;
	private static float AllAvrUsedCounts = 0;
	private static long InitTime = 0; // The time when the CTFs are inited
	private static long AllLastCleared = 0; // The time when the CTFs are last cleared.

	private static rwSaver SaveThread = null;
	private static Connection dbConnection = null;
	private static boolean Cleaning = false; // Shows if CachTable is clearing at the moment
	private static LogPrinter rwLog = null;
	public static Object SynchroRegistering = null;
	public static volatile byte State = Constants.NOT_INITED;
/**
 * rwCacher constructor. Here are loaded the global parameters for the rwCacher and started the save
 * <br>thread that periodically saves the Cache Table.
 */
public rwCacher(LogPrinter slog) {
	State = Constants.NOT_INITED;
	SynchroRegistering = null;
	SynchroRegistering = new Object();
	AllAvrUsedCounts = 0;
	FieldsInUse = 0;
	AllUsedCounts = 0;
	Cleaning = false;
	CleaningFactor = 0;
	dbConnection = null;
	InitTime = 0;
	MaxFields = 0;
	rwLog = null;
	rwLog = slog;
	if (rwLog == null) {
		State = Constants.LOG_ERROR;
	} else {
		try {
			MaxFields = rwConf.csh_MaxCachFieldsInRW;
			CleaningFactor = rwConf.cb_CleaningFactor;
			if (MaxFields < 1 || CleaningFactor < 1) {
				rwLog.log("rwCacher (constructor) : Error in saved csh_MaxCachFieldsInRW or rwConf.cb_CleaningFactor parameter.", LogPrinter.ERROR);
				rwLog.flush();
				State = Constants.INIT_ERROR;
			} else {
				InitTime = System.currentTimeMillis() / 1000;
				AllLastCleared = InitTime;				
				rwCachTable = new rwCachTableField[MaxFields + 1]; // ...ds + 1 because CachTable[0] is not used.
				for (int i = 0; i <= MaxFields; i++)
					rwCachTable[i] = new rwCachTableField();
				IndexesOf = new short[26][MaxFields];
				Numbers = new short[MaxFields];
				Others = new short[MaxFields];
				if (!rwCacherdbConnect()) {
					rwLog.log("rwCacher (constructor) : Error in getting db connection. Change properties.", LogPrinter.ERROR);
					rwLog.flush();
					State = Constants.CONN_ERROR;
				} else {
					SaveThread = new rwSaver(rwCachTable, MaxFields, rwLog);
					SaveThread.start();
					if (SaveThread.State == Constants.READY) {
						rwLog.log("rwCacher (constructor) : Save Thread started. rw Cache is ready to work.", LogPrinter.INFO);
						rwLog.flush();
						State = Constants.READY;
					} else {
						rwLog.log("rwCacher (constructor) : Error in starting Save Thread. Change properties. rw Cache is not ready to work.", LogPrinter.ERROR);
						rwLog.flush();
						State = Constants.SAVE_THREAD_ERROR;
					}
				}
			}
		} catch (Exception e) {
			rwLog.log("rwCacher (constructor) : Exception during init. MaxFields - " + MaxFields + ", ClearingFactor - " + CleaningFactor + ", InitTime - " + InitTime + ", rwCachTable - " + rwCachTable + ", dbConnection - " + dbConnection + ", SaveThread - " + SaveThread, LogPrinter.ERROR);
			rwLog.flush();
			State = Constants.INIT_ERROR;
		}
	}
}
/**
 * The function adds Cache Table indes number to index arrays.
 * @return boolean
 * @param rwChar char - the first sign of the rwString
 * @param Index short - the index in the cache table
 */
private boolean AddIndex(char rwChar, short Index) {
	short Count = 0;
	try {
		if (rwChar >= 'a' && rwChar <= 'z') {
			int First = ((short) (rwChar)) - ((short) ('a'));
			for (Count = 0; Count < MaxFields; Count++)
				if (IndexesOf[First][Count] == Constants.Zero_Key) {
					IndexesOf[First][Count] = Index;
					return true;
				}
		} else
			if (rwChar >= '0' && rwChar <= '9') {
				for (Count = 0; Count < MaxFields; Count++)
					if (Numbers[Count] == Constants.Zero_Key) {
						Numbers[Count] = Index;
						return true;
					}
			} else {
				for (Count = 0; Count < MaxFields; Count++)
					if (Others[Count] == Constants.Zero_Key) {
						Others[Count] = Index;
						return true;
					}
			}
	} catch (Exception e) {
		rwLog.log("rwCacher (AddIndex) : Exception - " + e, LogPrinter.ERROR);
		rwLog.flush();
	}
	return false;
}
/**
 * Destroys the Save thread and the Cache. It frees all resources allocated by the cacher
 */
public void destroy() {
	try {
		for (int i = 0; i < 3; i++) {
			if (!SaveThread.IsSaving) {
				break;
			} else
				Thread.sleep(1000);
		}
		SaveThread.suspend();
		SaveCache();
		SaveThread.rwSaverdbDisConnect();
		SaveThread.stop();
		rwLog.log("rwCacher (destoy): Save Thread stoped.", LogPrinter.INFO);
	} catch (Exception t) {
		rwLog.log("rwCacher (destoy): Exception on stopping Save Thread - " + t, LogPrinter.ERROR);
	}
	rwLog.log("\n\n rwCacher : Just before destroying rwCachTable it is : \n", LogPrinter.DEBUG);
	for (int i = 1; i <= MaxFields; i++)
		if (rwCachTable[i].cf_rwKey != Constants.No_Key) {
			rwLog.log("	Cell : " + i + " | " + rwCachTable[i].cf_rwKey + " | " + rwCachTable[i].cf_rwString + " | " + rwCachTable[i].cf_rwCounts + " | " + rwCachTable[i].cf_langKey + " | " + rwCachTable[i].cf_rwLastCounts + " | | " + rwCachTable[i].cf_NA + " | " + rwCachTable[i].cf_UsedCounts + " | " + rwCachTable[i].cf_AvrUsedCounts + " | " + rwCachTable[i].cf_Loaded + " ||", LogPrinter.DEBUG);
		}
	rwCacherdbDisConnect();
	rwCachTable = null;
	rwLog.log("rwCacher (destoy): system rw Cache Table destroyed.", LogPrinter.INFO);
	SaveThread = null;
	System.gc();
	Thread.yield();
}
/**
 * The function removes Cache Table indes number from index arrays.
 * @return boolean
 * @param rwChar char - the first sign of the rwString
 * @param Index short - the index in the cache table
 */
private boolean RemoveIndex(char rwChar, int Index) {
	short Count = 0;
	try {
		if (rwChar >= 'a' && rwChar <= 'z') {
			int First = ((int) (rwChar)) - ((int) ('a'));
			for (Count = 0; Count < MaxFields; Count++)
				if (IndexesOf[First][Count] == Index) {
					IndexesOf[First][Count] = Constants.Zero_Key;
					return true;
				}
		} else
			if (rwChar >= '0' && rwChar <= '9') {
				for (Count = 0; Count < MaxFields; Count++)
					if (Numbers[Count] == Index) {
						Numbers[Count] = Constants.Zero_Key;
						return true;
					}
			} else {
				for (Count = 0; Count < MaxFields; Count++)
					if (Others[Count] == Index) {
						Others[Count] = Constants.Zero_Key;
						return true;
					}
			}
	} catch (Exception e) {
		rwLog.log("rwCacher (RemoveIndex) : Exception : " + e, LogPrinter.ERROR);
		rwLog.flush();
	}
	return false;
}
/**
 * This method connects the rwCacher to 'rw' 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 rwCacherdbConnect() {
	try {
		Class.forName(rwConf.db_Drivers).newInstance();
		rwLog.log("rwCacher (rwCacherdbConnect) : Got a driver to " + dbFields.db_rwServerDB + " db.", LogPrinter.INFO);
	} catch (Exception E) {
		rwLog.log("rwCacher (rwCacherdbConnect) : Unable to load a driver to " + dbFields.db_rwServerDB + " db. Exception : " + E, LogPrinter.ERROR);
		rwLog.flush();		
		return false;
	}
	dbConnection = null;
	try {
		dbConnection = DriverManager.getConnection(rwConf.db_host + dbFields.db_rwServerDB, rwConf.db_user, rwConf.db_password);
		rwLog.log("rwCacher (rwCacherdbConnect) : Conection to " + dbFields.db_rwServerDB + " db Established.", LogPrinter.INFO);
		if (dbConnection == null || dbConnection.isClosed()) {
			rwLog.flush();					
			return false;
		}
		rwLog.flush();				
		return true;		
	} catch (SQLException E) {
		rwLog.log("rwCacher (rwCacherdbConnect) : SQLException in getting Connection to " + dbFields.db_rwServerDB + " db : " + E, LogPrinter.ERROR);
		rwLog.log("rwCacher (rwCacherdbConnect) : SQLException: " + E.getMessage(), LogPrinter.ERROR);
		rwLog.log("rwCacher (rwCacherdbConnect) : SQLState:     " + E.getSQLState(), LogPrinter.ERROR);
		rwLog.flush();				
		return false;
	}
}
/**
 * This method disconnects the rwCacher from 'rw' DB softly. If there is error during 
 * <br> disconneting procedure the connection is disconnected hard way (equals null).
 */

private void rwCacherdbDisConnect() {
	try {
		if (dbConnection != null) {
			dbConnection.close();
			rwLog.log("rwCacher (rwCacherdbDisConnect) : " + dbFields.db_rwServerDB + " db closed.", LogPrinter.INFO);
			rwLog.flush();
			dbConnection = null;
		}
		return;
	} catch (Exception e) {
		rwLog.log("rwCacher (rwCacherdbDisConnect) : Cannot close the " + dbFields.db_rwServerDB + " db \n" + e, LogPrinter.ERROR);
		rwLog.flush();
		return;
	}
}
/**
 * Cleans the Cache Table when it is full. The criteria is the average used count for the whole system and <br>
 * a percetage average used count for the specified Cache Table field.
 * @return boolean
 *	       <br> true  - if the method succeed
 * 		   <br> false - if the method failed
 */
private boolean rwCleanCachFields() {
	if (State != Constants.READY) {
		rwLog.log("rwCacher (rwCleanCachFields) : Error in Thread State - " + State, LogPrinter.ERROR);
		rwLog.flush();
		return false;
	}
	AllAvrUsedCounts = 0;
	String SQLStat = null;
	rwCachTableField Field = null;
	long TimeNow = (System.currentTimeMillis() / 1000) + 1;
	// int TempFactor = CleaningFactor;
	rwLog.log("\nrwCacher (rwCleanCachFields) : Begin Cleaning ...", LogPrinter.DEBUG);
	for (int Count = 1; Count <= MaxFields; Count++) {
		Field = rwCachTable[Count];
		do {
			synchronized (Field) {
				if (!Field.cf_NA) {
					Field.cf_NA = true;
					break;
				}
			} // sinchronized	
			try {
				Thread.sleep(20);
			} catch (Exception e) {
				rwLog.log("rwCacher (rwCleanCachFields) : Error on waiting for calculation of AvrUC in rwCleanCache!", LogPrinter.ERROR);
				rwLog.flush();
				return false;
			}
		} while (true);
		try {
			Field.cf_AvrUsedCounts = (((float) (AllLastCleared - Field.cf_Loaded)) * Field.cf_AvrUsedCounts + (float) Field.cf_UsedCounts) / ((float) (TimeNow - Field.cf_Loaded));
			Field.cf_UsedCounts = 0;
			Field.cf_NA = false;
			AllAvrUsedCounts += Field.cf_AvrUsedCounts;
			rwLog.log("rwCacher (rwCleanCachFields) : Cell : " + Count + " | rwKey = " + Field.cf_rwKey + " | UC = " + Field.cf_UsedCounts + " | AvrUC = " + Field.cf_AvrUsedCounts + " | L = " + Field.cf_Loaded, LogPrinter.DEBUG_2);
		} catch (Exception e) {
			Field.cf_NA = false;
			rwLog.log("rwCacher (rwCleanCachFields) : Error in recouculation of the field - " + Count + " |rwKey=" + Field.cf_rwKey + "|UC=" + Field.cf_UsedCounts + "|AvrUC=" + Field.cf_AvrUsedCounts + "|L=" + Field.cf_Loaded + "|NA=" + Field.cf_NA + "\n" + e, LogPrinter.ERROR);
			rwLog.flush();
			return false;
		}
	}
	AllAvrUsedCounts = AllAvrUsedCounts / MaxFields;
	AllAvrUsedCounts += 0.01;
	rwLog.log("rwCacher (rwCleanCachFields) : Befor removing TimeNow " + TimeNow + "\n AllAvrUC = " + AllAvrUsedCounts + " AllUC = " + AllUsedCounts + " and Factor =  " + CleaningFactor, LogPrinter.DEBUG_2);

	//do {
	// rwLog.log("--------------------- Factor will be " + TempFactor + " -------------------------" ,LogPrinter.DEBUG_2);	   	
	for (int Count = 1; Count <= MaxFields; Count++) {
		Field = rwCachTable[Count];
		if (Field.cf_AvrUsedCounts <= AllAvrUsedCounts) {
			do {
				synchronized (Field) {
					if (!Field.cf_NA) {
						Field.cf_NA = true;
						break;
					}
				} // sinchronized	
				try {
					Thread.sleep(20);
				} catch (Exception e) {
					rwLog.log("rwCacher (rwCleanCachFields) : Error on waiting for calculation of AvrUC in rwCleanCache!", LogPrinter.ERROR);
					rwLog.flush();
					return false;
				}
			} while (true);
			if (!rwWriteInDB(Field)) {
				Field.cf_NA = false;
				return false;
			}
			try {
				if (!RemoveIndex(Field.cf_rwString.toLowerCase().charAt(0), Count)) {
					Field.cf_NA = false;
					rwLog.log("rwCacher (rwCleanCachFields) : Cannot remove index from one of index arrays", LogPrinter.ERROR);
					rwLog.flush();
					return false;
				}
				Field.cf_rwKey = Constants.No_Key;
				Field.cf_rwString = null;
				Field.cf_langKey = 0;
				Field.cf_rwCounts = 0;
				Field.cf_UsedCounts = 0;
				Field.cf_rwLastCounts = 0;
				Field.cf_AvrUsedCounts = 0;
				Field.cf_Loaded = 0;
				Field.cf_NA = false;
				FieldsInUse--;
				rwLog.log("rwCacher (rwCleanCachFields) : rwCounts for rwKey | " + Field.cf_rwKey + " | updated and removed from CachTable", LogPrinter.DEBUG_2);
			} catch (Exception e1) {
				Field.cf_NA = false;
				rwLog.log("rwCacher (rwCleanCachFields) : Error in removing cache field - " + Count + " |rwKey=" + Field.cf_rwKey + "|UC=" + Field.cf_UsedCounts + "|AvrUC=" + Field.cf_AvrUsedCounts + "|L=" + Field.cf_Loaded + "|NA=" + Field.cf_NA + "\n" + e1, LogPrinter.ERROR);
				rwLog.flush();
			}
		} //if()
	} //for

	//  TempFactor += Constants.cb_IncreasingFactor;
	//} while (FieldsInUse == MaxFields);

	AllUsedCounts = 0;
	AllLastCleared = TimeNow;
	rwLog.log("\n\nrwCacher (rwCleanCachFields) : After removing InitTime = " + InitTime + " TimeNow " + TimeNow + "\n AllAvrUsedCounts = " + AllAvrUsedCounts + " AllUC = " + AllUsedCounts + " and Factor =  " + CleaningFactor, LogPrinter.DEBUG_2);
	for (int i = 1; i <= MaxFields; i++)
		rwLog.log("Cell : " + i + " | " + rwCachTable[i].cf_rwKey + " | " + rwCachTable[i].cf_rwCounts + " | " + rwCachTable[i].cf_langKey + " || " + rwCachTable[i].cf_NA + " | " + rwCachTable[i].cf_UsedCounts + " | " + rwCachTable[i].cf_AvrUsedCounts + " ||", LogPrinter.DEBUG_2);
	rwLog.log("\n\n", LogPrinter.DEBUG_2);
	rwLog.log("rwCacher (rwCleanCachFields) : rwCacheTable Cleaned.", LogPrinter.DEBUG);	
	return true;
}
/**
 * Registers new Cache Table field in the Cache Table.
 * @return boolean
 *	       <br> true  - if the method succeed
 * 		   <br> false - if the method failed
 */
public boolean rwRegisterCachField(long RrwKey, String RrwString, short RlangKey, int RrwCounts) {
	if (State != Constants.READY) {
		rwLog.log("rwCacher (rwRegisterCachField) : Error in Thread State - " + State, LogPrinter.ERROR);
		rwLog.flush();
		return false;
	}
	if (RrwKey < 255 || RrwString == null || RlangKey < 1 || RrwCounts < 1) {
		rwLog.log("rwCacher (rwRegisterCachField) : Error in the input param! - " + RrwKey + " , " + RrwString + " , " + RlangKey + " , " + RrwCounts, LogPrinter.ERROR);
		rwLog.flush();
		return false;
	}	
	int FieldNumber = 0;
	rwCachTableField Field = null; // = new rwCachTableField();
	try {
		synchronized (SynchroRegistering) {
			if (rwSearchForString(RrwString, RlangKey) == Constants.No_Key) {
				while (FieldsInUse == MaxFields) {
					if (Cleaning == true) {
						try {
							Thread.sleep(200);
						} catch (Exception e) {
							rwLog.log("rwCacher (rwRegisterCachField) : Exception on sleeping in rwRegisterCachField method!", LogPrinter.ERROR);
							rwLog.flush();
							return false;
						}
					} else {
						Cleaning = true;
						//		System.out.println("Begin Cleaning"); //dfdfsadfgasdfgadfgadfga						
						if (!rwCleanCachFields()) {
							Cleaning = false;
							rwLog.log("rwCacher (rwRegisterCachField) : Cannot Clean the cache table.", LogPrinter.ERROR);
							rwLog.flush();
							return false;
						}
						Cleaning = false;
					}
				}
				for (FieldNumber = 1; FieldNumber <= MaxFields; FieldNumber++) {
					// Here FieldNumber must start from 1 because 0 is not a valid value in Indexes arrays
					Field = rwCachTable[FieldNumber];
					if (Field.cf_rwKey == Constants.No_Key) {
						do {
							synchronized (Field) {
								if (!Field.cf_NA) {
									Field.cf_NA = true;
									break;
								}
							} // sinchronized	
							try {
								Thread.sleep(20);
							} catch (Exception e) {
								rwLog.log("rwCacher (rwRegisterCachField) : Error on waiting in Getting NA flag in rwRegisterCacheField!", LogPrinter.ERROR);
								rwLog.flush();
								return false;
							}
						} while (true);
						++FieldsInUse;
						if (!AddIndex(RrwString.toLowerCase().charAt(0), (short) FieldNumber)) {
							--FieldsInUse;
							Field.cf_NA = false;
							rwLog.log("rwCacher (rwRegisterCachField) : Error - AddIndex() failure!", LogPrinter.ERROR);
							rwLog.flush();
							return false;
						}
						//			System.out.println("Now enter " + RrwString + " in Field : " + Field);
						//						synchronized (Field) {
						Field.cf_rwKey = RrwKey;
						Field.cf_rwString = RrwString;
						Field.cf_langKey = RlangKey;
						Field.cf_rwCounts = RrwCounts;
						Field.cf_rwLastCounts = System.currentTimeMillis();
						Field.cf_Loaded = AllLastCleared;
						Field.cf_UsedCounts = 1;
						Field.cf_AvrUsedCounts = 0;
						Field.cf_NA = false;
						//						}
						AllUsedCounts++;
						rwLog.log("rwCacher (rwRegisterCachField) registerd : " + Field.cf_rwKey + " , " + Field.cf_rwString + " , " + Field.cf_langKey + " , " + Field.cf_rwCounts, LogPrinter.DEBUG);
						return true;
					} //if(... == No_Key)
				} // for
				rwLog.log("rwCacher (rwRegisterCachField) : " + RrwString + " has not entered in CT.", LogPrinter.ERROR);
				rwLog.flush();
				return false;
			} //if(rwSearch ...
			else {
				rwLog.log("rwCacher (rwRegisterCachField) : " + RrwString + " has already been registered.", LogPrinter.DEBUG_1);
				rwLog.flush();
				long res = rwResolveString(RrwString, RlangKey, RrwCounts);
				if (res == Constants.No_Key) {
					rwLog.log("rwCacher (rwRegisterCachField) : " + RrwString + " is tryed to be resolve second time but failed.", LogPrinter.ERROR);
					rwLog.flush();
					return false;
				} else {
					if (res == 0) {
						rwLog.log("rwCacher (rwRegisterCachField) : " + RrwString + " can not be resolved. Second Resolve failed.", LogPrinter.ERROR);
						rwLog.flush();
						return false;
					}
				}
				rwLog.log("rwCacher (rwRegisterCachField) resolved : " + RrwKey + " , " + RrwString + " , " + RlangKey + " , " + RrwCounts, LogPrinter.DEBUG);
				return true;
			}
		} //synchro
	} catch (Exception e) {
		rwLog.log("rwCacher (rwRegisterCachField) : Exception on '" + RrwString + "' Field :" + Field + ": - " + e, LogPrinter.ERROR);
		rwLog.flush();
	}
	return false;
}
/**
 * This method updates the rwCounts Cache Table Fild and returns boolean answer whether has found 
 * <br>rw with this rwKey. If there is no such returns false.
 * @return boolean 
 */
public boolean rwResolveKey(long prwKey, int prwCounts) {
	if (State != Constants.READY) {
		rwLog.log("rwCacher (rwResolveString) : Error in Thread State - " + State, LogPrinter.ERROR);
		rwLog.flush();
		return false;
	}
	int Count = 0;
	int index = 0;
	rwCachTableField Field = null;
	try {
		char p = (char) (prwKey % 256);
		if (p >= 'a' && p <= 'z') {
			int first = ((int) p) - ((int) 'a');
			for (Count = 0; Count < MaxFields; Count++) {
				index = IndexesOf[first][Count];
				Field = rwCachTable[index];
				if (prwKey == Field.cf_rwKey) {
					if (Field.cf_NA == true) {
						try {
							Thread.sleep(20);
							Count = 0;
						} catch (Exception e) {
							rwLog.log("rwCacher (rwResolveKey) : Exception on sleeping in rwResolveKey", LogPrinter.ERROR);
							rwLog.flush();
							return false;
						}
					} else {
						synchronized (Field) {
							if (!Field.cf_NA) {
								Field.cf_NA = true;
							} else {
								Count = 0;
							}
						} // sinchronized	
						Field.cf_rwCounts += prwCounts;
						Field.cf_rwLastCounts = System.currentTimeMillis();
						Field.cf_UsedCounts++;
						Field.cf_NA = false;
						AllUsedCounts++;
						rwLog.log("rwCacher (rwResolveKey) : resolved : " + Field.cf_rwKey + " , " + Field.cf_rwString + " , " + Field.cf_langKey + " , " + Field.cf_rwCounts, LogPrinter.DEBUG);
						return true;
					}
				}
			} //for
		} // if(p
		else
			if ((p >= '0') && (p <= '9')) {
				for (Count = 0; Count < MaxFields; Count++) {
					index = Numbers[Count];
					Field = rwCachTable[index];
					if (prwKey == Field.cf_rwKey) {
						if (Field.cf_NA == true) {
							try {
								Thread.sleep(20);
								Count = 0;
							} catch (Exception e) {
								rwLog.log("rwCacher (rwResolveKey) : Exception on sleeping in rwResKey", LogPrinter.DEBUG);
								rwLog.flush();
								return false;
							}
						} else {
							synchronized (Field) {
								if (!Field.cf_NA) {
									Field.cf_NA = true;
								} else {
									Count = 0;
								}
							} // sinchronized	
							Field.cf_rwCounts += prwCounts;
							Field.cf_rwLastCounts = System.currentTimeMillis();
							Field.cf_UsedCounts++;
							Field.cf_NA = false;
							AllUsedCounts++;
							rwLog.log("rwCacher (rwResolveKey) : resolved : " + Field.cf_rwKey + " , " + Field.cf_rwString + " , " + Field.cf_langKey + " , " + Field.cf_rwCounts, LogPrinter.DEBUG);
							return true;
						}
					}
				} //for     
			} else {
				for (Count = 0; Count < MaxFields; Count++) {
					index = Others[Count];
					Field = rwCachTable[index];
					if (prwKey == Field.cf_rwKey) {
						if (Field.cf_NA == true) {
							try {
								Thread.sleep(20);
								Count = 0;
							} catch (Exception e) {
								rwLog.log("rwCacher (rwResolveKey) : Exception on sleeping in rwResKey", LogPrinter.ERROR);
								rwLog.flush();
								return false;
							}
						} else {
							synchronized (Field) {
								if (!Field.cf_NA) {
									Field.cf_NA = true;
								} else {
									Count = 0;
								}
							} // sinchronized	
							Field.cf_rwCounts += prwCounts;
							Field.cf_rwLastCounts = System.currentTimeMillis();
							Field.cf_UsedCounts++;
							Field.cf_NA = false;
							AllUsedCounts++;
							rwLog.log("rwCacher (rwResolveKey) : resolved : " + Field.cf_rwKey + " , " + Field.cf_rwString + " , " + Field.cf_langKey + " , " + Field.cf_rwCounts, LogPrinter.DEBUG);
							return true;
						} //else 
					} //if
				} //for	  
			} //else
		return false;
	} catch (Exception e) {
		rwLog.log("rwCacher (rwResolveKey) : Exception on rwKey-" + prwKey + ", rwCounts-" + prwCounts + " " + e, LogPrinter.ERROR);
		rwLog.flush();
		return false;
	}
}
/**
 * This method updates the rwCounts Cache Table Fild and returns rwKey on givern rwString and langKey. 
 * <br>If there is no such returns Constants.No_Key constant.
 * @return rwKey long - found rwKey or Constants.No_Key 
 */
public long rwResolveString(String SrwString, short SlangKey, int SrwCounts) {
	if (State != Constants.READY) {
		rwLog.log("rwCacher (rwResolveString) : Error in Thread State - " + State, LogPrinter.ERROR);
		rwLog.flush();
		return Constants.No_Key;
	}
	int Count = 0;
	int index = 0;
	rwCachTableField Field = null;
	try {
		char p = SrwString.toLowerCase().charAt(0);
		if (p >= 'a' && p <= 'z') {
			int first = ((int) p) - ((int) 'a');
			for (Count = 0; Count < MaxFields; Count++) {
				index = IndexesOf[first][Count];
				Field = rwCachTable[index];
				if (SrwString.equals(Field.cf_rwString) && Field.cf_langKey == SlangKey) {
					if (Field.cf_NA == true) {
						try {
							Thread.sleep(20);
							Count = 0;
						} catch (Exception e) {
							rwLog.log("rwCacher (rwResolveString) : Error on waiting in Getting NA flag in rwResolveString!", LogPrinter.ERROR);
							rwLog.flush();
							return 0;
						}
					} else {
						synchronized (Field) {
							if (!Field.cf_NA) {
								Field.cf_NA = true;
							} else {
								Count = 0;
							}
						} // sinchronized	
						Field.cf_rwCounts += SrwCounts;
						Field.cf_rwLastCounts = System.currentTimeMillis();
						Field.cf_UsedCounts++;
						Field.cf_NA = false;
						AllUsedCounts++;
						rwLog.log("rwCacher (rwResolveString) : resolved - " + Field.cf_rwKey + " , " + Field.cf_rwString + " , " + Field.cf_langKey + " , " + Field.cf_rwCounts, LogPrinter.DEBUG);
						return Field.cf_rwKey;
					} //else
				} //if(equals
			} //for
		} // if(p
		else
			if ((p >= '0') && (p <= '9')) {
				for (Count = 0; Count < MaxFields; Count++) {
					index = Numbers[Count];
					Field = rwCachTable[index];
					if (SrwString.equals(Field.cf_rwString) && Field.cf_langKey == SlangKey) {
						if (Field.cf_NA == true) {
							try {
								Thread.sleep(20);
								Count = 0;
							} catch (Exception e) {
								rwLog.log("rwCacher (rwResolveString) : Error on waiting in Getting NA flag in rwResolveString!", LogPrinter.ERROR);
								rwLog.flush();
								return 0;
							}
						} else {
							synchronized (Field) {
								if (!Field.cf_NA) {
									Field.cf_NA = true;
								} else {
									Count = 0;
								}
							} // sinchronized	
							Field.cf_rwCounts += SrwCounts;
							Field.cf_rwLastCounts = System.currentTimeMillis();
							Field.cf_UsedCounts++;
							Field.cf_NA = false;
							AllUsedCounts++;
							rwLog.log("rwCacher (rwResolveString) : resolved - " + Field.cf_rwKey + " , " + Field.cf_rwString + " , " + Field.cf_langKey + " , " + Field.cf_rwCounts, LogPrinter.DEBUG);
							return Field.cf_rwKey;
						} //else
					}
				} //for     
			} else {
				for (Count = 0; Count < MaxFields; Count++) {
					index = Others[Count];
					Field = rwCachTable[index];
					if (SrwString.equals(Field.cf_rwString) && Field.cf_langKey == SlangKey) {
						if (Field.cf_NA == true) {
							try {
								Thread.sleep(20);
								Count = 0;
							} catch (Exception e) {
								rwLog.log("rwCacher (rwResolveString) : Error on waiting in Getting NA flag in rwResolveString!", LogPrinter.ERROR);
								rwLog.flush();
								return 0;
							}
						} else {
							synchronized (Field) {
								if (!Field.cf_NA) {
									Field.cf_NA = true;
								} else {
									Count = 0;
								}
							} // sinchronized	
							Field.cf_rwCounts += SrwCounts;
							Field.cf_rwLastCounts = System.currentTimeMillis();
							Field.cf_UsedCounts++;
							Field.cf_NA = false;
							AllUsedCounts++;
							rwLog.log("rwCacher (rwResolveString) : resolved - " + Field.cf_rwKey + " , " + Field.cf_rwString + " , " + Field.cf_langKey + " , " + Field.cf_rwCounts, LogPrinter.DEBUG);
							return Field.cf_rwKey;
						} //else 
					} //if
				} //for	  
			} //else
		return Constants.No_Key;
	} catch (Exception e) {
		rwLog.log("rwCacher (rwResolveString) : Exception - " + e, LogPrinter.ERROR);
		rwLog.flush();
		return Constants.No_Key;
	}
}
/**
 * This method only returns rwKey on givern rwString/langKey. If there is no such returns No_Key Constant.
 * @return rwKey long
 */
public long rwSearchForString(String SrwString, int SlangKey) {
	if (State != Constants.READY) {
		rwLog.log("rwCacher (rwSearchForString) : Error in Thread State - " + State, LogPrinter.ERROR);
		rwLog.flush();
		return Constants.No_Key;
	}
	int Count = 0;
	int index = 0;
	char p;	
	try {
		p = SrwString.toLowerCase().charAt(0);
		if (p >= 'a' && p <= 'z') {
			int first = ((int) p) - ((int) 'a');
			for (Count = 0; Count < MaxFields; Count++) {
				index = IndexesOf[first][Count];
				if (SrwString.equals(rwCachTable[index].cf_rwString) && rwCachTable[index].cf_langKey == SlangKey)
					return rwCachTable[index].cf_rwKey;
			} //for
		} // if(p
		else
			if ((p >= '0') && (p <= '9')) {
				for (Count = 0; Count < MaxFields; Count++) {
					index = Numbers[Count];
					if (SrwString.equals(rwCachTable[index].cf_rwString) && rwCachTable[index].cf_langKey == SlangKey)
						return rwCachTable[index].cf_rwKey;
				} //for     
			} else {
				for (Count = 0; Count < MaxFields; Count++) {
					index = Others[Count];
					if (SrwString.equals(rwCachTable[index].cf_rwString) && rwCachTable[index].cf_langKey == SlangKey)
						return rwCachTable[index].cf_rwKey;
				} //for	  
			}
		return Constants.No_Key;			
	} catch (Exception e) {
		rwLog.log("rwCacher (rwSearchForString) : Exception - " + e, LogPrinter.ERROR);
		rwLog.flush();
		return Constants.No_Key;
	}
}
/**
 * Updates the rwCounts and rwLastCounted properties of rw CacheTableField in the 'rw' DB.
 * @return boolean
 *	       <br> true  - if the method succeed
 * 		   <br> false - if the method failed
 */
private boolean rwWriteInDB(rwCachTableField Field) {
	String SQLStat = null;
	try {
		if (dbConnection == null)
			throw new SQLException();
		if (Field.cf_rwCounts != 0) {
			SQLStat = "UPDATE " + Constants.rwWhichTable(Field.cf_rwString.charAt(0), Constants.No_Key) + " SET " + dbFields.db_rwSumAllCounts + " = " + dbFields.db_rwSumAllCounts + " + " + String.valueOf(Field.cf_rwCounts) + " , " + dbFields.db_rwLastCount + " = '" + (new java.sql.Date(Field.cf_rwLastCounts)) + "' WHERE " + dbFields.db_rwKey + " = " + String.valueOf(Field.cf_rwKey);
			Statement stmt = dbConnection.createStatement();
			int result = stmt.executeUpdate(SQLStat);
			if (result == 1) {
				rwLog.log("rwCacher (rwWriteInDB) : rwString = " + Field.cf_rwString + " updated in the DB.", LogPrinter.DEBUG);
			} else {
				if (result > 1) {
					rwLog.log("rwCacher (rwWriteInDB) : Res from updating = " + result + ", rwKey = " + Field.cf_rwKey + ", rwCounts = " + Field.cf_rwCounts + ", rwString :" + Field.cf_rwString + ": is DUBLICATED.", LogPrinter.ERROR);
				} else {
					rwLog.log("rwCacher (rwWriteInDB) : Res from updating = " + result + ", rwKey = " + Field.cf_rwKey + ", rwCounts = " + Field.cf_rwCounts + ", rwString :" + Field.cf_rwString + ": not updated.", LogPrinter.ERROR);
				}
				rwLog.flush();
			}
			stmt.close();
		}
		return true;
	} catch (SQLException e) {
		try {
			if (dbConnection == null || dbConnection.isClosed()) {
				if (!rwCacherdbConnect()) {
					rwLog.log("rwCacher (rwWriteInDB) : rwdbConnect() failure.", LogPrinter.ERROR);
					rwLog.flush();
					return false;
				}
				rwLog.log("rwCacher (rwWriteInDB) : Reconnection to db done.", LogPrinter.INFO);
				rwLog.flush();
				return rwWriteInDB(Field);
			} else {
				rwLog.log("rwCacher (rwWriteInDB) : SQL Statement error - " + SQLStat + "\n" + e, LogPrinter.ERROR);
				rwLog.flush();
				return false;
			}
		} catch (Exception ex) {
			rwLog.log("rwCacher (rwWriteInDB) : Exception in re-connect: " + ex, LogPrinter.ERROR);
			rwLog.flush();
			return false;
		}
	} catch (NumberFormatException e) {
		rwLog.log("rwCacher (rwWriteInDB) : error format - " + SQLStat + "\n" + e, LogPrinter.ERROR);
		rwLog.flush();
		return false;
	} catch (Exception e) {
		rwLog.log("rwCacher (rwWriteInDB) : Exception - " + SQLStat + "\n" + e, LogPrinter.ERROR);
		rwLog.flush();
		return false;
	}
}
/**
 * Saves the cache using the SaveThread's method.
 * @return boolean
 */
public boolean SaveCache() {
	return SaveThread.SaveRwCache();
}
}

