/* 
 * Copyright 2015 Torridity.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package de.tor.tribes.ui.windows;

import de.tor.tribes.types.Attack;
import de.tor.tribes.ui.components.ColoredProgressBar;
import de.tor.tribes.ui.components.TimerPanel;
import de.tor.tribes.util.Constants;
import de.tor.tribes.util.GlobalOptions;
import de.tor.tribes.util.JOptionPaneHelper;
import de.tor.tribes.util.SystrayHelper;
import de.tor.tribes.util.xml.JDomUtils;
import java.applet.Applet;
import java.applet.AudioClip;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.BufferedInputStream;
import java.io.File;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.Clip;
import javax.swing.*;
import javax.swing.JSpinner.DateEditor;
import org.apache.commons.lang3.time.DateUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.jdom2.Document;
import org.jdom2.Element;

/**
 * @author Torridity
 */
public class ClockFrame extends javax.swing.JFrame implements ActionListener {

    private static Logger logger = LogManager.getLogger("ClockFrame");

    @Override
    public void actionPerformed(ActionEvent e) {
        if (e.getActionCommand().equals("RemoveTimer")) {
            removeTimer((TimerPanel) e.getSource());
        }
    }
    private TimerThread tThread = null;
    private static ClockFrame SINGLETON = null;
    private ColoredProgressBar cp = null;
    private final List<TimerPanel> timers = new ArrayList<>();

    public static synchronized ClockFrame getSingleton() {
        if (SINGLETON == null) {
            SINGLETON = new ClockFrame();
        }
        return SINGLETON;
    }

    /**
     * Creates new form ClockFrame
     */
    ClockFrame() {
        initComponents();
        jSpinner1.setValue(new Date(System.currentTimeMillis()));
        ((DateEditor) jSpinner1.getEditor()).getFormat().applyPattern("dd.MM.yy HH:mm:ss.SSS");
        tThread = new TimerThread(this);
        tThread.start();

        jCheckBox1.setSelected(GlobalOptions.getProperties().getBoolean("clock.alwaysOnTop"));

        setAlwaysOnTop(jCheckBox1.isSelected());
        cp = new ColoredProgressBar(0, 1000);
        jPanel1.add(cp, BorderLayout.CENTER);

        jComboBox1.setModel(new DefaultComboBoxModel(new String[]{"Alarm", "Homer", "LetsGo", "NHL", "Roadrunner", "Schwing", "Sirene", "StarTrek1", "StarTrek2"}));
        // <editor-fold defaultstate="collapsed" desc=" Init HelpSystem ">
        if (!Constants.DEBUG) {
            GlobalOptions.getHelpBroker().enableHelpKey(getRootPane(), "pages.clock_tool", GlobalOptions.getHelpBroker().getHelpSet());
        }
        restoreTimers();
        // </editor-fold>
    }

    private void removeTimer(TimerPanel pPanel, boolean pSave) {
        jTimerContainer.remove(pPanel);
        timers.remove(pPanel);
        storeTimers();
    }

    private void removeTimer(TimerPanel pPanel) {
        removeTimer(pPanel, true);
    }

