/*
 * Copyright 2009 Lari Natri <lari.natri@gmail.com>
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 * 
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 * 
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */


package compid.gui;

import net.aavalla.utils.jobpool.JobPool;
import net.aavalla.utils.jobpool.gui.JobPoolDialog;
import compid.application.CompidApp;
import net.aavalla.utils.jobpool.JobPoolMessageEvent;
import net.aavalla.utils.jobpool.JobPoolMessageListener;
import java.awt.Image;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.util.LinkedList;
import javax.swing.Timer;
import javax.swing.Icon;
import javax.swing.UIManager;
import org.jdesktop.application.Application;
import org.jdesktop.application.ResourceMap;

/**
 *
 * @author Lari Natri
 */
public class StatusPanel extends javax.swing.JPanel implements JobPoolMessageListener {

    public StatusPanel() {
        this(null);
    }

    /** Creates new form StatusPanel */
    public StatusPanel(Image icon) {

        initComponents();

        JobPool pool = CompidApp.getApplication().getJobPool();
        pool.addJobPoolMessageListenerSwing(this);
        
        UIManager.put("ProgressBar.repaintInterval", new Integer(100)); //NOI18N
        UIManager.put("ProgressBar.cycleTime", new Integer(8000)); //NOI18N



        threadPoolViewer = new JobPoolDialog(CompidApp.getApplication().getMainFrame(), false, pool, true,icon);
        threadPoolViewer.setTitle("Jobs - Compid");
        threadPoolViewer.setLocationRelativeTo(CompidApp.getApplication().getMainFrame());

        // status bar initialization - message timeout, idle icon and busy animation, etc

        this.pendingMessages = new LinkedList<String>();

        ResourceMap resourceMap = Application.getInstance(compid.application.CompidApp.class).getContext().getResourceMap(StatusPanel.class);
        int messageTimeout = resourceMap.getInteger("StatusBar.messageTimeout");
        messageTimer = new Timer(messageTimeout, new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                statusMessageLabel.setText("");
            }
        });
        messageTimer.setRepeats(false);

        int messageMinTime = resourceMap.getInteger("StatusBar.messageMinTime");
        messageMinTimeTimer = new Timer(messageMinTime, new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                if (pendingMessages.isEmpty()) return;
                messageTimer.restart();
                statusMessageLabel.setText(pendingMessages.removeFirst());
                if (!pendingMessages.isEmpty()) {
                    messageMinTimeTimer.restart();
                }
            }
        });
        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() {
            @Override
            public void actionPerformed(ActionEvent e) {
                busyIconIndex = (busyIconIndex + 1) % busyIcons.length;
                statusAnimationLabel.setIcon(busyIcons[busyIconIndex]);
            }
        });
        idleIcon = resourceMap.getIcon("StatusBar.idleIcon");
        statusAnimationLabel.setIcon(idleIcon);

        this.jobPoolMessageReceived(new JobPoolMessageEvent("",pool.getRunningThreadsCount(),pool.getUnfinishedRootJobsCount(),0));

    }

    @Override
    public void jobPoolMessageReceived(final JobPoolMessageEvent event) {

        if (!event.getMessage().isEmpty()) {
            if (statusMessageLabel.getText().equals("")) {
                statusMessageLabel.setText(event.getMessage());
                messageTimer.restart();
            } else {
                pendingMessages.addLast(event.getMessage());
                if (!messageMinTimeTimer.isRunning()) {
                    messageMinTimeTimer.restart();
                }
            }
        }

        int runningThreads = event.getRunningThreadsCount();
        int unfinishedRootJobsCount = event.getRunningRootJobsCount() + event.getQueuedRootJobsCount();
        if (runningThreads > 0) {
            if (!busyIconTimer.isRunning()) {
                statusAnimationLabel.setIcon(busyIcons[0]);
                busyIconIndex = 0;
                busyIconTimer.start();
            }
            //progressBar.setVisible(true);
            //progressBar.setIndeterminate(true);
        } else {
            busyIconTimer.stop();
            statusAnimationLabel.setIcon(idleIcon);
            //progressBar.setVisible(false);
            //progressBar.setValue(0);
        }
        if (unfinishedRootJobsCount < 1) {
            jobCountLabel.setText("No jobs");
        } else {
            jobCountLabel.setText(unfinishedRootJobsCount+" "
                    +(unfinishedRootJobsCount==1 ? "job" : "jobs")
                    +" utilizing "+runningThreads+" "
                    +(runningThreads==1 ? "thread" : "threads"));
        }

    }

    public void viewJobDialog() {
        this.showViewer(true);
    }

    private void showViewer(boolean show) {
        this.threadPoolViewer.setVisible(show);
    }

    /** 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() {

        statusMessageLabel = new javax.swing.JLabel();
        statusAnimationLabel = new javax.swing.JLabel();
        jobCountLabel = new javax.swing.JLabel();

        org.jdesktop.application.ResourceMap resourceMap = org.jdesktop.application.Application.getInstance(compid.application.CompidApp.class).getContext().getResourceMap(StatusPanel.class);
        setToolTipText(resourceMap.getString("Form.toolTipText")); // NOI18N
        setName("Form"); // NOI18N
        addMouseListener(new java.awt.event.MouseAdapter() {
            public void mouseClicked(java.awt.event.MouseEvent evt) {
                formMouseClicked(evt);
            }
        });

        statusMessageLabel.setText(resourceMap.getString("statusMessageLabel.text")); // NOI18N
        statusMessageLabel.setToolTipText(resourceMap.getString("statusMessageLabel.toolTipText")); // NOI18N
        statusMessageLabel.setName("statusMessageLabel"); // NOI18N
        statusMessageLabel.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mouseClicked(java.awt.event.MouseEvent evt) {
                statusMessageLabelMouseClicked(evt);
            }
        });

        statusAnimationLabel.setText(resourceMap.getString("statusAnimationLabel.text")); // NOI18N
        statusAnimationLabel.setToolTipText(resourceMap.getString("statusAnimationLabel.toolTipText")); // NOI18N
        statusAnimationLabel.setName("statusAnimationLabel"); // NOI18N
        statusAnimationLabel.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mouseClicked(java.awt.event.MouseEvent evt) {
                statusAnimationLabelMouseClicked(evt);
            }
        });

        jobCountLabel.setHorizontalAlignment(javax.swing.SwingConstants.TRAILING);
        jobCountLabel.setText(resourceMap.getString("jobCountLabel.text")); // NOI18N
        jobCountLabel.setToolTipText(resourceMap.getString("jobCountLabel.toolTipText")); // NOI18N
        jobCountLabel.setName("jobCountLabel"); // NOI18N
        jobCountLabel.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mouseClicked(java.awt.event.MouseEvent evt) {
                jobCountLabelMouseClicked(evt);
            }
        });

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
        this.setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
                .addContainerGap()
                .addComponent(statusMessageLabel, javax.swing.GroupLayout.DEFAULT_SIZE, 320, Short.MAX_VALUE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                .addComponent(jobCountLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 193, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(statusAnimationLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 24, javax.swing.GroupLayout.PREFERRED_SIZE))
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addComponent(statusAnimationLabel, javax.swing.GroupLayout.DEFAULT_SIZE, 15, Short.MAX_VALUE)
            .addComponent(jobCountLabel, javax.swing.GroupLayout.DEFAULT_SIZE, 15, Short.MAX_VALUE)
            .addComponent(statusMessageLabel, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 15, Short.MAX_VALUE)
        );
    }// </editor-fold>//GEN-END:initComponents

    private void formMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_formMouseClicked
        this.showViewer(true);
    }//GEN-LAST:event_formMouseClicked

    private void jobCountLabelMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_jobCountLabelMouseClicked
        this.formMouseClicked(evt);
    }//GEN-LAST:event_jobCountLabelMouseClicked

    private void statusMessageLabelMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_statusMessageLabelMouseClicked
        this.formMouseClicked(evt);
    }//GEN-LAST:event_statusMessageLabelMouseClicked

    private void statusAnimationLabelMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_statusAnimationLabelMouseClicked
        this.formMouseClicked(evt);
    }//GEN-LAST:event_statusAnimationLabelMouseClicked


    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JLabel jobCountLabel;
    private javax.swing.JLabel statusAnimationLabel;
    private javax.swing.JLabel statusMessageLabel;
    // End of variables declaration//GEN-END:variables

    private final Timer messageTimer;
    private final Timer busyIconTimer;
    private final Timer messageMinTimeTimer;
    private final Icon idleIcon;
    private final Icon[] busyIcons = new Icon[15];
    private final LinkedList<String> pendingMessages;
    private int busyIconIndex = 0;

    private JobPoolDialog threadPoolViewer;

}
