/**
 * @author student
/*******************************************************************************
 * Copyright (c) 2003 Clearfield Knowledge Solutions.
 * All rights reserved. This program and the accompanying materials 
 * are made available under the terms of the Common Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.k.co.nz/
 *******************************************************************************/
/** 
 * Copyright: Copyright (c) 2003
 * Company  : Clearfield Knowledge Solutions
 * @author  : Student - Paulmi Patel and Sameer Mitra
 * @version : 1.0
 * Date Created : Jul 8, 2003
 * Title : JavaBean.Customer_Interface.java
 * Desprition : This JavaBean class is responsible for processing requests initiated 
 * from the related jsp pages and validating the inputs by using classes from the
 * Validators package.
 * 
 */

/**Imported classes and packages */

package JavaBeans;
import Validators.*;
import XmlCommunication.*;
import nz.co.k.tms.ldap.*;
import DatabaseCommunication.*;

/**
 * @author student
 *
 * This class is being used as an engine that processes all incoming requests
 * from the java server pages.
 * 
 */
public class Customer_Interface {

	/**Class variables*/

	String message = "";
	boolean successful = true;
	
	private ServletConnection servletconn = new ServletConnection();
	private XmlGenerator xmlgenerator = new XmlGenerator();
	private XmlUnmarshal xmlunmarshal = new XmlUnmarshal();
	
	private CustomerManager customermanager = new CustomerManager();
	private CoffeeManager coffeemanager = new CoffeeManager();

	private Customer_Data customer;
	private Address_Data address;
	private CreditCard_Data card;
	private CoffeePreference_Data preference;
	private Coffee_Data[] totalcoffees = coffeemanager.readAllCoffees();
	private Coffee_Data coffee = totalcoffees[0];

	/**
	 * This method is being used for directing all incoming requests to 
	 * appropriate methods.
	 * @param action The action to be taken - identifies which method can be
	 * used to process the request.
	 * @param customer Customer details sent from the jsp.
	 * @param creditCard Credit card details sent from the jsp.
	 * @param address Address details sent from the jsp.
	 * @param coffee Coffee details sent from the jsp. 
	 * @return void
	 */
	public void processRequest(
		String action,
		Customer_Data customer,
		CreditCard_Data creditCard,
		Address_Data address,
		CoffeePreference_Data coffee) {
		message = "";
		setMessage("");
		this.customer = customer;
		this.address = address;
		this.card = creditCard;
		this.preference = coffee;

		if (action == null) {
			setMessage("");
		} else if (action.equals("Register Now")) {
			debugDataClasses();
			addCustomer();
		} else if (action.equals("Login")) {
			doLogin();
		} else if (action.equals("Order")) {
			debugDataClasses();
			orderCoffee();
			debugDataClasses();
		} else if (action.equals("Update Profile")) {
			debugDataClasses();
			updateCustomer();
			debugDataClasses();
		} else if (action.equals("Update Account")) {
			debugDataClasses();
			updateAccount();
		}

	}

