// Student name: _______________________________

import java.io.*;			// for files
import java.util.Date;
import java.text.*;			// to format dates
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;

class SortMarathon extends JFrame
                implements ActionListener,
                           WindowListener {

	private JLabel      titleLabel;
	private JLabel      numLabel;
	private JTextField   numField;
	private JLabel      showLabel;
	private JCheckBox   showCheckBox;
	private JButton     msgButton;
	private JButton     exitButton;
	private JLabel      resultLabel;
	private JTextArea   resultField;
	private JLabel      reportLabel;
	private JTextArea   reportField;
	private JScrollPane resultScrollPane, reportScrollPane;
   
	private static final int MAXWORDS = 2700;
	private static String[] word = new String[MAXWORDS];
	private static String[] copy = new String[MAXWORDS];
	private static int wordCount = 0; //number of words in word and copy
	private static String fileName = "unsorted.txt";
		// note:  files without paths must be located in the same folder
		//        as the .class file
	private static String temp[]; // used with Merge sort
		
	private static Date start_bubble, end_bubble,
		start_selection, end_selection,
		start_shell, end_shell;
		
	private static int // count assignments and ifs
		move_bubble, if_bubble,
		move_selection, if_selection,
		move_shell, if_shell;
	
	private static String LeftJustify(String st, int f)
	{
		while (st.length()<f)
			st = st + ' ';
		return st;	
	}
	
	private static String RightJustify(String st, int f)
	{
		while (st.length()<f)
			st = ' ' + st;
		return st;	
	}
	
	private static String RightJustify(int N, int f)
	{
		return RightJustify(""+N,f);
	}

	private static int ReadWords(FileInputStream stream, String[] w, int num2read) {
		// returns number of words read, num2read<=MAXWORDS
		InputStreamReader iStrReader = new InputStreamReader(stream);
		BufferedReader reader = new BufferedReader(iStrReader);
		String line;
		int ct = 0;
		try {
			line = reader.readLine();
			while (line != null && ct<num2read) {
				// process line of input here
				//System.out.println(line);
				w[ct] = line;
				ct++;
				line = reader.readLine();
			}
			return ct;
			
		} catch (IOException e) {
			System.out.println("\nError in file input:\n" + e.toString());
		}
		return 0;
	}
	
	private static int findMinimum(String[] w, int first, int ct) {
		int min = first; // start with first when searching for minimum
		for (int i=first+1; i<ct; i++) {
			if_selection++;
			if (w[i].compareTo(w[min])<0)
				min = i;
		}
		return min;
	}
	
	private static void swap(String[] w, int x, int y) {
		String temp = w[x]; // swaps pointers, thus changing order
		w[x] = w[y];
		w[y] = temp;
	}
	
	private static void bubbleSort(String[] w, int ct) {
		int k = 0;
		boolean exchangeMade = true;
		while ((k < ct-1) && exchangeMade) {
			exchangeMade = false;
			k++;
			for (int j=0; j<ct-k; j++) {
				if_bubble++;
				if (w[j].compareTo(w[j+1]) > 0) {
					swap (w, j, j+1);
					move_bubble+=3;  // swap moves three
					exchangeMade = true;
				}
			}
		}
	}
	
	private static String MyTimeFormat(Date t)
	{
		SimpleDateFormat df = new SimpleDateFormat("HH:mm:ss:SSS");
		return df.format(t);
	}
	
	private static String LeadingZeros(long n, int field) {
		String st = "0";
		for (int i=1; i<field; i++)
			st += "0";
		DecimalFormat df = new DecimalFormat(st);
		return df.format(n);
	}
	
	// overloads method above that formats a Date object
	private static String MyTimeFormat(long t)
	{
		long h,m,s,f;
		f = t % 100;
		t /= 100;
		s = t % 60;
		t /= 60;
		m = t % 60;
		t /= 60;
		h = t;
		return LeadingZeros(h,2) + ":" +
			LeadingZeros(m,2) + ":" +
			LeadingZeros(s,2) + ":" +
			LeadingZeros(f,3);
	}	
	

	// Constructor
	public SortMarathon(){
	
		titleLabel       = new JLabel("Sort Marathon ~ by _________________");
		numLabel         = new JLabel("Number of words (0 to " + MAXWORDS + ")");
		numField         = new JTextField("1000",5);
		showLabel        = new JLabel("");
		showCheckBox     = new JCheckBox("Show Words",true); // start checked
		msgButton        = new JButton("Start the Marathon");
		exitButton       = new JButton("Exit");
		resultLabel      = new JLabel("Words");
		resultField      = new JTextArea("",15,90); //15 rows, 50 cols
		resultField.setFont(new Font("Courier New", Font.PLAIN, 12));
		resultScrollPane = new JScrollPane(resultField);
		reportLabel      = new JLabel("Report");
		reportField      = new JTextArea("",10,90);
		reportField.setFont(new Font("Courier New", Font.PLAIN, 12));
		reportScrollPane = new JScrollPane(reportField);
		
		Container windowPane = getContentPane();
		GridBagLayout layout = new GridBagLayout();
		windowPane.setLayout (layout);
		
		addComponent(layout,titleLabel,    0,0,2,1);
		addComponent(layout,numLabel,      1,0,1,1);
		addComponent(layout,numField,      1,1,1,1);
		addComponent(layout,showLabel,     2,0,1,1);
		addComponent(layout,showCheckBox,  2,1,1,1);
		addComponent(layout,msgButton,     3,0,1,1);
		addComponent(layout,exitButton,    3,1,1,1);
		addComponent(layout,resultLabel,   4,0,2,1);
		addComponent(layout,resultScrollPane,   5,0,2,5);
		addComponent(layout,reportLabel,  10,0,2,1);
		addComponent(layout,reportScrollPane,  11,0,2,3);
		
		msgButton.addActionListener(this);
		exitButton.addActionListener(this);
		
		addWindowListener (this);
	}

	private void DisplayWords(String subtitle, String[] w, int ct) {
		resultField.append(subtitle + "\n");
		if (showCheckBox.isSelected()) {
			for (int i=0; i<ct; i++) {
				if (i>0 && i%10==0)
					resultField.append("\n");
				//resultField.append(" w[" + i + "]=");
				resultField.append(LeftJustify(w[i],6));
			}
			if ((ct-1)%10>0)
				resultField.append("\n");
			resultField.append(ct + " words in list.\n");
		}
		
	}
	
	private void GetWords() {
		int howmany = 0;
		try {
			howmany = Integer.parseInt(numField.getText().trim());
		} catch (NumberFormatException e) {
			howmany = 0;
		}
		try {
			//open an input connection on the file,
			FileInputStream stream = new FileInputStream(fileName);
			//read the file,
			wordCount = ReadWords(stream,word,howmany);
			//close the file.
			stream.close();
		} catch (IOException e) {
			System.out.println("\nError opening input file:\n" + e.toString());
		}	
	}
	
	private void CopyWords(String[] w, String c[], int ct) {
		for (int i=0; i<ct; i++)
			c[i] = w[i];
	}
	
	private void BubbleSortRoutine()
	{
			CopyWords(word,copy,wordCount);
			DisplayWords("Before Bubble sort",word,wordCount);

			//peform the sort and time it
			move_bubble = 0;
			if_bubble = 0;
			start_bubble = new Date();
			bubbleSort(copy,wordCount);
			end_bubble = new Date();
			
			DisplayWords("After Bubble sort",copy,wordCount);
			DisplayWords("Original Order",word,wordCount);
	}
	
	private void SelectionSortRoutine()
	{
			// student add code
	}
	
	private void ShellSortRoutine()
	{
			// student add code
	}
	
	private void DisplayReport() {
		final int W = 14;
		final int D = 14;
		reportField.setText(
		"Sort Marathon.  Number of words sorted: " + wordCount + "\n" +
		LeftJustify("Sort",W) +
		RightJustify("Start",W) +
		RightJustify("End",W) +
		RightJustify("Duration",D) +
		RightJustify("Comparisons",D) + 
		RightJustify("Movements",D) +"\n"
		);
		
		reportField.append(
		LeftJustify("Bubble",W) +
		RightJustify(MyTimeFormat(start_bubble), W) +
		RightJustify(MyTimeFormat(end_bubble), W) +
		RightJustify(MyTimeFormat(end_bubble.getTime()-start_bubble.getTime()), D) + 
		RightJustify(if_bubble,D) + 
		RightJustify(move_bubble,D) + "\n"
		);		
	}

	public void actionPerformed (ActionEvent e){
		JButton buttonObj = (JButton)e.getSource();
		if (buttonObj == msgButton){
			resultField.setText("");
			reportField.setText("");
			GetWords();
			BubbleSortRoutine();
			SelectionSortRoutine();
			ShellSortRoutine();
			DisplayReport();
		}else{
			// assume Exit button was clicked
			dispose();
			System.exit(0);
		}
	}

	public void windowClosing (WindowEvent e){
		System.exit(0); // close window when user clicks the X
	}

	public void windowActivated (WindowEvent e){}
	public void windowClosed (WindowEvent e){}
	public void windowDeactivated (WindowEvent e){}
	public void windowDeiconified (WindowEvent e){}
	public void windowIconified (WindowEvent e){}
	public void windowOpened (WindowEvent e){}

	private void addComponent(GridBagLayout layout,
					Component component,
					int row, int col,
					int width, int height) {
		GridBagConstraints c = new GridBagConstraints();
		
		c.fill = GridBagConstraints.NONE;
		c.anchor = GridBagConstraints.WEST;
		c.insets.bottom = 2;
		c.insets.top	= 2;
		c.insets.left	= 2;
		c.insets.right	= 2;
		c.weightx = 1;
		c.weighty = 1;
		
		c.gridx = col;
		c.gridy = row;
		c.gridwidth = width;
		c.gridheight = height;
		layout.setConstraints(component, c);
		getContentPane().add(component);
	}

	public static void main (String[] args){
		System.out.println("Running SortMarathon...");
		JFrame theGUI = new SortMarathon();
		theGUI.setSize(650, 700);  // width, height in pixels
		theGUI.setTitle("Sort Marathon");
		theGUI.setVisible(true);
	}
}