package ftp_client;

import java.util.ArrayList;
import java.util.concurrent.Semaphore;

import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Group;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.TableItem;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.graphics.Rectangle;

// Gestionnaire de comptes FTP et de connexion
public class ConnectionForm {

	/* Variables */
	private Semaphore s;			// Semaphore qui bloque le thread en attention la fermeture de la fenetre (meme principe que dans AskWindow)
	private FTPInfo DialogResult;	// Informations sur le compte FTP a connecter apres la fermeture de la fenetre
	ArrayList<FTPInfo> ftps;		// Comptes FTP enregistres
	
	/* Controls */
	// Fenetre et ses composants
	private Shell sShell = null;
	private Group group = null;
	private Group group1 = null;
	private LabelText TBaddress = null;
	private LabelText TBport = null;
	private LabelText TBuser = null;
	private LabelText TBpassword = null;
	private Table table = null;
	private Button button = null;
	private Button button1 = null;
	private Button checkBox = null;
	private Button checkBox1 = null;
	private Button checkBox2 = null;
	
	/* Constructor */
	// ftps : Comptes FTP enregistrees
	public ConnectionForm(ArrayList<FTPInfo> ftps){
		s = new Semaphore(0);
		s.release(); // Semaphore acquis d'origine
		if(ftps!=null) this.ftps = ftps;			// Si il n'y a des comptes enregistrees, alors les utiliser
		else this.ftps = new ArrayList<FTPInfo>();	// Sinon initialiser une liste vide
	}
	
	/* Disposed ? */
	// Si la fenetre n'est pas initialiser ou si elle est detruite, retourner vrai
	public boolean isDisposed(){ return sShell == null || sShell.isDisposed(); }
	
	/* Show It */
	// Afficher la fenetre et retourner le compte FTP a connecter
	// Fonction basee sur le meme principe que Ask() de AskWindow
	public FTPInfo Show(){
		// Aucune connexion a faire apres la fermeture de la fenetre, alors DialogResult = null
		DialogResult = null;
		try {
			s.acquire();
			Display.getDefault().asyncExec(new Runnable() {
	            public void run() {
	            	createSShell();
	        		refreshList();
	            	sShell.open();
	            }
	        });
			s.acquire();
		}catch (InterruptedException e){}
		s.release();
		return DialogResult;
	}

	/* Form Init */
	private void createSShell() {
		sShell = new Shell(Display.getDefault(), SWT.MIN);
		sShell.setText("Gestionnaire de connexions");
		createGroup();
		createGroup1();
		sShell.setLayout(null);
		sShell.setSize(new Point(423, 315));
		sShell.addShellListener(new org.eclipse.swt.events.ShellAdapter() {
			public void shellClosed(org.eclipse.swt.events.ShellEvent e) {
				s.release();
			}
		});
	}

	/**
	 * This method initializes group	
	 *
	 */
	private void createGroup() {
		group = new Group(sShell, SWT.NONE);
		group.setText("Connexions enregistrées");
		group.setBounds(new Rectangle(0, 0, 234, 287));
		group.setLayout(null);
		table = new Table(group, SWT.NONE);
		table.setHeaderVisible(true);
		table.setLinesVisible(false);
		table.setBounds(new Rectangle(3, 15, 226, 235));
		// Quand on selectionne un element de la liste, on met a jour les zones de saisie via la methode refreshValue()
		table.addSelectionListener(new org.eclipse.swt.events.SelectionAdapter() {
			public void widgetSelected(org.eclipse.swt.events.SelectionEvent e) {
				if(table.getSelectionCount() == 0) return;
				refreshValues();
			}
		});
		for (int i = 0; i < 2; i++)
	      new TableColumn(table, SWT.NONE);
	    table.getColumn(0).setText("Serveur");
	    table.getColumn(1).setText("Utilisateur");
	    // On remplit toute la largeur
	    for (int i = 0; i < 2; i++)
	    	table.getColumn(i).setWidth(table.getSize().x/2);
	    // Raccourcis clavier
	    table.addKeyListener(new org.eclipse.swt.events.KeyAdapter() {
			public void keyPressed(org.eclipse.swt.events.KeyEvent e) {
				if(table.getSelectionCount() == 0) return;
				
				if(e.character == SWT.CR)		 validate(true); // "Entree" valide et connecte (true)
				else if(e.character == SWT.DEL)  delete();		 // "Suppr" supprime le compte selectionne via la fonction delete()
			}
		});	
		button1 = new Button(group, SWT.NONE);
		button1.setText("Supprimer");
		button1.setBounds(new Rectangle(4, 252, 225, 31));
		// Le bouton "Supprimer" supprime le compte selectionne via la fonction delete()
		button1.addSelectionListener(new org.eclipse.swt.events.SelectionAdapter() {
			public void widgetSelected(org.eclipse.swt.events.SelectionEvent e) {
				delete();
			}
		});
	}
	
