package gui;

import java.awt.*;
import java.awt.event.*;
import java.rmi.RemoteException;
import javax.swing.*;
import javax.swing.table.*;
import server.*;
import shared.*;

public class DatabaseWindow implements WindowListener, ActionListener, Runnable, Updatable {
	
	private DatabaseServer m_server;
	private JFrame m_frame;
	private JTabbedPane m_mainTabbedPane;
	private JTextArea m_consoleText;
	private Font m_consoleFont;
	private JScrollPane m_consoleScrollPane;
    private JTable m_userDataTable;
    private JScrollPane m_userDataScrollPane;
    private JTable m_gameHistoryTable;
    private JScrollPane m_gameHistoryScrollPane;
	private JMenuBar m_menuBar;
	private JMenu m_fileMenu;
	private JMenuItem m_fileExitMenuItem;
	private JMenu m_manageMenu;
	private JMenuItem m_manageDeleteUserMenuItem;
	private JMenuItem m_manageDeleteUserHistoryMenuItem;
	private JMenu m_settingsMenu;
	private JCheckBoxMenuItem m_settingsAutoScrollConsoleWindowMenuItem;
	private JMenuItem m_settingsMaxConsoleHistoryMenuItem;
	private JMenu m_helpMenu;
	private JMenuItem m_helpAboutMenuItem;
	private boolean m_updating;
	private boolean m_initialized;
	private boolean m_running;
	private boolean m_autoSizeColumns;
	private Thread m_updateThread;
	final public static String USER_DATA_TABLENAME = "UserData";
	final public static String GAME_HISTORY_TABLENAME = "GameHistory";
	
	public DatabaseWindow() {
		// initialize window properties
		m_frame = new JFrame("Database Server Window");
		m_frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
		m_frame.setMinimumSize(new Dimension(320, 240));
		m_frame.setSize(new Dimension(640,480));
		m_frame.addWindowListener(this);
		
		// create the server
		m_server = new DatabaseServer();
		DatabaseServer.console.addTarget(this);
		m_initialized = false;
		m_running = false;
		m_updating = false;
		m_autoSizeColumns = true;
		
		// initialize gui components
		initMenu();
		initComponents();
	}
	
	// initialize the server window
	public boolean initialize(String databaseConfigFileName, String dbmsName, boolean integratedRegistry, int registryPort) {
		if(m_initialized) { return false; }
		
		// initialize the server
		if(!m_server.initialize(databaseConfigFileName, dbmsName, integratedRegistry, registryPort)) {
			JOptionPane.showMessageDialog(null, "Unable to initialize database server.", "Initialization Error", JOptionPane.ERROR_MESSAGE);
			return false;
		}
		
		// update and show the gui window
		update();
		m_frame.setVisible(true);
		
		m_initialized = true;
		
		// start the update thread
		m_updateThread = new Thread(this);
		m_updateThread.start();
		
		return true;
	}
	
	// initialize the menu
	private void initMenu() {
		m_menuBar = new JMenuBar();
		
		m_fileMenu = new JMenu("File");
		m_fileExitMenuItem = new JMenuItem("Exit");
		
		m_manageMenu = new JMenu("Manage");
		m_manageDeleteUserMenuItem = new JMenuItem("Delete User");
		m_manageDeleteUserHistoryMenuItem = new JMenuItem("Delete User History");
		
		m_settingsMenu = new JMenu("Settings");
		m_settingsAutoScrollConsoleWindowMenuItem = new JCheckBoxMenuItem("Auto-scroll Console Window");
		
		m_helpMenu = new JMenu("Help");
		m_helpAboutMenuItem = new JMenuItem("About");
		
		m_settingsAutoScrollConsoleWindowMenuItem.setSelected(DatabaseServer.console.getAutoScrollConsoleWindow());
		m_settingsMaxConsoleHistoryMenuItem = new JMenuItem("Max Console History");
		
		m_fileExitMenuItem.addActionListener(this);
		m_manageDeleteUserMenuItem.addActionListener(this);
		m_manageDeleteUserHistoryMenuItem.addActionListener(this);
		m_settingsAutoScrollConsoleWindowMenuItem.addActionListener(this);
		m_settingsMaxConsoleHistoryMenuItem.addActionListener(this);
		m_helpAboutMenuItem.addActionListener(this);
		
		m_fileMenu.add(m_fileExitMenuItem);
		
		m_manageMenu.add(m_manageDeleteUserMenuItem);
		m_manageMenu.add(m_manageDeleteUserHistoryMenuItem);
		
		m_settingsMenu.add(m_settingsAutoScrollConsoleWindowMenuItem);
		m_settingsMenu.add(m_settingsMaxConsoleHistoryMenuItem);
		
		m_helpMenu.add(m_helpAboutMenuItem);
		
		m_menuBar.add(m_fileMenu);
		m_menuBar.add(m_manageMenu);
		m_menuBar.add(m_settingsMenu);
		m_menuBar.add(m_helpMenu);
		
		m_frame.setJMenuBar(m_menuBar);
	}
	