    protected void updateTime(String time, int millis) {
        if (isVisible()) {
            jLabel1.setText(time);
            double markerMin = 0;
            double markerMax = 1000;
            double diff = markerMax - markerMin;
            float ratio = 0;
            if (diff > 0) {
                ratio = (float) ((millis - markerMin) / (markerMax - markerMin));
            }
            
            Color c1 = Color.GREEN;
            if (millis >= 500) {
                c1 = Color.YELLOW;
            }
            Color c2 = Color.RED;
            if (millis < 500) {
                c2 = Color.YELLOW;
                ratio += .5f;
            } else {
                ratio -= .5f;
            }
            int red = (int) Math.rint(c2.getRed() * ratio + c1.getRed() * (1f - ratio));
            int green = (int) Math.rint(c2.getGreen() * ratio + c1.getGreen() * (1f - ratio));
            int blue = (int) Math.rint(c2.getBlue() * ratio + c1.getBlue() * (1f - ratio));

            red = (red < 0) ? 0 : red;
            green = (green < 0) ? 0 : green;
            blue = (blue < 0) ? 0 : blue;
            red = (red > 255) ? 255 : red;
            green = (green > 255) ? 255 : green;
            blue = (blue > 255) ? 255 : blue;
            cp.setForeground(new Color(red, green, blue));
            cp.setValue(millis);
        }

        for (final TimerPanel p : timers.toArray(new TimerPanel[timers.size()])) {
            if (p.isExpired()) {
                SystrayHelper.showInfoMessage("Timer  '" + p.getName() + "' ist abgelaufen");
                //moved playing the sound to a new Thread because of graphic problems
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        playSound(p.getSound());
                    }
                }).start();
                removeTimer(p);
            } else {
                p.update();
            }
        }
    }

    private void addTimer() {
        String name = jTimerName.getText();
        if (name.length() < 1) {
            name = "Timer" + (timers.size() + 1);
        }

        TimerPanel panel = new TimerPanel(this, name, dateTimeField1.getSelectedDate().getTime(), (String) jComboBox1.getSelectedItem());
        timers.add(panel);
        jTimerContainer.add(panel);
        storeTimers();
    }

    public void addTimer(Attack pAttack, int pSecondsBefore) {
        if (pAttack == null) {
            return;
        }
        String name = pAttack.getSource() + " -> " + pAttack.getTarget();

        jTimerName.setText(name);
        dateTimeField1.setDate(new Date(pAttack.getSendTime().getTime() - (DateUtils.MILLIS_PER_SECOND * pSecondsBefore)));
        if (jComboBox1.getSelectedItem() == null) {
            jComboBox1.setSelectedIndex(0);
        }

        addTimer();
    }

    private void storeTimers() {
        Document timerDoc = JDomUtils.createDocument();
        Element timersElm = new Element("timers");
        for (TimerPanel p : timers) {
            timersElm.addContent(p.toXml("timer"));
        }
        timerDoc.getRootElement().addContent(timersElm);
        JDomUtils.saveDocument(timerDoc, "timers.xml");
    }

    private void restoreTimers() {
        try {
            File timerFile = new File("timers.xml");
            if (timerFile.exists()) {
                String message = "Die folgenden Timer sind zwischenzeitlich abgelaufen:\n";
                long l = message.length();
                Document d = JDomUtils.getDocument(timerFile);
                for (Element e : (List<Element>) JDomUtils.getNodes(d, "timers/timer")) {
                    TimerPanel p = new TimerPanel(this);
                    if (p.fromXml(e)) {
                        if (!p.isExpired()) {
                            timers.add(p);
                            jTimerContainer.add(p);
                        } else {
                            message += "* " + p.getName() + "\n";
                        }
                    } else {
                        logger.error("Failed to restore a timer");
                    }
                }
                if (message.length() > l) {
                    JOptionPaneHelper.showWarningBox(this, message, "Abgelaufene Timer");
                    storeTimers();
                }
            }
        } catch (Exception ioe) {
            logger.error("Failed to restore timers", ioe);
        }
    }

    public synchronized void playSound(String pSound) {
        Clip clip = null;
        AudioClip ac = null;
        try {
            if (org.apache.commons.lang3.SystemUtils.IS_OS_WINDOWS) {
                clip = AudioSystem.getClip();
                BufferedInputStream bin = new BufferedInputStream(ClockFrame.class.getResourceAsStream("/res/" + pSound + ".wav"));
                AudioInputStream inputStream = AudioSystem.getAudioInputStream(bin);
                clip.open(inputStream);
                clip.start();
            } else {
                ac = Applet.newAudioClip(ClockFrame.class.getResource("/res/" + pSound + ".wav"));
                ac.play();
            }
        } catch (Exception e) {
            logger.error("Failed to play sound", e);
        }
        try {
            Thread.sleep(2500);
        } catch (Exception ignored) {
        }

        try {
            if (clip != null) {
                clip.stop();
                clip.flush();
                clip = null;
            }

            if (ac != null) {
                ac.stop();
                ac = null;
            }
        } catch (Exception ignored) {
        }
    }

    /**
     * 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() {
        java.awt.GridBagConstraints gridBagConstraints;

        jSpinner1 = new javax.swing.JSpinner();
        jActivateTimerButton = new javax.swing.JToggleButton();
        jLabel1 = new javax.swing.JLabel();
        jPanel1 = new javax.swing.JPanel();
        jPanel2 = new javax.swing.JPanel();
        jCheckBox1 = new javax.swing.JCheckBox();
        jPanel3 = new javax.swing.JPanel();
        jComboBox1 = new javax.swing.JComboBox();
        dateTimeField1 = new de.tor.tribes.ui.components.DateTimeField();
        jLabel2 = new javax.swing.JLabel();
        jLabel3 = new javax.swing.JLabel();
        jTestAlert = new javax.swing.JButton();
        jButton1 = new javax.swing.JButton();
        jLabel4 = new javax.swing.JLabel();
        jTimerName = new org.jdesktop.swingx.JXTextField();
        jScrollPane1 = new javax.swing.JScrollPane();
        jTimerContainer = new javax.swing.JPanel();
        jButton2 = new javax.swing.JButton();
        jButton3 = new javax.swing.JButton();

        jSpinner1.setModel(new javax.swing.SpinnerDateModel(new java.util.Date(), null, null, java.util.Calendar.MILLISECOND));

        jActivateTimerButton.setBackground(new java.awt.Color(239, 235, 223));
        jActivateTimerButton.setText("Aktivieren");
        jActivateTimerButton.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mouseClicked(java.awt.event.MouseEvent evt) {
                fireActivateTimerEvent(evt);
            }
        });

        setTitle("Uhr");
        setMinimumSize(new java.awt.Dimension(280, 75));
        getContentPane().setLayout(new java.awt.GridBagLayout());

        jLabel1.setBackground(new java.awt.Color(239, 235, 223));
        jLabel1.setFont(new java.awt.Font("Verdana", 0, 36)); // NOI18N
        jLabel1.setText("Lade...");
        jLabel1.setBorder(new javax.swing.border.SoftBevelBorder(javax.swing.border.BevelBorder.RAISED));
        jLabel1.setOpaque(true);
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 0;
        gridBagConstraints.gridy = 1;
        gridBagConstraints.gridwidth = 2;
        gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
        gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
        getContentPane().add(jLabel1, gridBagConstraints);

        jPanel1.setMinimumSize(new java.awt.Dimension(100, 20));
        jPanel1.setPreferredSize(new java.awt.Dimension(279, 20));
        jPanel1.setLayout(new java.awt.BorderLayout());
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 0;
        gridBagConstraints.gridy = 0;
        gridBagConstraints.gridwidth = 2;
        gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
        gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
        gridBagConstraints.weightx = 1.0;
        getContentPane().add(jPanel1, gridBagConstraints);

        jPanel2.setLayout(new java.awt.BorderLayout());

        jCheckBox1.setText("Immer im Vordergrund");
        jCheckBox1.setHorizontalAlignment(javax.swing.SwingConstants.RIGHT);
        jCheckBox1.setMargin(new java.awt.Insets(5, 5, 5, 5));
        jCheckBox1.addChangeListener(new javax.swing.event.ChangeListener() {
            public void stateChanged(javax.swing.event.ChangeEvent evt) {
                fireAlwaysOnTopChangedEvent(evt);
            }
        });
        jPanel2.add(jCheckBox1, java.awt.BorderLayout.SOUTH);

        jPanel3.setLayout(new java.awt.GridBagLayout());

        jComboBox1.setModel(new javax.swing.DefaultComboBoxModel(new String[] { "Item 1", "Item 2", "Item 3", "Item 4" }));
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 1;
        gridBagConstraints.gridy = 2;
        gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
        gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
        gridBagConstraints.weightx = 1.0;
        gridBagConstraints.insets = new java.awt.Insets(5, 5, 5, 5);
        jPanel3.add(jComboBox1, gridBagConstraints);
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 1;
        gridBagConstraints.gridy = 1;
        gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
        gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
        gridBagConstraints.insets = new java.awt.Insets(10, 5, 5, 5);
        jPanel3.add(dateTimeField1, gridBagConstraints);

        jLabel2.setText("Zeit");
        jLabel2.setMaximumSize(new java.awt.Dimension(80, 14));
        jLabel2.setMinimumSize(new java.awt.Dimension(80, 14));
        jLabel2.setPreferredSize(new java.awt.Dimension(80, 14));
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 0;
        gridBagConstraints.gridy = 1;
        gridBagConstraints.fill = java.awt.GridBagConstraints.VERTICAL;
        gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
        gridBagConstraints.insets = new java.awt.Insets(5, 5, 5, 5);
        jPanel3.add(jLabel2, gridBagConstraints);

        jLabel3.setText("Sound");
        jLabel3.setMaximumSize(new java.awt.Dimension(80, 14));
        jLabel3.setMinimumSize(new java.awt.Dimension(80, 14));
        jLabel3.setPreferredSize(new java.awt.Dimension(80, 14));
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 0;
        gridBagConstraints.gridy = 2;
        gridBagConstraints.fill = java.awt.GridBagConstraints.VERTICAL;
        gridBagConstraints.insets = new java.awt.Insets(5, 5, 5, 5);
        jPanel3.add(jLabel3, gridBagConstraints);

        jTestAlert.setText("Testen");
        jTestAlert.setMaximumSize(new java.awt.Dimension(81, 23));
        jTestAlert.setMinimumSize(new java.awt.Dimension(81, 23));
        jTestAlert.setPreferredSize(new java.awt.Dimension(81, 23));
        jTestAlert.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mouseReleased(java.awt.event.MouseEvent evt) {
                fireTestSoundEvent(evt);
            }
        });
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 2;
        gridBagConstraints.gridy = 2;
        gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
        gridBagConstraints.insets = new java.awt.Insets(5, 5, 5, 5);
        jPanel3.add(jTestAlert, gridBagConstraints);

        jButton1.setText("Timer erstellen");
        jButton1.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mouseReleased(java.awt.event.MouseEvent evt) {
                fireCreateTimer(evt);
            }
        });
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 2;
        gridBagConstraints.gridy = 1;
        gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
        gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
        gridBagConstraints.insets = new java.awt.Insets(10, 5, 5, 5);
        jPanel3.add(jButton1, gridBagConstraints);

        jLabel4.setText("Name");
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 0;
        gridBagConstraints.gridy = 0;
        gridBagConstraints.fill = java.awt.GridBagConstraints.VERTICAL;
        gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
        gridBagConstraints.insets = new java.awt.Insets(10, 5, 5, 5);
        jPanel3.add(jLabel4, gridBagConstraints);

        jTimerName.setPrompt("Bitte Timername eingeben");
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 1;
        gridBagConstraints.gridy = 0;
        gridBagConstraints.gridwidth = 2;
        gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
        gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
        gridBagConstraints.insets = new java.awt.Insets(10, 5, 5, 5);
        jPanel3.add(jTimerName, gridBagConstraints);

        jPanel2.add(jPanel3, java.awt.BorderLayout.CENTER);

        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 0;
        gridBagConstraints.gridy = 2;
        gridBagConstraints.gridwidth = 2;
        gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
        gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
        getContentPane().add(jPanel2, gridBagConstraints);

        jScrollPane1.setBorder(javax.swing.BorderFactory.createTitledBorder("Aktive Timer"));
        jScrollPane1.setMinimumSize(new java.awt.Dimension(246, 150));
        jScrollPane1.setPreferredSize(new java.awt.Dimension(246, 150));

        jTimerContainer.setLayout(new java.awt.GridLayout(3, 3, 5, 5));
        jScrollPane1.setViewportView(jTimerContainer);

        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 0;
        gridBagConstraints.gridy = 3;
        gridBagConstraints.gridwidth = 2;
        gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
        gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
        gridBagConstraints.weighty = 1.0;
        getContentPane().add(jScrollPane1, gridBagConstraints);

        jButton2.setText("Alle Löschen");
        jButton2.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mouseReleased(java.awt.event.MouseEvent evt) {
                fireRemoveAllTimersEvent(evt);
            }
        });
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 0;
        gridBagConstraints.gridy = 4;
        gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
        gridBagConstraints.weightx = 1.0;
        getContentPane().add(jButton2, gridBagConstraints);

        jButton3.setText("Auswahl löschen");
        jButton3.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mouseReleased(java.awt.event.MouseEvent evt) {
                fireRemoveSelectedTimersEvent(evt);
            }
        });
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 1;
        gridBagConstraints.gridy = 4;
        gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
        gridBagConstraints.weightx = 1.0;
        getContentPane().add(jButton3, gridBagConstraints);

        pack();
    }// </editor-fold>//GEN-END:initComponents

private void fireActivateTimerEvent(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_fireActivateTimerEvent
    /*
     * if (jActivateTimerButton.isSelected()) { tThread.setNotifyTime(((Date) jSpinner1.getValue()).getTime()); } else {
     * tThread.setNotifyTime(-1); }
     */
}//GEN-LAST:event_fireActivateTimerEvent

