package gui;
 
import network.NetworkHandler;
import network.ObjManager;
import network.TransObj;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.layout.RowData;
import org.eclipse.swt.layout.RowLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Group;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.Text;
import other.DynamicCmdSelector;
import other.MsgBox;

/**
 * TabItemTransObj Klasse 
 * Dient zum Definieren, Ändern und Entfernen von Transportobjektdefinitionen,
 * dem Laden von und Speichern auf der Festplatte, sowie zur Synchronisation
 * der Daten auf der Client u. Serverseite 
 */
public class TabItemTransObj extends Composite implements DynamicCmdSelector {

	// Attribute
	private Table tTable = null;
	private Button bNew = null;
	private Button bChange = null;
	private Button bTOver = null;
	private Button bDelete = null;
	private Button bSync = null;
	private Label lName = null;
	private Label lRad = null;
	private Label lHeight = null;
	private Group gTransObj = null;
	private Group gButtons = null;
	private Label lNr = null;
	private Label lSync = null;
	private Text tNr = null;
	private Text tName = null;
	private Text tRad = null;
	private Text tHeight = null;
	private MainShell mainShell = null;

	private ObjManager objManager = null;
	boolean bNewEntry = false;
	boolean bChangeEntry = false;
	boolean bConnection = false;
	boolean bIsSync = false;
	boolean bIsDynCmdSelect = false;

	/**
	 * Konstruktor der einen TransObjViewer erzeugt
	 * @param mainSh Referenz auf die MainShell
	 * @param parent das Parent Composite
	 * @param style der SWT Style
	 * @param netH das vorherrschende NetworkHandler Objekt
	 */
	public TabItemTransObj(MainShell mainSh, Composite parent, int style, NetworkHandler netH) {
		super(parent, style);
		mainShell = mainSh;
		objManager=netH.getObjManager();
		initialize();
		connectionDisrupted();
	}	
	
	/* ##########################################################################
	 * 						VISUAL EDITOR
	 * ##########################################################################*/
	
	/**
	 * Methode die die ganzen Komponenten initialisiert und anordnet
	 */
	private void initialize() {
		GridLayout gridLayout = new GridLayout();
		gridLayout.numColumns = 2;
		gridLayout.marginTop = 5;
		gridLayout.marginBottom = 5;
		gridLayout.marginLeft = 5;
		gridLayout.marginRight = 5;
		this.setLayout(gridLayout);
        createTable();
        createGroupBtn();
        createGroupTxt();
        // Layout-Data-Objekte
		GridData gridDataTable = new GridData();
		gridDataTable.horizontalAlignment = org.eclipse.swt.layout.GridData.FILL;
		gridDataTable.verticalAlignment = org.eclipse.swt.layout.GridData.FILL;
		gridDataTable.grabExcessHorizontalSpace = true;
		gridDataTable.grabExcessVerticalSpace = true;
		tTable.setLayoutData(gridDataTable);
		GridData gridDataButtons = new GridData();
		gridDataButtons.horizontalAlignment = org.eclipse.swt.layout.GridData.FILL;
		gridDataButtons.verticalSpan = 2;
		gButtons.setLayoutData(gridDataButtons);
		GridData gridDataTransObj = new GridData();
		gridDataTransObj.horizontalAlignment = org.eclipse.swt.layout.GridData.FILL;
		gTransObj.setLayoutData(gridDataTransObj);
	}
	
	/**
	 * Diese Methode initialisiert die Tabelle und definiert deren 
	 * Aussehen
	 */    
	private void createTable(){
		tTable = new Table(this, SWT.FULL_SELECTION);		   
		tTable.setHeaderVisible(true);
		tTable.setLinesVisible(true);
        tTable.setFont(new org.eclipse.swt.graphics.Font(org.eclipse.swt.widgets.Display.getDefault(), "Tahoma", 12, org.eclipse.swt.SWT.NORMAL));
		tTable.setBounds(new org.eclipse.swt.graphics.Rectangle(20,21,500,249));
		tTable.addSelectionListener(new org.eclipse.swt.events.SelectionAdapter() { 
			public void widgetSelected(org.eclipse.swt.events.SelectionEvent e) {    
				selectionChanged(); //Auswahl geändert
			}
		});
		TableColumn tcNr = new TableColumn(tTable,SWT.NONE);
		tcNr.setText("Nr");
		tcNr.setWidth(100);
		tcNr.setResizable(false);
		TableColumn tcName = new TableColumn(tTable,SWT.NONE);
		tcName.setText("Name");
		tcName.setWidth(200);
		tcName.setResizable(false);
		TableColumn tcRad = new TableColumn(tTable,SWT.NONE);
		tcRad.setText("Radius");
		tcRad.setWidth(100);
		tcRad.setResizable(false);
		TableColumn tcHeight = new TableColumn(tTable,SWT.NONE);
		tcHeight.setText("Höhe");
		tcHeight.setWidth(100);
		tcHeight.setResizable(false);
		tTable.setSortColumn(tcNr);
	}
	