	// initialize the gui components
	private void initComponents() {
		// initialize the main tabbed pane
		m_mainTabbedPane = new JTabbedPane();
		
		// initialize the console tab
		m_consoleText = new JTextArea();
        m_consoleFont = new Font("Verdana", Font.PLAIN, 14);
        m_consoleText.setFont(m_consoleFont);
        m_consoleText.setEditable(false);
        m_consoleScrollPane = new JScrollPane(m_consoleText);
        m_mainTabbedPane.add(m_consoleScrollPane);
        
        m_mainTabbedPane.addTab("Console", null, m_consoleScrollPane, "Displays debugging output from the server.");
        
        m_frame.add(m_mainTabbedPane);
        
        // initialize the user data tab
        m_userDataScrollPane = new JScrollPane();
        m_userDataTable = new JTable() {
			private static final long serialVersionUID = 1L;
			
			public boolean isCellEditable(int row, int col) {
        		return false;
        	}
        };
        
        DefaultTableModel userDataTableModel = new DefaultTableModel(
        	null,
        	new String[] {
        		"UserName", "Password", "LastLogin", "JoinDate", "Wins", "Losses", "Draws"
        	}
        );
        
        m_userDataTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
        m_userDataTable.setModel(userDataTableModel);
        m_userDataScrollPane.setViewportView(m_userDataTable);
        m_mainTabbedPane.addTab("User Data", null, m_userDataScrollPane, "Displays the User Data table for debugging");
        
        // initialize the game history tab
        m_gameHistoryScrollPane = new JScrollPane();
        m_gameHistoryTable = new JTable() {
			private static final long serialVersionUID = 1L;
			
			public boolean isCellEditable(int row, int col) {
        		return false;
        	}
        };
        
        DefaultTableModel gameHistoryTableModel = new DefaultTableModel(
        	null,
        	new String[] {
        		"GameDate", "FirstPlayer", "SecondPlayer", "Outcome"
        	}
        );
        
        m_gameHistoryTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
        m_gameHistoryTable.setModel(gameHistoryTableModel);
        m_gameHistoryScrollPane.setViewportView(m_gameHistoryTable);
        m_mainTabbedPane.addTab("Game History", null, m_gameHistoryScrollPane, "Displays the Game History table for debugging");
	}
	
