/* ***************************************************************************+
 * ITX package (cnrg.itx) for telephony application programming.              *
 * Copyright (c) 1999  Cornell University, Ithaca NY.                         *
 * A copy of the license is distributed with this package.  Look in the docs  *
 * directory, filename GPL.  Contact information: bergmark@cs.cornell.edu     *
 ******************************************************************************/
package cnrg.itx.ds;

import java.io.*;
import java.net.*;
import java.util.Vector;

/**
 * CleanUpThread is used to remove from the directory database server invalid dynamic location(s) of the user authenticated with the DirectoryService object. <br>
 * It automatically starts by default after a user successfully called DirectoryService::declareIdentity. <br>
 * To turn off the cleanup thread, user can call DirectoryService::setCleanUp and pass it in false boolean value before calling DirectoryService::declareIdentity. <br>
 */
class CleanUpThread extends Thread
{
	private Digits m_Ext;
	private DSComm m_DSComm;
	private ArrayRecords m_DynamicLocRecs;
		
	// Returns the formatted byte array, to ensure valid passing of null-terminated byte array into cstub.dll
	private byte[] getFormatByteArray(String str) {
		String tmp = str + (char)0;
		return tmp.getBytes();
	}

	/**
	 * Constructor
	 * @param userExtension user's extension
	 */
	public CleanUpThread(Digits userExtension, DSComm dsComm){
		m_Ext = userExtension;
		m_DSComm = dsComm;
		m_DynamicLocRecs = m_DSComm.getRecord(getFormatByteArray(m_Ext.toString() + m_DSComm.getExt2DynamicLocListDomain()));
	}
	
	/**
	 * This is the routine the thread.start() begin running.
	 * This is the main routine to clean up invalid dynamic location(s) of a registered user
	 */
	public void run() {
		System.out.println(">>>>Cleanup Thread starts in background...\n");
		Vector states = new Vector();
		Vector locations = new Vector();
		
		try {
			sleep(2000);	// sleep for 2 sec.
		}catch (InterruptedException ex) {
		}
		
		if (m_DynamicLocRecs.count() <= 0) {
			System.out.println(">>>>Cleanup Thread finished with empty dynamic location list...");
			return;
		}

		String value = m_DynamicLocRecs.first();
		while (value != null) {
			Location newLoc = new Location(value);
			if (newLoc.isDialable()) {
				InetAddress addr = null;
				try {
					addr = InetAddress.getByName(newLoc.getIP());
					Socket sc = null;
					try {
						sc = new Socket(addr, newLoc.getPort());
						// connected -> location is valid
						sc.close();
					}catch (IOException ae) {
						locations.addElement(newLoc);
						states.addElement(new Boolean(false));
					}
				}catch(UnknownHostException ae) {
					locations.addElement(newLoc);
					states.addElement(new Boolean(false));
				}
			}
			value = m_DynamicLocRecs.next();					
		}
		
		try {
			sleep(3000);	// sleep for 3 sec.
		}catch (InterruptedException ex) {
		}
		
		int nCount=0;
		for (int i=0; i<locations.size(); i++) {
			Location loc = (Location)locations.elementAt(i);
			InetAddress addr = null;
			try {
				addr = InetAddress.getByName(loc.getIP());
				Socket sc = null;
				try {
					sc = new Socket(addr, loc.getPort());
					sc.close();	
				}catch (IOException ae) {
					Boolean b = (Boolean)states.elementAt(i);
					if (b.booleanValue() == false) { 
						// deleted if failed to connect two times in a roll
						m_DSComm.deleteRecord(getFormatByteArray(m_Ext.toString() + m_DSComm.getExt2DynamicLocListDomain()), getFormatByteArray(loc.toString()));
						nCount++;
					}
				}
			}catch(UnknownHostException ae) {
				Boolean b = (Boolean)states.elementAt(i);
				if (b.booleanValue() == false) {
					m_DSComm.deleteRecord(getFormatByteArray(m_Ext.toString() + m_DSComm.getExt2DynamicLocListDomain()), getFormatByteArray(loc.toString()));
					nCount++;
				}					
			}
		}
		System.out.println(">>>>Cleanup Thread finished with invalid dynamic location list removed (" + String.valueOf(nCount) + ").");
	}
	
}