	/**
	 * This method is being used for validating and adding new customer to
	 * TMS as well as the application database.
	 * @return void
	 */
	public void addCustomer() {
		
		/* * Performs customer details Validation*/
		CustomerValidator customerValidator = new CustomerValidator();
		boolean customervalid = customerValidator.validate(customer);

		/* * Performs password Validation*/
		NewLoginValidator newLoginValidator = new NewLoginValidator();
		boolean loginvalid = newLoginValidator.validate(customer);

		/* * Performs credit card Validation*/
		CreditCardValidator creditcardValidator = new CreditCardValidator();
		boolean cardvalid = creditcardValidator.validate(card);

		/* * Performs address Validation*/
		AddressValidator addressValidator = new AddressValidator();
		boolean addressvalid = addressValidator.validate(address);

		/* * Performs coffee Validation*/
		CoffeePreferenceValidator coffeePreferenceValidator =
			new CoffeePreferenceValidator();
		boolean coffeevalid = coffeePreferenceValidator.validate(preference);

		setSuccessful(true);

		/* * Notifies user if validation fails*/
		if (!loginvalid) {
			setSuccessful(false);
			System.out.println(
				"+++new Login Validators message:+++"
					+ newLoginValidator.getMessage());
			setMessage(newLoginValidator.getMessage());
		}
		if (!customervalid) {
			setSuccessful(false);
			System.out.println(
				"+++Customer Validators message:+++"
					+ customerValidator.getMessage());
			setMessage(customerValidator.getMessage());
		}
		if (!cardvalid) {
			setSuccessful(false);
			System.out.println(
				"+++Credit Card Validators message:+++"
					+ creditcardValidator.getMessage());
			setMessage(creditcardValidator.getMessage());
		}
		if (!addressvalid) {
			setSuccessful(false);
			System.out.println(
				"+++Address Validators message:+++"
					+ addressValidator.getMessage());
			setMessage(addressValidator.getMessage());
		}
		if (!coffeevalid) {
			setSuccessful(false);
			System.out.println(
				"+++Coffee Validators message:+++"
					+ coffeePreferenceValidator.getMessage());
			setMessage(coffeePreferenceValidator.getMessage());
		}

		/* * Send Confirmation if validation Successful*/
		if (successful) {

			//form xml message..
			String xmlstr = xmlgenerator.adminAddXml(customer, address);
			System.out.println("ADMIN ADD XML: "+xmlstr);

			//send and get xml message to/from TMS..
			String out = servletconn.sendXml(xmlstr);
			System.out.println("ADMIN ADD XML RESPONSE: "+out);

			//interpret xml message from TMS..
			setMessage(xmlunmarshal.readResponse(out));
			
			int code = Integer.parseInt(XmlUnmarshal.getCode());
			if (code != 0)
				return;

			int id = XmlUnmarshal.getNcbId();

			if (id != 0) {
				customer.setNcbId(id);
				//form xml message..
				String xmlauthstr =
					xmlgenerator.transactionAuthXml(customer, card);
				System.out.println("TRANSACTION AUTH XML: " + xmlauthstr);
				
				//send and get xml message to/from TMS..
				String outauth = servletconn.sendXml(xmlauthstr);
				System.out.println(
					"TRANSACTION AUTH XML RESPONSE : " + outauth);
				//interpret xml message from TMS..
				setMessage(xmlunmarshal.readResponse(outauth));

				customer.setAccount(
					Double
						.valueOf(customer.getPreBillingAmount())
						.doubleValue());
				customer.setPreference(preference);

				Coffee_Data temp =
					getCoffeeByDescription(preference.getDescription());
				preference.setItemCode(temp.getItemCode());

				//insert the customer into the local database.
				customermanager.insertCustomer(customer);

				setMessage("Your details have been added to TMS.");
				setMessage("Your UserName is " + customer.getUserName());
				setMessage("Please retain the userName to login.");

			}
		}
	}

	/**
	 * This method is being used for authentication of a customer using
	 * the LDAP server and retrieving all the customer information if the
	 * authentication is successful.
	 * @return void
	 */
	public void doLogin() {
		LoginValidator loginValidator = new LoginValidator();
		boolean loginvalid = loginValidator.validate(customer);
		setSuccessful(true);

		if (!loginvalid) {
			setSuccessful(false);
			setMessage(loginValidator.getMessage());
		} else {
			try {
				//check if user exists in local db..
				boolean check = customermanager.readCustomer(customer);

				if (!check) {
					setSuccessful(false);
					setMessage("User does not exist in Coffee purchasing application Database.");
					return;
				}

				//authenticate with LDAP..
				UserDetail ud =
					LdapHelper.authentiacteUser(
						customer.getUserName(),
						customer.getPassword());

				//get the Ncb Id from TMS..
				String ncbId =
					xmlunmarshal.readNcbServiceResponse(ud.getXmlPacket());
				int id = Integer.parseInt(ncbId);

				//get all the attributes of user..
				customer.setNcbId(id);

				//send enquiryNcb..
				String xmlstr = xmlgenerator.enquiryNcbXml(customer, null);
				System.out.println("ENQUIRY NCB XML: " + xmlstr);
				
				String out = servletconn.sendXml(xmlstr);
				System.out.println("ADMIN ADD XML RESPONSE: "+out);
				//read the attributes..
				String f = xmlunmarshal.readResponse(out);

				XmlUnmarshal.getCustomer(customer);

				customer.setNcbId(id);

				//send enquiryNcbAddress..
				String xmlstr2 =
					xmlgenerator.enquiryNcbAddressXml(customer, null);
				System.out.println("ENQUIRY NCB ADDRESS XML: " + xmlstr2);
								
				String out2 = servletconn.sendXml(xmlstr2);
				System.out.println("ENQUIRY NCB ADDRESS XML RESPONSE: " + out2);
				
				//read the attributes..
				String f2 = xmlunmarshal.readResponse(out2);

				XmlUnmarshal.getAddress(address);

				//read the customer account details from the local db.
				customermanager.readCustomer(customer);

				this.preference = customer.getPreference();
				this.coffee = getCoffeeByItemCode(preference.getItemCode());
				preference.setDescription(coffee.getDescription());
				customer.setPreference(preference);

			} catch (Exception e) {
				System.out.println("Unsuccessful login:");
				System.out.println("String : " + e.toString());
			}
		}
	}

