/*
 * BackupView.java
 */
package main;

import java.awt.AWTException;
import java.awt.Image;
import java.awt.MenuItem;
import java.awt.PopupMenu;
import java.awt.SystemTray;
import java.awt.TrayIcon;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.dom4j.DocumentException;
import org.jdesktop.application.Action;
import org.jdesktop.application.ResourceMap;
import org.jdesktop.application.SingleFrameApplication;
import org.jdesktop.application.FrameView;
import org.jdesktop.application.TaskMonitor;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.io.File;
import javax.swing.Timer;
import javax.swing.Icon;
import javax.swing.JDialog;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import schedule.ITask;
import schedule.ScheduleConfigManager;
import schedule.Scheduler;
import backupAndRecovery.BackupMetaContainer;
import java.awt.Cursor;

/**
 * The application's main frame.
 */
public class BackupView extends FrameView {

    private FrameView thisView = this;
    private boolean visible = true;

    public BackupView(SingleFrameApplication app) {
        super(app);

        // closing application only hides it
        app.getMainFrame().setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE);

        // set application icon
        ResourceMap m = BackupApp.getInstance().getContext().getResourceManager().getResourceMap(BackupView.class);
        Image image = m.getImageIcon("appIcon.icon").getImage();
        thisView.getFrame().setIconImage(image);

        // tray initialization
        initTray();

        initComponents();

        // status bar initialization - message timeout, idle icon and busy animation, etc
        ResourceMap resourceMap = getResourceMap();
        int messageTimeout = resourceMap.getInteger("StatusBar.messageTimeout");
        messageTimer = new Timer(messageTimeout, new ActionListener() {

            public void actionPerformed(ActionEvent e) {
                statusMessageLabel.setText("");
            }
        });
        messageTimer.setRepeats(false);
        int busyAnimationRate = resourceMap.getInteger("StatusBar.busyAnimationRate");
        for (int i = 0; i < busyIcons.length; i++) {
            busyIcons[i] = resourceMap.getIcon("StatusBar.busyIcons[" + i + "]");
        }
        busyIconTimer = new Timer(busyAnimationRate, new ActionListener() {

            public void actionPerformed(ActionEvent e) {
                busyIconIndex = (busyIconIndex + 1) % busyIcons.length;
                statusAnimationLabel.setIcon(busyIcons[busyIconIndex]);
            }
        });
        idleIcon = resourceMap.getIcon("StatusBar.idleIcon");
        statusAnimationLabel.setIcon(idleIcon);
        progressBar.setVisible(false);
        progressBar.setIndeterminate(true);

