/*
   COPYRIGHT (C) 2010 - 2013 by Alexander Wait. All Rights Reserved.

   This class builds the audio recorder GUI.

   @site http://www.javaika.com
   @author Alexander Wait
   @version 2012-05-05
*/



import java.awt.Color;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.awt.Insets;
import java.awt.event.*;
import java.io.File;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Timer;
import java.util.TimerTask;
import javax.swing.*;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;



public class AudioRecorderGui extends JApplet implements FocusListener, ComponentListener
{
   private static final String copyright = "Copyright (c) 2012 by Alexander Wait - All Rights Reserved";

   private static final long serialVersionUID = 1L;
   
   
   static boolean isApplication = false; 
   
   static boolean runRestricted = false;
   
   static boolean isVisible = false;
   
   
   private static final int SQL_TABLE_COLUMN_A = 0;
   
   private static final int SQL_TABLE_COLUMN_B = 1;
   
   private static final int SQL_TABLE_COLUMN_C = 2;
   
   private static final int SQL_TABLE_COLUMN_D = 3;
   
   private static final int SQL_TABLE_COLUMN_E = 4;
   
   private static final int SQL_TABLE_COLUMN_F = 5;
   
   private static final int SQL_TABLE_COLUMN_G = 6;
   
   private static final int SQL_TABLE_COLUMN_H = 6;
   
   
   private enum Procedure {START_RECORD, SAVE_FILE}
   
   private enum Record {NORMAL_RECORD, SCHEDULE_RECORD}
   
   
   private static final int FRAME_SIZE_X = 515;
   
   private static final int FRAME_SIZE_Y = 555;
   
   private static final int INPUT_PADDING_Y = 10;
   
   private static final int MAX_CHAPTER_TIME = 3600;
   
   private static final int SCHEDULE_ROW_LENGTH = 7;
   
   private static final int SCHEDULE_REFRESH_RATE = 100;
   
   private static final int WAVEFORM_REFRESH_RATE = 50;
   
   
   private static final String URL_PASTE_PROMPT = "Paste Address Here";
   
   
   private static final String RECORDER_CLEAR_ADDRESS = "http://" + Domain.getDomain()
   
   + "/bridge/audio-recorder-table-clear.php" + Domain.getPort(); // Port:80 
   
   
   private static final String SCHEDULE_CLEAR_ADDRESS = "http://" + Domain.getDomain() 
   
   + "/bridge/audio-recorder-schedule-clear.php" + Domain.getPort(); // Port:80
   
   
   private static final String RECORDER_WRITE_ADDRESS = "http://" + Domain.getDomain() 
   
   + "/bridge/audio-recorder-table-write.php" + Domain.getPort(); // Port:80 
   
   
   private static final String SCHEDULE_WRITE_ADDRESS = "http://" + Domain.getDomain() 
   
   + "/bridge/audio-recorder-schedule-write.php" + Domain.getPort(); // Port:80 
   
   
   private static final String RECORDER_READ_ADDRESS = "http://" + Domain.getDomain() 
   
   + "/bridge/audio-recorder-table-read.php" + Domain.getPort(); // Port:80
   
   
   private static final String SCHEDULE_READ_ADDRESS = "http://" + Domain.getDomain() 
   
   + "/bridge/audio-recorder-schedule-read.php" + Domain.getPort(); // Port:80
   
    
   //************************************** START INITIALISATION CODE **************************************//

   
   /**
    * Browser constructor.
    */
   public void init()
   {
      if (!isApplication) 
      { 
         String copyrightParam = getParameter("copyright");
         
         if ((copyrightParam == null) || !copyrightParam.equals(copyright)) 
         {
            Message.showMessage("Invalid Copyright", "WARNING", "warning"); 
         }       
         
         else if (!getDocumentBase().getHost().equals(Domain.getDomain())) 
         {
            Message.showMessage("Unauthorised Applet Use", "ERROR", "error");
         }
        
         else
         {
            try {getToolkit().getSystemClipboard();}
          
            catch (java.security.AccessControlException e) {runRestricted = true;} 
   

            userId = getParameter("id"); userPw = getParameter("pw");
         
            initialiser(); includeResizeEvent(); setJMenuBar(menuBar); 
         
            setSize(FRAME_SIZE_X,FRAME_SIZE_Y);
         }
      }
   }
 
   
   
   /**
    * Application constructor.
    */
   public AudioRecorderGui()
   {
      if (isApplication) 
      { 
         userId = "NON_MEMBER"; initialiser(); 
         
         
         frame = new JFrame();
         
         frame.setMinimumSize(new Dimension(FRAME_SIZE_X, FRAME_SIZE_Y));
         
         frame.setSize(FRAME_SIZE_X, FRAME_SIZE_Y); 
         
         frame.setLocationRelativeTo(null); 
         
         frame.setTitle("Recorder Program"); 
         
         frame.setJMenuBar(menuBar); 
         
         frame.add(contentPane); 
         
         
         setVisibility(); 
      }
   }
   
   
   
