/*
 *  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 jpa.tools.swing;

import java.awt.Color;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.concurrent.TimeUnit;

import javax.swing.Box;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.SwingWorker;
import javax.swing.Timer;

public class StatusBar extends JPanel implements PropertyChangeListener {
    private static final long serialVersionUID = 1L;
    private JProgressBar progressBar;
    private JProgressBar memoryBar;
    private JLabel messageText;
    private TaskProgress task;

    public StatusBar() {
        progressBar = new JProgressBar();
        memoryBar = new JProgressBar();

        messageText = new JLabel();

        setLayout(new GridLayout(1,0));
        add(messageText);
        add(Box.createHorizontalGlue());
        add(memoryBar);
        add(new JLabel("Total " + (Runtime.getRuntime().maxMemory()/1000000) + "MB"));
        add(progressBar);
        MemoryDisplay memory = new MemoryDisplay(memoryBar);
        new Timer(100, memory).start();
    }

    public void showMessage(String text) {
        messageText.setText(text);
    }

    public void startTimer(long duration, int interval, TimeUnit unit) {
        progressBar.setEnabled(true);
        if (duration > 0) {
            progressBar.setStringPainted(true);
            progressBar.setMaximum(100);
            progressBar.setMinimum(0);
            task = new TaskProgress(unit.toMillis(duration), interval);
            task.addPropertyChangeListener(this);
            task.execute();
        } else {
            progressBar.setStringPainted(false);
            progressBar.setIndeterminate(true);
            task = new TaskProgress(duration, interval);
            task.addPropertyChangeListener(this);
            task.execute();
        }
    }

    /**
     * Invoked when task's progress property changes.
     */
    @Override
    public void propertyChange(PropertyChangeEvent evt) {
        if ("progress".equals(evt.getPropertyName())) {
            progressBar.setValue((Integer)evt.getNewValue());
        }
    }


    public void stopTimer() {
        if (task != null) {
            task.cancel(true);
            task = null;
        }
        progressBar.setIndeterminate(false);
        progressBar.setString("");
        progressBar.setEnabled(false);
    }

    /*
     * Emits progress property from a background thread.
     */
    class TaskProgress extends SwingWorker<Void, Integer> {
        private long startTimeInMillis;
        private long _total = 100;
        private int _interval = 100;

        public TaskProgress(long total, int interval) {
            _total    = Math.max(total, 1);
            _interval = Math.max(interval, 1);
        }
        @Override
        public Void doInBackground() {
            startTimeInMillis = System.currentTimeMillis();
            long endTimeInMillis = startTimeInMillis + _total;
            long current = System.currentTimeMillis();
            while (current < endTimeInMillis && !isCancelled()) {
                try {
                    current = System.currentTimeMillis();
                    int pctComplete = (int)((100*(current - startTimeInMillis))/_total);
                    setProgress(pctComplete);
                    Thread.sleep(_interval);
                } catch (InterruptedException ignore) {
                }
            }
            return null;
        }
    }

    public class MemoryDisplay implements ActionListener {
        JProgressBar bar;
        public MemoryDisplay(JProgressBar bar) {
            this.bar = bar;
            bar.setStringPainted(true);
            bar.setMinimum(0);
            bar.setMaximum(100);
        }
        @Override
        public void actionPerformed(ActionEvent e) {
            Runtime jvm = Runtime.getRuntime();
            long totalMemory = jvm.totalMemory();
            long usedMemory = totalMemory-jvm.freeMemory();
            int usedPct = (int)((100*usedMemory)/totalMemory);
            bar.setForeground(getColor(usedPct));
            bar.setValue(usedPct);
            bar.setString(usedPct + "% (" + mb(usedMemory) + "/" + mb(totalMemory) + "MB) ");
        }

        private long mb(long m) {
            return m/1000000;
        }

        Color getColor(int pct) {
            int red = 255*pct/100;
            int green = 255*(100-pct)/100;
            return new Color(red, green, 0);
        }
    }

}
