package edu.sc.seis.gee.task;
import java.util.Map;

import javax.swing.JOptionPane;

import edu.iris.Fissures.model.TimeInterval;
import edu.iris.Fissures.model.UnitImpl;
import edu.sc.seis.fissuresUtil.cache.AbstractJob;
import edu.sc.seis.fissuresUtil.cache.JobTracker;
import edu.sc.seis.fissuresUtil.cache.WorkerThreadPool;
import edu.sc.seis.fissuresUtil.display.DisplayUtils;
import edu.sc.seis.fissuresUtil.display.SeismogramDisplay;
import edu.sc.seis.fissuresUtil.display.registrar.TimeEvent;
import edu.sc.seis.fissuresUtil.time.MicroSecondTimeRange;
import edu.sc.seis.fissuresUtil.xml.DCDataSetSeismogram;
import edu.sc.seis.fissuresUtil.xml.DataSetSeismogram;
import edu.sc.seis.fissuresUtil.xml.FDSNWSDataSetSeismogram;
import edu.sc.seis.fissuresUtil.xml.SeisDataChangeEvent;
import edu.sc.seis.fissuresUtil.xml.SeisDataChangeListener;
import edu.sc.seis.fissuresUtil.xml.SeisDataErrorEvent;
import edu.sc.seis.gee.CommonAccess;
import edu.sc.seis.gee.configurator.ConfigurationException;



public class DataFillTask implements Task{
    /**
     * Configures a <code>Task</code> with any needed parameters. The Task
     * should have default values for as many things as possible, but can
     * throw a ConfigureException if a required parameter is missing.
     *
     * @param params a <code>Map</code> value
     * @exception ConfigurationException if an error occurs
     */
    public void configure(Map params) throws ConfigurationException {
        this.params = params;
        if(params.containsKey("display")){
            String targetId = (String)params.get("display");
            display = ((ColumnSeismogramTask)CommonAccess.getCommonAccess().getTaskAction(targetId).getTask());
        }else {
            throw new ConfigurationException("fill display task requires a colSeisDisplay in the configuration");
        }

    }

    /**
     * Called when a task is to be executed, usually by a menu or toolbar
     * selection for simple tasks.
     *
     *
     * @exception Exception if an error occurs
     */
    public void invoke() throws Exception {
        JobTracker.getTracker().add(filler);
        dataFillPool.invokeLater(filler);
    }

    private WorkerThreadPool dataFillPool = new WorkerThreadPool("DataFill", 1);

    public boolean userWantsMoreThanSixHours(SeismogramDisplay disp){
        if(displayMoreThanADay || JOptionPane.showConfirmDialog(disp, warningMessage, "Fetch data",
                                                                JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE) == JOptionPane.YES_OPTION){
            displayMoreThanADay = true;
        }
        return displayMoreThanADay;
    }

    private DataFiller filler = new DataFiller();

    private class DataFiller extends AbstractJob{
        public DataFiller(){
            super("Data Expander");
            setFinished();
        }

        public void runJob() {
            setStatus("Getting seismograms");
            SeismogramDisplay disp = display.getDisplay();
            DataSetSeismogram[] seismos = disp.getSeismograms();
            TimeEvent event =  disp.getTimeConfig().fireTimeEvent();
            MicroSecondTimeRange timeRange = disp.getTimeConfig().fireTimeEvent().getTime();
            if(!timeRange.getInterval().greaterThan(SIX_HOURS) || userWantsMoreThanSixHours(disp)){
                for (int j = 0; j < seismos.length; j++) {
                    if (! (seismos[j] instanceof DCDataSetSeismogram || seismos[j] instanceof FDSNWSDataSetSeismogram)) {
                        // don't expand if it doesn't come from a DHI server
                        continue;
                    }
                    boolean expandBegin = false, expandEnd = false;
                    setStatus("Getting other components for " + (j + 1)+ "/" + seismos.length);
                    timeRange = event.getTime(seismos[j]);
                    if(seismos[j].getBeginMicroSecondDate().after(timeRange.getBeginTime())){
                        expandBegin = true;
                    }
                    if(seismos[j].getEndMicroSecondDate().before(timeRange.getEndTime())){
                        expandEnd = true;
                    }
                    if(expandBegin || expandEnd){
                        setStatus("Expanding time for " + (j + 1) + "/" + seismos.length);
                        DataSetSeismogram[] seisAndFriends = DisplayUtils.getComponents(seismos[j]);
                        if(expandBegin)
                            for (int i = 0; i < seisAndFriends.length; i++)
                                seisAndFriends[i].setBeginTime(timeRange.getBeginTime().getFissuresTime());
                        if(expandEnd)
                            for (int i = 0; i < seisAndFriends.length; i++)
                                seisAndFriends[i].setEndTime(timeRange.getEndTime().getFissuresTime());
                    }
                }
            }
            setFinished();
        }

    }

    private static boolean displayMoreThanADay = false;

    private static String warningMessage = "You are attempting to display over 6 hours worth of data.  This can cause slowness.  Are you sure you want to?";

    /**
     * Called when reset is invoked on gee or if this task is no longer being used
     *
     */
    public void destroy() {
    }

    private static TimeInterval SIX_HOURS = new TimeInterval(6, UnitImpl.HOUR);

    private Map params;

    private ColumnSeismogramTask display;

    private static final SeisDataChangeListener EMPTY_INITIATOR = new SeisDataChangeListener(){
        public void pushData(SeisDataChangeEvent sdce) {}

        public void error(SeisDataErrorEvent sdce) {}

        public void finished(SeisDataChangeEvent sdce) {}

    };
}