   /**
    * GUI initializer.
    * ESCA-JAVA0076:
    */
   private void initialiser()
   {
      recorder = new AudioRecorder();  
      
      
      
      // Initialize content pane and layout.
      
      contentPane = getContentPane(); contentPane.setLayout(new GridBagLayout());
      
      
      
      // Initialize menu bar GUI components.
      
      menuBar = new JMenuBar(); menuBar.add(createFileMenu()); 
      
      menuBar.add(createInputMenu()); menuBar.add(createSettingsMenu());
      
      
      
      // Initialize image icon GUI components.
      
      icon = new ImageIcon(AudioWaveform.getBufferedImage());
      
      
      
      // Initialize file browser GUI components.
      
      fBrowser = new FileBrowser();
      
      

      // Initialize JLabel GUI components.
      
      inputLabel = new JLabel("INPUT");
      
      inputLabel.setHorizontalAlignment(SwingConstants.LEFT);
      
      
      settingsLabel = new JLabel("SETTINGS");
      
      settingsLabel.setHorizontalAlignment(SwingConstants.LEFT);
      
      
      recordLabel = new JLabel("RECORD");
      
      recordLabel.setHorizontalAlignment(SwingConstants.LEFT);
      
      
      outputLabel = new JLabel("OUTPUT");
      
      outputLabel.setHorizontalAlignment(SwingConstants.LEFT);
      
      
      savingLabel = new JLabel("SAVING");
      
      savingLabel.setHorizontalAlignment(SwingConstants.LEFT);
      
      
      
      // Initialize text field GUI components.
      
      urlDisplay = new JTextField(10); 
      
      urlDisplay.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0));  
      
      urlDisplay.addFocusListener(this);
      
      urlDisplay.setEnabled(false);
      
      
      
      // Initialize text area GUI components.
      
      inputDisplay = new JTextArea(); inputDisplay.setEditable(false);
      
      inputDisplay.setFont(new Font("Dialog", Font.PLAIN, 11));

      inputDisplay.setText(" Attach microphone or line-in " +
      
      "cables (if required) before input searching");
      
      
      queueDisplay = new JTextArea(); 

      queueDisplay.setEditable(false);
      
      
      
      // Initialize combo box GUI components.
      
      browserBox = new JComboBox<String>(fBrowser.returnRoots());
      
      browserBox.addActionListener(new BrowseBoxListener());
      
      browserBox.setPreferredSize(new Dimension(396, 21));
      
      browserBox.setMaximumRowCount(4); 
      
      browserBox.setEnabled(false);
      
      
      recordFormatBox = new JComboBox<String>(formatChoices);
      
      recordFormatBox.addActionListener(new FileFormatHandler()); 
      
      recordFormatBox.setPreferredSize(new Dimension(60, 30));
      
      recordFormatBox.setMaximumRowCount(2); 
      
      recordFormatBox.setSelectedIndex(1);
      

      sampleRateBox = new JComboBox<String>(sampleRateChoices); 
      
      sampleRateBox.addActionListener(new SampleRateBoxHandler()); 
      
      sampleRateBox.setPreferredSize(new Dimension(75, 30));
      
      sampleRateBox.setMaximumRowCount(2); 
      
      sampleRateBox.setSelectedIndex(0);
      
      
      sampleSizeBox = new JComboBox<String>(sampleSizeChoices); 
      
      sampleSizeBox.addActionListener(new SampleSizeBoxHandler()); 
      
      sampleSizeBox.setPreferredSize(new Dimension(45, 30));
      
      sampleSizeBox.setMaximumRowCount(2);
      
      sampleSizeBox.setSelectedIndex(1);
      
      
      timeStartHour = new JComboBox<String>(DateAndTime.returnHourChoices()); 
      
      timeStartHour.insertItemAt("H", 0); timeStartHour.setMaximumRowCount(2); 
      
      timeStartHour.setPreferredSize(new Dimension(40, 17));
      
      timeStartHour.setSelectedIndex(0); 
      
      
      timeStartMinute = new JComboBox<String>(DateAndTime.returnMinuteChoices()); 
      
      timeStartMinute.insertItemAt("M", 0); timeStartMinute.setMaximumRowCount(2);
      
      timeStartMinute.setPreferredSize(new Dimension(40, 17));
      
      timeStartMinute.setSelectedIndex(0); 
       
      
      timeStartSecond = new JComboBox<String>(DateAndTime.returnSecondChoices()); 
      
      timeStartSecond.insertItemAt("S", 0); timeStartSecond.setMaximumRowCount(2);
      
      timeStartSecond.setPreferredSize(new Dimension(40, 17));
      
      timeStartSecond.setSelectedIndex(0); 
      
      
      timeFinishHour = new JComboBox<String>(DateAndTime.returnHourChoices()); 
      
      timeFinishHour.insertItemAt("H", 0); timeFinishHour.setMaximumRowCount(2);
      
      timeFinishHour.setPreferredSize(new Dimension(40, 17));
      
      timeFinishHour.setSelectedIndex(0); 
      
      
      timeFinishMinute = new JComboBox<String>(DateAndTime.returnMinuteChoices()); 
      
      timeFinishMinute.insertItemAt("M", 0); timeFinishMinute.setMaximumRowCount(2);
      
      timeFinishMinute.setPreferredSize(new Dimension(40, 17));
      
      timeFinishMinute.setSelectedIndex(0); 
      
      
      timeFinishSecond = new JComboBox<String>(DateAndTime.returnSecondChoices()); 
      
      timeFinishSecond.insertItemAt("S", 0); timeFinishSecond.setMaximumRowCount(2);
      
      timeFinishSecond.setPreferredSize(new Dimension(40, 17));
      
      timeFinishSecond.setSelectedIndex(0);
      
      
      
      // Initialize check box GUI components.
      
      useSchedule = new JCheckBox("Activate Schedule");
      
      useSchedule.addItemListener(new NormalScheduleClass()); 
      
      useSchedule.setFocusPainted(false);
      
      
      scheduleAddress = new JCheckBox("Record From Web"); 
      
      scheduleAddress.addItemListener(new AddressScheduleClass());
      
      scheduleAddress.setFocusPainted(false); 
      
      scheduleAddress.setEnabled(false);
      
      
      
      // Initialize radio button GUI components.
      
      saveDesktop = new JRadioButton(" Desktop ", true); 
      
      saveDesktop.addItemListener(new SaveHandler("desktop"));
      
      saveDesktop.setFocusPainted(false); 
      
     
      saveBrowse = new JRadioButton(" Folder ", false); 
      
      saveBrowse.addItemListener(new SaveHandler("browse"));
      
      saveBrowse.setFocusPainted(false); 
      
      
      mono = new JRadioButton("1", true); mono.setFocusPainted(false); 
      
      mono.addActionListener(new ChannelsListener()); 
      
      mono.setSelected(false); 
      
      
      stereo = new JRadioButton("2", true); stereo.setFocusPainted(false); 
      
      stereo.addActionListener(new ChannelsListener());  
      
      stereo.setSelected(true);
      
      
      
      // Initialize button group GUI components.
      
      group = new ButtonGroup(); group.add(mono); group.add(stereo); 
      
      
      
      // Initialize slider GUI components.
       
      volumeSlider = new JSlider();
      
      volumeSlider.addChangeListener(new BoundedChangeListener()); 
      
      volumeSlider.setPreferredSize(new Dimension(60, 30));   
      
      volumeSlider.setMajorTickSpacing(25); 

      volumeSlider.setPaintTicks(true);
      
      
      waveSlider = new JSlider();
      
      waveSlider.addChangeListener(new WaveZoomListener());
      
      waveSlider.setPreferredSize(new Dimension(60, 30));
      
      waveSlider.setMajorTickSpacing(25); 
      
      waveSlider.setMinorTickSpacing(5);
      
      waveSlider.setPaintTicks(true);
      
      
      
      // Initialize label GUI components.
      
      label = new JLabel(icon); 
      
      
      
      // Initialize scroll pane GUI components.

      scrollPane = new JScrollPane(queueDisplay, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, 

      JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
      
      
      scrollPane.setPreferredSize(new Dimension(310,70));
      
      
      liveWave = new JScrollPane(label, JScrollPane.VERTICAL_SCROLLBAR_NEVER,
      
      JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
          
      
      liveWave.setPreferredSize(new Dimension(465, 140));
      
      
      
      // Initialize progress bar GUI components.
      
      progressBar = new JProgressBar();  
      
      progressBar.setPreferredSize(new Dimension(180, 25));
      
      progressBar.setStringPainted(true); progressBar.setString("Pending");
      
      
      
      // Initialize button GUI components.
      
      add = new JButton("Add"); add.setFocusPainted(false); 
      
      add.setPreferredSize(new Dimension(125, 20));
      
      add.addActionListener(new AddButtonListener());
     
      
      clear = new JButton("Clear"); clear.setFocusPainted(false);
      
      clear.setPreferredSize(new Dimension(125, 20));
      
      clear.addActionListener(new ClearButtonListener());

      
      start = new JButton(new ImageIcon(this.getClass().getResource
      (
         "files/images/AudioRecorderStartNormal.png"))
      ); 
      
      
      start.setRolloverIcon(new ImageIcon(this.getClass().getResource
      (
         "files/images/AudioRecorderStartRollover.png"))
      );

      
      start.setPressedIcon(new ImageIcon(this.getClass().getResource
      (
         "files/images/AudioRecorderStartPressed.png"))
      );
      
      
      start.setBorder(BorderFactory.createEmptyBorder(0,0,0,0));
      
      start.setPreferredSize(new Dimension(115, 25)); 
      
      start.addActionListener(new StartButtonListener());
      
      
      cancel = new JButton(new ImageIcon(this.getClass().getResource
      (
         "files/images/AudioRecorderCancelNormal.png"))
      ); 
 
      
      cancel.setRolloverIcon(new ImageIcon(this.getClass().getResource
      (
         "files/images/AudioRecorderCancelRollover.png"))
      );

      
      cancel.setPressedIcon(new ImageIcon(this.getClass().getResource
      (
         "files/images/AudioRecorderCancelPressed.png"))
      );
      
      
      cancel.setBorder(BorderFactory.createEmptyBorder(0,0,0,0));
      
      cancel.setPreferredSize(new Dimension(115, 25));
      
      cancel.addActionListener(new CancelButtonListener());
      
      
      undo = new JButton(new ImageIcon(this.getClass().getResource
      (
         "files/images/InstallWizardUpNormal.png"))
      ); 
          
      
      undo.setRolloverIcon(new ImageIcon(this.getClass().getResource
      (
         "files/images/InstallWizardUpRollover.png"))
      );

      
      undo.setPressedIcon(new ImageIcon(this.getClass().getResource
      (
         "files/images/InstallWizardUpPressed.png"))
      );
      
      
      undo.setDisabledIcon(new ImageIcon(this.getClass().getResource
      (
         "files/images/InstallWizardUpDisabled.png"))
      );
      
      
      undo.setBorder(BorderFactory.createEmptyBorder(0,0,0,0));
      
      undo.addActionListener(new UndoBrowseListener());
      
      undo.setPreferredSize(new Dimension(41, 21));
      
      undo.setEnabled(false);
      
      
      
      // Initialize JPanel GUI components.
      
      scheduleButtonPanel = new JPanel(); 
      
      scheduleButtonPanel.setLayout(new GridLayout(2, 1));  
      
      
      inputPanel = new JPanel(); 
      
      inputPanel.setLayout (new FlowLayout(FlowLayout.LEADING));
      
      inputPanel.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0));
      

      channelPanel = new JPanel(); 
      
      channelPanel.setPreferredSize(new Dimension(100,63));
      
      channelPanel.setBorder(BorderFactory.createTitledBorder("Channels"));
      
      
      formatPanel = new JPanel(); 
      
      formatPanel.setPreferredSize(new Dimension(45,63));
      
      formatPanel.setBorder(BorderFactory.createTitledBorder("Format"));
      
      
      sampleRatePanel = new JPanel();
      
      sampleRatePanel.setPreferredSize(new Dimension(45,63));
      
      sampleRatePanel.setBorder(BorderFactory.createTitledBorder("Samples (Hz)"));
      
      
      sampleSizePanel = new JPanel();
      
      sampleSizePanel.setPreferredSize(new Dimension(70,63));
      
      sampleSizePanel.setBorder(BorderFactory.createTitledBorder("Bits"));
      
      
      volumePanel = new JPanel(); 
      
      formatPanel.setPreferredSize(new Dimension(50,63));
      
      volumePanel.setBorder(BorderFactory.createTitledBorder("Volume"));
      
      
      timeStartContainer = new JPanel(); 
      
      timeStartContainer.setBorder(BorderFactory.createTitledBorder("Record Start Time"));
      
      timeStartContainer.setLayout(new BoxLayout(timeStartContainer, BoxLayout.LINE_AXIS));
      
      
      timeFinishContainer = new JPanel(); 
      
      timeFinishContainer.setBorder(BorderFactory.createTitledBorder("Record Finish Time"));
      
      timeFinishContainer.setLayout(new BoxLayout(timeFinishContainer, BoxLayout.LINE_AXIS));
      
      
      recordPanel = new JPanel(); 
      
      recordPanel.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0));
      
      recordPanel.setLayout(new FlowLayout(FlowLayout.LEADING)); 
      
      
      queuePanel = new JPanel(); 
      
      queuePanel.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0));
      
      queuePanel.setLayout(new FlowLayout(FlowLayout.LEADING)); 
      
      
      activatePanel = new JPanel(); 
      
      activatePanel.setLayout(new GridLayout(3,1));
      
      
      browserPanel = new JPanel(); 
      
      browserPanel.setLayout(new FlowLayout());
      
      
      
      // Add GUI components to JPanels.

      timeStartContainer.add(timeStartHour); 
      
      timeStartContainer.add(Box.createRigidArea(new Dimension(10, 0)));
      
      timeStartContainer.add(timeStartMinute);
      
      timeStartContainer.add(Box.createRigidArea(new Dimension(10, 0)));
      
      timeStartContainer.add(timeStartSecond); 
      
      
      timeFinishContainer.add(timeFinishHour);
      
      timeFinishContainer.add(Box.createRigidArea(new Dimension(10, 0)));
      
      timeFinishContainer.add(timeFinishMinute); 
      
      timeFinishContainer.add(Box.createRigidArea(new Dimension(10, 0)));
      
      timeFinishContainer.add(timeFinishSecond);
      

      channelPanel.add(mono); channelPanel.add(stereo); 
      
      browserPanel.add(browserBox); browserPanel.add(undo); 
      
      scheduleButtonPanel.add(add); scheduleButtonPanel.add(clear);
      
      sampleSizePanel.add(sampleSizeBox); volumePanel.add(volumeSlider); 
      
      formatPanel.add(recordFormatBox);  sampleRatePanel.add(sampleRateBox);
      
      recordPanel.add(progressBar); recordPanel.add(start); recordPanel.add(cancel); 
      
      activatePanel.add(useSchedule); activatePanel.add(scheduleAddress); 
      
      activatePanel.add(urlDisplay); queuePanel.add(scrollPane);
    
      
      
      // Configure menu items.

      mainRadio.setSelected(true); saveMenuItem.setEnabled(false); clearMenuItem.setEnabled(false);
      


      // Method calls for GUI initialization.
      
      gridBagConstraints(); initialiseInputContainer(); setColors(); setGraphicIcons();
   }
   
   
   
   /**
    * Sets the background color.
    */
   private void setColors()
   {
      if (inputs != null)
      { 
         for (JRadioButton input : inputs) 
         {  
            input.setBackground
            (
               new Color (ColorFunctions.red(), ColorFunctions.green(), ColorFunctions.blue())
            );
         }
      } 
      
      contentPane.setBackground
      (
         new Color (ColorFunctions.red(), ColorFunctions.green(), ColorFunctions.blue())
      );
      
      timeStartContainer.setBackground
      (
         new Color (ColorFunctions.red(), ColorFunctions.green(), ColorFunctions.blue())
      );
      
      timeFinishContainer.setBackground
      (
         new Color (ColorFunctions.red(), ColorFunctions.green(), ColorFunctions.blue())
      );
      
      formatPanel.setBackground
      (
         new Color (ColorFunctions.red(), ColorFunctions.green(), ColorFunctions.blue())
      );
      
      inputPanel.setBackground
      (
         new Color (ColorFunctions.red(), ColorFunctions.green(), ColorFunctions.blue())
      );
     
      channelPanel.setBackground
      (
         new Color (ColorFunctions.red(), ColorFunctions.green(), ColorFunctions.blue())
      );
      
      browserPanel.setBackground
      (
         new Color (ColorFunctions.red(), ColorFunctions.green(), ColorFunctions.blue())
      );
      
      activatePanel.setBackground
      (
         new Color (ColorFunctions.red(), ColorFunctions.green(), ColorFunctions.blue())
      );
     
      scheduleButtonPanel.setBackground
      (
         new Color (ColorFunctions.red(), ColorFunctions.green(), ColorFunctions.blue())
      );
      
      recordPanel.setBackground
      (
         new Color (ColorFunctions.red(), ColorFunctions.green(), ColorFunctions.blue())
      );
      
      sampleRatePanel.setBackground
      (
         new Color (ColorFunctions.red(), ColorFunctions.green(), ColorFunctions.blue())
      );
      
      sampleSizePanel.setBackground
      (
         new Color (ColorFunctions.red(), ColorFunctions.green(), ColorFunctions.blue())
      );
      
      volumePanel.setBackground
      (
         new Color (ColorFunctions.red(), ColorFunctions.green(), ColorFunctions.blue())
      );
      
      queuePanel.setBackground
      (
         new Color (ColorFunctions.red(), ColorFunctions.green(), ColorFunctions.blue())
      );
      
      inputDisplay.setBackground
      (
         new Color (ColorFunctions.red(), ColorFunctions.green(), ColorFunctions.blue())
      );
      
      useSchedule.setBackground
      (
         new Color (ColorFunctions.red(), ColorFunctions.green(), ColorFunctions.blue())
      );
      
      waveSlider.setBackground
      (
         new Color (ColorFunctions.red(), ColorFunctions.green(), ColorFunctions.blue())
      );
      
      saveDesktop.setBackground
      (
         new Color (ColorFunctions.red(), ColorFunctions.green(), ColorFunctions.blue())
      );
      
      saveBrowse.setBackground
      (
         new Color (ColorFunctions.red(), ColorFunctions.green(), ColorFunctions.blue())
      );
      
      scheduleAddress.setBackground
      (
         new Color (ColorFunctions.red(), ColorFunctions.green(), ColorFunctions.blue())
      );
      
      urlDisplay.setBackground
      (
         new Color (ColorFunctions.red(), ColorFunctions.green(), ColorFunctions.blue())
      );
      
      queueDisplay.setBackground
      (
         new Color (ColorFunctions.red(), ColorFunctions.green(), ColorFunctions.blue())
      );
      
      mono.setBackground
      (
         new Color (ColorFunctions.red(), ColorFunctions.green(), ColorFunctions.blue())
      );
      
      stereo.setBackground
      (
         new Color (ColorFunctions.red(), ColorFunctions.green(), ColorFunctions.blue())
      );
      
      volumeSlider.setBackground
      (
         new Color (ColorFunctions.red(), ColorFunctions.green(), ColorFunctions.blue())
      );
      
      progressBar.setBackground
      (
         new Color (ColorFunctions.red(), ColorFunctions.green(), ColorFunctions.blue())
      );
   }
   
   
   
   /**
    * Sets icons for graphical elements.
    */
   private void setGraphicIcons()
   {
      mono.setIcon(new ImageIcon
      (this.getClass().getResource("files/images/RadioButtonNormalUnselected.png")));
             
      mono.setSelectedIcon(new ImageIcon
      (this.getClass().getResource("files/images/RadioButtonNormalSelected.png")));

      mono.setDisabledIcon(new ImageIcon
      (this.getClass().getResource("files/images/RadioButtonDisabledUnselected.png")));

      mono.setDisabledSelectedIcon(new ImageIcon
      (this.getClass().getResource("files/images/RadioButtonDisabledSelected.png")));
         
         
      stereo.setIcon(new ImageIcon
      (this.getClass().getResource("files/images/RadioButtonNormalUnselected.png")));
                     
      stereo.setSelectedIcon(new ImageIcon
      (this.getClass().getResource("files/images/RadioButtonNormalSelected.png")));

      stereo.setDisabledIcon(new ImageIcon
      (this.getClass().getResource("files/images/RadioButtonDisabledUnselected.png")));

      stereo.setDisabledSelectedIcon(new ImageIcon
      (this.getClass().getResource("files/images/RadioButtonDisabledSelected.png")));
      
      
      saveDesktop.setIcon(new ImageIcon
      (this.getClass().getResource("files/images/RadioButtonNormalUnselected.png")));
             
      saveDesktop.setSelectedIcon(new ImageIcon
      (this.getClass().getResource("files/images/RadioButtonNormalSelected.png")));

      saveDesktop.setDisabledIcon(new ImageIcon
      (this.getClass().getResource("files/images/RadioButtonDisabledUnselected.png")));

      saveDesktop.setDisabledSelectedIcon(new ImageIcon
      (this.getClass().getResource("files/images/RadioButtonDisabledSelected.png")));
      
      
      saveBrowse.setIcon(new ImageIcon
      (this.getClass().getResource("files/images/RadioButtonNormalUnselected.png")));
             
      saveBrowse.setSelectedIcon(new ImageIcon
      (this.getClass().getResource("files/images/RadioButtonNormalSelected.png")));

      saveBrowse.setDisabledIcon(new ImageIcon
      (this.getClass().getResource("files/images/RadioButtonDisabledUnselected.png")));

      saveBrowse.setDisabledSelectedIcon(new ImageIcon
      (this.getClass().getResource("files/images/RadioButtonDisabledSelected.png")));
         
         
      useSchedule.setIcon(new ImageIcon
      (this.getClass().getResource("files/images/CheckBoxNormalUnselected.png")));
                             
      useSchedule.setSelectedIcon(new ImageIcon
      (this.getClass().getResource("files/images/CheckBoxNormalSelected.png")));

      useSchedule.setDisabledIcon(new ImageIcon
      (this.getClass().getResource("files/images/CheckBoxDisabledUnselected.png")));

      useSchedule.setDisabledSelectedIcon(new ImageIcon
      (this.getClass().getResource("files/images/CheckBoxDisabledSelected.png")));
         
         
      scheduleAddress.setIcon(new ImageIcon
      (this.getClass().getResource("files/images/CheckBoxNormalUnselected.png")));
                                     
      scheduleAddress.setSelectedIcon(new ImageIcon
      (this.getClass().getResource("files/images/CheckBoxNormalSelected.png")));

      scheduleAddress.setDisabledIcon(new ImageIcon
      (this.getClass().getResource("files/images/CheckBoxDisabledUnselected.png")));

      scheduleAddress.setDisabledSelectedIcon(new ImageIcon
      (this.getClass().getResource("files/images/CheckBoxDisabledSelected.png")));
   
   }
   
   
   
   /**
    * Sets the grid bag layout.
    * ESCA-JAVA0076:
    */
   private void gridBagConstraints()
   {
      // Initialize grid bag layout of GUI.
      
      constraints = new GridBagConstraints();
      
      constraints.fill = GridBagConstraints.HORIZONTAL;
      
      
      
      // Grid bag constraints 1.
      
      constraints.insets = new Insets(25,0,0,0);
      
      
      constraints.ipadx = 0; 
      
      constraints.ipady = 0;

      constraints.gridwidth = 10;
      
      constraints.weightx = 0; 
      
      constraints.weighty = 0; 
      
      constraints.gridx = 0; 
      
      constraints.gridy = 0;
      
      
      contentPane.add(inputLabel, constraints);
      
     
      
      // Grid bag constraints 2.
      
      constraints.insets = new Insets(10,10,0,0);
      
      
      constraints.ipadx = 10; 
      
      constraints.ipady = 0;

      constraints.gridwidth = 10;
      
      constraints.weightx = 0; 
      
      constraints.weighty = 0; 
      
      constraints.gridx = 0; 
      
      constraints.gridy = 1;
      
      
      contentPane.add(inputDisplay, constraints);
      
      
      
      // Grid bag constraints 3.
      
      constraints.insets = new Insets(10,10,0,0);
      
      
      constraints.ipadx = 0; 
      
      constraints.ipady = 0;

      constraints.gridwidth = 10;
      
      constraints.weightx = 0; 
      
      constraints.weighty = 0; 
      
      constraints.gridx = 0; 
      
      constraints.gridy = 2;
      
      
      contentPane.add(inputPanel, constraints);
      
      
      
      // Grid bag constraints 4.
      
      constraints.insets = new Insets(20,0,0,0);
      
      
      constraints.ipadx = 0; 
      
      constraints.ipady = 0;

      constraints.gridwidth = 10;
      
      constraints.weightx = 0; 
      
      constraints.weighty = 0; 
      
      constraints.gridx = 0; 
      
      constraints.gridy = 3;
      
      
      contentPane.add(settingsLabel, constraints);
      
      
      
      // Grid bag constraints 5.
      
      constraints.insets = new Insets(10,10,0,0);
      
      
      constraints.ipadx = 0; 
      
      constraints.ipady = 0;

      constraints.gridwidth = 2;
      
      constraints.weightx = 0; 
      
      constraints.weighty = 0; 
      
      constraints.gridx = 0; 
      
      constraints.gridy = 4;
      
      
      contentPane.add(channelPanel, constraints);
      
      
      
      // Grid bag constraints 6.
      
      constraints.insets = new Insets(10,0,0,0);
      
      
      constraints.ipadx = 0; 
      
      constraints.ipady = 0;

      constraints.gridwidth = 2;
      
      constraints.weightx = 0; 
      
      constraints.weighty = 0; 
      
      constraints.gridx = 2; 
      
      constraints.gridy = 4;
      
      
      contentPane.add(formatPanel, constraints);
      
      
      
      // Grid bag constraints 7.
      
      constraints.insets = new Insets(10,0,0,0);
      
      
      constraints.ipadx = 0; 
      
      constraints.ipady = 0;

      constraints.gridwidth = 2;
      
      constraints.weightx = 0; 
      
      constraints.weighty = 0; 
      
      constraints.gridx = 4; 
      
      constraints.gridy = 4;
      
      
      contentPane.add(sampleRatePanel, constraints);
      
      
      
      // Grid bag constraints 8.
      
      constraints.insets = new Insets(10,0,0,0);
      
      
      constraints.ipadx = 0; 
      
      constraints.ipady = 0;

      constraints.gridwidth = 2;
      
      constraints.weightx = 0; 
      
      constraints.weighty = 0; 
      
      constraints.gridx = 6; 
      
      constraints.gridy = 4;
      
      
      contentPane.add(sampleSizePanel, constraints);
      
      
      
      // Grid bag constraints 9.
      
      constraints.insets = new Insets(10,0,0,0);
      
      
      constraints.ipadx = 0; 
      
      constraints.ipady = 0;

      constraints.gridwidth = 2;
      
      constraints.weightx = 0; 
      
      constraints.weighty = 0; 
      
      constraints.gridx = 8; 
      
      constraints.gridy = 4;
      
      
      contentPane.add(volumePanel, constraints);
      
      
      
      // Grid bag constraints 10.
      
      constraints.insets = new Insets(28,10,0,0);
      
      
      constraints.ipadx = 0; 
      
      constraints.ipady = 0;

      constraints.gridwidth = 6;
      
      constraints.weightx = 0; 
      
      constraints.weighty = 0; 
      
      constraints.gridx = 0; 
      
      constraints.gridy = 5;
      
      
      contentPane.add(queuePanel, constraints);
      
      
      
      // Grid bag constraints 11.
      
      constraints.insets = new Insets(28,10,0,0);
      
      
      constraints.ipadx = 0; 
      
      constraints.ipady = 0;

      constraints.gridwidth = 4;
      
      constraints.weightx = 0; 
      
      constraints.weighty = 0; 
      
      constraints.gridx = 6; 
      
      constraints.gridy = 5;
      
      
      contentPane.add(activatePanel, constraints);
      
      
      
      // Grid bag constraints 12.
      
      constraints.insets = new Insets(15,10,0,0);
      
      
      constraints.ipadx = 0; 
      
      constraints.ipady = 3;

      constraints.gridwidth = 3;
      
      constraints.weightx = 0; 
      
      constraints.weighty = 0; 
      
      constraints.gridx = 0; 
      
      constraints.gridy = 6;
      
      
      contentPane.add(timeStartContainer, constraints);
      
      
      
      // Grid bag constraints 13.
      
      constraints.insets = new Insets(15,10,0,0);
      
      
      constraints.ipadx = 0; 
      
      constraints.ipady = 3;

      constraints.gridwidth = 3;
      
      constraints.weightx = 0; 
      
      constraints.weighty = 0; 
      
      constraints.gridx = 3; 
      
      constraints.gridy = 6;
      
      
      contentPane.add(timeFinishContainer, constraints);
      
      
      
      // Grid bag constraints 14.
      
      constraints.insets = new Insets(15,10,0,0);
      
      
      constraints.ipadx = 0; 
      
      constraints.ipady = 0;

      constraints.gridwidth = 4;
      
      constraints.weightx = 0; 
      
      constraints.weighty = 0; 
      
      constraints.gridx = 7; 
      
      constraints.gridy = 6;
      
      
      contentPane.add(scheduleButtonPanel, constraints);
      
      
      
      // Grid bag constraints 15.
      
      constraints.anchor = GridBagConstraints.PAGE_END;
      
      constraints.insets = new Insets(30,0,0,0);
      
      
      constraints.ipadx = 0; 
      
      constraints.ipady = 0;

      constraints.gridwidth = 10;
      
      constraints.weightx = 0; 
      
      constraints.weighty = 1; 
      
      constraints.gridx = 0; 
      
      constraints.gridy = 7;
      
      
      contentPane.add(recordLabel, constraints);
      
      
      
      // Grid bag constraints 16.

      constraints.insets = new Insets(10,20,5,0);
      
      
      constraints.ipadx = 0; 
      
      constraints.ipady = 0;

      constraints.gridwidth = 10;
      
      constraints.weightx = 0; 
      
      constraints.weighty = 0; 
      
      constraints.gridx = 0; 
      
      constraints.gridy = 8;
      
      
      contentPane.add(recordPanel, constraints);
   }
   
   
   
   /**
    * Configures the output constraints.
    * ESCA-JAVA0076:
    */
   private void outputConstraints()
   {
      // Initialize grid bag layout of GUI.
     
      constraints = new GridBagConstraints();
      
      constraints.fill = GridBagConstraints.HORIZONTAL;
      
      
      
      // Grid bag constraints 1.
      
      constraints.insets = new Insets(25,0,0,0);
      
      
      constraints.ipadx = 0; 
      
      constraints.ipady = 0;

      constraints.gridwidth = 10;
      
      constraints.weightx = 0; 
      
      constraints.weighty = 0; 
      
      constraints.gridx = 0; 
      
      constraints.gridy = 0;
      
      
      contentPane.add(outputLabel, constraints);  
      
      
      
      // Grid bag constraints 2.
      
      constraints.insets = new Insets(25,10,0,0);
      
      
      constraints.ipadx = 0; 
      
      constraints.ipady = 0;

      constraints.gridwidth = 10;
      
      constraints.weightx = 0; 
      
      constraints.weighty = 0; 
      
      constraints.gridx = 0; 
      
      constraints.gridy = 1;
      
      
      contentPane.add(liveWave, constraints); 
      
      
      
      // Grid bag constraints 3.
      
      constraints.insets = new Insets(25,0,0,0);
      
      
      constraints.ipadx = 0; 
      
      constraints.ipady = 0;

      constraints.gridwidth = 10;
      
      constraints.weightx = 0; 
      
      constraints.weighty = 0; 
      
      constraints.gridx = 0; 
      
      constraints.gridy = 2;
      
      
      contentPane.add(waveSlider, constraints);
      
      
      
      // Grid bag constraints 4.
      
      constraints.anchor = GridBagConstraints.PAGE_END;
      
      constraints.insets = new Insets(25,0,0,0);
      
      
      constraints.ipadx = 0; 
      
      constraints.ipady = 0;

      constraints.gridwidth = 10;
      
      constraints.weightx = 0; 
      
      constraints.weighty = 1; 
      
      constraints.gridx = 0; 
      
      constraints.gridy = 3;
      
      
      contentPane.add(savingLabel, constraints);  
      
      
      
      // Grid bag constraints 5.
      
      constraints.insets = new Insets(25,0,0,25);
      
      
      constraints.ipadx = 100; 
      
      constraints.ipady = 0;

      constraints.gridwidth = 5;
      
      constraints.weightx = 0; 
      
      constraints.weighty = 0; 
      
      constraints.gridx = 0; 
      
      constraints.gridy = 4;
      
      
      contentPane.add(saveDesktop, constraints);  
      
      
      
      // Grid bag constraints 6.
      
      constraints.insets = new Insets(25,25,0,0);
      
      
      constraints.ipadx = 0; 
      
      constraints.ipady = 0;

      constraints.gridwidth = 5;
      
      constraints.weightx = 0; 
      
      constraints.weighty = 0; 
      
      constraints.gridx = 5; 
      
      constraints.gridy = 4;
      
      
      contentPane.add(saveBrowse, constraints);  
      
      
      
      // Grid bag constraints 7.
      
      constraints.insets = new Insets(25,0,80,0);
      
      
      constraints.ipadx = 0; 
      
      constraints.ipady = 0;

      constraints.gridwidth = 10;
      
      constraints.weightx = 0; 
      
      constraints.weighty = 0; 
      
      constraints.gridx = 0; 
      
      constraints.gridy = 5;
      
      
      contentPane.add(browserPanel, constraints);
   }
   
   
   //*************************************** END INITIALISATION CODE ***************************************//
   
    
   //************************************* START INTERFACE EVENT CODE **************************************//
   
   
   private class InputLineListener implements ActionListener
   {

      /**
       * Listen to input line record selection.
       * @param args
       */
      private InputLineListener(int args)
      {
         inputRadio = args;
      }

      public void actionPerformed(ActionEvent event)
      { 
         if (inputs[inputRadio].isSelected())
         {   
        
            inputDisplay.setText(" " + recorder.returnMixerName(inputRadio));
                
            recorder.setInputType(inputRadio);
             
         } 
          
      }

      int inputRadio;
   }
   
   
   public class FileFormatHandler implements ActionListener 
   {

      /** 
       * Listener for the sample rate box. 
       */
      public void actionPerformed(ActionEvent event) 
      {
         
         recorder.setFileExtension(((String)recordFormatBox.getSelectedItem()).toLowerCase());  
      }
   
   }
   
   
   
   public class SampleRateBoxHandler implements ActionListener 
   {

      /** 
       * Listener for the sample rate box. 
       */
      public void actionPerformed(ActionEvent event) 
      {
         
         recorder.setSampleRate(Integer.parseInt((String)sampleRateBox.getSelectedItem()));  
      }
   
   }
   
   
   
   public class SampleSizeBoxHandler implements ActionListener 
   {

      /** 
       * Listener for the sample size box. 
       */
      public void actionPerformed(ActionEvent event) 
      {
        
    
         recorder.setSampleSize(Integer.parseInt((String)sampleSizeBox.getSelectedItem()));  
      }
   
   }
   
   
   
   /**
    * Main radio listener. 
    * ESCA-JAVA0043:
    */
   private class MainRadioHandler implements ItemListener
   {
      
      public void itemStateChanged(ItemEvent event)
      {
         loadMainDisplay();
         
         contentPane.revalidate();
         
         contentPane.repaint();
      }
   }
   
   
   
   /**
    * Output radio listener.
    * ESCA-JAVA0043: 
    */
   private class OutputRadioHandler implements ItemListener
   {
      
      public void itemStateChanged(ItemEvent event)
      {
         loadOutputDisplay();
         
         contentPane.revalidate();
         
         contentPane.repaint();
      }
   }
   
   

   /**
    * Show working check box listener. 
    */
   private class ChannelsListener implements ActionListener
   {

      public void actionPerformed(ActionEvent event)
      {
         if (mono.isSelected())
         {
            recorder.setChannels(1);
         }
         
         if (stereo.isSelected())
         {
            recorder.setChannels(2);
         }
      }
   }
   
   
   
   /**
    * Scheduler check box listener. 
    */
   private class NormalScheduleClass implements ItemListener
   {
     
      public void itemStateChanged(ItemEvent event)
      {
         if (useSchedule.isSelected())
         {
            urlDisplay.setText("No Address");
            
            if (!isApplication)
            {
               scheduleAddress.setEnabled(true);
            }
            
         } 
         
         else
         {
            urlDisplay.setText("");
            
            if (!isApplication)
            {
               scheduleAddress.setEnabled(false);
            }         
         }
         
      }
   }
   
   
   
   /**
    * URL check box listener. 
    */
   private class AddressScheduleClass implements ItemListener
   { 
      public void itemStateChanged(ItemEvent event)
      {
      
         if (scheduleAddress.isSelected())
         {
            urlDisplay.setText(URL_PASTE_PROMPT);
            
            urlDisplay.setEnabled(true);
            
         } 
         
         else
         {
            urlDisplay.setText("No Address");
            
            urlDisplay.setEnabled(false);
            
         }
                
      }
            
   }
   
   
   
   private class BoundedChangeListener implements ChangeListener 
   {
  
     /**
       * This is the slider listener.
       */
      public void stateChanged(ChangeEvent changeEvent) 
      {
        
         Object source = changeEvent.getSource();

         if (source instanceof JSlider) 
         {
            JSlider theJSlider = (JSlider) source;
      
            if (!theJSlider.getValueIsAdjusting()) 
            {
               recorder.setRecordVolume(theJSlider.getValue());
            }
         }     
      }
   }
   
   
   
   private static class WaveZoomListener implements ChangeListener 
   {
  
     /**
       * This is the slider listener.
       */
      public void stateChanged(ChangeEvent changeEvent) 
      {
        
         Object source = changeEvent.getSource();

         if (source instanceof JSlider) 
         {
            JSlider theJSlider = (JSlider) source;
      
            if (!theJSlider.getValueIsAdjusting()) 
            {
               double value = 0.01 * theJSlider.getValue();
            
               
               AudioWaveform.setWidth
               (  
                  (int)(value * AudioWaveform.MAX_WIDTH + AudioWaveform.MIN_WIDTH)
               );
            }
         }     
      }
   }
   
   
   
   private class StartButtonListener implements ActionListener
   {
  
      /** 
       * Listener to start the recording. 
       */
      public void actionPerformed(ActionEvent event)
      {
         if (isInputSelected())
         {
            if (!startPressed)
            {
               setChapterRecordTime();
           
               if (!useSchedule.isSelected())
               {   
                  disableEnableControls(false);  
               
                  startPressed = true;
                     
                  recorder.setFileName("Record");  
                  
                  recorder.startRecord(); paintStopButton();
                             
                  new Progress(Procedure.START_RECORD).start();
               }
               
               else
               {
                  if ((!scheduleTimerRunning) && (recFileNumber.size() != 0)) 
                  {
                     disableEnableControls(false); runSchedule(); paintStopButton();
                     
                     activateProgressRefresher(Record.SCHEDULE_RECORD);
                  
                  }
               }
               
               runWaveformRefresh();
               
            }
         
            else
            {
               disableEnableControls(true);
           
               new Progress(Procedure.SAVE_FILE).start(); 
              
               new StopRecord().start(); paintStartButton();
            }
            
         }
      }
   }
   
   

   private class CancelButtonListener implements ActionListener
   {
  
      /** 
       * Listener to stop the recording. 
       */
      public void actionPerformed(ActionEvent event)
      {
         if (isInputSelected()) 
         {
            paintStartButton(); 
         
         
            if (startPressed)
            {
               recorder.cancelRecord(); progressTimer.cancel();
            
               startPressed = false; progressBar.setString("Recording Cancelled");
            }
         
            else
            {
               if (scheduleTimerRunning) 
               {
                  scheduleTimer.cancel(); progressTimer.cancel();
               
                  scheduleTimerRunning = false; progressBar.setString("Schedule Cancelled");
               }
            }
            
            if (startPressed) {waveformTimer.cancel();}
         
            disableEnableControls(true);
            
         }
      }
   }
  
   
   
   private class AddButtonListener implements ActionListener
   {
  
      private static final int ADDITION_MAX = 99;
  
      /** 
       * Listener to add info to scheduler.
       * ESCA-JAVA0266 
       */
      public void actionPerformed(ActionEvent event)
      {
         try
         {       
            if (useSchedule.isSelected() && (fileNameCount < ADDITION_MAX) 
            
            && (!urlDisplay.getText().equals(URL_PASTE_PROMPT)) && (isAfterReference())
            
            && (!isStartOverlapped()) && (!isFinishOverlapped()))
            {
               fileNameCount ++;
               
               
               writeToScheduleDisplay();
            
               addSchedulesToArrays();
            
               
               if (scheduleAddress.isSelected()) 
               {
                  urlDisplay.setText(URL_PASTE_PROMPT);
               }
               
               scheduleSet = true;
            
            }
         }
     
         catch (NumberFormatException e) 
         {System.out.println(Tools.thisPathAndLine() + e + "\n");}
      }
 
   }
   
   
   
   private class CheckSchedule extends TimerTask
   {

      /**
       * Displays the output and stops simulation if cycles exceeded. 
       */
      public void run()
      {
         testRecordActivation();
        
      }
   }
   
   
   
   private class RefreshWaveform extends TimerTask
   {

      /**
       * Displays the output and stops simulation if cycles exceeded. 
       */
      public void run()
      {
         icon = new ImageIcon(AudioWaveform.getBufferedImage());
         
         label.revalidate(); label.repaint(); 
      }
   }
   
   
   
   private class ClearButtonListener
   implements ActionListener
   {
  
      /** 
       * Listener to remove info from scheduler. 
       */
      public void actionPerformed(ActionEvent event)
      {
         if (scheduleAddress.isSelected()) 
         {
            urlDisplay.setText(URL_PASTE_PROMPT);
         } 
    
         queueDisplay.setText(""); scheduleSet = false;
         
         fileNameCount = 0; scheduledItemsRecorded = 0;
         
         recFileNumber.clear(); webAddress.clear(); 
         
         hourStart.clear(); minuteStart.clear();
         
         secondStart.clear(); hourFinish.clear(); 
         
         minuteFinish.clear(); secondFinish.clear();  
         
      }
   }
   
   
   
   private class StopRecord extends Thread 
   {

      private static final long RUN_DELAY = 600L;

      
      /** 
       * Thread that renders the audio file.
       */
      private StopRecord() 
      {
         setDaemon(true); 
         
      }
      
      
      /**
       * ESCA-JAVA0087:
       * ESCA-JAVA0266:
       */
      public void run() 
      {
         try {sleep(RUN_DELAY);}

         catch (InterruptedException e)
         {System.out.println(Tools.thisPathAndLine() + e + "\n");}

         recorder.stopRecord(); waveformTimer.cancel(); 
         
         
         startPressed = false;

         progressBar.setIndeterminate(false);
         
         progressBar.setString("Recording Completed");
      }
   }
   
   
   
   private class ProgressRefresher extends TimerTask
   {
      int seconds = 0; boolean schedule = false;
      
      
      /**
       * Sets the recording return type.
       * @param record
       * ESCA-JAVA0128: 
       */
      public ProgressRefresher(Record record)
      {
         if (record == Record.SCHEDULE_RECORD)
         {
            schedule = true;
         }
      }

      
      
      /**
       * Sets the progress bar elapsed time. 
       */
      public void run()
      {
         if (!schedule)
         {
            progressBar.setString("Recording (" + 
         
            DateAndTime.returnCounterTime(seconds, false) + ")");   
         }
         
         if (schedule)
         {
            progressBar.setString("Schedule Running (" + 
         
            DateAndTime.returnCounterTime(seconds, false) + ")");  
         }
         
         seconds ++;
      }
      
   }
   
   
   
   private class Progress extends Thread 
   {
      
      Procedure recorderAction;

      /**
       * Thread that controls progress bar.
       * @param procedure
       */
      private Progress(Procedure procedure) 
      {
         setDaemon(true);
         
         recorderAction = procedure;
      }
  
      
      /**
       * ESCA-JAVA0087:
       * ESCA-JAVA0266:
       */
      public void run() 
      {

         if (recorderAction == Procedure.START_RECORD)
         {        
            activateProgressRefresher(Record.NORMAL_RECORD);

         }
         
         else if (recorderAction == Procedure.SAVE_FILE)
         {
            progressTimer.cancel(); progressBar.setIndeterminate(true);
            
            progressBar.setString("Finalising Recording");
          
         }
         
      }
   }
   
   
   
   private class SaveHandler implements ItemListener
   {
      private String type; private ButtonGroup save;


      /**
       * Handles the install location.
       * @param handlerType
       */
      private SaveHandler (String handlerType)
      {
         type = handlerType; save = new ButtonGroup(); 
         
         save.add(saveDesktop); save.add(saveBrowse);
      }

      public void itemStateChanged(ItemEvent event)
      {
         if (type.equals("desktop"))
         {
            path = Tools.returnDesktopPath(); recorder.setSavePath(path);

            browserBox.setEnabled(false); undo.setEnabled(false);   
         }

         if (type.equals("browse"))
         {
            browserBox.setEnabled(true); undo.setEnabled(true);

            if (browserBox.getSelectedItem().equals("Select")) 
            {
               path = "";
            }

            else 
            {
               path = (String)browserBox.getSelectedItem();
            }
         }
      }
   }
   
   
   
   private class BrowseBoxListener   
   implements ActionListener
   {

      public void actionPerformed(ActionEvent event)
      {
         isValidDirectory();

         if (!invalidDirectory)
         {
            findPath(); setFolders(); 
            
            eraseList(); populateBox();
         }
      }
   }
   
   
   
   private class UndoBrowseListener
   implements ActionListener
   {

      public void actionPerformed(ActionEvent event)
      {
         eraseList(); path = "";

         String[] home = fBrowser.returnRoots();

         for (String element : home) 
         {
            browserBox.addItem(element);
         }
      }
   }
   
   
   
   public void focusGained(FocusEvent e) 
   {
      urlDisplay.setText("");
 
   }
   
   
   
   public void focusLost(FocusEvent e) {}
   
   
   
   /**
    * Overrides ComponentListener.
    */
   public void componentMoved(ComponentEvent e) {}
   
   
   public void componentResized(ComponentEvent e) {}
   
   
   public void componentShown(ComponentEvent e) {setContentDisplay(true);}
   
   
   public void componentHidden(ComponentEvent e) {setContentDisplay(false);}
   
   
   //************************************** END INTERFACE EVENT CODE ***************************************//
   
   
   //**************************************** START PUBLIC METHODS *****************************************//
  
   
   /**
    * Sets the visibility of the frame.
    */
   public void setVisibility()
   {
   
      if (isVisible) {frame.setVisible(true);}
      
      else {frame.setVisible(false);} 
   }
   
   

   /**
    * Displays or Hides contents of GUI.
    * @param shown
    */
   public void setContentDisplay(boolean shown)
   {
      menuBar.setVisible(shown);
         
      contentPane.setVisible(shown);
   }
   
   
   
   /**
    * Program stop.
    * ESCA-JAVA0266:
    */
   public void stop()
   {
      try 
      {
         recorder.cancelRecord();
      }
   
      catch (NullPointerException e) 
      {System.out.println(Tools.thisPathAndLine() + e + "\n");}
      
   }
   
   
   
   /**
    * Program destroy.
    * ESCA-JAVA0266:
    */
   public void destroy()
   {
      try 
      {
         recorder.cancelRecord();
      }
      
      catch (NullPointerException e) 
      {System.out.println(Tools.thisPathAndLine() + e + "\n");}  
      
   }
   
   
   
   /**
    * Opens a web page at a specified address from java script.
    * ESCA-JAVA0266:
    * @param address
    */
   public void openWebpage(String address)
   {
     
      try 
      {
         getAppletContext().showDocument
         (
            new URL("javascript:openPage(\"" + address + "\")")
         );
      }
   
      catch (MalformedURLException e) 
      {System.out.println(Tools.thisPathAndLine() + e + "\n");}
  
   }
   
   
   
   /**
    * Closes a web page from java script.
    * ESCA-JAVA0266:
    */
   public void closeWebpage()
   {
     
      try 
      {
         getAppletContext().showDocument
         (
            new URL("javascript:closePage()")
         );
      }
   
      catch (MalformedURLException e) 
      {System.out.println(Tools.thisPathAndLine() + e + "\n");}
  
   }
   
   
   //***************************************** END PUBLIC METHODS ******************************************//
   
   
   //**************************************** START PRIVATE METHODS ****************************************//
   
   
   /**
    * Reads settings from the database.
    */
   private void readFromDatabase()
   {
      recorderReadSettings = new ArrayList<String>(); fileNameCount = 0;
      
      recorderReadSettings = Portal.phpToJavaGate(RECORDER_READ_ADDRESS, userId, userPw, null);
      
      
      if (recorderReadSettings.size() != 0)
      {
         int input = Integer.parseInt(recorderReadSettings.get(SQL_TABLE_COLUMN_A));  
         
         
         if (recorder.returnMixerArrayLength() == 0)
         {
            inputDisplay.setText(" No recording ports detected on your computer");
         } 
     
         else if (input > recorder.returnMixerArrayLength()) {setRecordInput("1");}    
         
         else {setRecordInput(recorderReadSettings.get(SQL_TABLE_COLUMN_A));}
      
         setRecordChannels(recorderReadSettings.get(SQL_TABLE_COLUMN_B));
         
         setRecordFormat(recorderReadSettings.get(SQL_TABLE_COLUMN_C));
      
         setRecordSamples(recorderReadSettings.get(SQL_TABLE_COLUMN_D));
      
         setRecordDepth(recorderReadSettings.get(SQL_TABLE_COLUMN_E));

         setRecordVolume(recorderReadSettings.get(SQL_TABLE_COLUMN_F));
         
         setNormalSchedule(recorderReadSettings.get(SQL_TABLE_COLUMN_G));
         
         setAddressSchedule(recorderReadSettings.get(SQL_TABLE_COLUMN_H));
      }
      
      initialiseScheduleFromDatabase();
      
   }
   
   
   
   /**
    * Reads the record schedule from the database.
    */
   private void initialiseScheduleFromDatabase()
   {
      scheduleReadSettings = new ArrayList<String>();
      
      scheduleReadSettings = Portal.phpToJavaGate(SCHEDULE_READ_ADDRESS, userId, userPw, null);
      
      
      if (scheduleReadSettings.size() != 0)
      {
         int rows = scheduleReadSettings.size() / SCHEDULE_ROW_LENGTH;
     
     
         for (int i = 0; i < rows; i ++)
         {
             fileNameCount ++;      
             
             populateRecordScheduleDisplay(i);  
          
             populateRecordScheduleArrays(i);
             
         }
         
      }
           
   }
   
   
   
   /**
    * Populates the record schedule display.
    * @param index
    */
   private void populateRecordScheduleDisplay(int index)
   {
      queueDisplay.append
       
       (
          " Record(" + DateAndTime.returnDigitMask
            (fileNameCount,2) + ").wav" + Tools.returnSpace(5)
       
          + DateAndTime.returnDigitMask(Integer.parseInt
            (scheduleReadSettings.get(SQL_TABLE_COLUMN_B + (SCHEDULE_ROW_LENGTH * index))), 2) + ":" 
            
          + DateAndTime.returnDigitMask(Integer.parseInt
            (scheduleReadSettings.get(SQL_TABLE_COLUMN_C + (SCHEDULE_ROW_LENGTH * index))), 2) + ":" 
            
          + DateAndTime.returnDigitMask(Integer.parseInt
            (scheduleReadSettings.get(SQL_TABLE_COLUMN_D + (SCHEDULE_ROW_LENGTH * index))), 2)
            
          + " - " 
            
          + DateAndTime.returnDigitMask(Integer.parseInt
            (scheduleReadSettings.get(SQL_TABLE_COLUMN_E + (SCHEDULE_ROW_LENGTH * index))), 2) + ":" 
            
          + DateAndTime.returnDigitMask(Integer.parseInt
            (scheduleReadSettings.get(SQL_TABLE_COLUMN_F + (SCHEDULE_ROW_LENGTH * index))), 2) + ":" 
            
          + DateAndTime.returnDigitMask(Integer.parseInt
            (scheduleReadSettings.get(SQL_TABLE_COLUMN_G + (SCHEDULE_ROW_LENGTH * index))), 2) 
            
          + Tools.returnSpace(5) + "Loaded" + Tools.returnNewline(1)
      
       );    
   
   }
   
   
   
   /**
    * Populates the record schedule arrays.
    * @param index
    */
   private void populateRecordScheduleArrays(int index)
   {
      recFileNumber.add(fileNameCount);
       
      webAddress.add(scheduleReadSettings.get(SQL_TABLE_COLUMN_A 
      + (SCHEDULE_ROW_LENGTH * index))); 
       
      hourStart.add(Integer.parseInt(scheduleReadSettings.get(SQL_TABLE_COLUMN_B 
      + (SCHEDULE_ROW_LENGTH * index)))); 
       
      minuteStart.add(Integer.parseInt(scheduleReadSettings.get(SQL_TABLE_COLUMN_C 
      + (SCHEDULE_ROW_LENGTH * index))));
       
      secondStart.add(Integer.parseInt(scheduleReadSettings.get(SQL_TABLE_COLUMN_D 
      + (SCHEDULE_ROW_LENGTH * index)))); 
       
      hourFinish.add(Integer.parseInt(scheduleReadSettings.get(SQL_TABLE_COLUMN_E 
      + (SCHEDULE_ROW_LENGTH * index)))); 
       
      minuteFinish.add(Integer.parseInt(scheduleReadSettings.get(SQL_TABLE_COLUMN_F 
      + (SCHEDULE_ROW_LENGTH * index)))); 
       
      secondFinish.add(Integer.parseInt(scheduleReadSettings.get(SQL_TABLE_COLUMN_G 
      + (SCHEDULE_ROW_LENGTH * index))));   
   }
   
   
   
   /**
    * Transfers the settings to the database.
    */
   private void transferToDatabase()
   { 
   
      writeScheduleToDatabase();
     
      
      writeSettings = new ArrayList<String>();
      
      writeSettings.add(getRecordInput());
      
      writeSettings.add(getRecordChannels());
      
      writeSettings.add(getRecordFormat());
      
      writeSettings.add(getRecordSamples());
      
      writeSettings.add(getRecordDepth());
      
      writeSettings.add(getRecordVolume());
      
      writeSettings.add(getNormalSchedule());
      
      writeSettings.add(getAddressSchedule());
      
      
      Portal.javaToPhpGate(RECORDER_WRITE_ADDRESS, userId, userPw, writeSettings);
 
   }
   
   
   
   /**
    * Writes the schedule to the database.
    */
   private void writeScheduleToDatabase()
   {

      Portal.clearFromDatabase(SCHEDULE_CLEAR_ADDRESS, userId, userPw, null);

      
      for (int i = 0; i < recFileNumber.size(); i ++)
      {
         scheduleSettings = new ArrayList<String>();
         
         scheduleSettings.add(webAddress.get(i));   
         
         scheduleSettings.add(Integer.toString(hourStart.get(i))); 
         
         scheduleSettings.add(Integer.toString(minuteStart.get(i))); 
         
         scheduleSettings.add(Integer.toString(secondStart.get(i))); 
         
         scheduleSettings.add(Integer.toString(hourFinish.get(i)));  
         
         scheduleSettings.add(Integer.toString(minuteFinish.get(i)));
         
         scheduleSettings.add(Integer.toString(secondFinish.get(i)));
         
        
         Portal.javaToPhpGate(SCHEDULE_WRITE_ADDRESS, userId, userPw, scheduleSettings); 
         
      }
   
   }

   
   
   /**
    * Clears the settings from the database.
    */
   private void clearDatabase()
   { 
      Portal.clearFromDatabase(RECORDER_CLEAR_ADDRESS, userId, userPw, null); 
      
      Portal.clearFromDatabase(SCHEDULE_CLEAR_ADDRESS, userId, userPw, null); 
      
   }
   
   
   
   /**
    * Starts and stops the recording as 
    * controlled by the scheduled information.
    */
   private void testRecordActivation()
   {
      if (!scheduleIsRecording) {startScheduledRecording();}  
         
      else {stopScheduledRecording();}
         
   }
   
   
   
   /**
    * Starts the scheduled recording if 
    * the current time falls in the 
    * range of a set schedule.
    */
   private void startScheduledRecording()
   {
      for (int i = 0; i < fileNameCount; i ++)
      {
         if (DateAndTime.isBeforeCurrentTime
         (hourStart.get(i), minuteStart.get(i), secondStart.get(i)) 
         
         && (!DateAndTime.isBeforeCurrentTime
         (hourFinish.get(i), minuteFinish.get(i), secondFinish.get(i))))
         {
            recorder.setFileName("Record(" + (i+1) + ")");
            
            
            if (scheduleAddress.isSelected()) { openWebpage(webAddress.get(i));}
            
            
            recorder.startRecord(); scheduleInfoIndex = i; scheduleIsRecording = true;  
         }       
      }   
   }
   
   
   
   /**
    * Stops the scheduled recording if 
    * the current time falls outside 
    * the range of a set schedule.
    */
   private void stopScheduledRecording()
   {
      if (DateAndTime.isBeforeCurrentTime(hourFinish.get(scheduleInfoIndex), 
      minuteFinish.get(scheduleInfoIndex), secondFinish.get(scheduleInfoIndex)))      
      {
         recorder.stopRecord(); scheduleIsRecording = false; scheduledItemsRecorded ++; 

         
         if (scheduledItemsRecorded == recFileNumber.size())
         {
            scheduleTimer.cancel(); progressTimer.cancel(); disableEnableControls(true);
               
            scheduleTimerRunning = false; progressBar.setIndeterminate(false);
               
            progressBar.setString("Scheduled Record Complete");
            
            paintStartButton();
         }
         
         if (scheduleAddress.isSelected()) {closeWebpage();} 
      }  
   }
   
   
   
   /**
    * Writes record schedule 
    * information to the schedule display.
    */
   private void writeToScheduleDisplay()
   {
      if (scheduleSet) {queueDisplay.append(Tools.returnNewline(1));}

      
      queueDisplay.append
       (

          " Record(" + DateAndTime.returnDigitMask(fileNameCount,2) + ").wav" + 
          
          Tools.returnSpace(5) + DateAndTime.returnDigitMask(getStartHour(),2) + ":" + 
          
          DateAndTime.returnDigitMask(getStartMinute(),2) + ":" + 
          
          DateAndTime.returnDigitMask(getStartSecond(),2) + " - " + 
          
          DateAndTime.returnDigitMask(getFinishHour(),2) + ":" + 
          
          DateAndTime.returnDigitMask(getFinishMinute(),2) + ":" + 
          
          DateAndTime.returnDigitMask(getFinishSecond(),2) + Tools.returnSpace(5) + 
          
          getScheduleAddressStatus()
       
       );  
   }
   
   
   
   /**
    * Adds the set schedule to the schedule arrays.
    */
   private void addSchedulesToArrays()
   {
      recFileNumber.add(fileNameCount); webAddress.add(urlDisplay.getText()); 
       
      hourStart.add(getStartHour()); minuteStart.add(getStartMinute()); 
       
      secondStart.add(getStartSecond()); hourFinish.add(getFinishHour()); 
       
      minuteFinish.add(getFinishMinute()); secondFinish.add(getFinishSecond());  
   }
   
   
   
   /**
    * paints the start button.
    */
   private void paintStartButton()
   {
      start.setIcon(new ImageIcon
      (this.getClass().getResource("files/images/AudioRecorderStartNormal.png"))); 
      
      start.setRolloverIcon(new ImageIcon
      (this.getClass().getResource("files/images/AudioRecorderStartRollover.png")));

      start.setPressedIcon(new ImageIcon
      (this.getClass().getResource("files/images/AudioRecorderStartPressed.png")));
      
   }
   
   
   
   /**
    * Paints the stop button.
    */
   private void paintStopButton()
   {
      start.setIcon(new ImageIcon
      (this.getClass().getResource("files/images/AudioRecorderStopNormal.png"))); 
      
      start.setRolloverIcon(new ImageIcon
      (this.getClass().getResource("files/images/AudioRecorderStopRollover.png")));

      start.setPressedIcon(new ImageIcon
      (this.getClass().getResource("files/images/AudioRecorderStopPressed.png")));
      
   }
   
   
   
   /**
    * Disables or enables the controls.
    * ESCA-JAVA0266:
    * @param type
    */
   private void disableEnableControls(boolean type)
   {
      try
      {
         for (JRadioButton input : inputs) 
         {
            input.setEnabled(type);
         }
      }
      
      catch (NullPointerException e) 
      {System.out.println(Tools.thisPathAndLine() + e + "\n");}
 
  
      mono.setEnabled(type); stereo.setEnabled(type); 
      
      recordFormatBox.setEnabled(type); sampleRateBox.setEnabled(type); 
      
      sampleSizeBox.setEnabled(type); volumeSlider.setEnabled(type);
      
   }
   
   
   
   /**
    * initializes the input container.
    */
   private void initialiseInputContainer()
   {
      inputPanel.revalidate(); inputPanel.repaint();
   }
   
   
   
   /**
    * Refreshed the audio port selection.
    */
   private void searchAudioPorts()
   {
      if (!runRestricted) 
      {
         recorder.setValidMixers();
      } 
      
      setInputs(); initialiseInputContainer();  
      
      if ((!(userId == null)) && (!userId.equals("NON_MEMBER")) && (!runRestricted)) 
      {saveMenuItem.setEnabled(true); clearMenuItem.setEnabled(true); readFromDatabase();}
       
   }
   
   
   
   /**
    * Runs the record scheduler.
    */
   private void runWaveformRefresh()
   { 
      waveformTimer = new Timer();
      
      waveformTimer.schedule(new RefreshWaveform(), 0, WAVEFORM_REFRESH_RATE);
   }
   
   
   
   /**
    * Runs the record scheduler.
    */
   private void runSchedule()
   { 
      scheduleTimer = new Timer(); scheduleTimerRunning = true;
      
      scheduleTimer.schedule(new CheckSchedule(), 0, SCHEDULE_REFRESH_RATE);
   }
   
   
   
   /**
    * Activates the progress bar refresher.
    * @param record
    */
   private void activateProgressRefresher(Record record)
   {
      final int SPEED = 1000; progressTimer = new Timer(); 
      
      progressTimer.schedule (new ProgressRefresher(record), 0, SPEED);    
   }
   
   
   
   /**
    * Adds save mode menu item and listener that responds appropriately.
    * @return menuItem 
    */
   private JMenuItem saveMode() 
   {

      saveMenuItem = new JMenuItem("Save Settings");
   
      class MenuItemListener implements ActionListener
      {
         public void actionPerformed(ActionEvent event)  
         {
            transferToDatabase();
            
         }
      }

      ActionListener listener = new MenuItemListener(); 
      saveMenuItem.addActionListener(listener);

      return saveMenuItem;
   }
   
   
   
   /**
    * Adds a port refresh menu item and responds appropriately.
    * @return menuItem 
    */
   private JMenuItem refreshMode() 
   {

      JMenuItem refreshMenuItem = new JMenuItem("Search");
   
      class MenuItemListener implements ActionListener
      {
         public void actionPerformed(ActionEvent event)  
         {    
            searchAudioPorts();
            
         }
      }

      ActionListener listener = new MenuItemListener(); 
      refreshMenuItem.addActionListener(listener);

      return refreshMenuItem;
   }
   
   
   
   /**
    * Adds clear mode menu item and listener that responds appropriately.
    * @return menuItem 
    */
   private JMenuItem clearMode() 
   {

      clearMenuItem = new JMenuItem("Clear Settings");
   
      class MenuItemListener implements ActionListener
      {
         public void actionPerformed(ActionEvent event)  
         {
            
            clearDatabase();
         }
      }

      ActionListener listener = new MenuItemListener(); 
      clearMenuItem.addActionListener(listener);

      return clearMenuItem;
   }
   
   
   
   /**
    * Adds a file menu. 
    * @return menu
    */
   private JMenu createFileMenu()
   {

      JMenu menu = new JMenu("File"); 
      
      menu.add(saveMode()); 
      
      menu.add(clearMode());

      return menu;
   }
   
   
   
   /**
    * Adds a input menu. 
    * @return menu
    */
   private JMenu createInputMenu()
   {

      JMenu menu = new JMenu("Input"); 
      
      menu.add(refreshMode()); 
      
      return menu;
   }
   
   
   
   /**
    * Adds a view menu. 
    * @return menu
    */
   private JMenu createSettingsMenu()
   {

      JMenu menu = new JMenu("Settings"); 
      
      
      ButtonGroup viewGroup = new ButtonGroup();
      
      
      mainRadio = new JRadioButtonMenuItem("Main Display");
      
      mainRadio.addItemListener(new MainRadioHandler());
      
      outputRadio = new JRadioButtonMenuItem("Output Display");
      
      outputRadio.addItemListener(new OutputRadioHandler());
      
      
      viewGroup.add(mainRadio); viewGroup.add(outputRadio);
      
      
      menu.add(mainRadio); menu.add(outputRadio);
      
      
      return menu;
   }
   
   
   
   /**
    * Returns true if an input selection has been made.
    * @return
    */
   private boolean isInputSelected()
   {
      boolean selection = false; 
   
      if (recorder.returnMixerArrayLength() != 0)
      {
         for (JRadioButton input : inputs) 
         {
            if (input.isSelected())
            {
               selection = true; break;
            }
         }
      }
      
      return selection;
   }
   
   
   
   /**
    * Tests if schedule is after reference.
    * @return
    */
   private boolean isAfterReference()
   {
      return 
   
      DateAndTime.isAfterReferenceTime(getStartHour(), getStartMinute(), 
      getStartSecond(), getFinishHour(), getFinishMinute(), getFinishSecond());
   
   }
   
   
   
   /**
    * Tests if start schedule to be 
    * added overlaps already stored entries.
    * @return
    */
   private boolean isStartOverlapped()
   {
      return
      
      DateAndTime.isOverlapped(hourStart, minuteStart, 
      secondStart, hourFinish, minuteFinish, secondFinish, 
      getStartHour(), getStartMinute(), getStartSecond(), fileNameCount);
   
   }
   
   
   
   /**
    * Tests if finish schedule to be 
    * added overlaps already stored entries.
    * @return
    */
   private boolean isFinishOverlapped()
   {
      return 
 
      DateAndTime.isOverlapped(hourStart, minuteStart, 
      secondStart, hourFinish, minuteFinish, secondFinish, 
      getFinishHour(), getFinishMinute(), getFinishSecond(), fileNameCount); 
  
   }
   
   
   
   /**
    * Sets the folders.
    */
   private void setFolders()
   {
      fBrowser.setDirectoryList(new File(path), false);
   }

   

   /**
    * Erases the list.
    */
   private void eraseList()
   {
      browserBox.removeAllItems();
   }



   /**
    * Populates the box.
    */
   private void populateBox()
   {
      browserBox.addItem(path); 

      for (int i = 0; i < fBrowser.folderList.length; i ++)
      {
         browserBox.addItem(fBrowser.folderList[i]);
      }
   }
   
   
   
   /**
    * Sets the path.
    */
   private void findPath()
   {
      String selectedDirectory = (String)browserBox.getSelectedItem(); 

      if ((!selectedDirectory.equals(path)))
      {
         if (rootStep)
         {
            path += selectedDirectory;
            
            rootStep = false; 
         }

         else
         {
            path += (selectedDirectory + "\\"); 
         }
      }
      
      recorder.setSavePath(path);
   }
   
   
   
   /**
    * Tests if a directory is valid.
    */
   private void isValidDirectory()
   {
      invalidDirectory = false;
      
      String selectedDirectory = (String)browserBox.getSelectedItem(); 

      try
      {
         if (rootStep)
         {
            fBrowser.setDirectoryList(new File(selectedDirectory), false);
         }

         else
         {
            fBrowser.setDirectoryList(new File(path + selectedDirectory), false);
         }
      }

      catch (java.lang.NullPointerException e)
      {
         invalidDirectory = true;
      }
   }
   
   
   
   /**
    * Sets the record inputs
    */
   private void setInputs()
   {
      inputPanel.removeAll(); ButtonGroup select = new ButtonGroup();
      
      inputs = new JRadioButton[recorder.returnMixerArrayLength()];

      for (int i = 0; i < recorder.returnMixerArrayLength(); i ++)
      {
         inputs[i] = new JRadioButton("Input " + (i + 1), false);
         
         
         inputs[i].setBackground
         (
            new Color
            (
               ColorFunctions.red(), ColorFunctions.green(), ColorFunctions.blue()
            )
         );
         
         
         inputs[i].setIcon(new ImageIcon
         (this.getClass().getResource("files/images/RadioButtonNormalUnselected.png")));
             
         inputs[i].setSelectedIcon(new ImageIcon
         (this.getClass().getResource("files/images/RadioButtonNormalSelected.png")));

         inputs[i].setDisabledIcon(new ImageIcon
         (this.getClass().getResource("files/images/RadioButtonDisabledUnselected.png")));

         inputs[i].setDisabledSelectedIcon(new ImageIcon
         (this.getClass().getResource("files/images/RadioButtonDisabledSelected.png")));
         

         inputs[i].setFocusPainted(false); 
         
         select.add(inputs[i]); inputPanel.add(inputs[i]);
         
         inputs[i].addActionListener(new InputLineListener(i));
      }
        
      if (recorder.returnMixerArrayLength() > 0)
      {
         inputPanel.setLayout(new FlowLayout(FlowLayout.LEADING, 
         getInputHorizontalPadding(), INPUT_PADDING_Y)); 
    
         inputDisplay.setText(" Select from available recording inputs below");
         
         inputPanel.setVisible(true);
      }
         
      else 
      {
         
         inputDisplay.setText(" No inputs available to record from");
      }
      
   }
   
   
   
   /**
    * Sets the maximum recording time for a record chapter.
    */
   private void setChapterRecordTime()
   {
      double channelsFactor = 1; double rateFactor = 1; double sizeFactor = 1; 
       
      if (stereo.isSelected()) {channelsFactor = 0.5;}
      
      rateFactor = Double.parseDouble(sampleRateBox.getItemAt(0)) 
      / Integer.parseInt((String)sampleRateBox.getSelectedItem());
        
      sizeFactor = Double.parseDouble(sampleSizeBox.getItemAt(0)) 
      / Integer.parseInt((String)sampleSizeBox.getSelectedItem());
         
      recorder.setAllowedRecordSeconds
      (
         (int)(MAX_CHAPTER_TIME * channelsFactor * rateFactor * sizeFactor)
      );
   
   }
   
   
   
   /**
    * Sets the record input.
    * @param type
    */
   private void setRecordInput(String type)
   {
      inputs[Integer.parseInt(type)-1].setSelected(true);
      
      recorder.setInputType(Integer.parseInt(type)-1);
      
      inputDisplay.setText(" " + recorder.returnMixerName(Integer.parseInt(type)-1));
       
   }
   
   
   
   /**
    * Sets the record input.
    * @param type
    */
   private void setRecordChannels(String type)
   {
     if (type.equals("1"))
     {
        mono.setSelected(true);
     }
     
     if (type.equals("2"))
     {
        stereo.setSelected(true);
     }
      
     recorder.setChannels(Integer.parseInt(type));
          
   }
   
   
   
   /**
    * Sets the record format setting.
    * @param value
    */
   private void setRecordFormat(String value)
   {
      if (value.equals("AIFF"))
      {
         recordFormatBox.setSelectedIndex(0);
      }
  
      if (value.equals("WAV"))
      {
         recordFormatBox.setSelectedIndex(1);
      }

      recorder.setRecordFormat(value.toLowerCase());
      
   }
   
   
   
   /**
    * Sets the record channel setting.
    * @param value
    */
   private void setRecordSamples(String value)
   {
      if (value.equals("44100"))
      {
         sampleRateBox.setSelectedIndex(0);
      }
  
      if (value.equals("48000"))
      {
         sampleRateBox.setSelectedIndex(1);
      }
       
      if (value.equals("96000"))
      {
         sampleRateBox.setSelectedIndex(2);
      }
 
      if (value.equals("192000"))
      {
         sampleRateBox.setSelectedIndex(3);
      }

      recorder.setSampleRate(Integer.parseInt(value));
      
   }
   
   
   
   /**
    * Sets the record channel setting.
    * @param value
    */
   private void setRecordDepth(String value)
   {
      if (value.equals("8"))
      {
         sampleSizeBox.setSelectedIndex(0);
      }

      if (value.equals("16"))
      {
         sampleSizeBox.setSelectedIndex(1);
      }
      
      recorder.setSampleSize(Integer.parseInt(value));
   }
   
   
   
   /**
    * Sets the record volume.
    * @param value
    */
   private void setRecordVolume(String value)
   {
      volumeSlider.setValue(Integer.parseInt(value));
      
      recorder.setRecordVolume(volumeSlider.getValue());
      
   }
   
   
   
   /**
    * Sets the schedule active check box.
    * @param value
    */
   private void setNormalSchedule(String value)
   {
      if (value.equals("0"))
      {
         useSchedule.setSelected(false);
         
         scheduleAddress.setEnabled(false);
      }
      
      if (value.equals("1"))
      {
         urlDisplay.setText("No Address");
         
         useSchedule.setSelected(true);
         
         scheduleAddress.setEnabled(true);
      }
   
   }
   
   
   
   /**
    * Sets the web schedule check box.
    * @param value
    */
   private void setAddressSchedule(String value)
   {
      if (value.equals("0"))
      {
         scheduleAddress.setSelected(false);  
         
         urlDisplay.setEnabled(false);
      }
      
      if (value.equals("1"))
      {
         urlDisplay.setText(URL_PASTE_PROMPT);
         
         scheduleAddress.setSelected(true);  
         
         urlDisplay.setEnabled(true);
      }
   
   }
   
   
   
   /**
    * Returns the horizontal padding for the input radio buttons.
    * ESCA-JAVA0076:
    * @return
    */
   private int getInputHorizontalPadding()
   {   
      int number = recorder.returnMixerArrayLength();
      int padding = 0;

      switch (number)
      {
         case 1: padding = 200; break; case 2: padding = 100; break;  
         
         case 3: padding = 67;  break; case 4: padding = 40;  break;
         
         case 5: padding = 23;  break; case 6: padding = 11;  break;
         
         case 7: padding = 2;   break;

         default: break;
      }
      
      return padding;
   }
   
   
   
   /**
    * Returns the URL status of the record schedule.
    * @return
    */
   private String getScheduleAddressStatus()
   {
      if (scheduleAddress.isSelected())
      {
         return "Address";
      }
   
      else 
      {
         return "No Address";
      }   
   }
   
   
   
   /**
    * Returns the record input setting.
    * @return
    */
   private String getRecordInput()
   {
      int input = 0;
      
      for (int i = 0; i < inputs.length; i ++)
      {
         if (inputs[i].isSelected())
         {
            input = (i + 1);
         }
      } 
      
      return Integer.toString(input);
   }
   
   
   
   /**
    * Returns the record channel setting.
    * @return
    */
   private String getRecordChannels()
   {
      String channels = ""; 
  
      if (mono.isSelected())
      {
         channels = "1";
     
      }
      
      if (stereo.isSelected())
      {
         channels = "2";
      }
      
      return channels;
   }



   /**
    * Returns the record channel setting.
    * @return
    */
   private String getRecordFormat()
   {
      String format = "";
      
      format = (String)recordFormatBox.getSelectedItem();
      
      return format;
   }
   
   
   
   /**
    * Returns the record channel setting.
    * @return
    */
   private String getRecordSamples()
   {
      String samples = "";
      
      samples = (String)sampleRateBox.getSelectedItem();
      
      return samples;
   }
   
   
   
   /**
    * Returns the record channel setting.
    * @return
    */
   private String getRecordDepth()
   {
      String depth = "";
      
      depth = (String)sampleSizeBox.getSelectedItem();
      
      return depth;
   }
   
   
   
   /**
    * Returns the record channel setting.
    * @return
    */
   private String getRecordVolume()
   {
      String volume = "";
      
      volume = Integer.toString(volumeSlider.getValue());
      
      return volume;
   }
   
   
   
   /**
    * Returns the normal schedule setting.
    * @return
    */
   private String getNormalSchedule()
   {
      String normalSchedule = "";
   
      if (useSchedule.isSelected()) {normalSchedule = "1";}
      
      else {normalSchedule = "0";}
      
      
      return normalSchedule;
   }
   
   
   
   /**
    * Returns the address schedule setting.
    * @return
    */
   private String getAddressSchedule()
   {
      String addressSchedule = "";
   
      if (scheduleAddress.isSelected()) {addressSchedule = "1";}
      
      else {addressSchedule = "0";}
   
      
      return addressSchedule;
   }
   
   
   
   /**
    * Returns the combo box record start hour.
    * @return
    */
   private int getStartHour()
   {
      return (Integer.parseInt((String)timeStartHour.getSelectedItem()));
   }
   
   
   
   /**
    * Returns the combo box record start minute.
    * @return
    */
   private int getStartMinute()
   {
      return (Integer.parseInt((String)timeStartMinute.getSelectedItem()));
   }
   
   
   
   /**
    * Returns the combo box record start second.
    * @return
    */
   private int getStartSecond()
   {
      return (Integer.parseInt((String)timeStartSecond.getSelectedItem()));
   }
   
   
   
   /**
    * Returns the combo box record finish hour.
    * @return
    */
   private int getFinishHour()
   {
      return (Integer.parseInt((String)timeFinishHour.getSelectedItem()));
   }
   
   
   
   /**
    * Returns the combo box record finish minute.
    * @return
    */
   private int getFinishMinute()
   {
      return (Integer.parseInt((String)timeFinishMinute.getSelectedItem()));
   }
   
   
   
   /**
    * Returns the combo box record finish second.
    * @return
    */
   private int getFinishSecond()
   {
      return (Integer.parseInt((String)timeFinishSecond.getSelectedItem()));
   }
   
   
   
   /**
    * Loads the main display.
    */
   private void loadMainDisplay()
   {
      contentPane.removeAll();
      
      gridBagConstraints();
   }
   
   
   
   /**
    * Loads the output display.
    */
   private void loadOutputDisplay()
   {
      contentPane.removeAll();
      
      outputConstraints();
   }  
   
   
   
   /**
    * Window resize event.
    */
   private void includeResizeEvent()
   {
      this.addComponentListener 
      (
         new ComponentAdapter() 
         {
            public void componentResized(ComponentEvent e) 
            {
               appletDisplayHandler();
            }
          
         }
      ); 
   }
   
   
   
   /**
    * Controls the JApplet component visibility. 
    * ESCA-JAVA0266:
    */
   private void appletDisplayHandler()
   {
      final String ZOOM_WARNING = 
   
      "It appears that web pages in your browser are zoomed out. \n\n" +
      "In order to display the applet, your browser needs to be set \n" +
      "at its default zoom level of 100% or greater. \n\n" +
      "Sorry about that.";
   
   
      if ((getWidth() < FRAME_SIZE_X) || (getHeight() < FRAME_SIZE_Y))
      {
         contentPane.setVisible(false); menuBar.setVisible(false);
      
         
         if (!zoomWarningShown) 
         {
            Message.showMessage(ZOOM_WARNING, "Browser zoom setting", "warning");
            
            zoomWarningShown = true;
         } 
      }
       
      else 
      {
         contentPane.setVisible(true); menuBar.setVisible(true);
      } 
   }
   
   
   //***************************************** END PRIVATE METHODS *****************************************//
   
   
   //********************************************** START MAIN *********************************************//
   
 
   /**
    * Main
    * @param a
    */
   public static void main(String[] a)
   {
      isApplication = true;
      
      isVisible = true;
     
      new AudioRecorderGui();
   }
   
   
   //*********************************************** END MAIN **********************************************//
   
  
   /**
    * ESCA-JAVA0007:
    */
   public JFrame frame;
   
   private JLabel label;
   private ImageIcon icon;
   private JMenuBar menuBar;
   private ButtonGroup group;
   private Timer progressTimer;
   private FileBrowser fBrowser;
   private JTextField urlDisplay;
   private Container contentPane;
   private JRadioButton[] inputs;
   private AudioRecorder recorder;
   private boolean zoomWarningShown;
   private JProgressBar progressBar;
   private String userId, userPw, path;
   private GridBagConstraints constraints;
   private JScrollPane liveWave, scrollPane;
   private JSlider volumeSlider, waveSlider;
   private Timer scheduleTimer, waveformTimer;
   private JTextArea inputDisplay, queueDisplay;
   private JMenuItem saveMenuItem, clearMenuItem;
   private JCheckBox useSchedule, scheduleAddress;
   private JButton start, cancel, add, clear, undo;
   
   private String[] sampleSizeChoices = { "8", "16"};
   
   private String[] formatChoices = { "AIFF", "WAV"};
   
   private JRadioButtonMenuItem mainRadio, outputRadio;
   
   private ArrayList<String> webAddress = new ArrayList<String>();
   private ArrayList<Integer> hourStart = new ArrayList<Integer>();
   private ArrayList<Integer> hourFinish = new ArrayList<Integer>();
   private ArrayList<Integer> minuteStart = new ArrayList<Integer>();
   private ArrayList<Integer> secondStart = new ArrayList<Integer>();
   private ArrayList<Integer> minuteFinish = new ArrayList<Integer>();
   private ArrayList<Integer> secondFinish = new ArrayList<Integer>();
   private ArrayList<Integer> recFileNumber = new ArrayList<Integer>();
   
   private JRadioButton mono, stereo, saveDesktop, saveBrowse;
   
   private boolean scheduleSet, scheduleIsRecording, 
   scheduleTimerRunning, startPressed, rootStep, invalidDirectory;
   
   private int fileNameCount,  scheduleInfoIndex, scheduledItemsRecorded;
   private String[] sampleRateChoices = { "44100", "48000", "96000", "192000"};
   
   private JLabel inputLabel, settingsLabel, recordLabel, outputLabel, savingLabel;
   
   private JComboBox<String> sampleRateBox, sampleSizeBox, timeStartHour, recordFormatBox, 
   browserBox, timeStartMinute, timeStartSecond, timeFinishHour, timeFinishMinute, timeFinishSecond;
   
   private ArrayList<String> writeSettings, scheduleSettings, recorderReadSettings, scheduleReadSettings;
   
   private JPanel inputPanel, channelPanel, sampleRatePanel, activatePanel, scheduleButtonPanel, browserPanel, 
   recordPanel, sampleSizePanel, formatPanel, volumePanel, timeStartContainer, timeFinishContainer, queuePanel;
   
   
   //********************************************** END CLASS **********************************************//
    
}