        // connecting action tasks to status bar via TaskMonitor
        taskMonitor = new TaskMonitor(getApplication().getContext());
        taskMonitor.addPropertyChangeListener(new java.beans.PropertyChangeListener() {

            public void propertyChange(java.beans.PropertyChangeEvent evt) {
                String propertyName = evt.getPropertyName();
                if ("started".equals(propertyName)) {
                    if (!busyIconTimer.isRunning()) {
                        statusAnimationLabel.setIcon(busyIcons[0]);
                        busyIconIndex = 0;
                        busyIconTimer.start();
                    }
                    progressBar.setVisible(true);
                    progressBar.setIndeterminate(true);
                } else if ("done".equals(propertyName)) {
                    busyIconTimer.stop();
                    statusAnimationLabel.setIcon(idleIcon);
                    progressBar.setVisible(false);
                    progressBar.setValue(0);
                } else if ("message".equals(propertyName)) {
                    String text = (String) (evt.getNewValue());
                    statusMessageLabel.setText((text == null) ? "" : text);
                    messageTimer.restart();
                } else if ("progress".equals(propertyName)) {
                    int value = (Integer) (evt.getNewValue());
                    progressBar.setVisible(true);
                    progressBar.setIndeterminate(false);
                    progressBar.setValue(value);
                }
            }
        });

    }

    @Action
    public void showAboutBox() {
        if (aboutBox == null) {
            JFrame mainFrame = BackupApp.getApplication().getMainFrame();
            aboutBox = new BackupAboutBox(mainFrame);
            aboutBox.setLocationRelativeTo(mainFrame);
        }
        BackupApp.getApplication().show(aboutBox);
    }

    @Action
    public void showConfigDialog() {
        if (configDialog == null) {
            JFrame mainFrame = BackupApp.getApplication().getMainFrame();
            configDialog = new ConfigurationView(mainFrame);
            configDialog.setLocationRelativeTo(mainFrame);
        }
        configDialog.reloadConfig();
        BackupApp.getApplication().show(configDialog);
    }

    public void showWorking() {
        thisView.getFrame().setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
        taskMonitor.getPropertyChangeListeners()[0].propertyChange(new java.beans.PropertyChangeEvent(this, "started", null, null));

    }

    public void hideWorking() {
        thisView.getFrame().setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
        taskMonitor.getPropertyChangeListeners()[0].propertyChange(new java.beans.PropertyChangeEvent(this, "done", null, null));
    }

    @Action
    public void openFile() {
        int returnVal = fcBackup.showOpenDialog(thisView.getFrame());

        if (returnVal == JFileChooser.APPROVE_OPTION) {
            txtFile.setText(fcBackup.getSelectedFile().toString());
        }
    }

    @Action
    public void backupFile() {
        File file = new File(txtFile.getText());
        if (!file.exists() || !file.canRead()) {
            JOptionPane.showMessageDialog(null, "Could not read file.");
            return;
        }
        new Thread() {

            @Override
            public void run() {
                AppManager.backupFile(txtFile.getText());
                hideWorking();
            }
        }.start();
        showWorking();
    }

    @Action
    public void searchBackups() {
        Thread t = new Thread() {

            @Override
            public void run() {

                BackupMetaContainer[] metas = AppManager.searchBackups(txtFind.getText());
                BackupListModel model = new BackupListModel(metas);
                tblBackups.setModel(model);
                model.fireTableDataChanged();

                hideWorking();
            }
        };

        showWorking();
        t.start();
    }

    @Action
    public void recoverBackup() {
        if (tblBackups.getRowCount() < 1) {
            JOptionPane.showMessageDialog(null, "Please, search for backup first.");
            return;
        }

        if (tblBackups.getSelectedRowCount() == 0) {
            JOptionPane.showMessageDialog(null, "Please, select backup to recover.");
            return;
        }

        if (tblBackups.getSelectedRowCount() > 1) {
            JOptionPane.showMessageDialog(null, "Please, select only one backup to recover.");
            return;
        }

        showWorking();

        int index = tblBackups.convertRowIndexToModel(tblBackups.getSelectedRow());

        BackupListModel model = (BackupListModel) tblBackups.getModel();
        final BackupMetaContainer meta = model.getMeta(index);

        fcRecovery.setSelectedFile(new File(meta.getFilename()));
        int returnVal = fcRecovery.showSaveDialog(thisView.getFrame());
        if (returnVal == JFileChooser.APPROVE_OPTION) {
            final File out = fcRecovery.getSelectedFile();
            Thread t = new Thread() {

                @Override
                public void run() {
                    AppManager.recover(meta, out);
                    hideWorking();
                }
            };
            t.start();
        }

    }

    @Action
    public void deleteBackup() {
        if (tblBackups.getRowCount() < 1) {
            JOptionPane.showMessageDialog(null, "Please, search for backup first.");
            return;
        }

        if (tblBackups.getSelectedRowCount() == 0) {
            JOptionPane.showMessageDialog(null, "Please, select backup to delete.");
            return;
        }

        int[] selected = tblBackups.getSelectedRows();

        BackupListModel model;
        BackupMetaContainer meta = null;
        for (int i = 0; i < selected.length; i++) {
            int index = tblBackups.convertRowIndexToModel(selected[i]);
            model = (BackupListModel) tblBackups.getModel();
            meta = model.getMeta(index);

            //TODO: krajsi vystup pre viac vybratych backupov
            int resp = JOptionPane.showConfirmDialog(getComponent(),
                    "Are you sure to delete backup of " + meta.getFilename() +
                    " created at " + meta.getBackupTime() +
                    "?\n If deleted, backup can not be recovered.",
                    "Confirmation",
                    JOptionPane.YES_NO_OPTION);
            if (resp != JOptionPane.YES_OPTION) {
                return;
            }

            final BackupMetaContainer meta0 = meta;
            new Thread() {

                @Override
                public void run() {
                    AppManager.delete(meta0, true);
                    scheduleChanged(ScheduleConfigManager.getScheduleConfigManager());
                    hideWorking();
                }
            }.start();
            showWorking();
        }

        BackupMetaContainer[] metas = AppManager.searchBackups(meta.getFilename());
        model = new BackupListModel(metas);
        tblBackups.setModel(model);
        model.fireTableDataChanged();
        hideWorking();
    }

    @Action
    public void schedule() throws DocumentException {
        ScheduleConfigManager manager = ScheduleConfigManager.getScheduleConfigManager();
        int dom;
        int dow;
        int hour;
        int minute;

        if (txtDayOfMonth.getText().compareToIgnoreCase("any") == 0) {
            dom = ITask.ANYTIME;
        } else {
            dom = Integer.parseInt(txtDayOfMonth.getText());
        }
        if (dom != ITask.ANYTIME && (dom < 1 || dom > 31)) {
            return;
        }

        dow = cbxDayOfWeek.getSelectedIndex();
        if (dow == 0) {
            dow = ITask.ANYTIME;
        }

        try {
            if (txtHour.getText().compareToIgnoreCase("any") == 0) {
                hour = ITask.ANYTIME;
            } else {
                hour = Integer.parseInt(txtHour.getText());
            }
            minute = Integer.parseInt(txtMinute.getText());
        } catch (NumberFormatException ex) {
            return;
        }

        if ((hour != ITask.ANYTIME) && (hour < 0 || hour > 23)) {
            return;
        }

        if (minute < 0 || minute > 59) {
            return;
        }
        try {
            manager.addTask(ScheduleConfigManager.BACKUP, txtFile.getText(), dom, dow, hour, minute);
            scheduleChanged(manager);
        } catch (IllegalArgumentException ex) {
        }
    }

    @Action
    public void removeFromSchedule() {
        if (tblSchedule.getRowCount() < 1) {
            JOptionPane.showMessageDialog(null, "No actions to delete.");
            return;
        }

        if (tblSchedule.getSelectedRowCount() < 1) {
            JOptionPane.showMessageDialog(null, "Please, select action to delete.");
            return;
        }

        int index = tblSchedule.convertRowIndexToModel(tblSchedule.getSelectedRow());
        ScheduleConfigManager manager = ScheduleConfigManager.getScheduleConfigManager();
        manager.deleteTask(index);
        scheduleChanged(manager);


    }

    private void scheduleChanged(ScheduleConfigManager manager) {

        try {
            manager.saveConfig();
            Scheduler scheduler = Scheduler.getScheduler();
            scheduler.clear();
            manager.parseFile(scheduler);
            scheduler.reschedule();

            BackupScheduleModel model = new BackupScheduleModel();
            tblSchedule.setModel(model);
            model.fireTableDataChanged();
        } catch (IllegalArgumentException ex) {
            Logger.getLogger(BackupView.class.getName()).log(Level.SEVERE, null, ex);
        } catch (DocumentException ex) {
            Logger.getLogger(BackupView.class.getName()).log(Level.SEVERE, null, ex);
        } catch (FileNotFoundException ex) {
            Logger.getLogger(BackupView.class.getName()).log(Level.SEVERE, null, ex);
        } catch (IOException ex) {
            Logger.getLogger(BackupView.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    private void initTray() {
        // mostly taken from http://java.sun.com/developer/technicalArticles/J2SE/Desktop/javase6/systemtray/
        if (SystemTray.isSupported()) {
            SystemTray tray = SystemTray.getSystemTray();
            ResourceMap m = BackupApp.getInstance().getContext().getResourceManager().getResourceMap(BackupView.class);

            //Image image = Toolkit.getDefaultToolkit().getImage("bcp.png");
            Image image = m.getImageIcon("trayIcon.icon").getImage();

            MouseListener mouseListener = new MouseListener() {

                public void mouseClicked(MouseEvent e) {
                    //System.out.println("Tray Icon - Mouse clicked!");
                    if (visible) {
                        BackupApp.getApplication().hide(thisView);
                    } else {
                        BackupApp.getApplication().show(thisView);
                    }
                    visible = !visible;
                }

                public void mouseEntered(MouseEvent e) {
                    //System.out.println("Tray Icon - Mouse entered!");
                }

                public void mouseExited(MouseEvent e) {
                    //System.out.println("Tray Icon - Mouse exited!");
                }

                public void mousePressed(MouseEvent e) {
                    //System.out.println("Tray Icon - Mouse pressed!");
                }

                public void mouseReleased(MouseEvent e) {
                    //System.out.println("Tray Icon - Mouse released!");
                }
            };

            PopupMenu popup = initTrayPopup();

            trayIcon = new TrayIcon(image, "Backup", popup);
            trayIcon.setImageAutoSize(true);
            trayIcon.addMouseListener(mouseListener);

            try {
                tray.add(trayIcon);
            } catch (AWTException e) {
                System.err.println("Tray Icon could not be created.");
            }

        } else {
            BackupApp.getApplication().getMainFrame().setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        }
    }

    private PopupMenu initTrayPopup() {
        ActionListener exitListener = new ActionListener() {

            public void actionPerformed(ActionEvent e) {
                // Recycle exit method.
                exitMenuItemActionPerformed(e);
                System.exit(0);
            }
        };

        PopupMenu popup = new PopupMenu();

        MenuItem exitItem = new MenuItem("Exit");
        exitItem.addActionListener(exitListener);

        popup.add(exitItem);

        return popup;
    }

    /** This method is called from within the constructor to
     * initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is
     * always regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        mainPanel = new javax.swing.JPanel();
        jtpContainer = new javax.swing.JTabbedPane();
        jpBackup = new javax.swing.JPanel();
        txtFile = new javax.swing.JTextField();
        btnBackupFile = new javax.swing.JButton();
        btnOpen = new javax.swing.JButton();
        jSeparator1 = new javax.swing.JSeparator();
        jSeparator2 = new javax.swing.JSeparator();
        lblBackup = new javax.swing.JLabel();
        lblSchedule = new javax.swing.JLabel();
        lblWeek = new javax.swing.JLabel();
        jLabel1 = new javax.swing.JLabel();
        lblHour = new javax.swing.JLabel();
        lblMinute = new javax.swing.JLabel();
        cbxDayOfWeek = new javax.swing.JComboBox();
        txtDayOfMonth = new javax.swing.JTextField();
        txtHour = new javax.swing.JTextField();
        txtMinute = new javax.swing.JTextField();
        jScrollPane2 = new javax.swing.JScrollPane();
        tblSchedule = new javax.swing.JTable();
        btnAddSchedule = new javax.swing.JButton();
        btnDelSchedule = new javax.swing.JButton();
        jLabel2 = new javax.swing.JLabel();
        jpRecovery = new javax.swing.JPanel();
        btnRecover = new javax.swing.JButton();
        txtFind = new javax.swing.JTextField();
        btnFind = new javax.swing.JButton();
        jScrollPane1 = new javax.swing.JScrollPane();
        tblBackups = new javax.swing.JTable();
        btnDelete = new javax.swing.JButton();
        menuBar = new javax.swing.JMenuBar();
        javax.swing.JMenu fileMenu = new javax.swing.JMenu();
        javax.swing.JMenuItem exitMenuItem = new javax.swing.JMenuItem();
        javax.swing.JMenu optionsMenu = new javax.swing.JMenu();
        javax.swing.JMenuItem configurationMenuItem = new javax.swing.JMenuItem();
        javax.swing.JMenu helpMenu = new javax.swing.JMenu();
        javax.swing.JMenuItem aboutMenuItem = new javax.swing.JMenuItem();
        statusPanel = new javax.swing.JPanel();
        javax.swing.JSeparator statusPanelSeparator = new javax.swing.JSeparator();
        statusMessageLabel = new javax.swing.JLabel();
        statusAnimationLabel = new javax.swing.JLabel();
        progressBar = new javax.swing.JProgressBar();
        fcBackup = new javax.swing.JFileChooser();
        fcRecovery = new javax.swing.JFileChooser();

        mainPanel.setMinimumSize(new java.awt.Dimension(145, 0));
        mainPanel.setName("mainPanel"); // NOI18N

        jtpContainer.setMinimumSize(new java.awt.Dimension(140, 44));
        jtpContainer.setName("jtpContainer"); // NOI18N

        jpBackup.setName("jpBackup"); // NOI18N

        org.jdesktop.application.ResourceMap resourceMap = org.jdesktop.application.Application.getInstance(main.BackupApp.class).getContext().getResourceMap(BackupView.class);
        txtFile.setText(resourceMap.getString("txtFile.text")); // NOI18N
        txtFile.setName("txtFile"); // NOI18N

        javax.swing.ActionMap actionMap = org.jdesktop.application.Application.getInstance(main.BackupApp.class).getContext().getActionMap(BackupView.class, this);
        btnBackupFile.setAction(actionMap.get("backupFile")); // NOI18N
        btnBackupFile.setMnemonic('B');
        btnBackupFile.setText(resourceMap.getString("btnBackupFile.text")); // NOI18N
        btnBackupFile.setName("btnBackupFile"); // NOI18N

        btnOpen.setAction(actionMap.get("openFile")); // NOI18N
        btnOpen.setMnemonic('O');
        btnOpen.setText(resourceMap.getString("btnOpen.text")); // NOI18N
        btnOpen.setActionCommand(resourceMap.getString("btnOpen.actionCommand")); // NOI18N
        btnOpen.setName("btnOpen"); // NOI18N

        jSeparator1.setName("jSeparator1"); // NOI18N

        jSeparator2.setName("jSeparator2"); // NOI18N

        lblBackup.setText(resourceMap.getString("lblBackup.text")); // NOI18N
        lblBackup.setName("lblBackup"); // NOI18N

        lblSchedule.setText(resourceMap.getString("lblSchedule.text")); // NOI18N
        lblSchedule.setName("lblSchedule"); // NOI18N

        lblWeek.setText(resourceMap.getString("lblWeek.text")); // NOI18N
        lblWeek.setName("lblWeek"); // NOI18N

        jLabel1.setText(resourceMap.getString("jLabel1.text")); // NOI18N
        jLabel1.setName("jLabel1"); // NOI18N

        lblHour.setText(resourceMap.getString("lblHour.text")); // NOI18N
        lblHour.setName("lblHour"); // NOI18N

        lblMinute.setText(resourceMap.getString("lblMinute.text")); // NOI18N
        lblMinute.setName("lblMinute"); // NOI18N

        cbxDayOfWeek.setModel(new javax.swing.DefaultComboBoxModel(new String[] { "Any", "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"}));
        cbxDayOfWeek.setName("cbxDayOfWeek"); // NOI18N

        txtDayOfMonth.setText(resourceMap.getString("txtDayOfMonth.text")); // NOI18N
        txtDayOfMonth.setName("txtDayOfMonth"); // NOI18N

        txtHour.setText(resourceMap.getString("txtHour.text")); // NOI18N
        txtHour.setName("txtHour"); // NOI18N

        txtMinute.setText(resourceMap.getString("txtMinute.text")); // NOI18N
        txtMinute.setName("txtMinute"); // NOI18N

        jScrollPane2.setName("jScrollPane2"); // NOI18N

        tblSchedule.setAutoCreateRowSorter(true);
        tblSchedule.setModel(new BackupScheduleModel());
        tblSchedule.setAutoscrolls(false);
        tblSchedule.setFillsViewportHeight(true);
        tblSchedule.setName("tblSchedule"); // NOI18N
        jScrollPane2.setViewportView(tblSchedule);
        //tblSchedule.setFillsViewportHeight(true);

        btnAddSchedule.setAction(actionMap.get("schedule")); // NOI18N
        btnAddSchedule.setMnemonic('S');
        btnAddSchedule.setText(resourceMap.getString("btnAddSchedule.text")); // NOI18N
        btnAddSchedule.setName("btnAddSchedule"); // NOI18N

        btnDelSchedule.setAction(actionMap.get("removeFromSchedule")); // NOI18N
        btnDelSchedule.setText(resourceMap.getString("btnDelSchedule.text")); // NOI18N
        btnDelSchedule.setName("btnDelSchedule"); // NOI18N

        jLabel2.setText(resourceMap.getString("jLabel2.text")); // NOI18N
        jLabel2.setName("jLabel2"); // NOI18N

        javax.swing.GroupLayout jpBackupLayout = new javax.swing.GroupLayout(jpBackup);
        jpBackup.setLayout(jpBackupLayout);
        jpBackupLayout.setHorizontalGroup(
            jpBackupLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(jpBackupLayout.createSequentialGroup()
                .addGap(22, 22, 22)
                .addGroup(jpBackupLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addComponent(lblSchedule)
                    .addGroup(jpBackupLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
                        .addGroup(jpBackupLayout.createSequentialGroup()
                            .addGroup(jpBackupLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                                .addComponent(lblWeek, javax.swing.GroupLayout.Alignment.TRAILING)
                                .addComponent(jLabel1, javax.swing.GroupLayout.Alignment.TRAILING)
                                .addComponent(lblHour, javax.swing.GroupLayout.Alignment.TRAILING)
                                .addComponent(lblMinute, javax.swing.GroupLayout.Alignment.TRAILING))
                            .addGap(18, 18, 18)
                            .addGroup(jpBackupLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
                                .addComponent(txtMinute)
                                .addComponent(txtHour)
                                .addComponent(txtDayOfMonth)
                                .addComponent(cbxDayOfWeek, javax.swing.GroupLayout.PREFERRED_SIZE, 56, javax.swing.GroupLayout.PREFERRED_SIZE)))
                        .addGroup(jpBackupLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
                            .addComponent(btnDelSchedule, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                            .addComponent(btnAddSchedule, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))))
                .addGap(20, 20, 20)
                .addGroup(jpBackupLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addComponent(jLabel2)
                    .addGroup(jpBackupLayout.createSequentialGroup()
                        .addGap(10, 10, 10)
                        .addComponent(jScrollPane2, javax.swing.GroupLayout.DEFAULT_SIZE, 392, Short.MAX_VALUE)))
                .addContainerGap())
            .addComponent(jSeparator1, javax.swing.GroupLayout.DEFAULT_SIZE, 597, Short.MAX_VALUE)
            .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jpBackupLayout.createSequentialGroup()
                .addContainerGap(383, Short.MAX_VALUE)
                .addComponent(lblBackup)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                .addComponent(btnBackupFile, javax.swing.GroupLayout.PREFERRED_SIZE, 80, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addContainerGap())
            .addComponent(jSeparator2, javax.swing.GroupLayout.DEFAULT_SIZE, 597, Short.MAX_VALUE)
            .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jpBackupLayout.createSequentialGroup()
                .addContainerGap()
                .addComponent(txtFile, javax.swing.GroupLayout.DEFAULT_SIZE, 487, Short.MAX_VALUE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                .addComponent(btnOpen, javax.swing.GroupLayout.PREFERRED_SIZE, 80, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addContainerGap())
        );
        jpBackupLayout.setVerticalGroup(
            jpBackupLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(jpBackupLayout.createSequentialGroup()
                .addContainerGap()
                .addGroup(jpBackupLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(txtFile, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addComponent(btnOpen))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                .addComponent(jSeparator1, javax.swing.GroupLayout.PREFERRED_SIZE, 2, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                .addGroup(jpBackupLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(btnBackupFile)
                    .addComponent(lblBackup))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                .addComponent(jSeparator2, javax.swing.GroupLayout.PREFERRED_SIZE, 10, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(jpBackupLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(lblSchedule)
                    .addComponent(jLabel2))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(jpBackupLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addGroup(jpBackupLayout.createSequentialGroup()
                        .addGroup(jpBackupLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                            .addComponent(lblWeek)
                            .addComponent(cbxDayOfWeek, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                        .addGroup(jpBackupLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                            .addComponent(jLabel1)
                            .addComponent(txtDayOfMonth, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                        .addGroup(jpBackupLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                            .addComponent(lblHour)
                            .addComponent(txtHour, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                        .addGroup(jpBackupLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                            .addComponent(lblMinute)
                            .addComponent(txtMinute, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                        .addComponent(btnAddSchedule)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                        .addComponent(btnDelSchedule))
                    .addComponent(jScrollPane2, javax.swing.GroupLayout.DEFAULT_SIZE, 211, Short.MAX_VALUE))
                .addContainerGap())
        );

        jtpContainer.addTab(resourceMap.getString("jpBackup.TabConstraints.tabTitle"), jpBackup); // NOI18N

        jpRecovery.setName("jpRecovery"); // NOI18N

        btnRecover.setAction(actionMap.get("recoverBackup")); // NOI18N
        btnRecover.setText(resourceMap.getString("btnRecover.text")); // NOI18N
        btnRecover.setName("btnRecover"); // NOI18N

        txtFind.setText(resourceMap.getString("txtFind.text")); // NOI18N
        txtFind.setName("txtFind"); // NOI18N

        btnFind.setAction(actionMap.get("searchBackups")); // NOI18N
        btnFind.setMnemonic('F');
        btnFind.setText(resourceMap.getString("btnFind.text")); // NOI18N
        btnFind.setName("btnFind"); // NOI18N

        jScrollPane1.setName("jScrollPane1"); // NOI18N

        tblBackups.setModel(new main.BackupListModel(null));
        tblBackups.setFillsViewportHeight(true);
        tblBackups.setName("tblBackups"); // NOI18N
        jScrollPane1.setViewportView(tblBackups);
        tblBackups.setAutoCreateRowSorter(true);

        btnDelete.setAction(actionMap.get("deleteBackup")); // NOI18N
        btnDelete.setText(resourceMap.getString("btnDelete.text")); // NOI18N
        btnDelete.setName("btnDelete"); // NOI18N

        javax.swing.GroupLayout jpRecoveryLayout = new javax.swing.GroupLayout(jpRecovery);
        jpRecovery.setLayout(jpRecoveryLayout);
        jpRecoveryLayout.setHorizontalGroup(
            jpRecoveryLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(jpRecoveryLayout.createSequentialGroup()
                .addContainerGap()
                .addGroup(jpRecoveryLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 577, Short.MAX_VALUE)
                    .addGroup(jpRecoveryLayout.createSequentialGroup()
                        .addComponent(txtFind, javax.swing.GroupLayout.DEFAULT_SIZE, 487, Short.MAX_VALUE)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                        .addComponent(btnFind, javax.swing.GroupLayout.PREFERRED_SIZE, 80, javax.swing.GroupLayout.PREFERRED_SIZE))
                    .addGroup(jpRecoveryLayout.createSequentialGroup()
                        .addComponent(btnDelete)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 424, Short.MAX_VALUE)
                        .addComponent(btnRecover, javax.swing.GroupLayout.PREFERRED_SIZE, 90, javax.swing.GroupLayout.PREFERRED_SIZE)))
                .addContainerGap())
        );
        jpRecoveryLayout.setVerticalGroup(
            jpRecoveryLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(jpRecoveryLayout.createSequentialGroup()
                .addContainerGap()
                .addGroup(jpRecoveryLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(txtFind, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addComponent(btnFind))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 260, Short.MAX_VALUE)
                .addGap(11, 11, 11)
                .addGroup(jpRecoveryLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(btnRecover)
                    .addComponent(btnDelete))
                .addContainerGap())
        );

        jtpContainer.addTab(resourceMap.getString("jpRecovery.TabConstraints.tabTitle"), jpRecovery); // NOI18N

        javax.swing.GroupLayout mainPanelLayout = new javax.swing.GroupLayout(mainPanel);
        mainPanel.setLayout(mainPanelLayout);
        mainPanelLayout.setHorizontalGroup(
            mainPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGap(0, 602, Short.MAX_VALUE)
            .addGroup(mainPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                .addComponent(jtpContainer, javax.swing.GroupLayout.DEFAULT_SIZE, 602, Short.MAX_VALUE))
        );
        mainPanelLayout.setVerticalGroup(
            mainPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGap(0, 378, Short.MAX_VALUE)
            .addGroup(mainPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                .addComponent(jtpContainer, javax.swing.GroupLayout.DEFAULT_SIZE, 378, Short.MAX_VALUE))
        );

        menuBar.setName("menuBar"); // NOI18N

        fileMenu.setText(resourceMap.getString("fileMenu.text")); // NOI18N
        fileMenu.setName("fileMenu"); // NOI18N

        exitMenuItem.setAction(actionMap.get("quit")); // NOI18N
        exitMenuItem.setName("exitMenuItem"); // NOI18N
        exitMenuItem.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                exitMenuItemActionPerformed(evt);
            }
        });
        fileMenu.add(exitMenuItem);

        menuBar.add(fileMenu);

        optionsMenu.setText(resourceMap.getString("optionsMenu.text")); // NOI18N
        optionsMenu.setName("optionsMenu"); // NOI18N

        configurationMenuItem.setAction(actionMap.get("showConfigDialog")); // NOI18N
        configurationMenuItem.setText(resourceMap.getString("configurationMenuItem.text")); // NOI18N
        configurationMenuItem.setName("configurationMenuItem"); // NOI18N
        configurationMenuItem.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                configurationMenuItemActionPerformed(evt);
            }
        });
        optionsMenu.add(configurationMenuItem);

        menuBar.add(optionsMenu);

        helpMenu.setText(resourceMap.getString("helpMenu.text")); // NOI18N
        helpMenu.setName("helpMenu"); // NOI18N

        aboutMenuItem.setAction(actionMap.get("showAboutBox")); // NOI18N
        aboutMenuItem.setName("aboutMenuItem"); // NOI18N
        helpMenu.add(aboutMenuItem);

        menuBar.add(helpMenu);

        statusPanel.setName("statusPanel"); // NOI18N

        statusPanelSeparator.setName("statusPanelSeparator"); // NOI18N

        statusMessageLabel.setName("statusMessageLabel"); // NOI18N

        statusAnimationLabel.setHorizontalAlignment(javax.swing.SwingConstants.LEFT);
        statusAnimationLabel.setName("statusAnimationLabel"); // NOI18N

        progressBar.setName("progressBar"); // NOI18N

        javax.swing.GroupLayout statusPanelLayout = new javax.swing.GroupLayout(statusPanel);
        statusPanel.setLayout(statusPanelLayout);
        statusPanelLayout.setHorizontalGroup(
            statusPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addComponent(statusPanelSeparator, javax.swing.GroupLayout.DEFAULT_SIZE, 602, Short.MAX_VALUE)
            .addGroup(statusPanelLayout.createSequentialGroup()
                .addContainerGap()
                .addComponent(statusMessageLabel)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 432, Short.MAX_VALUE)
                .addComponent(progressBar, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(statusAnimationLabel)
                .addContainerGap())
        );
        statusPanelLayout.setVerticalGroup(
            statusPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(statusPanelLayout.createSequentialGroup()
                .addComponent(statusPanelSeparator, javax.swing.GroupLayout.PREFERRED_SIZE, 2, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                .addGroup(statusPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(statusMessageLabel)
                    .addComponent(statusAnimationLabel)
                    .addComponent(progressBar, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addGap(3, 3, 3))
        );

        fcBackup.setName("fcBackup"); // NOI18N

        fcRecovery.setName("fcRecovery"); // NOI18N

        setComponent(mainPanel);
        setMenuBar(menuBar);
        setStatusBar(statusPanel);
    }// </editor-fold>//GEN-END:initComponents

    private void exitMenuItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_exitMenuItemActionPerformed
        AppManager.stop();
    }//GEN-LAST:event_exitMenuItemActionPerformed

    private void configurationMenuItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_configurationMenuItemActionPerformed
        // TODO add your handling code here:
    }//GEN-LAST:event_configurationMenuItemActionPerformed
    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JButton btnAddSchedule;
    private javax.swing.JButton btnBackupFile;
    private javax.swing.JButton btnDelSchedule;
    private javax.swing.JButton btnDelete;
    private javax.swing.JButton btnFind;
    private javax.swing.JButton btnOpen;
    private javax.swing.JButton btnRecover;
    private javax.swing.JComboBox cbxDayOfWeek;
    private javax.swing.JFileChooser fcBackup;
    private javax.swing.JFileChooser fcRecovery;
    private javax.swing.JLabel jLabel1;
    private javax.swing.JLabel jLabel2;
    private javax.swing.JScrollPane jScrollPane1;
    private javax.swing.JScrollPane jScrollPane2;
    private javax.swing.JSeparator jSeparator1;
    private javax.swing.JSeparator jSeparator2;
    private javax.swing.JPanel jpBackup;
    private javax.swing.JPanel jpRecovery;
    private javax.swing.JTabbedPane jtpContainer;
    private javax.swing.JLabel lblBackup;
    private javax.swing.JLabel lblHour;
    private javax.swing.JLabel lblMinute;
    private javax.swing.JLabel lblSchedule;
    private javax.swing.JLabel lblWeek;
    private javax.swing.JPanel mainPanel;
    private javax.swing.JMenuBar menuBar;
    private javax.swing.JProgressBar progressBar;
    private javax.swing.JLabel statusAnimationLabel;
    private javax.swing.JLabel statusMessageLabel;
    private javax.swing.JPanel statusPanel;
    private javax.swing.JTable tblBackups;
    private javax.swing.JTable tblSchedule;
    private javax.swing.JTextField txtDayOfMonth;
    private javax.swing.JTextField txtFile;
    private javax.swing.JTextField txtFind;
    private javax.swing.JTextField txtHour;
    private javax.swing.JTextField txtMinute;
    // End of variables declaration//GEN-END:variables
    // Custom declaration
    private TrayIcon trayIcon;
    // End of custom declaration
    private final Timer messageTimer;
    private final Timer busyIconTimer;
    private final Icon idleIcon;
    private final Icon[] busyIcons = new Icon[15];
    private int busyIconIndex = 0;
    private JDialog aboutBox;
    private TaskMonitor taskMonitor;
    private ConfigurationView configDialog;
}
