package network;
 
import other.ConnectionNotifier;
import other.SettingsData;
import other.Timer;
import other.TimerListener;

/**
 * NetworkHandler Klasse
 * Dient zur Verwaltung und Überwachung aller drei Netzwerkverbindungen
 * Übernimmt den Aufbau, die Kontrolle und Beendung der Netzwerkkommunikation
 */
public class NetworkHandler implements TimerListener, ConnectionNotifier {

	// Network
	private DBModule dbModule;
	private ObjManager objManager;
	private NClient nClient;
	private FTPModule ftpModule;
	
	// Timer
	private Timer cmdObserver;
	private Timer netObserver;
	
	// Queues
	private Queue comQueue = null;
	private Queue msgQueue = null;
	
	// IP-Adresse
	private String ipAddress;
	
	// Handler dieser Klasse (Hauptfenster)
    private ConnectionNotifier mHandler;
	
	/**
	 * Konstruktor
	 * @param handl Referenz auf MainShell zur Übermittlung v. Statusmeldungen und Nachrichten
	 * @param setData beinhaltet die gesamten Einstellungen für den Verbindungsaufbau
	 */
	public NetworkHandler(ConnectionNotifier handl, SettingsData setData){
		mHandler = handl;
		initialize(setData);
		ipAddress = setData.ipAddress;
	}
	
	/**
	 * Destruktor
	 * Beendet Timer
	 */
	protected void finalize(){
		netObserver.stop();
		if(cmdObserver.isrunning()) cmdObserver.stop();
	}

	/* ##########################################################################
	 * 						ÖFFENTLICHE METHODEN
	 * ##########################################################################*/		
	
	/** ######################## INTERFACE ######################## */
	
	/**
	 * Methode, die vom Timer aufgerufen wird
	 * @param t Timer der die Methode in regelmäßigen Abständen aufruft
	 */
    public void timerAction(Timer t){
    	System.out.println("Timer action");

    	// FTP-Leitung:
    	// Wenn verbunden --> Konnektivität checken
    	// Wenn generell oder erst dadurch nicht verbunden --> neu verbinden
    	if(isFtpConnected()){
    		ftpModule.checkConnection();
    		mHandler.messageEvent(new Message(Message.REFRESH_FTP));
    	}
    	if(!isFtpConnected()) connectFtp();
    	
    	//System.out.println("Timer: FTP completed");
    	
    	// das gleiche mit der SQL-Leitung
    	if(isSqlConnected()) dbModule.checkConnection();
    	if(!isSqlConnected()) connectSql();
    	
    	//System.out.println("Timer: SQL completed");
    	
    	// Cmd-Leitung muss hier nicht überprüft werden,
    	// da es dafür ja einen eigenen Timer gibt
    	if(isCmdConnected()) nClient.checkConnection();
    	if(!isCmdConnected()) connectCmd();
    	if(!isCmdConnected()) disposeOfQueueCommands();
    	
    	//System.out.println("Timer: Socket completed");
    	
    	// Debug: Status ausgeben
    	System.out.println("Status Cmd: " + nClient.isConnected() + ", Sql: " +
    			dbModule.isConnected() + ", Ftp: " + ftpModule.isConnected());
    }
	
	/**
	 * Methode, die aufgerufen wird, wenn eine Verbindung abgebrochen wurde
	 */
	public void connectionNotification(){
		// Ans Hauptfenster weiterreichen
		mHandler.connectionNotification();
	}
	
	/**
	 * Methode, die aufgerufen wird, wenn eine Nachricht vom Roboter gekommen ist
	 */
	public void messageEvent(final Message msg){
		// Ans Hauptfenster weiterreichen
		mHandler.messageEvent(msg);
	}
	
	/**
	 * Aktualisiert die Einstellung laut SettingsData-Objekt
	 * @param setData beinhaltet die Daten für den Verbindungsaufbau
	 */
	public void updateSettings(SettingsData setData){
		ipAddress = setData.ipAddress;
		dbModule.setLoginData(setData.sqlUser, setData.sqlPassw);
		ftpModule.setLoginData(setData.ftpUser, setData.ftpPassw, setData.ftpDir);
		cmdObserver.setInterval(setData.cmdTimerInterv);
		netObserver.setInterval(setData.netTimerInterv);
	}
	
	/**
	 * Startet den Timer, der automatisch Verbindungen
	 * aufbaut und überprüft
	 */
	public void startTimer(){
		netObserver.start();
	}
	
