/**
 * 
 */
package gui;

import java.awt.Color;
import java.net.URL;
import org.apache.pivot.beans.BXML;
import org.apache.pivot.beans.BXMLSerializer;
import org.apache.pivot.beans.Bindable;
import org.apache.pivot.collections.ArrayList;
import org.apache.pivot.collections.HashMap;
import org.apache.pivot.collections.List;
import org.apache.pivot.collections.Map;
import org.apache.pivot.util.Resources;
import org.apache.pivot.wtk.Application;
import org.apache.pivot.wtk.BoxPane;
import org.apache.pivot.wtk.Button;
import org.apache.pivot.wtk.ButtonPressListener;
import org.apache.pivot.wtk.Component;
import org.apache.pivot.wtk.ComponentMouseButtonListener;
import org.apache.pivot.wtk.Display;
import org.apache.pivot.wtk.Form;
import org.apache.pivot.wtk.Frame;
import org.apache.pivot.wtk.Label;
import org.apache.pivot.wtk.MessageType;
import org.apache.pivot.wtk.Mouse;
import org.apache.pivot.wtk.Orientation;
import org.apache.pivot.wtk.Prompt;
import org.apache.pivot.wtk.PushButton;
import org.apache.pivot.wtk.TableView;
import org.apache.pivot.wtk.TextInput;
import org.apache.pivot.wtk.Window;
import system.Acquisto;
import system.Cliente;
import system.Negozio;
import system.Prodotto;
import utility.ReadData;
import utility.WriteData;

/*La quantità di codice è enorme per una sola classe. Questo è dovuto al fatto che la definizione dei frames e la conseguente definizione dei listeners
  dei bottoni è molto onerosa in termini di codice. Inoltre,  vista la gestione dei dati, la definizione di tali frames, o listeners, in classi separate 
  sarebbe stata molto complicata e avrebbe richiesto il passaggio di molti dati.  
 */
 

/**
 * Classe responsabile della definizione dell'interfaccia grafica, delle sue funzionalità, e del suo interfacciamento con il Negozio.
 * 
 * @author Andrea Zinelli, 241192
 *
 */


public class GUI extends Window implements Application, Bindable{	

	
	private Negozio negozio;	
	private Window window = null;	
	private Cliente loggedClient = null;
	private List<Prodotto> carrello = new ArrayList<Prodotto>();
	private Prodotto selectedItem = null;
	private Prodotto selectedItemCarrello = null;
	private Prodotto tip;
	
	@BXML
	private TableView dataTable;
	@BXML
	private TableView purchaseTable;
	@BXML
	private PushButton loginButton;
	@BXML
	private PushButton registrationButton;
	@BXML
	private PushButton addButton;
	@BXML
	private PushButton removeButton;
	@BXML
	private PushButton purchaseButton;
	//@BXML
	//private PushButton listButton;
	@BXML
	private PushButton adminAddButton;
	@BXML
	private PushButton adminRemoveButton;
	@BXML
	private Label myLabel;
	@BXML	
	private Label tipLabel;
	@BXML
	private PushButton	tipButton;
	
	/**
	 * Metodo responsabile del binding dei vari component provenienti dal file BXML che definisce l'interfaccia, e passati, attraverso un ID, ai corrispondenti valori 
	 * identificati dal tag @BXML.
	 */
	@Override
    public void initialize(Map<String, Object> namespace, URL location, Resources resources) {
        loginButton.getButtonPressListeners().add(loginListener);
        registrationButton.getButtonPressListeners().add(registerListener);
        addButton.getButtonPressListeners().add(addListener);
        removeButton.getButtonPressListeners().add(removeListener);
        purchaseButton.getButtonPressListeners().add(purchaseListener);
        dataTable.getComponentMouseButtonListeners().add(itemSelection);
        purchaseTable.getComponentMouseButtonListeners().add(itemSelectionCarrello);        
        adminAddButton.getButtonPressListeners().add(adminAddListener);
        adminRemoveButton.getButtonPressListeners().add(adminRemoveListener);
        tipButton.getButtonPressListeners().add(tipListener);
        
        
        List<Map<String, String>> data = new ArrayList<Map<String, String>>();	
		Map<String, String> map;			
		for(int i = 0; i < negozio.getProductNumber(); i++){
			map = new HashMap<String, String>();
			map.put("category", negozio.products.get(i).category);
			map.put("brand", negozio.products.get(i).brand);
			map.put("model", negozio.products.get(i).model);
			map.put("price", Float.toString(negozio.products.get(i).price)+"$");
			data.add(map);
		}dataTable.setTableData(data);
    }

