///////////////////////////////////////////////////////////////////////////////
//                   ALL STUDENTS COMPLETE THESE SECTIONS
// Title:            InteractiveDBTester
// Files:            InteractiveDBTester.java, CustomerDatabase.java
// Semester:         CS367 Summer 2014
//
// Author:           Josh Chansard
// Email:            chansard@wisc.edu
// CS Login:         chansard
// Lecturer's Name:  Beck Hasti
// Lab Section:      N/A?
//
//////////////////////////// 80 columns wide //////////////////////////////////

package assignment1;

import java.util.*;
import java.io.*;

/**
 * Allows for interacting with a CustomerDatabase built via an input file 
 * specified as a command-line argument via console commands.
 *
 * @author Josh Chansard
 */
public class InteractiveDBTester {
	/**
	 * Main method lists available options to interact with CustomerDatabase
	 * and performs them based on user input. 
	 * 
	 * @param args Specify the filepath of your CustomerDatabase input .txt file.
	 */
		
    public static void main(String[] args) {

    	// quit if no input file specified 
    	if (args.length != 1) {
    		System.out.println("Please provide input file as command-line argument.");
    		return;
    	} 
    	
    	// create CustomerDatabase from input file 
   		File inputFile = new File(args[0]);
   		CustomerDatabase customers = createCustomerDatabaseFromFile(inputFile);

   		Scanner stdin = new Scanner(System.in);  // for reading console input
        printOptions();
        boolean done = false;
        while (!done) {
            System.out.print("Enter option ( dfhisqr ): ");
            String input = stdin.nextLine();
            input = input.toLowerCase();  // convert input to lower case

            // only do something if the user enters at least one character
            if (input.length() > 0) {
                char choice = input.charAt(0);  // strip off option character
                String remainder = "";  // used to hold the remainder of input
                if (input.length() > 1) {
                    // trim off any leading or trailing spaces
                    remainder = input.substring(1).trim(); 
                }

                switch (choice) {
                
                case 'd':
                	discontinueProduct(customers, remainder);
                    break;


                case 'f':
                    findCustomer(customers, remainder);
                    break;

                case 'h': 
                    printOptions();
                    break;

                case 'i':
                    printDatabaseInformation(customers);
                    break;
                    
                case 's':
                    searchForProduct(customers, remainder);
                    break;

                case 'q':
                    done = true;
                    System.out.println("quit");
                    break;

                case 'r':
                    removeCustomer(customers, remainder);
                    break;

                default:  // ignore any unknown commands
                    break;
                }
            }
        }
        
        stdin.close();
    }

    /**
     * Prints the list of command options along with a short description of
     * one.  This method should not be modified.
     */
    private static void printOptions() {
        System.out.println("d <product> - discontinue the given <product>");
        System.out.println("f <customer> - find the given <customer>");
        System.out.println("h - display this help menu");
        System.out.println("i - display information about this customer database");
        System.out.println("s <product> - search for the given <product>");
        System.out.println("q - quit");
        System.out.println("r <customer> - remove the given <customer>");
    }
    
    /**
     * Creates and returns a CustomerDatabase object with customers and their 
     * wishlists populated from the input .txt file specified as a command-line
     * parameter.
     * 
     * @param inputFile The .txt input File object containing the customer info 
     * @return A CustomerDatabase object created from the information in inputFile
     */
    private static CustomerDatabase createCustomerDatabaseFromFile(File inputFile) {
    	CustomerDatabase customers = new CustomerDatabase();
   		try {
   			Scanner inFile = new Scanner(inputFile);
   			while (inFile.hasNext()) {
   	    		String customerInfo = inFile.nextLine();
   	    		String[] tokens = customerInfo.split(",");
   	    		String Username = tokens[0].toLowerCase();
   	    		customers.addCustomer(Username);
   	    		for (int i = 1; i < tokens.length; i++) {
   	    			customers.addProduct(Username, tokens[i].toLowerCase());
   	    		}
   	    	}
   			inFile.close();
   		} catch (FileNotFoundException e) {
   			System.out.println("Error: Cannot access input file.");
   		} 
    	return customers;
    }
    
    /**
     * If product is not in the database, display "product not found". 
     * Otherwise, discontinue product (i.e., remove the product from all the
     * wish lists in which it appears) and display "product discontinued".
     * 
     * @param customers The CustomerDatabase object being modified
     * @param p The product to discontinue
     */
    private static void discontinueProduct(CustomerDatabase customers, String p) {
    	if (customers.removeProduct(p)) {
    		System.out.println("product discontinued");
    	} else {
    		System.out.println("product not found");
    	}
    }
    
    /**
     * If customer is not in the database, display "customer not found". 
     * Otherwise, find customer and display the customer (on one line) in the
     * format: customer:product1,product2,product3
     * 
     * @param customers The CustomerDatabase object being modified
     * @param c The desired customer's username
     */
    private static void findCustomer(CustomerDatabase customers, String c) {
   		List<String> products = customers.getProducts(c);
   		if (products != null) {
   			System.out.print(c + ":");
   			printListWithCommas(products);
   			System.out.println();
   		} else {
   			System.out.println("customer not found");
   		}
    }
    
