/*
 * Copyright 2010-2015 Institut Pasteur.
 * 
 * This file is part of Icy.
 * 
 * Icy 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.
 * 
 * Icy 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 Icy. If not, see <http://www.gnu.org/licenses/>.
 */
package icy.gui.frame.progress;

import icy.common.listener.ProgressListener;
import icy.system.thread.ThreadUtil;
import icy.util.StringUtil;

import java.awt.BorderLayout;

import javax.swing.BorderFactory;
import javax.swing.JProgressBar;

/**
 * A progress TaskFrame (thread safe)
 * 
 * @author fab & stephane
 */
public class ProgressFrame extends TaskFrame implements ProgressListener, Runnable
{
    /**
     * gui
     */
    JProgressBar progressBar;

    /**
     * length (in bytes) of download
     */
    protected double length;
    /**
     * current position (in bytes) of download
     */
    protected double position;

    /**
     * current message
     */
    protected String message;
    /**
     * current tooltip
     */
    protected String tooltip;

    /**
     * internals
     */
    // private final SingleProcessor processor;

    public ProgressFrame(final String message)
    {
        super("");

        // default
        length = 100d;
        position = -1d;
        // processor = new SingleProcessor(true);
        this.message = message;

        ThreadUtil.invokeLater(new Runnable()
        {
            @Override
            public void run()
            {
                progressBar = new JProgressBar();
                progressBar.setString(buildMessage(message));
                progressBar.setStringPainted(true);
                progressBar.setIndeterminate(true);
                progressBar.setBorder(BorderFactory.createEmptyBorder());
                progressBar.setMinimum(0);
                // this is enough for a smooth progress
                progressBar.setMaximum(1000);

                mainPanel.setLayout(new BorderLayout());
                mainPanel.add(progressBar, BorderLayout.CENTER);

                pack();
            }
        });
    }

    protected String buildMessage(String message)
    {
        return "  " + message + "  ";
    }

    @Override
    public void run()
    {
        // don't spent too much time in EDT
        ThreadUtil.sleep(10);
        updateDisplay();
    }

    public void refresh()
    {
        // refresh (need single delayed execution)
        ThreadUtil.runSingle(this);
    }

    protected void updateDisplay()
    {
        // repacking need to be done on EDT
        ThreadUtil.invokeNow(new Runnable()
        {
            @Override
            public void run()
            {
                // position information
                if ((position != -1d) && (length > 0d))
                {
                    // remove indeterminate state
                    if (progressBar.isIndeterminate())
                        progressBar.setIndeterminate(false);

                    // set progress
                    final int value = (int) (position * 1000d / length);
                    if (progressBar.getValue() != value)
                        progressBar.setValue(value);
                }
                else
                {
                    // set indeterminate state
                    if (!progressBar.isIndeterminate())
                        progressBar.setIndeterminate(true);
                }

                final String text = buildMessage(message);

                // set progress message
                if (!StringUtil.equals(progressBar.getString(), text))
                {
                    progressBar.setString(text);
                    // so component is resized according to its string length
                    progressBar.invalidate();

                    // repack frame
                    pack();
                }

                // set tooltip
                if (!StringUtil.equals(progressBar.getToolTipText(), tooltip))
                    progressBar.setToolTipText(tooltip);
            }
        });
    }

    public String getMessage()
    {
        return message;
    }

    public void setMessage(String value)
    {
        if (message != value)
        {
            message = value;
            refresh();
        }
    }

    // we want tooltip set on the progress component only
    @Override
    public void setToolTipText(String value)
    {
        if (tooltip != value)
        {
            tooltip = value;
            refresh();
        }
    }

    /**
     * @return the length
     */
    public double getLength()
    {
        return length;
    }

    /**
     * @param value
     *        the length to set
     */
    public void setLength(double value)
    {
        if (length != value)
        {
            length = value;
            refresh();
        }
    }

    /**
     * @return the position
     */
    public double getPosition()
    {
        return position;
    }

    /**
     * increment progress position
     */
    public void incPosition()
    {
        setPosition(position + 1);
    }

    /**
     * @param value
     *        the position to set
     */
    public void setPosition(double value)
    {
        if (position != value)
        {
            position = value;
            refresh();
        }
    }

    /**
     * @deprecated use {@link #setPosition(double)} instead
     */
    @Deprecated
    public void setProgress(int value)
    {
        setPosition(value);
    }

    @Override
    public boolean notifyProgress(double position, double length)
    {
        setPosition(position);
        setLength(length);

        return true;
    }

}