	/**
	 * Class constructor. Inizializza il negozio.
	 */
	public GUI(){
		
		negozio = ReadData.read("clients.txt", "products.txt");		
	}
	
	
/**
 * Listener per l'individuazione del prodotto del catalogo selezionato dal cliente.
 */
	
	private ComponentMouseButtonListener itemSelection = new ComponentMouseButtonListener(){
		@Override
		public boolean mouseClick(Component component, Mouse.Button button, int x, int y, int count){   
			
			
			int row = dataTable.getRowAt(y);
			selectedItem = negozio.products.get(row);			
			
			return false;
		}

		@Override
		public boolean mouseDown(Component arg0,
				org.apache.pivot.wtk.Mouse.Button arg1, int arg2, int arg3) {
			// TODO Auto-generated method stub
			return false;
		}

		@Override
		public boolean mouseUp(Component arg0,
				org.apache.pivot.wtk.Mouse.Button arg1, int arg2, int arg3) {
			// TODO Auto-generated method stub
			return false;
		}
		
	};
	
	/**
	 * Listener per l'individuazione del prodotto del carrello selezionato dal cliente.
	 */
	
	private ComponentMouseButtonListener itemSelectionCarrello = new ComponentMouseButtonListener(){
		@Override
		public boolean mouseClick(Component component, Mouse.Button button, int x, int y, int count){   //CHANGE TO MOUSE DOWN (?)
			
			
			int row = purchaseTable.getRowAt(y);
			selectedItemCarrello = carrello.get(row);			
			
			return false;
		}

		@Override
		public boolean mouseDown(Component arg0,
				org.apache.pivot.wtk.Mouse.Button arg1, int arg2, int arg3) {
			// TODO Auto-generated method stub
			return false;
		}

		@Override
		public boolean mouseUp(Component arg0,
				org.apache.pivot.wtk.Mouse.Button arg1, int arg2, int arg3) {
			// TODO Auto-generated method stub
			return false;
		}
		
	};
	
	/**
	 * Listener per la gestione del PushButton Login. Responsabile della creazione del frame contenente il form per l'inserimento dati.
	 */
	