/*
   COPYRIGHT (C) 2010 - 2013 by Alexander Wait. All Rights Reserved.

   This class provides audio recording features.

   @site http://www.javaika.com
   @author Alexander Wait
   @version 2012-05-05
*/



import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.SequenceInputStream;
import java.util.ArrayList;
import javax.sound.sampled.*;
import javax.sound.sampled.Mixer.Info;



public class AudioRecorder 
{

   private static final boolean SIGNED = true;
   private static final boolean BIG_ENDIAN = true;
   
   private static final int VOLUME_SLIDER_DIVISOR = 100;
  
   
   //************************************** START INITIALISATION CODE **************************************//
   
   
   /**
    * Initializes the recorder.
    */
   public AudioRecorder()
   {   
      waveform = new AudioWaveform();

  
      sampleRate = 44100; audioChannels = 2;
      
      sampleSize = 16; inputType = 0;
      
      volumeSliderValue = 0.5f;
      
      fileExtension = "wav";
      
      
      if (!AudioRecorderGui.runRestricted) 
      {
         setSavePath(Tools.returnDesktopPath());
      }
      
   }
   
   
   //*************************************** END INITIALISATION CODE ***************************************//
   
   
   //**************************************** START PUBLIC METHODS *****************************************//
   
   
   /**
    * Populates the mixer array-list with all valid mixer inputs. 
    * A data line is a valid mixer record input if the line is 
    * closed and no exception is thrown.
    * ESCA-JAVA0166:
    * ESCA-JAVA0266:
    */
   public void setValidMixers()
   {
      validMixers.clear();
      
      format = getFormat(); 
      

      mixerPort = AudioSystem.getMixerInfo();
      
      dataLineInfo = new DataLine.Info(TargetDataLine.class, format);
      
     
      for (Info element : mixerPort)
      {
         try
         {       
            Mixer mixer = AudioSystem.getMixer(element);
            
            if (!((TargetDataLine)mixer.getLine(dataLineInfo)).isOpen())
            {
               validMixers.add(mixer);
            }
         }
       
         catch (Exception e) {continue;}  // Illegal argument exception
        
      } 
   }
   
   
   
