import java.util.*;

/**
 * The CustomerDatabase class is used to represent a collection of Customer objects.
 * 
 * @author Lindsey Gregor, CS 367
 */
public class CustomerDatabase {
	List<Customer> customerDB; //customer database
	
	/**
	 * Constructs an empty customer database.
	 */
	public CustomerDatabase() {
		customerDB = new ArrayList<Customer>();
	}
	/**
	 * Returns a customer when given a username.
	 * 
	 * @param c the username of the customer to find
	 * @return Customer cust
	 * @throws NoSuchElementException
	 */
	private Customer getCustomer(String c) {
		c = c.toLowerCase();
		Iterator<Customer> iter = iterator();
		while (iter.hasNext()) {
			Customer cust = iter.next();
			if (cust.getUsername().equals(c)) {
				return cust;
			}
		}
		//if here, no customer with that username in database
		throw new NoSuchElementException();
	}
	
	/**
	 * Adds a customer to the database with an empty wish list. Does nothing if
	 * customer already in database.
	 * 
	 * @param c the username of the customer to add
	 */
	public void addCustomer(String c) {
		c = c.toLowerCase();
		if (!containsCustomer(c)) {
			//add new customer with username c to db
			customerDB.add(new Customer(c));
		}
	}
	
	/**
	 * Adds a product to the customer's wish list. Does nothing if product already
	 * in wish list.
	 * 
	 * @param c the username of the customer to add a product for
	 * @param p the product to add
	 */
	public void addProduct(String c, String p) {
		c = c.toLowerCase();
		p = p.toLowerCase();
		try {
			if (!hasProduct(c, p)) {
				//add p in lower case to customer c's wishlist
				getCustomer(c).getWishlist().add(p);
			}
		} catch (NoSuchElementException ex) {
			throw new IllegalArgumentException();
		}
	}
	
	/**
	 * Looks for customer in database when given a username.
	 * 
	 * @param c the username of the customer to look for
	 * @return true if customer in database or false
	 */
	public boolean containsCustomer(String c) {
		c = c.toLowerCase();
		try {
			return getCustomer(c) != null;
		} catch (NoSuchElementException ex) {
			return false;
		}
	}
	
	/**
	 * Returns true if the given product is in at least one customer's wish list.
	 * 
	 * @param p the product to search for
	 * @return true if the product is found or false
	 */
	public boolean containsProduct(String p) {
		p = p.toLowerCase();
		boolean containsProd = false;
		Iterator<Customer> dbIter = iterator();
		//iterate over customer database to get wish lists
		while (dbIter.hasNext()) {
			List<String> currWishlist = dbIter.next().getWishlist();
			if (currWishlist.contains(p)) {
				containsProd = true;
				break;
			}
		}
		return containsProd;
	}
	
	/**
	 * Iterates over the given customer's wishlist to determine if it contains
	 * the given product.
	 * 
	 * @param c the username of the customer to look at
	 * @param p the name of the product
	 * @return true if customer's wish list has the given product or false
	 */
	public boolean hasProduct(String c, String p) {
		c = c.toLowerCase();
		p = p.toLowerCase();
		boolean hasProd = false;
		if (containsCustomer(c)) {
			List<String> wishlist = getCustomer(c).getWishlist();
			if (wishlist.contains(p)) {
				hasProd = true;
			}
		}
		return hasProd;
	}
	
	/**
	 * Returns a list of customers that have product p in their wish list or 
	 * null if p not in any customer's wish list.
	 * 
	 * @param p the product to find
	 * @return list of customers with product p in their wish list or null
	 */
	public List<String> getCustomers(String p) {
		p = p.toLowerCase();
		if (containsProduct(p)) {
			List<String> customers = new ArrayList<String>();
			Iterator<Customer> dbIter = iterator();
			//iterate over customer database
			while (dbIter.hasNext()) {
				Customer cust = dbIter.next();
				List<String> wishlist = cust.getWishlist();
				if (wishlist.contains(p)) {
					customers.add(cust.getUsername());
				}
			}
			return customers;
		} else {
			return null;
		}
	}
	
	/**
	 * Returns the wish list for the given customer or null if customer isn't in 
	 * the database.
	 * 
	 * @param c the username of the customer
	 * @return customer c's wish list or null
	 */
	public List<String> getProducts(String c) {
		c = c.toLowerCase();
		try {
			return getCustomer(c).getWishlist();
		} catch (NoSuchElementException ex) {
			return null;
		}
	}
	
	/**
	 * Returns an iterator for the customer database.
	 * 
	 * @return iterator for customer database
	 */
	public Iterator<Customer> iterator() {
		return customerDB.iterator();
	}
	
	/**
	 * Removes the customer from the database when given a username.
	 * 
	 * @param c the username of the customer to remove
	 * @return false if customer not in database or true
	 */
	public boolean removeCustomer(String c) {
		c = c.toLowerCase();
		boolean success = false;
		if (containsCustomer(c)) {
			Iterator<Customer> dbIter = iterator();
			//iterate over db to look for customer
			while (dbIter.hasNext()) {
				Customer cust = dbIter.next();
				if (cust.getUsername().equals(c)) {
					customerDB.remove(cust);
					break; //only one customer with that username in db
				}
			}
			success = true;
		}
		return success;
	}
	
	/**
	 * Removes the given product from all customer's wish lists with that given product.
	 * 
	 * @param p the product to remove
	 * @return false if product not in database or true
	 */
	public boolean removeProduct(String p) {
		p = p.toLowerCase();
		boolean success = false;
		if (containsProduct(p)) {
			Iterator<Customer> dbIter = iterator();
			//iterate over the database
			while (dbIter.hasNext()) {
				Customer cust = dbIter.next();
				List<String> currWishlist = cust.getWishlist();
				if (currWishlist.contains(p)) {
					currWishlist.remove(p);
				}
			}
			success = true;
		}
		return success;
	}
	
	/**
	 * Returns the number of customers in the database.
	 * 
	 * @return the number of customers
	 */
	public int size() {
		return customerDB.size();
	}	
}