	private void createGroup1() {
		group1 = new Group(sShell, SWT.NONE);
		group1.setText("Nouvelle connexion");
		group1.setBounds(new Rectangle(238, 0, 177, 287));
		group1.setLayout(null);
		TBaddress = new LabelText(group1, "Adresse du serveur");
		TBaddress.setBounds(new Rectangle(3, 50, 171, 24));
		TBaddress.addModifyListener(verifIfItsOk);
		TBaddress.addKeyListener(keyValidate);	
		TBport = new LabelText(group1, "Port du serveur (21 par défaut)");
		TBport.setBounds(new Rectangle(3, 75, 171, 24));
		TBport.addKeyListener(keyValidate);
		TBuser = new LabelText(group1, "Nom d'utilisateur");
		TBuser.setBounds(new Rectangle(3, 115, 171, 24));
		TBuser.addModifyListener(verifIfItsOk);
		TBuser.addKeyListener(keyValidate);	
		TBpassword = new LabelText(group1, "Mot de passe", true);
		TBpassword.setBounds(new Rectangle(3, 140, 171, 24));
		TBpassword.addModifyListener(verifIfItsOk);
		TBpassword.addKeyListener(keyValidate);
		checkBox = new Button(group1, SWT.CHECK);
		checkBox.setText("Enregistrer les données");
		checkBox.setBounds(new Rectangle(4, 180, 171, 20));
		checkBox.setSelection(true);
		checkBox.setEnabled(false);
		checkBox2 = new Button(group1, SWT.CHECK);
		checkBox2.setBounds(new Rectangle(4, 200, 150, 20));
		checkBox2.setText("Ne pas quitter en validant");
		checkBox1 = new Button(group1, SWT.CHECK);
		checkBox1.setText("Se connecter en quittant");
		checkBox1.setBounds(new Rectangle(4, 220, 171, 20));
		checkBox1.setSelection(true);
		checkBox1.setEnabled(false);
		button = new Button(group1, SWT.NONE);
		button.setText("Enregistrer");
		button.setBounds(new Rectangle(4, 252, 171, 31));
		button.addSelectionListener(new org.eclipse.swt.events.SelectionAdapter() {
			public void widgetSelected(org.eclipse.swt.events.SelectionEvent e) {
				validate(false);
			}
		});
	}
	
	// Ecouteur des zones de saisie, si elles sont correctement remplies, alors on peut activer les cases a cocher
	org.eclipse.swt.events.ModifyListener verifIfItsOk = new org.eclipse.swt.events.ModifyListener() {
		public void modifyText(org.eclipse.swt.events.ModifyEvent e) {
			checkBox.setEnabled( TBuser.getText().length()>0 && TBpassword.getText().length()>0 && TBaddress.getText().length()>0 );
			checkBox1.setEnabled( checkBox.isEnabled() );
		}
	};

	// Ecouteur des zones de saisie pour les raccourcis clavier
	org.eclipse.swt.events.KeyAdapter keyValidate = new org.eclipse.swt.events.KeyAdapter() {
		public void keyPressed(org.eclipse.swt.events.KeyEvent e) {
			if(e.character == SWT.CR)		 validate(true); // "Entree" valide et connecte (true)
		}
	};
	