	/**
	 * Diese Methode initialisiert die Groupbox für die Buttons	und
	 * ordnet diese mit Hilfe eines Layoutmanagers an
	 */    
	private void createGroupBtn(){
		// GroupBox erzeugen
		gButtons = new Group(this, SWT.NONE);
		gButtons.setText("Transport-Objekte");
		gButtons.setFont(new Font(Display.getDefault(), "Tahoma", 10, SWT.BOLD));
		// Layout
		RowLayout rowLayout = new RowLayout();
		rowLayout.type = org.eclipse.swt.SWT.VERTICAL;
		rowLayout.justify = false;
		rowLayout.pack = true;
		rowLayout.spacing = 15;
		rowLayout.marginLeft = 5;
		rowLayout.marginRight = 5;
		rowLayout.marginBottom = 5;
		rowLayout.marginTop = 5;
		rowLayout.fill = true;
		gButtons.setLayout(rowLayout);
		// Layout-Data (Größe der Buttons)
		RowData rowData = new org.eclipse.swt.layout.RowData();
		rowData.width = 160;
		rowData.height = 35;
		// Buttons erstellen
        bNew = new Button(gButtons, SWT.NONE);
        bChange = new Button(gButtons, SWT.NONE);
        bTOver = new Button(gButtons, SWT.NONE);
        bDelete = new Button(gButtons, SWT.NONE);
        bSync = new Button(gButtons, SWT.NONE);
        lSync = new Label(gButtons, SWT.CENTER);
        // Button-Eigenschaften
        bNew.setText("Neu");
        bNew.setLayoutData(rowData);
        bChange.setText("Ändern");
        bChange.setLayoutData(rowData);
        bTOver.setText("Übernehmen");
        bTOver.setLayoutData(rowData);
        bDelete.setText("Löschen");
        bDelete.setLayoutData(rowData);
        bSync.setText("Synchronisieren");
        bSync.setLayoutData(rowData);
        lSync.setText("-");
		lSync.setFont(new Font(Display.getDefault(), "Tahoma", 10, SWT.BOLD));
        lSync.setLayoutData(rowData);
        // Action Listener
        bNew.addSelectionListener(new org.eclipse.swt.events.SelectionAdapter() { 
        	public void widgetSelected(org.eclipse.swt.events.SelectionEvent e) {    
        		clickBNew(); //Neu-Button geklickt
        	}
        });
        bChange.addSelectionListener(new org.eclipse.swt.events.SelectionAdapter() { 
        	public void widgetSelected(org.eclipse.swt.events.SelectionEvent e) {    
        		clickBChange(); //Ändern-Button geklickt
        	}
        });
        bTOver.addSelectionListener(new org.eclipse.swt.events.SelectionAdapter() { 
        	public void widgetSelected(org.eclipse.swt.events.SelectionEvent e) {    
        		clickBTOver(); //Übernehmen-Button geklickt 
        	}
        });
        bDelete.addSelectionListener(new org.eclipse.swt.events.SelectionAdapter() { 
        	public void widgetSelected(org.eclipse.swt.events.SelectionEvent e) {    
        		clickBDelete(); //Löschen-Button geklickt
        	}
        });
        bSync.addSelectionListener(new org.eclipse.swt.events.SelectionAdapter() { 
        	public void widgetSelected(org.eclipse.swt.events.SelectionEvent e) {    
        		clickBSync(); //Synchronisieren-Button geklickt
        	}
        });

	}