	/**
	 * This method is being used for ordering a coffee. This involves validation
	 * of the requested coffee, sending messages to TMS in order to carry
	 * out the transaction.
	 * @return void
	 */
	public void orderCoffee() {
		//get correct preference and coffee from order.jsp..
		this.coffee = getCoffeeByDescription(preference.getDescription());
		preference.setItemCode(coffee.getItemCode());

		customer.setPreference(preference);

		CoffeePreferenceValidator coffeePreferenceValidator =
			new CoffeePreferenceValidator();

		boolean coffeevalid = coffeePreferenceValidator.validate(preference);

		setSuccessful(true);

		if (!coffeevalid) {
			setSuccessful(false);
			setMessage(coffeePreferenceValidator.getMessage());
		}
		double account = customer.getAccount();
		double purchase =
			coffee.getPrice() * Integer.parseInt(preference.getQuantity());
		purchase = round(purchase, 2);
		if (account < purchase) {
			setSuccessful(false);
			setMessage("You do not have sufficient funds to make the transaction.");
		}
		if (successful) {
			/** Send transactionAuth message*/
			/**Get the Authorised cardInfo*/
			String xmlstr =
				xmlgenerator.transactionPurchaseXml(
					customer,
					address,
					preference,
					coffee);
			System.out.println("TRANSACTION PURCHASE XML: " + xmlstr);
			
			String outxml = servletconn.sendXml(xmlstr);
			System.out.println("PURCHASE XML RESPONSE: " + outxml);

			String xmlstr2 =
				xmlgenerator.transactionSettlementXml(
					customer,
					card,
					preference,
					coffee);
			System.out.println("ORDERING SETTLEMENT XML: " + xmlstr2);
			
			String outxml2 = servletconn.sendXml(xmlstr2);
			System.out.println("SETTLEMENT XML RESPONSE: " + outxml2);

			//update account details..
			double ac = customer.getAccount();
			double cost =
				Integer.parseInt(preference.getQuantity()) * coffee.getPrice();
			double newac = round(ac - cost, 2);

			java.text.DecimalFormat df = new java.text.DecimalFormat("0.00");

			customer.setAccount(newac);

			//update the customer account in the local db.
			customermanager.updateCustomer(customer);

			//update the coffee preference in local db.
			customermanager.updateCoffeePreference(customer);

			setMessage("The total cost is : $" + df.format(round(cost, 2)));
			setMessage("The order has been received.");
			setMessage(
				"The coffee will be delivered to you at: "
					+ preference.getDeliveryHour()
					+ "."
					+ preference.getDeliveryMinute());
			//customer.getAccount()+"0");

			if (customer.getAccount() <= 10.0) {
				setMessage("REMINDER :Your account balance is low.");
				setMessage("You can top up your account by clicking on the update account button.");
			}
		}

	}