	private ButtonPressListener loginListener = new ButtonPressListener(){
		@Override
		public void buttonPressed(final Button button){
			
			Frame frame = new Frame();
			Form form = new Form();
			PushButton submitButton = new PushButton("Submit");
			final Label errorLabel = new Label();
			
			Form.Section loginInformation = new Form.Section();
			loginInformation.setHeading("Login Information");
			
			final TextInput usernameTextInput = new TextInput();
			usernameTextInput.setPrompt("username");
			final TextInput passwordTextInput = new TextInput();
			passwordTextInput.setPrompt("password");
			passwordTextInput.setPassword(true);
			
			final BoxPane loginBP = new BoxPane();
			loginBP.setOrientation(Orientation.VERTICAL);
			loginBP.add(usernameTextInput);
			loginBP.add(passwordTextInput);
			
			loginInformation.add(loginBP);
			
			BoxPane buttonBP = new BoxPane();
			
			errorLabel.getStyles().put("color", Color.RED);
			
			buttonBP.setOrientation(Orientation.VERTICAL);
			buttonBP.add(submitButton);
			buttonBP.add(errorLabel);
			
			loginInformation.add(buttonBP);
			
			form.getSections().add(loginInformation);
			
			
			frame.setPreferredHeight(180);
			frame.setPreferredWidth(480);
			frame.setTitle("Login");
			
			frame.setContent(form);			
			frame.open(getDisplay());
			
			/**
			 * Listener per la lettura dei dati inseriti nel form, alla pressione del PushButton Submit, e della loro elaborazione
			 */
			
			submitButton.getButtonPressListeners().add(new ButtonPressListener(){
				 @Override
				 public void buttonPressed(Button button) {
					 
					 String username = usernameTextInput.getText();
					 String password = passwordTextInput.getText();					
											
					 Form.Flag flag = null;
					 
					 if(username.length()==0||password.length()==0){
						 flag = new Form.Flag(MessageType.ERROR, "Login Information is missing...");
					 }
					 if (flag == null) {
						 errorLabel.setText("");			             
					 	//management logic goes here...
						 loggedClient = negozio.LoginCheck(username, password);
						 if(loggedClient == null){
							 errorLabel.setText("Wrong Username or Password");
							 flag = new Form.Flag(MessageType.ERROR, "Wrong Username or Password");
						 }            
					 } else {
						 errorLabel.setText("Some required information is missing.");
					 }
					 Form.setFlag(loginBP, flag);				
					 if(flag == null){
						 myLabel.setText("Welcome, " + loggedClient.name);
						 tip = null;
						 tipLabel.setText("");
						 Acquisto tip2 =  loggedClient.SelectMostFrequent();
						 if(tip2!=null){ 
							 tip = new Prodotto(tip2.ID, tip2.category, tip2.brand, tip2.model, tip2.price);
							 tipLabel.setText(tip.category + "  " + tip.brand + "  " + tip.model);
						 }
						 Prompt.prompt("Login Successful!", GUI.this);
					 }
				 }				 
			});			
		}		
	};		
	
	/**
	 * Listener per la gestione del PushButton Register. Responsabile della creazione del frame contenente il form per l'inserimento dati.
	 */
	
	private ButtonPressListener registerListener = new ButtonPressListener(){
		
		@Override
		public void buttonPressed(final Button button){
			
			Frame frame = new Frame();
			Form form = new Form();
			final Label errorLabel = new Label();
			PushButton submitButton = new PushButton("Submit");
				
			Form.Section personalInformation = new Form.Section();
			Form.Section loginInformation = new Form.Section();
			personalInformation.setHeading("Personal Information");
			loginInformation.setHeading("Login Information");
			
			final TextInput lastNameTextInput = new TextInput();
			lastNameTextInput.setPrompt("Last Name");
			final TextInput firstNameTextInput = new TextInput();
			firstNameTextInput.setPrompt("First Name");
			final TextInput addressTextInput = new TextInput();
			addressTextInput.setPrompt("Full Address");
			final TextInput CFTextInput = new TextInput();
			CFTextInput.setPrompt("Fiscal Code");
			final TextInput usernameTextInput = new TextInput();
			usernameTextInput.setPrompt("username");
			final TextInput passwordTextInput = new TextInput();
			passwordTextInput.setPrompt("password");
			passwordTextInput.setPassword(true);
			
			
			
			final BoxPane personalBP = new BoxPane();
			personalBP.setOrientation(Orientation.VERTICAL);
			personalBP.add(lastNameTextInput);
			personalBP.add(firstNameTextInput);
			personalBP.add(addressTextInput);
			personalBP.add(CFTextInput);
			
			personalInformation.add(personalBP);
			
			final BoxPane loginBP = new BoxPane();
			loginBP.setOrientation(Orientation.VERTICAL);
			loginBP.add(usernameTextInput);
			loginBP.add(passwordTextInput);
			
			loginInformation.add(loginBP);
			
			BoxPane buttonBP = new BoxPane();
			buttonBP.setOrientation(Orientation.VERTICAL);
			
			errorLabel.getStyles().put("color", Color.RED);

			buttonBP.add(submitButton);
			buttonBP.add(errorLabel);
			
			loginInformation.add(buttonBP);
			
			form.getSections().add(personalInformation);
			form.getSections().add(loginInformation);
			
			
			frame.setPreferredHeight(360);
			frame.setPreferredWidth(480);
			frame.setTitle("Register");
			
			frame.setContent(form);			
			frame.open(getDisplay());
			
			/**
			 * Listener per la lettura dei dati inseriti nel form, alla pressione del PushButton Submit, e della loro elaborazione
			 */
			submitButton.getButtonPressListeners().add(new ButtonPressListener(){
				 @Override
		            public void buttonPressed(Button button) {
					 
					 String lastName = lastNameTextInput.getText();
					 String firstName = firstNameTextInput.getText();
					 String address = addressTextInput.getText();
					 String CF = CFTextInput.getText();
					 String username = usernameTextInput.getText();
					 String password = passwordTextInput.getText();
					 Cliente thisClient = new Cliente(negozio.getClientNumber()+1, firstName, lastName, address, CF, username, password);
												
					 Form.Flag flagP = null;
					 Form.Flag flagL = null;
					 if(lastName.length()==0 || firstName.length()==0 || address.length()==0 || CF.length()==0){
					    flagP = new Form.Flag(MessageType.ERROR, "Personal Information is missing...");					    
					 }if(username.length()==0||password.length()==0){
						flagL = new Form.Flag(MessageType.ERROR, "Login Information is missing...");
					 }
					 Form.setFlag(personalBP, flagP);
					 Form.setFlag(loginBP, flagL);
					 if (flagP == null && flagL == null) {
						 errorLabel.setText("");			            
			             if(!negozio.AddClient(thisClient)) errorLabel.setText("Username is already taken");
			             else{
			            	 WriteData.writeClients("clients.txt", negozio);	
			            	 Prompt.prompt("Registration Successful!", GUI.this);
			            	 loggedClient = thisClient;
			            	 myLabel.setText("Welcome, " + loggedClient.name);	
			            	 tip = null;
			            	 tipLabel.setText("");
			            	 Acquisto tip2 =  loggedClient.SelectMostFrequent();
							 if(tip2 != null){
								 tip = new Prodotto(tip2.ID, tip2.category, tip2.brand, tip2.model, tip2.price);
								 tipLabel.setText(tip.category + "  " + tip.brand + "  " + tip.model);
							 }							
			             }
			             //						
			         } else {
			             errorLabel.setText("Some required information is missing.");
			         }
				 }				 
			});			
		}		
	};	
	