	/* Refresh table with FTPInfos */
	// Rafraichir la liste des comptes enregistres
	void refreshList(){
		// On efface tout pour commencer
		table.removeAll();
		TableItem ti;
		ti = new TableItem(table, SWT.NONE);
		// On ajoute un element "vide" pour creer un nouveau compte
		ti.setText(new String[]{"<Nouveau>"});
		// On colorise (voir juste en bas la meme ligne)
		ti.setBackground( ((table.getItemCount()%2 == 1) ? new Color(Display.getCurrent(), 245, 245, 255) : new Color(Display.getCurrent(), 255, 255, 255) ) );
		// On ajoute tous les comptes enregistres a la liste
		for(FTPInfo fi : ftps){
			ti = new TableItem(table, SWT.NONE);
			ti.setText(new String[]{fi.address+":"+fi.port, fi.user});
			// On colorise 1 element sur 2 pour faire jolie 
			ti.setBackground( ((table.getItemCount()%2 == 1) ? new Color(Display.getCurrent(), 245, 245, 255) : new Color(Display.getCurrent(), 255, 255, 255) ) );
		}
	}
	
	/* Validate (save FTPInfo file) */
	// Validation, on enregistre les modifications/nouveaux comptes et on demande la connexion si voulue
	public void validate(boolean forcequit){
		if(		TBaddress.getText().length()==0 ||
				TBuser.getText().length()==0    ||
				TBpassword.getText().length()==0 ) return;
		
		// Port 21 par defaut
		int port = 21;
		try{
			port = Integer.parseInt(TBport.getText());
		}catch(Exception ex){}
		
		FTPInfo fi = new FTPInfo(TBaddress.getText(), port, TBuser.getText(), TBpassword.getText());

		// Si on veut enregistrer le nouveau compte, on demande l'ajout (modification si deja existant) via la classe ConnectionManager
		if(checkBox.getSelection() && table.getSelectionIndex()<1)
			ConnectionManager.addFTPInfo(ftps, fi);
		// Sinon on enregistre juste les motifications (aucun effet si le compte n'existe pas)
		else if(checkBox.getSelection() && table.getSelectionIndex()>=1)
			ConnectionManager.changeFTPInfo(ftps, table.getSelectionIndex()-1, fi);
		
		// On enregistre les comptes
		ConnectionManager.writeFTPInfos(ftps);
		
		// Si on ferme en validant, on ferme la fenetre, en precisant si il faut etablir une connexion juste apres via DialogResult
		if(forcequit || !checkBox2.getSelection()){
			if(checkBox1.getSelection())
				DialogResult = fi;
			sShell.close();
			sShell.dispose();
		}else refreshList(); // Sinon on rafraichi juste la liste des comptes
	}
	
	/* Remove selected FTPInfo */
	// Effacer le compte selectionne
	void delete(){
		if(table.getSelectionCount() == 0) return;
		
		int idx = table.getSelectionIndex();
		if(idx == 0) return;
		// On le supprime de la table...
		table.remove(idx);
		// ...et de la liste des comptes enregistres
		ftps.remove(idx-1);
		// Puis on selectionne le premier compte enregistre, ou le compte "vide"
		table.select(Math.min(table.getItemCount(), 1));
		// Et on rafraichi les valeurs des zones de saisie
		refreshValues();
	}
	
	/* Associate textbox with FTPInfo */
	// Rafraichir les zones de texte avec le compte selectionne
	void refreshValues(){
		int idx = table.getSelectionIndex();
		// Si rien de selectionne ou si la selection est sur le compte "vide", on vide toutes les zones de saisie
		if(idx<=0){
			TBaddress.setText("");
			TBport.setText("");
			TBuser.setText("");
			TBpassword.setText("");
		}else{
		// Sinon on les remplies avec le compte FTP en question
			FTPInfo fi = ftps.get(idx-1);
			TBaddress.setText(fi.address);
			TBport.setText(fi.port+"");
			TBuser.setText(fi.user);
			TBpassword.setText(fi.password);
		}
	}
	
	/* Bring to Front */
	// Rappel la fenetre au premier plan
	public void Activate(){
		if(sShell != null && !sShell.isDisposed()) sShell.setActive();
	}

}