   /**
    * Starts the recording.
    */
   public void startRecord() {setVolume(); captureAudio();}
   
   
   
   /**
    * Stops the record capture.
    */
   public void stopRecord() {running = false; createAudioFile();}
   
   
   
   /**
    * Cancels the record capture.
    */
   public void cancelRecord() {running = false;}
   
  
   
   /**
    * Sets the record volume.
    * @param volume
    */
   public void setRecordVolume(float volume) {volumeSliderValue = (volume / VOLUME_SLIDER_DIVISOR);}
   
   
   
   /**
    * Returns the name of a mixer object.
    * @param index
    * @return
    */
   public String returnMixerName(int index) {return validMixers.get(index).getMixerInfo().toString();}
   
   
   
   /**
    * Sets the allowed record seconds.
    * @param seconds
    */
   public void setAllowedRecordSeconds(int seconds) {allowedRecordSeconds = seconds;}

   
   
   /**
    * Sets the input type.
    * @param type
    */
   public void setInputType(int type) {inputType = type;}
   
   
   
   /**
    * Sets the sample rate.
    * @param rate
    */
   public void setSampleRate(int rate) {sampleRate = rate;}
   
   
   
   /**
    * Sets the sample rate.
    * @param format
    */
   public void setRecordFormat(String format) {fileExtension = format;}
   
   
   