	/**
	 * Diese Methode initialisiert die Groupbox	für die Eingabe und
	 * ordnet alle benötigten Komponenten an
	 */    
	private void createGroupTxt() {
		// GroupBox erzeugen
		gTransObj = new Group(this, SWT.NONE);
		GridLayout gridLayout = new GridLayout();
		gridLayout.numColumns = 4;
		gTransObj.setLayout(gridLayout);
		gTransObj.setText("Daten");
		gTransObj.setFont(new Font(Display.getDefault(), "Tahoma", 10, SWT.BOLD));
		// LayoutData-Objekte erzeugen
		GridData gridDataExpress = new GridData();
		gridDataExpress.grabExcessHorizontalSpace = true;
		gridDataExpress.horizontalAlignment = org.eclipse.swt.layout.GridData.FILL;
		GridData gridDataWidthHint = new GridData();
		gridDataWidthHint.widthHint = 90;
		GridData gridDataFill = new GridData();
		gridDataFill.horizontalAlignment = org.eclipse.swt.layout.GridData.FILL;
		// Widgets erzeugen
		lNr = new Label(gTransObj, SWT.CENTER);
		lName = new Label(gTransObj, SWT.LEFT);
        lRad = new Label(gTransObj, SWT.LEFT);
        lHeight = new Label(gTransObj, SWT.LEFT);
		tNr = new Text(gTransObj, SWT.BORDER | SWT.RIGHT);
		tName = new Text(gTransObj, SWT.BORDER | SWT.LEFT);
		tRad = new Text(gTransObj, SWT.BORDER | SWT.RIGHT);
		tHeight = new Text(gTransObj, SWT.BORDER | SWT.RIGHT);
		// Eigenschaften der Widgets
		lNr.setText("Nr");
		lNr.setFont(gTransObj.getFont());
		lNr.setLayoutData(gridDataFill);
        lName.setText("Name");
        lName.setFont(gTransObj.getFont());
        lName.setLayoutData(gridDataFill);
        lRad.setText("Radius");
        lRad.setLayoutData(gridDataFill);
        lRad.setFont(gTransObj.getFont());
        lHeight.setText("Höhe");
        lHeight.setLayoutData(gridDataFill);
        lHeight.setFont(gTransObj.getFont());
		tNr.setFont(gTransObj.getFont());
		tNr.setEditable(false);
		tNr.setEnabled(false);
		tName.setFont(gTransObj.getFont());
		tName.setLayoutData(gridDataExpress);
		tName.setEnabled(false);
		tRad.setFont(gTransObj.getFont());
		tRad.setLayoutData(gridDataWidthHint);
		tRad.setEnabled(false);
		tHeight.setFont(gTransObj.getFont());
		tHeight.setLayoutData(gridDataWidthHint);
		tHeight.setEnabled(false);
	}
	
	/* ##########################################################################
	 * 						EREIGNISSE
	 * ##########################################################################*/
	
	/**
	 * Wird vom Hauptfenster aufgerufen, wenn gerade
	 * eine Verbindung aufgebaut wurde.
	 */
	public void connectionEstablished(){
		bConnection = true;
		objManager.syncPrgStart();
		refreshTable();
		bSync.setEnabled(true);
		bIsSync = true;
		updateSyncText();
	}
	
	/**
	 * Wird vom Hauptfenster aufgerufen, wenn die Verbindung
	 * gerade unterbrochen wurde.
	 */
	public void connectionDisrupted(){
		bConnection = false;
		bSync.setEnabled(false);
		bIsSync = false;
		updateSyncText();
	}

	/* ##########################################################################
	 * 						ÖFFENTLICHE METHODEN
	 * ##########################################################################*/	
	
	/**
	 * Ermittelt, ob die dynamsiche Command-Auswahl möglich ist
	 */
	public boolean isDynamicCmdPossible(){
		return (objManager.count()>0);
	}
	
	/**
	 * Startet die dynamische Auswahl von Commands
	 */
	public void startDynamicCmdSelect(String cmd){
		bIsDynCmdSelect = true;
		bNew.setEnabled(false);
		bChange.setEnabled(false);
		bTOver.setEnabled(false);
		bDelete.setEnabled(false);
		bSync.setEnabled(false);
	}
	
	/**
	 * Bricht die dynamische Auswahl von Kommandos ab
	 *
	 */
	public void cancelDynamicCmdSelect() {
		bIsDynCmdSelect = false;
		bNew.setEnabled(true);
		bChange.setEnabled(true);
		bTOver.setEnabled(true);
		bDelete.setEnabled(true);
		bSync.setEnabled(bConnection);
	}	
	