	/**
	 * This method is being used for update a customer's details. This involves
	 * validation of the new details, updating the details by sending updateXml
	 * to TMS, and update the application database.
	 * @return void
	 */
	public void updateCustomer() {
		//		get correct preference and coffee from order.jsp..
		this.coffee = getCoffeeByDescription(preference.getDescription());
		preference.setItemCode(coffee.getItemCode());
		System.out.println("DESCRIPTION : " + preference.getDescription());
		customer.setPreference(preference);

		setSuccessful(true);
		setMessage("");
		/* * Performs password Validation*/
		NewLoginValidator newLoginValidator = new NewLoginValidator();
		boolean loginvalid = newLoginValidator.validate(customer);

		/* * Performs customer details Validation*/
		CustomerValidator customerValidator = new CustomerValidator();
		boolean customervalid = customerValidator.validate(customer);

		/* * Performs address Validation*/
		AddressValidator addressValidator = new AddressValidator();
		boolean addressvalid = addressValidator.validate(address);

		/* * Performs coffee Validation*/
		CoffeePreferenceValidator coffeePreferenceValidator =
			new CoffeePreferenceValidator();
		boolean coffeevalid = coffeePreferenceValidator.validate(preference);

		/* * Notifies user if validation fails*/
		if (!loginvalid) {
			setSuccessful(false);
			System.out.println(
				"+++new Login Validators message:+++"
					+ newLoginValidator.getMessage());
			setMessage(newLoginValidator.getMessage());
		}
		if (!customervalid) {
			setSuccessful(false);
			System.out.println(
				"+++Customer Validators message:+++"
					+ customerValidator.getMessage());
			setMessage(customerValidator.getMessage());
		}
		if (!addressvalid) {
			setSuccessful(false);
			System.out.println(
				"+++Address Validators message:+++"
					+ addressValidator.getMessage());
			setMessage(addressValidator.getMessage());
		}
		if (!coffeevalid) {
			setSuccessful(false);
			System.out.println(
				"+++Coffee Validators message:+++"
					+ coffeePreferenceValidator.getMessage());
			setMessage(coffeePreferenceValidator.getMessage());
		}
		/* * Send Confirmation if validation Successful*/
		if (successful) {
			System.out.println(
				"+++===+++" + customer.getPassword() + "+++===+++");
			String xmlstr = xmlgenerator.adminUpdateXml(customer, address);
			System.out.println("ADMIN UPDATE XML: " + xmlstr);

			//send and get xml message to/from TMS..
			String out = servletconn.sendXml(xmlstr);
			System.out.println("ADMIN UPDATE XML RESPONSE: "+out);
			
			//interpret xml message from TMS..
			xmlunmarshal.readResponse(out);

			setMessage("Your details have been updated.\n");
			setMessage("Your UserName is " + customer.getUserName() + "\n");

			customer.setPreference(preference);

			//update the customer account in the local db.
			customermanager.updateCustomer(customer);

			//update the coffee preference of the customer in the local db.
			customermanager.updateCoffeePreference(customer);

		}
	}

	/**
	 * This method is being used for updating only the user account, unlike
	 * updateCustomer method, this method does not update other details of the
	 * customer.
	 * @return void
	 */
	public void updateAccount() {
		//		get correct preference and coffee from order.jsp..
		this.coffee = getCoffeeByDescription(preference.getDescription());
		preference.setItemCode(coffee.getItemCode());
		System.out.println("DESCRIPTION : " + preference.getDescription());
		customer.setPreference(preference);

		setSuccessful(true);
		try {
			CustomerValidator cv = new CustomerValidator();
			boolean custValid = cv.validate(customer);

			if (!custValid) {
				setSuccessful(false);
				clearMessage();
				setMessage(cv.getMessage());
			}

			if (successful) {
				double newacc =
					customer.getAccount()
						+ Double.parseDouble(customer.getPreBillingAmount());
				newacc = round(newacc, 2);

				java.text.DecimalFormat df =
					new java.text.DecimalFormat("0.00");
				double e = Double.parseDouble(df.format(newacc));

				customer.setAccount(e);

				//update the customer account in the local db.
				customermanager.updateCustomer(customer);

				setMessage("Your account has been updated.");
				setMessage("The new account value is : $" + df.format(newacc));
			}
		} catch (Exception e) {
			System.out.println("update account exception :" + e.toString());

		}
	}

	/**
	 * This method is being used for debugging purposes. A note of caution - 
	 * be careful when you call this method as this method can throw a 
	 * nullpointer exception if either customer, address, 
	 * @return void
	 */
	private void debugDataClasses() {
		try {

			System.out.println("++++++++++++++CUSTOMER+++++++++++++");
			System.out.println("Customer FName: " + customer.getFirstName());
			System.out.println("Customer LName: " + customer.getLastName());
			System.out.println("Customer UserName: " + customer.getUserName());
			System.out.println("Customer Password: " + customer.getPassword());
			System.out.println("Customer Account: " + customer.getAccount());
			System.out.println(
				"Customer PreBill: " + customer.getPreBillingAmount());
			System.out.println("+++++++++++++END CUSTOMER+++++++++++");
			System.out.println();
			System.out.println("++++++++++++++ADDRESS+++++++++++++");
			System.out.println("Address Floor: " + address.getFloor());
			System.out.println("Address Office: " + address.getOffice());
			System.out.println("Address Building: " + address.getBuilding());
			System.out.println("Address Street: " + address.getStreet());
			System.out.println("Address Email: " + address.getEmail());
			System.out.println("Address Phone: " + address.getPhoneNumber());
			System.out.println("+++++++++++++END ADDRESS+++++++++++");
			System.out.println();
			System.out.println("++++++++++++++COFFEE PREF+++++++++++++");
			System.out.println(
				"Preference Itemcode: " + preference.getItemCode());
			System.out.println(
				"Preference Description: " + preference.getDescription());
			System.out.println(
				"Preference Quantity: " + preference.getQuantity());
			System.out.println(
				"Preference deliveryHour: " + preference.getDeliveryHour());
			System.out.println(
				"Preference deliveryMinute: " + preference.getDeliveryMinute());
			System.out.println("+++++++++++++END COFFEE PREF+++++++++++");
			System.out.println();
			System.out.println("++++++++++++++COFFEE+++++++++++++++");
			System.out.println("Coffee Itemcode: " + coffee.getItemCode());
			System.out.println(
				"Coffee Description: " + coffee.getDescription());
			System.out.println("Coffee Type: " + coffee.getType());
			System.out.println("Coffee Size: " + coffee.getSize());
			System.out.println("Coffee Price: " + coffee.getPrice());
			System.out.println("+++++++++++++END COFFEE+++++++++++");
			System.out.println();
		} catch (Exception e) {
			System.err.println(e.toString());
		}
	}