   /**
    * Sets the sample size.
    * @param size
    */
   public void setSampleSize(int size) {sampleSize = size;}
   
   
   
   /**
    * Sets the number of audio channels.
    * @param channels
    */
   public void setChannels(int channels) {audioChannels = channels;}
   
   
   
   /**
    * Sets the file name.
    * @param name
    */
   public void setFileName(String name) {fileName = name;}
   
   
   
   /**
    * Sets the save path.
    * @param path
    */
   public void setSavePath(String path) {savePath = path;}
   
   
   
   /**
    * Sets the file extension.
    * @param ext
    */
   public void setFileExtension(String ext) {fileExtension = ext;}
   
   
   
   /**
    * Returns the file extension.
    * @return
    */
   public String returnFileExtension() {return fileExtension;}
   
   
   
   /**
    * Returns the save path.
    * @return
    */
   public String returnSavePath() {return savePath;}
   
   
   
   /**
    * Returns the size of the mixer array.
    * @return
    */
   public int returnMixerArrayLength() {return validMixers.size();}
   
   
   
   /**
    * Returns the audio input stream.
    * @return
    */
   public AudioInputStream returnAudioInputStream() {return dump;}
   
   
   //***************************************** END PUBLIC METHODS ******************************************//


   //**************************************** START PRIVATE METHODS ****************************************//
   
   
   /**
    * Sets the record volume from the JSlider unit.
    * ESCA-JAVA0049:
    */
   private void setVolume()
   {
      javax.sound.sampled.Mixer.Info[] mixers = AudioSystem.getMixerInfo();
      
      
      for (Info mixerInfo : mixers) 
      {
         Mixer mixer = AudioSystem.getMixer(mixerInfo);
        
         Line.Info[] lineinfos = mixer.getTargetLineInfo();
        
         for(Line.Info lineinfo : lineinfos)
         {
            try 
            {     
               Line testLine = mixer.getLine(lineinfo); testLine.open();
               

               if (testLine.isControlSupported(FloatControl.Type.VOLUME)) 
               {
               
                  FloatControl control = (FloatControl) testLine.getControl(FloatControl.Type.VOLUME);
 
                  control.setValue(volumeSliderValue); 
               } 
               
               else if (testLine.isControlSupported(FloatControl.Type.MASTER_GAIN))
               {
           
                  FloatControl control = (FloatControl) testLine.getControl(FloatControl.Type.MASTER_GAIN); 
              
                  control.setValue(volumeSliderValue);
               }
               
               else {testLine.close();}
               
            } 
            
            catch (LineUnavailableException e) {continue;}
         }
      } 
      
   }
   
   
   