	// update the server window
	public void update() {
		m_updating = true;
		
		m_settingsAutoScrollConsoleWindowMenuItem.setSelected(DatabaseServer.console.getAutoScrollConsoleWindow());
		
		// automatically scroll the console text
		try {
			m_consoleText.setText(DatabaseServer.console.toString());
			
			if(DatabaseServer.console.getAutoScrollConsoleWindow()) {
				m_consoleText.setCaretPosition(m_consoleText.getText().length());
			}
		}
		catch(Exception e) { }
		
		m_updating = false;
	}
	
	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) { }
	
	public void windowClosing(WindowEvent e) {
		if(e.getSource() == m_frame) {
			stop();
			m_server.stop();
			m_frame.dispose();
		}
	}
	
	public void actionPerformed(ActionEvent e) {
		if(m_updating) { return; }
		
		// close the server
		if(e.getSource() == m_fileExitMenuItem) {
			stop();
			m_server.stop();
			System.exit(0);
		}
		// prompt to delete a user
		else if(e.getSource() == m_manageDeleteUserMenuItem) {
			// obtain the names of all users with accounts
			String[] userNames = null;
			try { userNames = DatabaseServer.database.getUserNames(); }
			catch(RemoteException e2) { return; }
			if(userNames == null) { return; }
			if(userNames.length == 0) {
				JOptionPane.showMessageDialog(m_frame, "No users in database to delete.", "No Users", JOptionPane.WARNING_MESSAGE);
				return;
			}
			
			// prompt for a user to delete
			String userName = (String) JOptionPane.showInputDialog(null, "Choose a user to delete:", "Delete User", JOptionPane.QUESTION_MESSAGE, null, userNames, userNames[0]);
			if(userName == null) { return; }
			
			// delete the user
			try { DatabaseServer.database.deleteUser(userName); }
			catch(RemoteException e2) { }
		}
		// prompt to delete a user's history
		else if(e.getSource() == m_manageDeleteUserHistoryMenuItem) {
			// prompt for all user names who have played a game 
			String[] userNames = null;
			try { userNames = DatabaseServer.database.getUserNamesFromHistory(); }
			catch(RemoteException e2) { return; }
			if(userNames == null) { return; }
			if(userNames.length == 0) {
				JOptionPane.showMessageDialog(m_frame, "No history in database to delete.", "No Users in History", JOptionPane.WARNING_MESSAGE);
				return;
			}
			
			// prompt for a user whose history should be deleted
			String userName = (String) JOptionPane.showInputDialog(null, "Choose a user's history to delete:", "Delete User History", JOptionPane.QUESTION_MESSAGE, null, userNames, userNames[0]);
			if(userName == null) { return; }
			
			// delete the selected user's history
			try { DatabaseServer.database.deleteUserHistory(userName); }
			catch(RemoteException e2) { }
		}
		// change the console auto scrolling
		else if(e.getSource() == m_settingsAutoScrollConsoleWindowMenuItem) {
			DatabaseServer.console.setAutoScrollConsoleWindow(m_settingsAutoScrollConsoleWindowMenuItem.isSelected());
		}
		// change the maximum number of elements the console can h old
		else if(e.getSource() == m_settingsMaxConsoleHistoryMenuItem) {
			// prompt for the maximum console history size
			String input = JOptionPane.showInputDialog(m_frame, "Please enter the maximum console history size:", DatabaseServer.console.getMaxConsoleHistory());
			if(input == null) { return; }
			
			// set the new console history size
			int maxConsoleHistory = -1;
			try {
				maxConsoleHistory = Integer.parseInt(input);
			}
			catch(NumberFormatException e2) {
				JOptionPane.showMessageDialog(m_frame, "Invalid number entered for maximum console history.", "Invalid Number", JOptionPane.ERROR_MESSAGE);
				return;
			}
			
			DatabaseServer.console.setMaxConsoleHistory(maxConsoleHistory);
		}
		// display help message
		else if(e.getSource() == m_helpAboutMenuItem) {
			JOptionPane.showMessageDialog(m_frame, "Connect Four Database Server\nCreated by Kevin Scroggins & Corey Faibish", "About Database Server", JOptionPane.INFORMATION_MESSAGE);
		}
	}
	
	// stop the server
	public void stop() {
		// reset initialization variables
		m_initialized = false;
		m_running = false;
		
		// stop all threads
		try { m_updateThread.interrupt(); } catch(Exception e) { }
	}
	
	// indefinitely update the gui window
	public void run() {
		if(!m_initialized) { return; }
		
		m_running = true;
		
		while(m_running) {
			// update database view tables
			try { DatabaseServer.database.updateTable(USER_DATA_TABLENAME, m_userDataTable, m_autoSizeColumns); } catch(Exception e) { }
			try { DatabaseServer.database.updateTable(GAME_HISTORY_TABLENAME, m_gameHistoryTable, m_autoSizeColumns); } catch(Exception e) { }
			
			// only autosize columns once
			m_autoSizeColumns = false;
			
			try { Thread.sleep(1000L); }
			catch(InterruptedException e) { }
		}
		
	}
	
}