	/**
	 * Neu-Button wurde geklickt
	 * Leert alle Felder und aktiviert diese, famit eine spätere
	 * Parameter eingabe möglicht ist
	 */
	public void clickBNew(){
		//Felder freischalten
		tNr.setText(Integer.toString(objManager.getFreeNr()));
		tName.setText("");
		tRad.setText("");
		tHeight.setText("");
		// En- und disablen
		setEditState(true);
		setEnableState(false);
		// Flag setzen
		bNewEntry=true;
		bIsSync = false;
		updateSyncText();
	}
	
	/**
	 * Überprüft, ob der Benutzer gerade eine Änderung macht
	 * @return true, wenn editiert wird, sonst false
	 */
	public boolean isEditing(){
		return (bNewEntry||bChangeEntry);
	}
	
	/**
	 * Löschen-Button wurde geklickt
	 * Entfernt das aktuell gewählte Transportobjekt aus der Tabelle
	 */
	public void clickBDelete(){
		bIsSync = false;
		updateSyncText();
		
		// Vorher Neu oder Ändern geklickt?
		if(bNewEntry||bChangeEntry){
			// ursprünglichen Zustand wiederherstellen
			bNewEntry=false;
			bChangeEntry=false;
			setEditState(false);
			setEnableState(true);
			// Text in den Eingabefeldern löschen
			tNr.setText("");
			tName.setText("");
			tRad.setText("");
			tHeight.setText("");
			return;
		}
		
		if(MsgBox.showYesNoQuestion("Wollen Sie dieses Objekt wirklich löschen?")){
			objManager.getTransObj(Integer.parseInt(tTable.getItem(tTable.getSelectionIndex()).getText())).setDeleted(false);
			tTable.remove(tTable.getSelectionIndex());
			//Feldinhalt leeren
			tNr.setText("");
			tName.setText("");
			tRad.setText("");
			tHeight.setText("");
		}
	}
	
	/**
	 * Synchronisieren-Button wurde geklickt
	 * Synchronisiert die Transport Objekte in der Tabelle des 
	 * Clients und in der Datenbank auf der Serverseite
	 */
	public void clickBSync(){
		if(!bConnection) return;
		objManager.syncTransObj();
		refreshTable();
		bIsSync = true;
		updateSyncText();
	}
	
	/**
	 * Veranlasst eine Speicherung aller Transportobjekte in einen Ordner
	 */
	public void saveAllIntoFolder(){
		if(objManager.count()==0){
			MsgBox.showError("Keine Transportobjekte definiert.");
			return;
		}
		String p = MsgBox.askDirectory("Bitte Verzeichnis zum Speichern der Transportobjekte wählen:");
		if(p!=null) objManager.saveFiles(p);
	}
	
	/**
	 * Veranlasst, dass aus einem Ordner Transportobjekte geladen werden
	 */
	public void loadFromFolder(){
		String p = MsgBox.askDirectory("Bitte Verzeichnis zum Laden der Transportobjekte wählen:");
		if(p!=null){
			objManager.loadFiles(p);
			refreshTable();
		}
	}
	
	
	/* ##########################################################################
	 * 						HILFSMETHODEN
	 * ##########################################################################*/

	/**
	 * Stoppt die dynamische Auswahl von Commands
	 * @param sel String der das Kommando nach dynamischer Auswahl repräsentiert
	 */
	private void stopDynamicCmdSelect(String sel){
		cancelDynamicCmdSelect();
		mainShell.stopDynamicCommandSelect("SetTransObj("+sel+")");
	}	

	/**
	 * Zeigt die in der Tabelle ausgewählten Daten unten an
	 */
	private void selectionChanged(){
		// Schauen, ob dynamisches Auswählen aktiv
		if(bIsDynCmdSelect){
			stopDynamicCmdSelect(tTable.getItem(tTable.getSelectionIndex()).getText(0));
			return;
		}
		//Textfelder belegen
		tNr.setText(tTable.getItem(tTable.getSelectionIndex()).getText(0));
		tName.setText(tTable.getItem(tTable.getSelectionIndex()).getText(1));
		tRad.setText(tTable.getItem(tTable.getSelectionIndex()).getText(2));
		tHeight.setText(tTable.getItem(tTable.getSelectionIndex()).getText(3));
	}	