   /**
    * Records the audio from a specified source.
    * ESCA-JAVA0266:
    * ESCA-JAVA0049:
    * ESCA-JAVA0061:
    */
   private void captureAudio()
   {
      try 
      {  
         format = getFormat(); 
         
         recordChapterNumber = 0; hasExceededLimit = false;
         
         dataLineInfo = new DataLine.Info(TargetDataLine.class, format);
          
         line = (TargetDataLine) validMixers.get(inputType).getLine(dataLineInfo);
         
         line.open(format); line.start();
        
        
         Runnable runner = new Runnable() 
         {
            int bufferSize = (int)format.getSampleRate() * format.getFrameSize();

            byte[] buffer = new byte[bufferSize];
            
            public void run() 
            {
               out = new ByteArrayOutputStream(); running = true; initialised = false;
               
               int chapterRecordSeconds = 0;
               
               try 
               {
                  while (running) 
                  {
                     int count = line.read(buffer, 0, buffer.length);
       
                     if (count > 0) 
                     {
                        out.write(buffer, 0, count);
                        
                        if ((!appendLock))
                        {
                           setBytes();
                        
                           if (!initialised)
                           {
                              dump = new AudioInputStream(input, format, value);
                        
                              initialised = true;
                           }
                        
                           else
                           {
                              temp = new AudioInputStream(input, format, value);
                           
                              appendStream();
                              
                           }
                           
                           out = new ByteArrayOutputStream();  
                        }
                      
                     }
                     
                     chapterRecordSeconds ++;
                     
                     if (chapterRecordSeconds >= allowedRecordSeconds)
                     { 
                        hasExceededLimit = true;
                        
                        chapterRecordSeconds = 0;
                        
                        createAudioFile();
                     }
                  }
            
                  out.close(); line.close(); 
               } 
               
               catch (IOException e) 
               {
                  System.out.println(Tools.thisPathAndLine() + e + "\n");
               }
            }
         };

         Thread captureThread = new Thread(runner); captureThread.start();
      } 
      
      catch (LineUnavailableException e)
      {
         System.out.println(Tools.thisPathAndLine() + e + "\n");
      }
      
      catch (IndexOutOfBoundsException e)
      {
         System.out.println(Tools.thisPathAndLine() + e + "\n");
      }
   }
  
   
   
   /**
    * Refreshes the byte buffer.
    * ESCA-JAVA0170:
    * ESCA-JAVA0266:
    */
   private void setBytes()
   {
      try 
      {
         byte[] audio = out.toByteArray();  waveform.setAudioInputStream(temp, audio);
     
         value = out.toByteArray().length / format.getFrameSize();
      
         input = new ByteArrayInputStream(audio); 
      
      } 
     
      catch (OutOfMemoryError e)
      {System.out.println(Tools.thisPathAndLine() + e + "\n");}
      
   }
   
   
   
   /**
    * Appends data.
    */
   private void appendStream()
   {  
      dump = new AudioInputStream
      (
         new SequenceInputStream(dump, temp),     
         dump.getFormat(), dump.getFrameLength() + temp.getFrameLength()
      );
      
   }
   
   
   
   /**
    * Creates the audio wave file.
    * ESCA-JAVA0266:
    */
   private void createAudioFile()
   {
      appendLock = true; 
      
      Runnable runner = new Runnable()
      {  
         public void run() 
         {
            runningSave = true;  
            
            recordFileDestination = null;
         
            
            while (runningSave)
            {  
               if (hasExceededLimit)
               {
                  recordFileDestination = new File
                  (
                     savePath + returnChapterFileName() + "." + returnFileExtension()
                  ); 
               }
               
               else
               {
                  recordFileDestination = new File
                  (
                     savePath + fileName + "." + returnFileExtension()
                  ); 
               }
                  
               renderAudioFile();  
            } 
         }
      };
      
      Thread captureThread = new Thread(runner); captureThread.start();
        
   }
   
   
   
   /**
    * Renders the audio file.
    * ESCA-JAVA0266:
    */
   private void renderAudioFile()
   {
      try
      {   
         if (returnFileExtension().equals("wav"))
         {
            AudioSystem.write
            (
    
               dump, AudioFileFormat.Type.WAVE, 
               recordFileDestination 
            );
         }
       
         if (returnFileExtension().equals("aiff"))
         {
            AudioSystem.write
            (
    
               dump, AudioFileFormat.Type.AIFF, 
               recordFileDestination 
            );
         }   
       
      }

      catch (IOException e) 
      {System.out.println(Tools.thisPathAndLine() + e + "\n");}
       
       
      finally {runningSave = false; initialised = false; appendLock = false;}   
   
   }
   

   
   /**
    * Sets the audio format for recording.
    * @return
    */
   private static AudioFormat getFormat() 
   {
      return new AudioFormat(sampleRate, sampleSize, audioChannels, SIGNED, BIG_ENDIAN);
 
   }
   

   
   /**
    * Returns the file name of the file to be saved 
    * if maximum runtime memory has been reached.
    * @return
    */
   private String returnChapterFileName()
   {
      recordChapterNumber ++;  
      
      return (fileName + " Chapter(" + recordChapterNumber + ")");
   }
   
   
   //***************************************** END PRIVATE METHODS *****************************************//
   

   TargetDataLine line;
   File recordFileDestination;
  
   private InputStream input;
   private AudioFormat format;
   private Mixer.Info[] mixerPort;
   private AudioWaveform waveform;
   private int recordChapterNumber;
   private float volumeSliderValue;
   private int allowedRecordSeconds;
   private ByteArrayOutputStream out;
   protected boolean running = false;
   private DataLine.Info dataLineInfo;
   private AudioInputStream temp, dump;
   private String fileName, fileExtension, savePath;
   ArrayList<Mixer> validMixers = new ArrayList<Mixer>();
   ArrayList<String> mixerNames = new ArrayList<String>();
   ArrayList<Control[]> audioControls = new ArrayList<Control[]>();
   private boolean appendLock, initialised, hasExceededLimit, runningSave;
   private static int sampleRate, sampleSize, audioChannels, inputType, value;
   
   
  //********************************************** END CLASS **********************************************//

}


/*
   COPYRIGHT (C) 2010 - 2013 by Alexander Wait. All Rights Reserved.

   This class constructs a waveform image from an audio file.

   @site http://www.javaika.com
   @author Alexander Wait
   @version 2010-07-18
*/



import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.geom.Line2D;
import java.awt.image.BufferedImage;
import java.util.Vector;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;



public class AudioWaveform 
{
   private static final int DEFAULT_IMAGE_SIZE_X = 445;
   private static final int DEFAULT_IMAGE_SIZE_Y = 100;
   private static final int HEIGHT = 100;
   private static final int BC = 238;
   private static final int WC = 255;
   
   
   // ESCA-JAVA0116:
   public static final int DEFAULT_WIDTH = 20000;
   
   // ESCA-JAVA0116:
   public static final int MAX_WIDTH = 40000;
   
   // ESCA-JAVA0116:
   public static final int MIN_WIDTH = 445;
   
   
   //************************************** START INITIALISATION CODE **************************************//

   
   /**
    * Class constructor.
    */
   public AudioWaveform()
   {
      setWidth(DEFAULT_WIDTH);
   
      initialiseBufferedImage(); initialiseGraphics();
   }
   
   
   //*************************************** END INITIALISATION CODE ***************************************//
   
   
   //**************************************** START PUBLIC METHODS *****************************************//
   
   
   /**
    * Sets the audio input stream for the waveform.
    * @param stream
    * @param bytes
    */
   public void setAudioInputStream(AudioInputStream stream, byte[] bytes)
   { 
      audioInputStream = stream; audioBytes = bytes.clone();
      
      
      if (audioInputStream != null)
      {
         clearGraphics(); createWaveForm();
      } 
   }
   
   
   
   /**
    * Sets the render width.
    * @param value
    */
   public static void setWidth(int value) {width = value;}
   
   
   
   /**
    * Returns the render width.
    * @return
    */
   public static int getWidth() {return width;}
   
   
   
   /**
    * Returns the buffered image.
    * @return
    */
   public static BufferedImage getBufferedImage() {return bufferedImage;}
   
   
   //**************************************** END PUBLIC METHODS *******************************************//
   
   
   //**************************************** START PRIVATE METHODS ****************************************//
   
   
   /**
    * Initializes the buffered image waveform.
    */
   private static void initialiseBufferedImage()
   {
      bufferedImage = new BufferedImage
      (
         DEFAULT_IMAGE_SIZE_X, DEFAULT_IMAGE_SIZE_Y, BufferedImage.TYPE_INT_ARGB
      );
      
   }
   
   
   
   /**
    * Initializes the wave graphics.
    */
   private void initialiseGraphics()
   {
      graphics = bufferedImage.createGraphics();
      
      graphics.setBackground(backgroundColor); 
      
      graphics.setColor(waveColor);  
     
      
      clearGraphics();
   }
   
   
   
   /**
    * Clears the graphics.
    */
   private void clearGraphics()
   {
      graphics.clearRect(0, 0, getWidth(), HEIGHT);
   
   }
   

   
   /**
    * Creates the waveform.
    * ESCA-JAVA0166:
    * ESCA-JAVA0266:
    * ESCA-JAVA0076:
    */
   private void createWaveForm() 
   {
      lines.removeAllElements(); format = audioInputStream.getFormat();
      

      try 
      {
         if (format.getSampleSizeInBits() == 16) {renderSixteenBits();}
         
         if (format.getSampleSizeInBits() == 8) {renderEightBits();}

         
         createLines();
      } 
         
      catch (Exception e) {System.out.println(Tools.thisPathAndLine() + e + "\n");}

   }
   
   
   
   /**
    * Creates the line strokes.
    * ESCA-JAVA0076:
    */
   private void createLines()
   {
      int frames_per_pixel = audioBytes.length / format.getFrameSize() / getWidth();
       
      byte my_byte = 0; double y_last = 0; int numChannels = format.getChannels();
          
       
      if (audioData != null)
      {
         for (double x = 0; x < getWidth(); x++) 
         {
            int idx = (int) (frames_per_pixel * numChannels * x);
              
            if (format.getSampleSizeInBits() == 8) 
            {
               my_byte = (byte) audioData[idx];
            } 
             
            else 
            {
               my_byte = (byte) (128 * audioData[idx] / 32768 );
            }
              
            int i = HEIGHT * (128 - my_byte) / 256; double y_new = (double) i;
              
            lines.add(new Line2D.Double(x, y_last, x, y_new));
              
            y_last = y_new;
         }
         
         createSampleOnGraphicsContext();
      }   

   }
   
   
   
   /**
    * Creates the sample on graphics.
    */
   private void createSampleOnGraphicsContext() 
   {
      for (int i = 1; i < lines.size(); i++) 
      {
         graphics.draw(lines.get(i));
      }
   }
   
   
   
   /**
    * Renders 16 bit file.
    * ESCA-JAVA0076:
    */
   private void renderSixteenBits()
   {
      int nlengthInSamples = audioBytes.length / 2;
       
      audioData = new int[nlengthInSamples];
            
      if (format.isBigEndian()) 
      {
         for (int i = 0; i < nlengthInSamples; i++) 
         {
            /* First byte is MSB (high order) */
                   
            int MSB = (int) audioBytes[2*i];
                    
            /* Second byte is LSB (low order) */
                    
            int LSB = (int) audioBytes[2*i+1];
                    
            audioData[i] = MSB << 8 | (255 & LSB);
         }
      } 
       
      else 
      {
         for (int i = 0; i < nlengthInSamples; i++) 
         {
            /* First byte is LSB (low order) */
                   
            int LSB = (int) audioBytes[2*i];
                  
            /* Second byte is MSB (high order) */
                   
            int MSB = (int) audioBytes[2*i+1];
                  
            audioData[i] = MSB << 8 | (255 & LSB);
         }
      }
      
   }
   
   
   
   /**
    * Renders 8 bit file.
    * ESCA-JAVA0076:
    */
   private void renderEightBits()
   {
      int nlengthInSamples = audioBytes.length;
       
      audioData = new int[nlengthInSamples];
            
      if (format.getEncoding().toString().startsWith("PCM_SIGN")) 
      {
         for (int i = 0; i < audioBytes.length; i++) 
         {
            audioData[i] = audioBytes[i];
         }
      } 
       
      else 
      {
         for (int i = 0; i < audioBytes.length; i++) 
         {
            audioData[i] = audioBytes[i] - 128;
         }
      }   
   }
   
   
   //***************************************** END PRIVATE METHODS *****************************************//

   
   private static int width;
   private AudioFormat format;
   private Graphics2D graphics;
   private int[] audioData = null;  
   private byte[] audioBytes = null;
   private static BufferedImage bufferedImage;
   private AudioInputStream audioInputStream;
   private Color waveColor = new Color(WC, WC, WC);
   private Color backgroundColor = new Color(BC, BC, BC);
   private Vector<Line2D.Double> lines = new Vector<Line2D.Double>();
   
   
   //********************************************** END CLASS **********************************************//
   
}


/*
   COPYRIGHT (C) 2010 -2013 by Alexander Wait. All Rights Reserved.

   This class defines colors and color methods.

   @site http://www.javaika.com
   @author Alexander Wait
   @version 2012-05-18
*/



public class ColorFunctions
{

   private static final int HEXADECIMAL_BASE = 16;
   
   private static final int COLOR_COMPONENT_RED = 250;
   
   private static final int COLOR_COMPONENT_GREEN = 250;
   
   private static final int COLOR_COMPONENT_BLUE = 250;
   
   
   