	/**
	 * Stoppt den Timer, der automatisch Verbindungen
	 * aufbaut und überprüft
	 */
	public void stopTimer(){
		netObserver.stop();
	}
	
	/** ######################### CONNECT ######################### */
	
	/**
	 * Verbindet alle Clients
	 */
	public void connect(){
		if(!isCmdConnected()) connectCmd();
		if(!isSqlConnected()) connectSql();
		if(!isFtpConnected()) connectFtp();
	}
	
	/**
	 * Verbindet die Command-Leitung
	 */
	public void connectCmd(){
		if(nClient.connect(ipAddress)) cmdObserver.start();
	}
	
	/**
	 * Verbindet die SQL-Leitung
	 */
	public void connectSql(){
		dbModule.connect(ipAddress);
	}
	
	/**
	 * Verbindet die FTP-Leitung
	 */
	public void connectFtp(){
		ftpModule.connect(ipAddress);
	}
	
	/** ####################### DISCONNECT ####################### */
	
	/**
	 * Trennt alle Clients
	 */
	public void disconnect(){
		disconnectCmd();
		disconnectSql();
		disconnectFtp();
	}
	/**
	 * Trennt die Command-Leitung
	 */
	public void disconnectCmd(){
		cmdObserver.stop();
		nClient.disconnect();
	}
	/**
	 * Trennt die SQL-Leitung
	 */
	public void disconnectSql(){
		dbModule.disconnect();
	}
	/**
	 * Trennt die FTP-Leitung
	 */
	public void disconnectFtp(){
		ftpModule.disconnect();
	}
	
	/** ###################### IS-CONNECTED ###################### */
	
	/**
	 * Liefert zurück, ob alle Clients verbunden sind.
	 * @return true wenn verbunden, sonst false
	 */
	public boolean isConnected(){
		return isCmdConnected() && 
			isSqlConnected() && isFtpConnected();
	}
	/**
	 * Liefert zurück, ob der Client der Command-Leitung verbunden ist.
	 * @return true wenn verbunden, sonst false
	 */
	public boolean isCmdConnected(){
		return nClient.isConnected();
	}
	/**
	 * Liefert zurück, ob der Client der SQL-Leitung verbunden ist.
	 * @return true wenn verbunden, sonst false
	 */
	public boolean isSqlConnected(){
		return dbModule.isConnected();
	}
	/**
	 * Liefert zurück, ob der Client der FTP-Leitung verbunden ist.
	 * @return true wenn verbunden, sonst false
	 */
	public boolean isFtpConnected(){
		return ftpModule.isConnected();
	}
	
	/** ###################### GET-METHODEN ###################### */
	
	public DBModule getDBModule(){			return dbModule; 	}
	public ObjManager getObjManager(){		return objManager; 	}
	public NClient getNClient(){			return nClient; 	}
	public FTPModule getFTPModule(){		return ftpModule; 	}
	public Queue getComQueue(){				return comQueue; 	}
	public Queue getMsgQueue(){				return msgQueue; 	}
	
	// IP-Adresse
	public String getIPAddress(){			return ipAddress;	}
	public void setIPAddress(String ip){	ipAddress = ip;		}
	
	/* ##########################################################################
	 * 						HILFSMETHODEN
	 * ##########################################################################*/		

/**
 * Erstellt alle Objekte und initialisiert diese
 * @param setData Objekt mit den Daten zum Verbindungsaufbau
 */
private void initialize(SettingsData setData){
	// Queues
	comQueue = new Queue();
	msgQueue = new Queue();
	// Command-Leitung
	nClient = new NClient(comQueue, msgQueue, this);
	// SQL-Leitung
	dbModule = new DBModule(this);
	dbModule.setLoginData(setData.sqlUser, setData.sqlPassw);
	objManager = new ObjManager(comQueue, dbModule);
	// FTP-Leitung
	ftpModule = new FTPModule(this);
	ftpModule.setLoginData(setData.ftpUser, setData.ftpPassw, setData.ftpDir);
	// Timer
	cmdObserver = new Timer(setData.cmdTimerInterv);
	cmdObserver.addTimerListener(nClient);
	netObserver = new Timer(setData.netTimerInterv);
	netObserver.addTimerListener(this);
	// Debug
	System.out.println("Netzwerkobjekte erzeugt.");
}

/**
 * Entfernt überflüssige Commands aus der Command-Queue,
 * wenn Socket-Verbindung noch nicht aufgebaut
 */
private void disposeOfQueueCommands(){
	while(comQueue.size()>0) comQueue.dequeue();

}

}