	/**
	 * Listener per il PushButton Purchase. Alla sua pressione, il carrello viene svuotato e i prodotti al luo interno vengono inseriti
	 * nella lista acquisti dello specifico cliente.
	 */
	
	private ButtonPressListener purchaseListener = new ButtonPressListener(){
		@Override
		public void buttonPressed(Button button) {
			
			if(loggedClient == null) Prompt.prompt("You must be logged in to purchase items!", GUI.this);
			else if(carrello.getLength() == 0) Prompt.prompt("You didn't add any items!", GUI.this);
			else{
				for(int i = 0; i < carrello.getLength(); i++){
					Acquisto item = new Acquisto(carrello.get(i));
					loggedClient.AddItem(item);
				}							
				WriteData.writeClientItems(loggedClient);
				Prompt.prompt("Item(s) successfully purchased!", GUI.this);  //maybe add a control dialogue
				List<Map<String, String>> data = new ArrayList<Map<String, String>>();
				purchaseTable.setTableData(data);
				carrello.clear();
				
			}
		}
	};
	
	/**
	 * Listener per il PushButton Add. Alla sua pressione, l'oggetto selezionato dal catalogo viene spostato nel carrello. Se nessun
	 * oggetto viene selezionato, l'interfaccia avverte il cliente.
	 */
	
	private ButtonPressListener addListener = new ButtonPressListener(){
		@Override
		public void buttonPressed(Button button) {
			
			if(loggedClient == null) Prompt.prompt("You must be logged in to add items!", GUI.this);
			else if(selectedItem == null) Prompt.prompt("You didn't select an item!", GUI.this);
			else{
				carrello.add(selectedItem);
				
				 List<Map<String, String>> data = new ArrayList<Map<String, String>>();	
				 Map<String, String> map;			
				 for(int i = 0; i < carrello.getLength(); i++){
					map = new HashMap<String, String>();
					map.put("category", carrello.get(i).category);
					map.put("brand", carrello.get(i).brand);
					map.put("model", carrello.get(i).model);
					map.put("price", Float.toString(carrello.get(i).price)+"$");
					data.add(map);
				}purchaseTable.setTableData(data); 
			}
		}
	};
	
