package de.visone.crawl.gui;

import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;

import javax.swing.AbstractAction;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JProgressBar;

import de.visone.crawl.xml.ProgressListener;
import de.visone.crawl.xml.ProgressProducer;

/**
 * Displays the crawler's progress.
 * 
 * @author Joschi
 * @author matthias
 */
@SuppressWarnings("serial")
public class CrawlerProgress extends JDialog implements ProgressListener {
    private static final String CURRENT_DEPTH = "current depth: ";

    private static final String PROGRESS_AT_DEPTH = "progress at depth ";

    private static final int GRANULARITY = 10000;

    private final JProgressBar mainProgress;
    private final JProgressBar secondaryProgress;
    private final JLabel secondaryLabel;

    private ProgressProducer crawler;

    public CrawlerProgress(final JFrame parent, final ProgressProducer crawler) {
        super(parent, "crawling...", true);
        this.crawler = crawler;
        mainProgress = new JProgressBar();
        secondaryProgress = new JProgressBar();
        mainProgress.setMaximum(GRANULARITY);
        secondaryProgress.setMaximum(GRANULARITY);
        secondaryLabel = new JLabel(PROGRESS_AT_DEPTH + 0);
        progressAdvanced(0, 1, 0);
        mainProgress.setIndeterminate(true);
        secondaryProgress.setIndeterminate(true);

        setLayout(new GridBagLayout());
        final GridBagConstraints gbc = new GridBagConstraints();
        gbc.fill = GridBagConstraints.HORIZONTAL;
        gbc.insets = new Insets(2, 2, 2, 2);
        gbc.gridx = 1;
        gbc.gridy = 0;
        gbc.gridwidth = 2;
        gbc.weightx = 1;
        add(mainProgress, gbc);
        gbc.gridy = 1;
        add(secondaryProgress, gbc);

        gbc.gridx = 0;
        gbc.weightx = 0;
        gbc.gridwidth = 1;
        add(secondaryLabel, gbc);
        gbc.gridy = 0;
        add(new JLabel("current depth"), gbc);

        final JButton cancel = new JButton(new AbstractAction("cancel") {
            @Override
            public void actionPerformed(final ActionEvent e) {
                // dispose() takes care of actually cancelling the crawler
                CrawlerProgress.this.dispose();
            }
        });
        gbc.gridy = 2;
        gbc.gridx = 2;
        add(cancel, gbc);
        pack();

        if (parent != null)
            setLocationRelativeTo(parent);
        setDefaultCloseOperation(DISPOSE_ON_CLOSE);
        toFront();
        crawler.setProgressListener(this);
        mainProgress.setIndeterminate(false);
        secondaryProgress.setIndeterminate(false);
    }

    /** {@inheritDoc} */
    @Override
    public void progressAdvanced(final int depth, final int maxdepth,
            final double secondary) {
        secondaryLabel.setText(PROGRESS_AT_DEPTH + depth);
        if (maxdepth == 0)
            mainProgress.setValue(GRANULARITY);
        else
            mainProgress.setValue(depth * GRANULARITY / maxdepth);
        secondaryProgress.setValue((int) (secondary * GRANULARITY));
    }

    /** {@inheritDoc} */
    @Override
    public void finished(final String url, final Exception e) {
        if (e != null) {
            AbstractCrawlCard.printErrorDialog(url, e, this);
        }
        progressAdvanced(1, 1, 1);
        dispose();
    }

    /** {@inheritDoc} */
    @Override
    public boolean isActive() {
        return crawler != null;
    }

    /** Disposes the dialog and stops the crawler. */
    @Override
    public void dispose() {
        if (crawler != null) {
            crawler.cancelAction();
        }
        crawler = null;
        super.dispose();
    }
}