   private ColorFunctions() {}
   
   
   //**************************************** START PUBLIC METHODS *****************************************//

   
   /**
    * Returns the color in hexadecimal format.
    * @param sliderValue
    * @return
    */
   public static String returnHexadecimalColor(int sliderValue)
   {
      String compFirst = ""; String compSecond = ""; int counter = -1;
 
      for (int i = 0; i < HEXADECIMAL_BASE; i ++)
      {
         compFirst = returnComponent(i);

          for (int j = 0; j < HEXADECIMAL_BASE; j ++)
          {
             compSecond = returnComponent(j); counter ++; 
  
             if (counter == sliderValue)
             {
                break;
             }
             
          }
  
          if (counter == sliderValue)
          {
             break;
          }
  
       }
   
       return 
       (
          "#" + compFirst + compSecond + compFirst + 
          
          compSecond + compFirst + compSecond
       );
   
   }
   
   
   
   /**
    * Return the set red color component 
    * for setting the programs background color. 
    * @return
    */
   public static int red()
   {
      return COLOR_COMPONENT_RED;
   }
   
   
   
   /**
    * Return the set green color component 
    * for setting the programs background color. 
    * @return
    */
   public static int green()
   {
      return COLOR_COMPONENT_GREEN;
   }
   
   
   
   /**
    * Return the set blue color component 
    * for setting the programs background color. 
    * @return
    */
   public static int blue()
   {
      return COLOR_COMPONENT_BLUE;
   }
   
   
   //***************************************** END PUBLIC METHODS ******************************************//


   //**************************************** START PRIVATE METHODS ****************************************//
   
   
   /**
    * Returns the hexadecimal component.
    * ESCA-JAVA0076:
    * @param index
    * @return
    */
   private static String returnComponent(int index)
   {
      String component = "";
  
      switch (index)
      {
         case 10: component = "A"; break; case 11: component = "B"; break;  
         
         case 12: component = "C"; break; case 13: component = "D"; break; 
         
         case 14: component = "E"; break; case 15: component = "F"; break;
   
         default: component = Integer.toString(index); break;
      }
   
      return component;   
   }
   
 
   //***************************************** END PRIVATE METHODS *****************************************//

   
   //********************************************** END CLASS **********************************************//
   
}


/*
   COPYRIGHT (C) 2010 -2013 by Alexander Wait. All Rights Reserved.

   This class returns date and time and provides functions relating to time.

   @site http://www.javaika.com
   @author Alexander Wait
   @version 2012-04-18
*/



import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.GregorianCalendar;



public class DateAndTime 
{

   private static final int DAY_INDEX = 2; 
   private static final int MONTH_INDEX = 1; 
   private static final int YEAR_INDEX = 0; 
   
   private static final int MILLISECONDS_PER_SECOND = 1000;
   private static final int SECONDS_PER_MINUTE = 60;
   private static final int MINUTES_PER_HOUR = 60;
   private static final int HOURS_PER_DAY = 24;
   
   private static final int DAYS_IN_WEEK = 7;
   private static final int DAYS_IN_YEAR = 365;
   private static final int WEEKS_IN_YEAR = 52;   
   private static final int MONTHS_IN_YEAR = 12;
   private static final int FORTNIGHTS_IN_YEAR = 26;
   
   private static Calendar now = Calendar.getInstance();
   
   public static enum Elements {YEAR, MONTH, DAY}
   

   private DateAndTime() {}
   
   
   //**************************************** START PUBLIC METHODS *****************************************//
   
   
   /**
    * Tests and compares two dates.
    * @param dateFirst
    * @param dateSecond
    * @return
    */
   public static boolean dateComparison(String dateFirst, String dateSecond) 
   {
      String[] first = dateFirst.split("[-]", 0); 
      
      String[] second = dateSecond.split("[-]", 0);

      int firstDayInt = Integer.parseInt(first[DAY_INDEX]); 
      
      int firstMonthInt = Integer.parseInt(first[MONTH_INDEX]); 
      
      int firstYearInt = Integer.parseInt(first[YEAR_INDEX]); 
      
      int secondDayInt = Integer.parseInt(second[DAY_INDEX]); 
      
      int secondMonthInt = Integer.parseInt(second[MONTH_INDEX]); 
      
      int secondYearInt = Integer.parseInt(second[YEAR_INDEX]);

      return 
      
        compareDates(firstDayInt, firstMonthInt, 
        firstYearInt, secondDayInt, secondMonthInt, secondYearInt);
   }



   /**
    * Compares two dates to test if one date is more current than the other. 
    * @param fstDay
    * @param fstMonth
    * @param fstYear
    * @param sndDay
    * @param sndMonth
    * @param sndYear
    * @return
    */
   public static boolean compareDates(int fstDay, int fstMonth, 
   int fstYear, int sndDay, int sndMonth, int sndYear)
   {
      if (sndYear > fstYear) {return true;}

      else if (sndYear < fstYear) {return false;}

      else
      {
         if (sndMonth > fstMonth) {return true;}

         else if (sndMonth < fstMonth) {return false;}

         else 
         {
            if (sndDay >= fstDay) {return true;}

            else {return false;}
         }
      }
   }
   
   
   
   /**
    * Returns true if the time given is before current time.
    * @param hour
    * @param minute
    * @param second
    * @return
    */
   public static boolean isBeforeCurrentTime(int hour, int minute, int second)
   {
      
      if (returnHour() > hour) {return true;}
     
      else if (returnHour() < hour) {return false;}
  
      else 
      {
         if (returnMinute() > minute) {return true;}
         
         else if (returnMinute() < minute) {return false;}
       
         else 
         {
            if (returnSecond() > second) {return true;}
        
            else {return false;}
         }
      } 
  
   }
   
   
   
   /**
    * Returns true if the time to be tested is after the reference.
    * @param hour
    * @param minute
    * @param second
    * @param testHour
    * @param testMinute
    * @param testSecond
    * @return
    */
   public static boolean isAfterReferenceTime(int hour, int minute, 
   int second, int testHour, int testMinute, int testSecond)
   {
  
      if (hour < testHour) {return true;}
      
      else if (hour > testHour) {return false;}
   
      else 
      {
    
         if (minute < testMinute) {return true;}
         
         else if (minute > testMinute) {return false;}
         
         else 
         {
      
            if (second < testSecond) {return true;}
        
            else {return false;}
         }
      } 
  
   }
   
   
   
   /**
    * Finds the difference between two times in hours.
    * @param startHour
    * @param startMinute
    * @param endHour
    * @param endMinute
    * @return
    */
   public static double timeDifferenceHours(int startHour, 
   int startMinute, int endHour, int endMinute)
   {
      double endMinutes = endHour * MINUTES_PER_HOUR + endMinute;
      
      double startMinutes = startHour * MINUTES_PER_HOUR + startMinute;
   
      return ((endMinutes - startMinutes) / MINUTES_PER_HOUR);
   }

   
   
   /**
    * Returns true if a specified time is within one of a list of ranges.
    * @param startHour
    * @param startMinute
    * @param startSecond
    * @param finishHour
    * @param finishMinute
    * @param finishSecond
    * @param hour
    * @param minute
    * @param second
    * @param length
    * @return
    */
   public static boolean isOverlapped(ArrayList<Integer> startHour, 
   ArrayList<Integer> startMinute, ArrayList<Integer> startSecond, 
   ArrayList<Integer> finishHour, ArrayList<Integer> finishMinute, 
   ArrayList<Integer> finishSecond, int hour, int minute, 
   int second, int length)
   {

      boolean overlapped = false; 
   
      for (int i = 0; i < length; i ++)
      {
         if (isAfterReferenceTime
         (startHour.get(i), startMinute.get(i), 
         startSecond.get(i), hour, minute, second)
         
         && (!isAfterReferenceTime
         (finishHour.get(i), finishMinute.get(i), 
         finishSecond.get(i), hour, minute, second)))
         {
            overlapped = true;
            
         }
               
      }
      
     return overlapped;
     
   }
   
   
   
   /**
    * Tests if a year is a leap year.
    * @param year
    * @return
    */
   public static boolean isLeapYear(int year)
   {
      boolean leapYear = false;
      
      final int LEAP_DIVISOR_SHORT = 4;
      
      final int LEAP_DIVISOR_MIDDLE = 100;
      
      final int LEAP_DIVISOR_LONG = 400;
      
      
      if ((year % LEAP_DIVISOR_SHORT) == 0)
      {
         if ((year % LEAP_DIVISOR_MIDDLE) != 0)
         {
            leapYear = true;
         }
         
         if (((year % LEAP_DIVISOR_MIDDLE) == 0) 
         && ((year % LEAP_DIVISOR_LONG) == 0))
         {
            leapYear = true;
         }
         
      }
      
     
      return leapYear;

   }
   
   
   
   /**
    * Returns todays date.
    * @param includeTimeMask
    * @return
    */
   public static String returnTodaysDate(boolean includeTimeMask)
   {
      refreshCalendar(); now.getTime();
   
      
      String todaysDate = ""; String timeMask = "00:00:00";
      
      SimpleDateFormat date = new SimpleDateFormat("YYYY-MM-dd");
      
     
      if (includeTimeMask)
      {
         todaysDate = date.format(now.getTime()) + " " + timeMask;
      }
      
      else
      {
         todaysDate = date.format(now.getTime());
      }
      
      
      return todaysDate; 
   }
   
   
   
   /**
    * Returns a specific element of a date string.
    * @param date
    * @param component
    * @return
    */
   public static String returnSplitDate(String date, Elements component)
   {
      String element = null;
      
      
      String[] elementArray = date.split("-");
      
      
      if (component.equals(Elements.YEAR))
      {
         element = elementArray[0];
      }
      
      if (component.equals(Elements.MONTH))
      {
         element = elementArray[1];
      }
      
      if (component.equals(Elements.DAY))
      {
         element = elementArray[2];
      }

      
      return element;
      
   }
   

   
   /**
    * Returns the name of a month expressed as an integer.
    * ESCA-JAVA0076:
    * @param month
    * @return
    */
   public static String returnMonthName(int month)
   {
      String monthName = null;

      
      switch (month)
      {
         case 1: monthName = "January"; break;
         
         case 2: monthName = "February"; break;
         
         case 3: monthName = "March"; break;
         
         case 4: monthName = "April"; break;
         
         case 5: monthName = "May"; break;
           
         case 6: monthName = "June"; break;
         
         case 7: monthName = "July"; break;
         
         case 8: monthName = "August"; break;
         
         case 9: monthName = "September"; break;
         
         case 10: monthName = "October"; break;
         
         case 11: monthName = "November"; break;
         
         case 12: monthName = "December"; break;
      
         default: monthName = "Invalid Input"; break;
      }
      
      
      return monthName;
   }
   
   
   
   /**
    * Returns a list of dates.
    * @param year
    * @param heading
    * @return
    */
   public static String[] returnDateList(int year, String heading)
   {
   
      ArrayList<String> list = new ArrayList<String>();
     
      
      if (heading != null) {list.add(heading);}
      
      
      for (int i = 1; i <= MONTHS_IN_YEAR; i ++)
      {
         int bound = returndaysInMonth(i);
         
         
         if (isLeapYear(year) && (i == 2)) {bound ++;}
         
         
         for (int j = 1; j <= bound; j ++)
         {
            list.add(year + "-" + returnDigitMask(i, 2) + "-" + returnDigitMask(j, 2)); 
         }
        
      }
  
      
      String[] dates = new String[list.size()];
      
      list.toArray(dates);
      
      return dates;
   }
   
   
   
   /**
    * Returns the days of a specified month.
    * ESCA-JAVA0076:
    * @param month
    * @return
    */
   public static int returndaysInMonth(int month)
   {
      int days = -1; final int SHORT = 28; 
   
      final int MIDDLE = 30; final int LONG = 31;
  
      switch (month)
      {
         case 1: days = (LONG); break; case 2: days = (SHORT); break;
         
         case 3: days = (LONG); break; case 4: days = (MIDDLE); break;
         
         case 5: days = (LONG); break; case 6: days = (MIDDLE); break;
         
         case 7: days = (LONG); break; case 8: days = (LONG); break;
         
         case 9: days = (MIDDLE); break; case 10: days = (LONG); break;
         
         case 11: days = (MIDDLE); break; case 12: days = (LONG); break;  
      
         default: return days;         
      }
   
      return days;  
   }
   
   
   
   /**
    * Converts an integer to a mask.
    * ESCA-JAVA0076:
    * @param value
    * @param maxValueLength
    * @return
    */
   public static String returnDigitMask(int value, int maxValueLength)
   {     
      String digit = Integer.toString(value); String trailing = "";
      
      if (digit.length() == maxValueLength)
      {
         return digit;
      }
   
      else
      {
         for (int i = digit.length(); i < maxValueLength; i ++)
         {
            trailing += "0";
         }
     
         return (trailing + digit); 
      } 
   }
   
   
   
   /**
    * Returns the seconds elapsed in counter format (HH:MM:SS).
    * @param counter
    * @param millisecondCount
    * @return
    */
   public static String returnCounterTime(long counter, boolean millisecondCount)
   {
      String counterTime = ""; 
  
  
      setCounterHours((short)0); setCounterMinutes((short)0);
      
      setCounterSeconds((short)0); setCounterMilliseconds((short)0);
  
      
      final int DIGIT_LENGTH = 2; final double MILLIS_DIVISOR = 100;
      
   
      for (int i = 0; i < counter; i ++)
      {
         if (millisecondCount) {counterMilliseconds ++;} 
         
         else {counterSeconds ++;}
         
         
         if (counterMilliseconds == MILLISECONDS_PER_SECOND) 
         
         {setCounterMilliseconds((short)0); counterSeconds ++;}
         
         
         if (counterSeconds == SECONDS_PER_MINUTE) 
         
         {setCounterSeconds((short)0); counterMinutes ++;}
         
         if (counterMinutes == MINUTES_PER_HOUR) 
         
         {setCounterMinutes((short)0); counterHours ++;}
      }
      
      
      if (millisecondCount) 
      {
         counterTime = ":" + (int)Math.floor(getCounterMilliseconds() / MILLIS_DIVISOR);
      }
      
      
      counterTime = 
      (
         returnDigitMask(getCounterHours(), DIGIT_LENGTH) + ":" +
             
         returnDigitMask(getCounterMinutes(), DIGIT_LENGTH) + ":" +
     
         returnDigitMask(getCounterSeconds(), DIGIT_LENGTH) + counterTime
      );
      
      
      return counterTime;
      
   }
   
   
   
   /**
    * Returns the formatted time (24 hour or standard)
    * @param twentyFourHour
    * @return
    */
   public static String returnFormattedTime(boolean twentyFourHour)
   {
      refreshCalendar(); String time = ""; 
      
      
      DateFormat full = new SimpleDateFormat("HH:mm:ss");
      
      DateFormat standard = new SimpleDateFormat("h:mm:ss");
      
      
      if (twentyFourHour) {time = full.format(now.getTime());}
      
      else {time = standard.format(now.getTime());}
  
        
      return time;   
   }
   
   
   
   /**
    * Returns the day at the start of the given year.
    * ESCA-JAVA0076:
    * @param year
    * @return
    */
   public static int returnStartDayAsInt(int year)
   {
      Calendar cal = new GregorianCalendar(year, Calendar.JANUARY, 1);
  
      return (cal.get(Calendar.DAY_OF_WEEK));
   }
   
   
   
   /**
    * Returns the day at the start of the given year.
    * ESCA-JAVA0076:
    * @param year
    * @return
    */
   public static int returnEndDayAsInt(int year)
   {
      Calendar cal = new GregorianCalendar(year, Calendar.DECEMBER, 31);
  
      return (cal.get(Calendar.DAY_OF_WEEK));
   }
   
   
   
   /**
    * Returns the specific day of week as an integer.
    * 1 = Sunday, 2 = Monday, 3 = Tuesday ...
    * ESCA-JAVA0076:
    * @param year
    * @param month
    * @param day
    * @return
    */
   public static int returnDayOfWeekAsInt(int year, int month, int day)
   {
      Calendar cal = null; 

      
      switch (month)
      {
         case 1: cal = new GregorianCalendar(year, Calendar.JANUARY, day); break;
         
         case 2: cal = new GregorianCalendar(year, Calendar.FEBRUARY, day); break;
         
         case 3: cal = new GregorianCalendar(year, Calendar.MARCH, day); break;
         
         case 4: cal = new GregorianCalendar(year, Calendar.APRIL, day); break;
         
         case 5: cal = new GregorianCalendar(year, Calendar.MAY, day); break;  
        
         case 6: cal = new GregorianCalendar(year, Calendar.JUNE, day); break;
         
         case 7: cal = new GregorianCalendar(year, Calendar.JULY, day); break;
         
         case 8: cal = new GregorianCalendar(year, Calendar.AUGUST, day); break;
         
         case 9: cal = new GregorianCalendar(year, Calendar.SEPTEMBER, day); break;
         
         case 10: cal = new GregorianCalendar(year, Calendar.OCTOBER, day); break;
         
         case 11: cal = new GregorianCalendar(year, Calendar.NOVEMBER, day); break;
         
         case 12: cal = new GregorianCalendar(year, Calendar.DECEMBER, day); break;
         
         
         default: return (-1);
      
      }
      
  
      return (cal.get(Calendar.DAY_OF_WEEK));
   }
   
  
   
   /**
    * Returns a list of years between the given 
    * parameter and the current year.
    * @param year
    * @return
    */
   public static String[] returnYearChoices(int year)
   {
     
      int difference = Math.abs(returnYear() - year);
      
      String[] choices = new String[difference +1];
 
  
      if (year < returnYear())
      {
         for (int i = 0; i <= difference; i ++)
         {
            choices[i] = Integer.toString(year + i);
         }
      }
      
      if (year > returnYear())
      {
         for (int i = 0; i <= difference; i ++)
         {
            choices[i] = Integer.toString(returnYear() + i); 
         }
      }
      
      return choices;
      
   }
   

   
   /**
    * Returns a list for seconds.
    * @return
    */
   public static String[] returnSecondChoices()
   {
      
     
      String[] secondList = new String[SECONDS_PER_MINUTE];
   
      for (int i = 0; i < SECONDS_PER_MINUTE; i ++)  
      {
         secondList[i] = Integer.toString(i);
      
      }
      
      return secondList;
   }
   
   
   