	/**
	 * This utility method is being used for rounding a double to
	 * the given number of decimal places.
	 * @param x The original double that is to be rounded.
	 * @param dec The number of decimal places the double has to be rounded to.
	 * @return double The resulting rounded double.
	 */
	public double round(double x, int dec) {
		double multiple = Math.pow(10, dec);
		return Math.round(x * multiple) / multiple;
	}

	/**
	 * This utility method is being used for getting the Coffee_Data given
	 * an itemcode.
	 * @param itemCode Coffee item code.
	 * @return Coffee_Data Coffee details.
	 */
	private Coffee_Data getCoffeeByItemCode(String itemCode) {
		Coffee_Data result = null;
		int count = 0;
		for (int g = 0; g < totalcoffees.length; g++) {
			Coffee_Data temp = (Coffee_Data) totalcoffees[g];
			if (itemCode.equals(temp.getItemCode())) {
				result = temp;
				count++;
				break;
			}
		}
		return result;
	}

	
	/**
	 * This utility method is being used for getting the Coffee_Data given
	 * a coffee description.
	 * @param desc Coffee description.
	 * @return Coffee_Data Coffee details.
	 */
	private Coffee_Data getCoffeeByDescription(String desc) {
		Coffee_Data result = null;
		int count = 0;
		for (int g = 0; g < totalcoffees.length; g++) {
			Coffee_Data temp = (Coffee_Data) totalcoffees[g];
			if (desc.equals(temp.getDescription())) {
				result = temp;
				count++;
				break;
			}
		}
		return result;
	}
	
	
	/**
	 * This method is being used for setting messages that are displayed
	 * on the java server pages
	 * @param s The message to be displayed.
	 * @return void
	 */
	public void setMessage(String s) {
		this.message += s + "<br>";
	}
	
	
	/**
	 * This method is being used for clearing up all the concatenated messages.
	 * @return void
	 */
	public void clearMessage() {
		this.message = "";
	}
	
	
	/**
	 * This method is being used for getting the message to be displayed on 
	 * the java server pages.
	 * @return String The message to be displayed.
	 */
	public String getMessage() {
		return message;
	}

	
	/**
	 * This method is being used for setting the success boolean - defining
	 * whether the validation was successful.
	 * @param b Defines whether validation was successful.
	 * @return void
	 */
	public void setSuccessful(boolean b) {
		this.successful = b;
	}
	
	/**
	 * This method is being used for getting and checking the success - if
	 * the validation was successful or not.
	 * @return boolean Defines whether the validation was successful.
	 */
	public boolean getSuccessful() {
		return successful;
	}

	/**
	 * This method is being used for getting the customer.
	 * @return Customer_Data Customer details.
	 */
	public Customer_Data getCustomer() {
		return this.customer;
	}
	
	
	/**
	 * This method is being used for getting the address data.
	 * @return Address_Data Address details.
	 */
	public Address_Data getAddress() {
		return this.address;
	}
	
	
	/**
	 * This method is being used for getting the coffee data.
	 * @return Coffee_Data Coffee details.
	 */
	public Coffee_Data getCoffee() {
		return this.coffee;
	}
	
	
	/**
	 * This method is being used for getting the coffee preference data.
	 * @return CoffeePreference_Data Coffee preference details.
	 */
	public CoffeePreference_Data getPreference() {
		return this.preference;
	}
	
	
	/**
	 * Method: getCreditCard
	 * This method is being used for getting the credit card data.
	 * @return CreditCard_Data Credit card details.
	 */
	public CreditCard_Data getCreditCard() {
		return card;
	}

}
