package orderprocessing;

import java.io.*;
import java.util.*;
import java.text.*;

class Maintenance
{	/** Writes all customer records to a file in a format from which they
	* 	can be restored with the restore function. They are written in customer 
    *	number order. 
    */
    private static void dumpCustomers(BufferedWriter out)
    {	try    
		{	ArrayList list = sortedKeys(Customer.keys());
            Iterator it = list.iterator();
			Customer c;
			while (it.hasNext())
        	{	c = Customer.get((String)it.next());
            	out.write(c.key());
                out.newLine();
                out.write(c.name());
                out.newLine();
                out.write((""+c.billingAddress()).replace('\n','~'));
                out.newLine();
                out.write((""+c.shippingAddress()).replace('\n','~'));
                out.newLine();
                out.write(""+c.billingTerms());
                out.newLine();
                out.write(""+c.isActive());
                out.newLine();
                out.newLine();// separator
        	}  
		}
        catch(IOException ex)
        {	System.out.println("Customer Write Failed. " + ex);
        }
    }
    /** Returns a sorted list of the results returned by the iterator.
    *	Requires that the iterator return Comparable items.
    */
    public static ArrayList sortedKeys(Iterator i)
   {	ArrayList result = new ArrayList();
        while (i.hasNext())
        {	result.add(i.next());
        }        
        Collections.sort(result);
        return result;
    }
     
    /** Returns a sorted list of the results returned by the iterator.
    *	Sorted in order of the Comparator.
    */
    public static ArrayList sortedKeys(Iterator i, Comparator c)
    {	ArrayList result = new ArrayList();
        while (i.hasNext())
        {	result.add(i.next());
        }        
        Collections.sort(result, c);
        return result;
    }
    
    
    /** Adds customers from a file. Note that the customer number line is required
    *	but not used. The Customer class assigns customer numbers. init the database
    *	first if you want the results of the file to replace the objects in the 
    *	database. In this case the records should be in the order required. 
    */
    private static void restoreCustomers(BufferedReader in)
    {	try 
    	{	String num;
        	while ((num = in.readLine()) != null && !num.equals("ORDERS"))
            {	String name = in.readLine();
        		String cAddress = in.readLine();
                String sAddress = in.readLine();
                String bt = in.readLine().substring(14);    
            	Address custAddress = new Address(cAddress, "~");
                Address shipAddress = new Address(sAddress, "~");
                BillingTerms terms= BillingTerms.get(bt);
                Customer c = new Customer(name, custAddress, shipAddress, terms);
                boolean active = in.readLine().equals("true")?true:false;
                if(!active) Customer.remove(c.key());
                
            	in.readLine(); // separator line
            }
    	}
        catch(IOException ex)
        {	System.out.println("Customer Restore Failed. " + ex);
    		System.exit(1);    
        }
    }
  	
    /** creates an empty database. All records are lost.
    */
    private static void initDatabase()
    {	OrderProcessor.close(OrderProcessor.databaseName());
    }
    
    private static void dumpOrders(BufferedWriter out)
    {	try    
    	{   ArrayList list = sortedKeys(Order.keys());
            Iterator it = list.iterator();
    		Order order;
            out.write("ORDERS");
            out.newLine();
    		while (it.hasNext())
    		{	order = Order.get((String)it.next());
        		out.write(order.key());
                out.newLine();    
        		out.write(order.customer().key());
                out.newLine(); 
                out.write(order.billingTerms().toString().substring(14));
                out.newLine();
                out.write(order.shippingAddress().toString().replace('\n','~')); 
                out.newLine(); 
                out.write(sdf.format(order.orderDate().getTime()));
                out.newLine();
                out.write(sdf.format(order.requestedShippingDate().getTime()));
                out.newLine();
                out.write(sdf.format(order.cancelDate().getTime())); 
                out.newLine();
                out.write(""+order.size());
                out.newLine();
                Iterator j = order.orderedItems();
                while (j.hasNext())
                {	OrderItem item = (OrderItem)j.next();
            		dumpOrderItem(item,out);    
                }
                out.newLine();                
    		}
    	}
 	   catch(IOException ex)
    	{	System.out.println("Order Write Failed. " + ex);
    	}
    }
    
    private static void dumpOrderItem(OrderItem o, BufferedWriter out) throws IOException
    {	out.write("" + o.itemNumber()+ "~" + o.quantity() + "~" + o.unitPrice() + "~" + o.description());
    	out.newLine();
    }
    
    private static OrderItem restoreOrderItem(BufferedReader in) throws IOException
    {	String line  = in.readLine();
		return OrderItem.genOrderItem(line, "~");    
    }
    