	/**
	 * Listener per il PushButton Remove. Alla sua pressione, l'oggetto selezionato dal carrello viene rimosso. Se nessun
	 * oggetto viene selezionato, l'interfaccia avverte il cliente.
	 */
	
	private ButtonPressListener removeListener = new ButtonPressListener(){
		@Override
		public void buttonPressed(Button button) {
			
			if(loggedClient == null) Prompt.prompt("You must be logged in to remove items!", GUI.this);
			else if(selectedItemCarrello == null) Prompt.prompt("You didn't select an item!", GUI.this);
			else{
				carrello.remove(selectedItemCarrello);
				selectedItemCarrello = null;
				
				 List<Map<String, String>> data = new ArrayList<Map<String, String>>();	
				 Map<String, String> map;			
				 for(int i = 0; i < carrello.getLength(); i++){
					map = new HashMap<String, String>();
					map.put("category", carrello.get(i).category);
					map.put("brand", carrello.get(i).brand);
					map.put("model", carrello.get(i).model);
					map.put("price", Float.toString(carrello.get(i).price)+"$");
					data.add(map);
				}purchaseTable.setTableData(data);
			}
		}
	};
		
	/**
	 * Listener per il PushButton Add an Item. Alla sua pressione, viene aperto un form per l'inserimento dei dati dell'oggetto da inserire a catalogo.
	 */
	private ButtonPressListener adminAddListener = new ButtonPressListener(){
		@Override
		public void buttonPressed(Button button) {
			
			if(loggedClient == null) Prompt.prompt("You must be the admin to add items!", GUI.this);			
			else{
				if(loggedClient.username.equals("Admin")){
					//registration frame composition
					Frame frame = new Frame();
					Form form = new Form();
					final Label errorLabel = new Label();
					PushButton submitButton = new PushButton("Submit");
					
					Form.Section productInformation = new Form.Section();
				
					productInformation.setHeading("Product Information");
				
				
					final TextInput categoryTextInput = new TextInput();
					categoryTextInput.setPrompt("Category");
					final TextInput brandTextInput = new TextInput();
					brandTextInput.setPrompt("Brand");
					final TextInput modelTextInput = new TextInput();
					modelTextInput.setPrompt("Model");
					final TextInput priceTextInput = new TextInput();
					priceTextInput.setPrompt("Price");			
				
					final BoxPane productBP = new BoxPane();
					productBP.setOrientation(Orientation.VERTICAL);
					productBP.add(categoryTextInput);
					productBP.add(brandTextInput);
					productBP.add(modelTextInput);
					productBP.add(priceTextInput);
				
					productInformation.add(productBP);
				
				
					BoxPane buttonBP = new BoxPane();
					buttonBP.setOrientation(Orientation.VERTICAL);
				
					errorLabel.getStyles().put("color", Color.RED);

					productBP.add(submitButton);
					productBP.add(errorLabel);			
				
					form.getSections().add(productInformation);		
				
				
					frame.setPreferredHeight(360);
					frame.setPreferredWidth(480);
					frame.setTitle("Add a Product");
				
					frame.setContent(form);			
					frame.open(getDisplay());
					
					/**
					 * Listener per la lettura dei dati inseriti nel form, alla pressione del PushButton Submit, e della loro elaborazione
					 */
					submitButton.getButtonPressListeners().add(new ButtonPressListener(){
						 @Override
				            public void buttonPressed(Button button) {
							 
							 String category = categoryTextInput.getText();
							 String brand = brandTextInput.getText();
							 String model = modelTextInput.getText();
							 String price = priceTextInput.getText();								 
							 Form.Flag flag = null;							 
							 if(category.length()==0 || brand.length()==0 || model.length()==0 || price.length()==0){
							    flag = new Form.Flag(MessageType.ERROR, "Product Information is missing...");		 
							 }
							 if(!price.matches("[-+]?\\d*\\.?\\d+") && flag == null) flag = new Form.Flag(MessageType.ERROR, "Price is not a number...");
							 Form.setFlag(productBP, flag);							 
							 if (flag == null) {
								 errorLabel.setText("");	        
					             
					             if(!negozio.AddProduct(new Prodotto(negozio.getHighestProductID() + 1, category, brand, model, Float.parseFloat(price)))) errorLabel.setText("Item is already the database");
					             else{
					            	 WriteData.writeProducts("products.txt", negozio);	
					            	 Prompt.prompt("Item inserted correctly!", GUI.this);	
					            	 List<Map<String, String>> data = new ArrayList<Map<String, String>>();	
					         		Map<String, String> map;			
					         		for(int i = 0; i < negozio.getProductNumber(); i++){
					         			map = new HashMap<String, String>();
					         			map.put("category", negozio.products.get(i).category);
					         			map.put("brand", negozio.products.get(i).brand);
					         			map.put("model", negozio.products.get(i).model);
					         			map.put("price", Float.toString(negozio.products.get(i).price)+"$");
					         			data.add(map);
					         		}dataTable.setTableData(data);
					             }
					             //						
					         } else {
					             errorLabel.setText("Some required information is missing.");
					         }
						 }				 
					});	
				}else{
					Prompt.prompt("You must be the admin to add items!", GUI.this);	
				}
			}
			
		}
	};
	