    /**
     * Prints information about the customer database, namely:
     * - The number of customers and unique products in the database,
     * - The largest, smallest, and average number of products a customer
     * 	 has in their iwshlist
     * - The largest, smallest, and average number of times a product appears
     *   in any customer's wishlist
     * - The most popular products in the database
     * 
     * @param customers The CustomerDatabase object being modified
     */
    private static void printDatabaseInformation(CustomerDatabase customers) {
    	/*
    	 * We can easily get the number of customers and the products per customer
    	 * information using our CustomerDatabase and its methods. The products
    	 * per customer information is less easily attainable with our current
    	 * CustomerDatabase, but we can use our CustomerDatabase to make a backwards
    	 * "ProductDatabase" where Username is the product name and Wishlist contains
    	 * the names of the customers who want that product. We can use this info
    	 * to find the customers per product information and the number of products.
    	 */	
    	CustomerDatabase products = new CustomerDatabase();
    	
    	// Initialize all the customer info we'll use in the information printout
    	// PPC = productsPerCustomer
    	int mostPPC = 0, leastPPC = customers.size(), averagePPC = 0;
    	
    	// Iterate over the customers in the database to populate the products
    	// per customer information and to create our "ProductDatabase"
    	Iterator<Customer> customerIterator = customers.iterator();
    	while (customerIterator.hasNext()) {
    		
    		// Grab the next customer in the database and get their wishlist
    		Customer cust = customerIterator.next();
     		List<String> custWishlist = cust.getWishlist();
     		int numProds = custWishlist.size();
     		
     		// Check to see if the current customer's wishlist size beats the
     		// current values in mostPPC and leastPPC. Also, add the size
     		// to averagePPC so we can get the average later.
     		
     		if (numProds > mostPPC) {
     			mostPPC = numProds;
     		}
     		if (numProds < leastPPC) {
     			leastPPC = numProds;
     		}
     		averagePPC += numProds;
     		
     		//Iterate over the products in the current customer's wishlist
    		Iterator<String> custWishlistIterator = custWishlist.iterator();
    		while (custWishlistIterator.hasNext()) {
    			
    			//Grab the next product in the current customer's wishlist and
    			//add it to the products CustomerDatabase as a "customer"
    			String prod = custWishlistIterator.next();
    			products.addCustomer(prod);
    			
    			//Now, add the current customer's username as a "product" to the
    			//products CustomerDatabase.
    			products.addProduct(prod,cust.getUsername());
    		}
    	}
    	
    	//Now that we have our reverse ProductDatabase, we can iterate over it to
    	//find the information we need.
    	
    	//CPP = customers per product
    	int mostCPP = 0, leastCPP = products.size(), averageCPP = 0;
    	List<String> mostPopularProducts = new ArrayList<String>();
    	
    	Iterator<Customer> productsIterator = products.iterator();
    	while (productsIterator.hasNext()) {

    		//Get the next product in the products CustomerDatabase
    		Customer prod = productsIterator.next();
    		
    		//Get the number of customers whose wishlist this product appears on
    		int numCustomers = prod.getWishlist().size();
    		
    		//If numCustomers > the current mostCPP, clear out mostPopularProducts
    		//and add the current product to it. Otherwise, if numCustomers == the
    		//current mostCPP, add the current product to the list without clearing.
    		if (numCustomers > mostCPP) {
    			mostCPP = numCustomers;
    			mostPopularProducts.clear();
    			mostPopularProducts.add(prod.getUsername());
     		} else if (numCustomers == mostCPP) {
     			mostPopularProducts.add(prod.getUsername());
     		}
    		
    		//As with the customers CustomerDatabase, set the new leastCPP if 
    		//appropriate and keep a running total in averageCPP.
     		if (numCustomers < leastCPP) {
     			leastCPP = numCustomers;
     		}
     		averageCPP += numCustomers;
    	}
    	
    	//Calculate averages
    	averagePPC = (int) Math.round((double) averagePPC / customers.size());
    	averageCPP = (int) Math.round((double) averageCPP / products.size());
    	
    	//Finally, we have all our information, so we can print it out    	
    	System.out.println("Customers: " + customers.size() + ", " + "Products: " + 
  			  products.size());
    	System.out.println("# of products/customer: most " + mostPPC + ", least " + 
  			  leastPPC + ", average " + averagePPC);  
    	System.out.println("# of customers/product: most " + mostCPP + ", least " + 
  			  leastCPP + ", average " + averageCPP);
    	System.out.print("Most popular product: ");
    	printListWithCommas(mostPopularProducts);
    	System.out.println(" [" + mostCPP + "]");
    }
    
    /**
     * If product is not in the database, display "product not found". Otherwise, 
     * search for product and display the product along with the customers who 
     * have that product in their wish list (on one line) in the format:
     * product:customer1,customer2,customer3
     * 
     * @param customers The CustomerDatabase object being modified
     * @param p The product to search for
     */
    private static void searchForProduct(CustomerDatabase customers, String p) {
    	List<String> customersWithProduct = customers.getCustomers(p);
    	if (customersWithProduct != null) {
    		System.out.print(p + ":");
    		printListWithCommas(customersWithProduct);
    		System.out.println();
    	} else {
    		System.out.println("product not found");
    	}
    }
    
    /**
     * If customer is not in the database, display "customer not found". Otherwise, 
     * remove customer and display "customer removed".
     * @param customers The CustomerDatabase object being modified
     * @param c The customer to remove
     */
    private static void removeCustomer(CustomerDatabase customers, String c) {
    	if (customers.removeCustomer(c)) {
    		System.out.println("customer removed");
    	} else {
    		System.out.println("customer not found");
    	}
    }

    /**
     * Prints a List of Strings, separating them by commas and not adding a
     * comma after the final item.
     * 
     * @param l The List to be printed
     */
    private static void printListWithCommas(List<String> l) {
    	Iterator<String> iter = l.iterator();
    	while (iter.hasNext()) {
    		System.out.print(iter.next());
    		if (iter.hasNext()) {
    			System.out.print(",");
    		}
    	}
    }
}
	