    private static void restoreOrders(BufferedReader in)
    {	try
    	{	String num;
			while ((num = in.readLine()) != null && !num.equals("INVOICES"))
        	{	Customer cust = Customer.get(in.readLine().trim());
        		    
    			BillingTerms terms = BillingTerms.get(in.readLine().trim()); 
            	Address shipAddress = new Address(in.readLine().trim(), "~");
                CalculationCalendar od = new CalculationCalendar();
                CalculationCalendar	sd = new CalculationCalendar(); 
                CalculationCalendar cd = new CalculationCalendar();
                
        		try
        		{	od.setTime(sdf.parse(in.readLine().trim()));
        			sd.setTime(sdf.parse(in.readLine().trim()));
        			cd.setTime(sdf.parse(in.readLine().trim()));
        		}
        		catch(ParseException e)
        		{	System.out.println("Illegal date");  // dialog box?
        			return;
        		}  
        		int size = Integer.parseInt(in.readLine());
                ArrayList items = new ArrayList(size);
                for(int i = 0; i < size; ++i)
                {	OrderItem o = restoreOrderItem(in);
            		items.add(o);    
                }
                
                Order order = new Order(cust, shipAddress, terms, items, od, sd, cd);
                
            	in.readLine(); // separator
        	} 
    	}
        catch(IOException ex)
        {	System.out.println("Order restore failed. " + ex);
    		System.exit(1);    
        }
    }
    
    private static void dumpInvoices(BufferedWriter out)
    {	try
    	{	out.write("INVOICES");
			out.newLine(); 
			ArrayList list = sortedKeys(Invoice.keys());
			Iterator it = list.iterator();
            Invoice invoice;
            while (it.hasNext())
            {	invoice = Invoice.get((String)it.next());
        		out.write(invoice.key());
                out.newLine();    
           	 	out.write(invoice.order().key());
           	 	out.newLine();
           	 	out.write(""+invoice.size());
           	 	out.newLine();
           	 	Iterator j = invoice.shipableItems();
           	 	while (j.hasNext())
           	 	{	OrderItem item = (OrderItem)j.next();
           	 		dumpOrderItem(item,out);
                }
            	out.newLine();
            }          
    	}
    	catch(IOException ex)
    	{	System.out.println("Invoice Write Failed. " + ex);
    	}
    }
    
    private static void restoreInvoices(BufferedReader in)
    {	try
    	{  
    		String num;
    		while ((num = in.readLine()) != null && !num.equals("INVENTORY"))
    	    {	Order order = Order.get(in.readLine().trim());
    	    		    
              	int size = Integer.parseInt(in.readLine());
        		ArrayList items = new ArrayList(size);
        		for(int i = 0; i < size; ++i)
        		{	OrderItem o = restoreOrderItem(in);
    				items.add(o);    
        		}
        
        		Invoice invoice = new Invoice(order, items);
 
    			in.readLine(); // separator
    		} 
    	}
		catch(IOException ex)
		{	System.out.println("Order restore failed. " + ex);
   	 		System.exit(1);    
		}
    }
    
    private static void dumpInventory(BufferedWriter out)
    { 	try
    	{	out.write("INVENTORY");
    		out.newLine(); 
            
    	}
    	catch(IOException ex)
    	{	System.out.println("Inventory Write Failed. " + ex);
    	}
    }
    
    private static void restoreInventory(BufferedReader in)
    {	
    }
    
    private static SimpleDateFormat sdf = new SimpleDateFormat("EEE MMM dd yyyy");
    
    public static void main(final String [] args)throws IOException
    {//	OrderProcessor.open(OrderProcessor.databaseName());
    //	System.out.println(keys());
    
    	if(args.length < 2)
    	{	System.out.println("Usage requires parameters 'save filename' OR 'restore filename'");
    		return;
        }    
    	String filename = args[1];
    	String command = args[0].toUpperCase();
    	if (command.equals("SAVE"))
        {// Save in text file.
        	System.out.println("Saving");  
        	BufferedWriter out = new BufferedWriter(new FileWriter(filename));
           	OrderProcessor.open(OrderProcessor.databaseName());
            dumpCustomers(out);
            dumpOrders(out);
            dumpInvoices(out);
            dumpInventory(out);
            out.close();
        }
       	else if (command.equals("RESTORE"))
       	{// Restore from textfile.
       		System.out.println("Restoring.");
            BufferedReader in = new BufferedReader(new FileReader(filename));
         	initDatabase(); // Make database empty.
         	restoreCustomers(in);
            restoreOrders(in);
            restoreInvoices(in);
            restoreInventory(in);
         	OrderProcessor.close(OrderProcessor.databaseName());
       	}
       	else System.out.println("Usage requires parameters 'save filename' OR 'restore filename'");
    
    }
}