	/**
	 * Ändern-Button wurde geklickt
	 * Aktiviert die Eingabefelder zur Änderung der Daten
	 */
	private void clickBChange(){
		if(tTable.getSelectionIndex()>=0){
			// En- und disablen
			setEditState(true);
			setEnableState(false);
			bChangeEntry = true;
			bIsSync = false;
			updateSyncText();
		}
	}
	
	/**
	 * Übernehmen-Button wurde geklickt
	 * Übernimmt die Werte aus den Eingabedfeldern in die Tabelle
	 * Entweder neuer Eintrag od. Ändern eines bestehenden
	 */
	private void clickBTOver(){	
		//Neues Objekt hinzufügen
		if(bNewEntry){
			try{
				objManager.addTransObj(new TransObj(Integer.parseInt(tNr.getText()),
						tName.getText(),Float.parseFloat(tRad.getText()),
						Float.parseFloat(tHeight.getText())));	
				objManager.getTransObjAt(objManager.count()-1).addToTable(tTable);
				tTable.setSelection(tTable.getItemCount()-1);
				// En- und disablen
				setEditState(false);
				setEnableState(true);
				// Flag setzen
				bNewEntry=false;
			}catch(NumberFormatException e){
				MsgBox.showError("Ungültiger Radius oder Höhenwert!");	
			}
		}
		//Altes Objekt ändern
		else if(bChangeEntry){
			try{
				//Werte in TransObj hinterlegen
				TransObj t = new TransObj();
				t = objManager.getTransObj(Integer.parseInt(tNr.getText()));
				t.setNr(Integer.parseInt(tNr.getText()));
				t.setName(tName.getText());
				t.setRad(Float.parseFloat(tRad.getText()));
				t.setHeight(Float.parseFloat(tHeight.getText()));
				t.setSynchronized(false);
				
				//Werte in Tabelle eintragen
				tTable.getItem(tTable.getSelectionIndex()).setText(0,Integer.toString(t.getNr()));
				tTable.getItem(tTable.getSelectionIndex()).setText(1,t.getName());
				tTable.getItem(tTable.getSelectionIndex()).setText(2,Float.toString(t.getRad()));
				tTable.getItem(tTable.getSelectionIndex()).setText(3,Float.toString(t.getHeight()));
				// En- und disablen
				setEditState(false);
				setEnableState(true);
				// Flag setzen
				bChangeEntry=false;
			}catch(NumberFormatException e){
				MsgBox.showError("Ungültiger Radius oder Höhenwert!");		
			}
		}
	}	
	
	/**
	 * Setzt den Status der Eingabefelder
	 * @param bEnabled der Status der gesetzt werden soll
	 */
	private void setEditState(boolean bEnabled){
		tNr.setEnabled(bEnabled);
		tName.setEnabled(bEnabled);
		tRad.setEnabled(bEnabled);
		tHeight.setEnabled(bEnabled);
	}
	
	/**
	 * Alle Buttons außer Übernehmen- und Löschen-Buttons
	 * ein- oder ausschalten
	 * @param bEnabled der Status der gesetzt werden soll
	 */
	private void setEnableState(boolean bEnabled){
		bNew.setEnabled(bEnabled);
		bChange.setEnabled(bEnabled);
		//bDelete.setEnabled(bEnabled);
		bSync.setEnabled(bEnabled);
	}
	
	/**
	 * Aktualisiert die Tabelle
	 */
	private void refreshTable(){
		// Tabelle leeren
		tTable.removeAll();
		// Alle durchlaufen u. hinzufügen
		for(int i=0;i<objManager.count();i++)
			objManager.getTransObjAt(i).addToTable(tTable);	
	}
	
	/**
	 * Ändert Text und Farbe des Labels, das den 
	 * Synchronisationsstatus angibt
	 */
	private void updateSyncText(){
		if(bIsSync){
			lSync.setText("Synchronisiert");
			lSync.setForeground(Display.getDefault().getSystemColor(SWT.COLOR_GREEN));
		}else{
			lSync.setText("Nicht synchronisiert");
			lSync.setForeground(Display.getDefault().getSystemColor(SWT.COLOR_RED));
		}
	}
	
}