   /**
    * Returns a list for minutes.
    * @return
    */
   public static String[] returnMinuteChoices()
   {
      
     
      String[] minuteList = new String[MINUTES_PER_HOUR];
   
      for (int i = 0; i < MINUTES_PER_HOUR; i ++)  
      {
         minuteList[i] = Integer.toString(i);
      
      }
      
      return minuteList;
   }
   
   
   
   /**
    * Returns a list for hours.
    * @return
    */
   public static String[] returnHourChoices()
   {
      String[] hourList = new String[HOURS_PER_DAY];
   
      for (int i = 0; i < HOURS_PER_DAY; i ++)  
      {
         hourList[i] = Integer.toString(i);
      
      }
      
      return hourList;
   }
   
   
   
   /**
    * Returns the current year.
    * @return
    */
   public static int returnYear()
   {
      refreshCalendar(); 

      return (now.get(Calendar.YEAR));
   }
   
   
   
   /**
    * Returns the current year.
    * @return
    */
   public static int returnMonth()
   {
      refreshCalendar(); 
 
      return (now.get(Calendar.MONTH) + 1);
   }
    
   
   
   /**
    * Returns the current year.
    * @return
    */
   public static int returnDay()
   { 
      refreshCalendar(); 
   
      return (now.get(Calendar.DATE));
   }
   
   
   
   /**
    * Returns the hour in double digits.
    * @return
    */
   public static String returnHourDouble()
   {
      return returnDigitMask(returnHour(), 2);
   }
   
   
   
   /**
    * Returns the minute in double digits.
    * @return
    */
   public static String returnMinuteDouble()
   {
      return returnDigitMask(returnMinute(), 2);
   }
   
   
   
   /**
    * Returns the second in double digits.
    * @return
    */
   public static String returnSecondDouble()
   {
      return returnDigitMask(returnSecond(), 2);
   }
   
   
 
   /**
    * Returns the hour.
    * @return
    */
   public static int returnHour()
   {
      refreshCalendar(); 
   
      DateFormat hours = new SimpleDateFormat("HH");
      
      return (Integer.parseInt(hours.format(now.getTime())));
   }

   
   
   /**
    * Returns the minutes.
    * @return
    */
   public static int returnMinute()
   {
      refreshCalendar(); 
   
      DateFormat minutes = new SimpleDateFormat("mm");
      
      return (Integer.parseInt(minutes.format(now.getTime())));
   }
   
   
   
   /**
    * Returns the seconds.
    * @return
    */
   public static int returnSecond()
   {
      refreshCalendar();  
   
      DateFormat seconds = new SimpleDateFormat("ss");
      
      return (Integer.parseInt(seconds.format(now.getTime())));
   }
   
   
   
   /**
    * Returns the current stage of the day as AM or PM.
    * @return
    */
   public static String returnAmOrPm()
   {
      refreshCalendar(); 
     
      DateFormat ampm = new SimpleDateFormat("a");
        
      return (ampm.format(now.getTime()));   
   }
   
   
   
   /**
    * Returns the days in a year.
    * @param year
    * @return
    */
   public static int returnDays(int year)
   {
      if (DateAndTime.isLeapYear(year))
      {
         return getDaysLeapYear();
      }
      
      else
      {
         return DateAndTime.getDaysNormalYear();
      }   
   }
   
   
   
   /**
    * Refreshes the calendar.
    */
   public static void refreshCalendar()
   {
      now = Calendar.getInstance();
   }
   
  
   
   /**
    * Sets the counter hours.
    * @param value
    */
   public static void setCounterHours(short value) {counterHours = value;}
   
   
   
   /**
    * Sets the counter minutes.
    * @param value
    */
   public static void setCounterMinutes(short value) {counterMinutes = value;}
   
   
   
   /**
    * Sets the counter seconds.
    * @param value
    */
   public static void setCounterSeconds(short value) {counterSeconds = value;}
   
   
   
   /**
    * Sets the counter milliseconds.
    * @param value
    */
   public static void setCounterMilliseconds(short value) {counterMilliseconds = value;}
   
   
   
   /**
    * Returns the counter hours.
    * @return
    */
   public static short getCounterHours() {return counterHours;}
   
   
   
   /**
    * Returns the counter minutes.
    * @return
    */
   public static short getCounterMinutes() {return counterMinutes;}
   
   
   
   /**
    * Returns the counter seconds.
    * @return
    */
   public static short getCounterSeconds() {return counterSeconds;}
   
   
   
   /**
    * Returns the counter milliseconds.
    * @return
    */
   public static short getCounterMilliseconds() {return counterMilliseconds;}
   
   
   
   /**
    * Returns the days in a week.
    * @return
    */
   public static int getDaysInWeek() {return DAYS_IN_WEEK;}

   
   /**
    * Returns the days in a year.
    * @return
    */
   public static int getDaysNormalYear() {return DAYS_IN_YEAR;}
   
   
   /**
    * Returns the days in a year.
    * @return
    */
   public static int getDaysLeapYear() {return (DAYS_IN_YEAR + 1);}
   
   
   /**
    * Returns the weeks in a year.
    * @return
    */
   public static int getWeeksInYear() {return WEEKS_IN_YEAR;}
   
   
   /**
    * Returns the fort-nights in a year.
    * @return
    */
   public static int getFortnightsInYear() {return FORTNIGHTS_IN_YEAR;}
   
   
   /**
    * Returns the months in a year.
    * @return
    */
   public static int getMonthsInYear() {return MONTHS_IN_YEAR;}
   
   
   /**
    * Returns the seconds per minute.
    * @return
    */
   public static int getSecondsPerMinute() {return SECONDS_PER_MINUTE;}
   
   
   /**
    * Returns the seconds per minute.
    * @return
    */
   public static int getHoursPerWeek() {return HOURS_PER_DAY * DAYS_IN_WEEK;}
   
   
   //***************************************** END PUBLIC METHODS ******************************************//
   
   
   
   private static short counterHours, counterMinutes, counterSeconds, counterMilliseconds;
   
   
   //********************************************** END CLASS **********************************************//
 
}


/*
   COPYRIGHT (C) 2010 - 2013 by Alexander Wait. All Rights Reserved.

   This class returns the domain attributes.

   @site http://www.javaika.com
   @author Alexander Wait
   @version 2012-07-06
*/



public class Domain 
{
  
   private static final String DOMAIN = "javaika.com";

   private static final boolean RUN_LOCAL = false; 
   
   private static final boolean prefix = true;
   
   private static final String PORT = "80";
   
   
   private Domain() {}
   
   
   //**************************************** START PUBLIC METHODS *****************************************//
   
   
   /**
    * Returns the domain name.
    * @return
    */
   public static final String getDomain()
   {
      if (prefix)
      {
         return ("www." + DOMAIN);
      }
      
      else
      {
         return (DOMAIN);
      }
   }
   
   
   
   /**
    * Returns the port number.
    * @return
    */
   public static final String getPort()
   {
      if (RUN_LOCAL)
      {
         return (":" + PORT);
         
      }
      
      else {return ("");} 
   }
   
   
   //***************************************** END PUBLIC METHODS ******************************************//
   
   
   //********************************************** END CLASS **********************************************//

}


/*
   COPYRIGHT (C) 2010 Alexander Wait. All Rights Reserved.

   Defines a file browser for the install wizard.

   @site http://www.javaika.com
   @author Alexander Wait
   @version 2010-07-18
*/



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



public class FileBrowser
{

   String[] folderList;
   
   
   //************************************** START INITIALISATION CODE **************************************//


   /**
    * Initializes the driver roots.
    */
   public FileBrowser()
   {
      roots = File.listRoots();
   }
   
   
   //*************************************** END INITIALISATION CODE ***************************************//
   
   
   //**************************************** START PUBLIC METHODS *****************************************//


   /**
    * Returns the roots.
    * @return driveNames
    */
   public String[] returnRoots()
   {

      String[] driveNames = new String[roots.length + 1];

      driveNames[0] = "Select";

      for (int i = 0; i < roots.length; i ++)
      {
         driveNames[i + 1] = roots[i].toString(); 
      }

      return driveNames;
   }

   
   /**
    * Populates the directory list with folder names.
    * @param dir
    * @param includeHidden
    */
   public void setDirectoryList(File dir, boolean includeHidden)
   {
      File[] listDir = dir.listFiles(); 

      for (File element : listDir)
      {
         if (element.isDirectory()) 
         {
            if (includeHidden)
            {
               folders.add(element);
            }

            else
            {
               if (!element.isHidden()) {folders.add(element);}
            }
         }  
      }

      folderList = new String[folders.size()]; 
      
      for (int i = 0; i < folders.size(); i ++)
      {
         folderList[i] = folders.get(i).getName();
      }

      folders.clear();
   }
   
   
   //***************************************** END PUBLIC METHODS ******************************************//


   private File[] roots; 
   
   ArrayList<File> drives = new ArrayList<File>();
   ArrayList<File> folders = new ArrayList<File>();
   
   
   //********************************************** END CLASS **********************************************//

}


/*
   COPYRIGHT (C) 2010 - 2013 by Alexander Wait. All Rights Reserved.

   This class displays message dialogs.

   @site http://www.javaika.com
   @author Alexander Wait
   @version 2011-07-18
*/



import javax.swing.*;



public class Message
{

   private Message(){}
   
   
   //**************************************** START PUBLIC METHODS *****************************************//


   /**
    * Displays a message dialog.
    * @param text
    * @param heading
    * @param type 
    */
   public static void showMessage(String text, String heading, String type)
   {
      new JOptionPane(); Object[] options = {}; 

      if (type.equals("error"))
      {
         JOptionPane.showOptionDialog(null, text, heading,  
         JOptionPane.YES_OPTION, JOptionPane.ERROR_MESSAGE, null, options, null);
      }

      if (type.equals("information"))
      {
         JOptionPane.showOptionDialog(null, text, heading, 
         JOptionPane.YES_OPTION, JOptionPane.INFORMATION_MESSAGE, null, options, null);
      }

      if (type.equals("warning"))
      {
         JOptionPane.showOptionDialog(null, text, heading, 
         JOptionPane.YES_OPTION, JOptionPane.WARNING_MESSAGE, null, options, null);
      }

      if (type.equals("question"))
      {
         JOptionPane.showOptionDialog(null, text, heading, 
         JOptionPane.YES_OPTION, JOptionPane.QUESTION_MESSAGE, null, options, null);
      }
   }
   
   
   //***************************************** END PUBLIC METHODS ******************************************//
   
   
   //********************************************** END CLASS **********************************************//
   
}


/*
   COPYRIGHT (C) 2010 - 2013 by Alexander Wait. All Rights Reserved.

   This class provides a bridge that connects java with PHP
   scripts on the server for writing information from the 
   java application to a remote database on the server. 
   The class also receives data from PHP server scripts
   upon request for this information.

   @site http://www.javaika.com
   @author Alexander Wait
   @version 2012-03-18
*/



import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLEncoder;
import java.util.ArrayList;



public class Portal
{
   
 
   private Portal(){}
   
   
   //**************************************** START PUBLIC METHODS *****************************************//
   

   /**
    * Sends data to a specified PHP script address.
    * ESCA-JAVA0266:
    * @param address
    * @param userId
    * @param userPw
    * @param data
    */
   public static void javaToPhpGate(String address, String userId, String userPw, ArrayList<String> data) 
   {
      scriptAddress = address;


      try 
      {
         url = new URL(scriptAddress); conn = url.openConnection(); conn.setDoOutput(true); 
      

         dataSend = URLEncoder.encode("userId", "UTF-8") + "=" + URLEncoder.encode(userId, "UTF-8")

         + "&" + URLEncoder.encode("userPw", "UTF-8") + "=" + URLEncoder.encode(userPw, "UTF-8");
         
         
         if (data != null) {setVariableValues(data);} sendData(); 
         
         reader = new BufferedReader(new InputStreamReader(conn.getInputStream())); 


         while ((dataRecieve = reader.readLine()) != null) 
         {

            System.out.println(dataRecieve);
         }


         reader.close();
         
      }
      
      catch (IOException e) {System.out.println(Tools.thisPathAndLine() + e + "\n");}

   }
   
  
   
   /**
    * Receives data from a specified PHP script address.
    * ESCA-JAVA0266:
    * @param address
    * @param userId
    * @param userPw
    * @param data
    * @return
    */ 
   public static ArrayList<String> phpToJavaGate(String address, String userId, String userPw, ArrayList<String> data)
   { 
      scriptAddress = address; 

      ArrayList<String> output = new ArrayList<String>();
   

      try
      { 
         url = new URL(scriptAddress); conn = url.openConnection(); conn.setDoOutput(true);
     

         dataSend = URLEncoder.encode("userId", "UTF-8") + "=" + URLEncoder.encode(userId, "UTF-8")

         + "&" + URLEncoder.encode("userPw", "UTF-8") + "=" + URLEncoder.encode(userPw, "UTF-8");
         
         
         if (data != null) {setVariableValues(data);} sendData(); 
         
         reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));
       
         
         while ((dataRecieve = reader.readLine()) != null) 
         {
            output.add(dataRecieve);
         }
        

         reader.close();
        
      }
      
      catch (IOException e) {System.out.println(Tools.thisPathAndLine() + e + "\n");}
      

      return output;
         
   }
   
   
   
   /**
    * Clears database records using a specified PHP script address.
    * ESCA-JAVA0266:
    * @param address
    * @param userId
    * @param userPw
    * @param data
    */
   public static void clearFromDatabase(String address, String userId, String userPw, ArrayList<String> data) 
   {
      scriptAddress = address;


      try 
      {
         url = new URL(scriptAddress); conn = url.openConnection(); conn.setDoOutput(true); 
      

         dataSend = URLEncoder.encode("userId", "UTF-8") + "=" + URLEncoder.encode(userId, "UTF-8")

         + "&" + URLEncoder.encode("userPw", "UTF-8") + "=" + URLEncoder.encode(userPw, "UTF-8");
         
         
         if (data != null) {setVariableValues(data);} sendData();
         
         reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));


         while ((dataRecieve = reader.readLine()) != null) 
         {

            System.out.println(dataRecieve);
         }


         reader.close();
         
      }
      
      catch (IOException e) {System.out.println(Tools.thisPathAndLine() + e + "\n");}

   }
   
   
   //***************************************** END PUBLIC METHODS ******************************************//


   //**************************************** START PRIVATE METHODS ****************************************//

   
   /**
    * Sets the PHP variable values.
    * ESCA-JAVA0266:
    * @param data
    */
   private static void setVariableValues(ArrayList<String> data)
   {
      try
      {
         for (int i = 0; i < data.size(); i ++)
         {
            String variableName = "variable_" + Integer.toString(i+1);
       
            dataSend += "&" + URLEncoder.encode(variableName, "UTF-8") +

            "=" + URLEncoder.encode(data.get(i), "UTF-8");
         } 
      }
      
      catch (UnsupportedEncodingException e) {System.out.println(Tools.thisPathAndLine() + e + "\n");}
   }

   
   
   /**
    * Sends data to the appropriate PHP script.
    * ESCA-JAVA0266:
    */
   private static void sendData()
   {
      try
      {    
         writer = new BufferedWriter(new OutputStreamWriter(conn.getOutputStream()));
  
         writer.write(dataSend); writer.flush(); writer.close();
      }
 
      catch (MalformedURLException e) {System.out.println(Tools.thisPathAndLine() + e + "\n");}

      catch (IOException e) {System.out.println(Tools.thisPathAndLine() + e + "\n");}
   
   }


   //***************************************** END PRIVATE METHODS *****************************************//
   
   
   private static URL url;
   private static String dataSend;
   private static URLConnection conn;
   private static String dataRecieve;
   private static String scriptAddress;
   private static BufferedReader reader;
   private static BufferedWriter writer;
   
   
   //********************************************** END CLASS **********************************************//
   
}


/*
   COPYRIGHT (C) 2010 - 2013 by Alexander Wait. All Rights Reserved.

   This class provides handy tools.

   @site http://www.javaika.com
   @author Alexander Wait
   @version 2012-02-01
*/



public class Tools 
{

   private static final int EXCEPTION_LINE_BEAK = 2;
   
   
   private Tools() {}
   
   
   //**************************************** START PUBLIC METHODS *****************************************//


   /**
    * This method returns the line number and path where it's called.
    * The syntax new Exception().getStackTrace()[0].getLineNumber() 
    * will only give the current line number of the source file.
    * @return
    */
   public static String thisPathAndLine()
   {
   
      String lineAndPath = ""; String stackTrace = "";
 
      stackTrace = new Exception().getStackTrace()[1].toString();
      
      
      for (int i = stackTrace.length()-1; i >= 0; i --)
      {
         if (stackTrace.charAt(i) == ')') {continue;} 
        
         else if (stackTrace.charAt(i) == '(') {break;}
        
         else {lineAndPath = (stackTrace.charAt(i) + lineAndPath);}
      }
         
      return lineAndPath + returnNewline(EXCEPTION_LINE_BEAK);
      
   }
   
   
   
   /**
    * Delays execution.
    * @param length
    */
   public static void delay(long length) 
   {
      for (long i = 0; i < length; i ++) {}
   }
   
  
 
   /**
    * This method returns a space.
    * @param length
    * @return
    */
   public static String returnSpace(int length)
   {
      String space = "";
      
      
      for (int i = 0; i < length; i ++)
      {
         space += " ";
      }
      
      return space;
   }
   
   
   
   /**
    * Assigns newlines to a string.
    * @param lines
    * @return
    */
   public static String returnNewline(int lines)
   {
      String newline = "";
      
      
      for (int i = 0; i < lines; i++)
      {
         newline += "\n";
      }
      
      
      return newline;
   
   }
   
   
   
   /**
    * Returns the users desktop path.
    * @return
    */
   public static String returnDesktopPath()
   {
      return (System.getProperty("user.home") + "/Desktop").replace("\\", "/") + "/"; 
   }
   

   //***************************************** END PUBLIC METHODS ******************************************//

   
   //********************************************** END CLASS **********************************************//
   
}