private void fireAlwaysOnTopChangedEvent(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_fireAlwaysOnTopChangedEvent
    setAlwaysOnTop(jCheckBox1.isSelected());
    GlobalOptions.addProperty("clock.alwaysOnTop", Boolean.toString(jCheckBox1.isSelected()));
}//GEN-LAST:event_fireAlwaysOnTopChangedEvent

private void fireTestSoundEvent(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_fireTestSoundEvent
    final String sound = (String) jComboBox1.getSelectedItem();
    //moved playing the sound to a new Thread because of graphic problems
    new Thread(new Runnable() {
        @Override
        public void run() {
            playSound(sound);
        }
    }).start();
}//GEN-LAST:event_fireTestSoundEvent

    private void fireCreateTimer(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_fireCreateTimer
        addTimer();
    }//GEN-LAST:event_fireCreateTimer

    private void fireRemoveAllTimersEvent(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_fireRemoveAllTimersEvent
        for (TimerPanel p : timers.toArray(new TimerPanel[]{})) {
            removeTimer(p, false);
        }
        storeTimers();
        JOptionPaneHelper.showInformationBox(this, "Timer entfernt", "Alle Timer wurden entfernt.");
    }//GEN-LAST:event_fireRemoveAllTimersEvent

    private void fireRemoveSelectedTimersEvent(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_fireRemoveSelectedTimersEvent
        int removed = 0;
        for (TimerPanel p : timers.toArray(new TimerPanel[]{})) {
            if (p.isSelected()) {
                removeTimer(p, false);
                removed++;
            }
        }
        storeTimers();
        JOptionPaneHelper.showInformationBox(this, "Timer entfernt", removed + " Timer wurden entfernt.");
    }//GEN-LAST:event_fireRemoveSelectedTimersEvent

    /**
     * @param args the command line arguments
     */
    public static void main(String args[]) {

        java.awt.EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                ClockFrame cf = new ClockFrame();
                cf.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
                cf.setVisible(true);
            }
        });
    }
    // Variables declaration - do not modify//GEN-BEGIN:variables
    private de.tor.tribes.ui.components.DateTimeField dateTimeField1;
    private javax.swing.JToggleButton jActivateTimerButton;
    private javax.swing.JButton jButton1;
    private javax.swing.JButton jButton2;
    private javax.swing.JButton jButton3;
    private javax.swing.JCheckBox jCheckBox1;
    private javax.swing.JComboBox jComboBox1;
    private javax.swing.JLabel jLabel1;
    private javax.swing.JLabel jLabel2;
    private javax.swing.JLabel jLabel3;
    private javax.swing.JLabel jLabel4;
    private javax.swing.JPanel jPanel1;
    private javax.swing.JPanel jPanel2;
    private javax.swing.JPanel jPanel3;
    private javax.swing.JScrollPane jScrollPane1;
    private javax.swing.JSpinner jSpinner1;
    private javax.swing.JButton jTestAlert;
    private javax.swing.JPanel jTimerContainer;
    private org.jdesktop.swingx.JXTextField jTimerName;
    // End of variables declaration//GEN-END:variables
}

class TimerThread extends Thread {

    private ClockFrame mParent;
    private final SimpleDateFormat FORMAT = new SimpleDateFormat("HH:mm:ss:SSS");

    public TimerThread(ClockFrame pParent) {
        mParent = pParent;
        setName("ClockTimer");
        setDaemon(true);
    }

    public void setNotifyTime(long pTime) {
    }

    @Override
    public void run() {
        while (true) {
            long currentTime = System.currentTimeMillis();
            mParent.updateTime(FORMAT.format(new Date(currentTime)), (int) DateUtils.getFragmentInMilliseconds(new Date(), Calendar.SECOND));
            if (mParent.isVisible()) {
                mParent.repaint();
            } else {
                try {
                    Thread.sleep(100);
                } catch (InterruptedException ignored) {
                }
            }

            try {
                Thread.sleep(50);
            } catch (InterruptedException ignored) {
            }
        }
    }
}