	/**
	 * Listener per il PushButton Remove an Item. Alla sua pressione, l'oggetto del catalogo selezionato viene rimosso.
	*/
	
	private ButtonPressListener adminRemoveListener = new ButtonPressListener(){
		@Override
		public void buttonPressed(Button button) {
			
			if(loggedClient == null || !loggedClient.username.equals("Admin")) Prompt.prompt("You must be the admin to remove items!", GUI.this);			
			else if(selectedItem == null) Prompt.prompt("You didn't select an item!", GUI.this);
			else{
				negozio.RemoveProduct(selectedItem);
				selectedItem = null;
				
				WriteData.writeProducts("products.txt", negozio);	
				Prompt.prompt("Item removed correctly!", GUI.this);	
				List<Map<String, String>> data = new ArrayList<Map<String, String>>();	
        		Map<String, String> map;			
        		for(int i = 0; i < negozio.getProductNumber(); i++){
        			map = new HashMap<String, String>();
        			map.put("category", negozio.products.get(i).category);
        			map.put("brand", negozio.products.get(i).brand);
        			map.put("model", negozio.products.get(i).model);
        			map.put("price", Float.toString(negozio.products.get(i).price)+"$");
        			data.add(map);
        		}dataTable.setTableData(data);
			}
				
			
		}
	};
	
	private ButtonPressListener tipListener = new ButtonPressListener(){
		@Override
		public void buttonPressed(Button button) {
			
			if(loggedClient == null) Prompt.prompt("You must be logged in!", GUI.this);
			else{
				if(tip != null){
					carrello.add(tip); 
					List<Map<String, String>> data = new ArrayList<Map<String, String>>();			//put this in a function UpdateTable.
					Map<String, String> map;			
					for(int i = 0; i < carrello.getLength(); i++){
						map = new HashMap<String, String>();
						map.put("category", carrello.get(i).category);
						map.put("brand", carrello.get(i).brand);
						map.put("model", carrello.get(i).model);
						map.put("price", Float.toString(carrello.get(i).price)+"$");
						data.add(map);
					}purchaseTable.setTableData(data); 
				}				
			}			
		}
	};

	@Override	
	public void startup(Display display, Map<String, String> properties) throws Exception {						
				BXMLSerializer bxmlSerializer = new BXMLSerializer();				
				window = (Window)bxmlSerializer.readObject(GUI.class, "GUI.bxml");				
				window.open(display);					
    }
	
	@Override
	public boolean shutdown(boolean optional) {
        if (window != null) {        	
        	
            window.close();
        }
 
        return false;
    }		
	
    @Override
    public void suspend() {
    }
 
    @Override
    public void resume() {
    }    
    
}
    



