package edu.sc.seis.gee.task;

import java.awt.Cursor;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionListener;
import java.util.HashMap;
import java.util.Map;
import javax.swing.JOptionPane;
import edu.iris.Fissures.AuditInfo;
import edu.iris.Fissures.IfEvent.EventAccessOperations;
import edu.iris.Fissures.IfNetwork.Channel;
import edu.iris.Fissures.IfSeismogramDC.RequestFilter;
import edu.sc.seis.fissuresUtil.cache.AbstractJob;
import edu.sc.seis.fissuresUtil.cache.EventUtil;
import edu.sc.seis.fissuresUtil.cache.JobTracker;
import edu.sc.seis.fissuresUtil.cache.WorkerThreadPool;
import edu.sc.seis.fissuresUtil.dataset.Organizer;
import edu.sc.seis.fissuresUtil.display.PlottableDisplay;
import edu.sc.seis.fissuresUtil.exceptionHandler.GlobalExceptionHandler;
import edu.sc.seis.fissuresUtil.xml.DataSetSeismogram;
import edu.sc.seis.gee.CommonAccess;
import edu.sc.seis.gee.FrameManager;
import edu.sc.seis.gee.configurator.ConfigurationException;

/**
 * PlottableSelectionTask.java
 * 
 * @author Created by Charlie Groves
 */
public class PlottableSelectionTask extends MouseAdapter implements Task,
        MouseMotionListener {

    public void configure(Map params) throws ConfigurationException {
        CommonAccess commonAccess = CommonAccess.getCommonAccess();
        String taskId = (String)params.get("plottableTask");
        TaskAction taskAction = commonAccess.getTaskAction(taskId);
        task = (PlottableTask)taskAction.getTask();
        if(task == null) {
            throw new ConfigurationException("Invalid configuration, plottableTask in plottableSelectionTask must be set");
        }
        taskId = (String)params.get("loadSeismogram");
        taskAction = commonAccess.getTaskAction(taskId);
        loadSeismogram = (LoadSeismogram)taskAction.getTask();
        taskId = (String)params.get("colSeisDisplay");
        colSeisTaskAction = commonAccess.getTaskAction(taskId);
        colSeisTask = (DataSetRealTimePlayerTask)colSeisTaskAction.getTask();
    }

    public void invoke() throws Exception {
        display = task.getDisplay();
        display.addMouseMotionListener(this);
        display.addMouseListener(this);
        task.setPlottableTool(this);
    }

    public void destroy() {
        if(display != null) {
            display.removeMouseMotionListener(this);
            display.removeSelection();
        }
    }

    public void mouseClicked(MouseEvent e) {
        if(active()) {
            RequestFilter filter = display.getRequestFilter(e.getX(), e.getY());
            if(filter != null) {
                extractor.extract(filter);
            }
        }
    }

    private class SeismogramExtractor extends AbstractJob {

        public SeismogramExtractor() {
            super("Day Viewer Extractor");
            JobTracker.getTracker().add(this);
            setFinished();
        }

        public void extract(RequestFilter filter) {
            internalFilter = filter;
            previousExtracts.put(internalFilter, Boolean.FALSE);
            extractorPool.invokeLater(this);
        }

        private RequestFilter internalFilter;

        public void runJob() {
            setFinished(false);
            RequestFilter filter = internalFilter;
            try {
                setStatus("Loading seismogram from filter");
                DataSetSeismogram seismogram = loadSeismogram.retrieveSeismogram(filter);
                if(seismogram == null){
                    JOptionPane.showMessageDialog(FrameManager.getManager().getCurrentPanel(),
                                                  "The seismogram server had no data for this extraction window.",
                                                  "No data extracted",
                                                  JOptionPane.INFORMATION_MESSAGE);
                    return;
                }
                Channel[] chans = task.getChannels();
                setStatus("Loading filter");
                DataSetSeismogram[] friends = new DataSetSeismogram[chans.length];
                for(int i = 0; i < chans.length; i++) {
                    if(chans[i].get_id().equals(filter.channel_id)) {
                        friends[i] = seismogram;
                    } else {
                        RequestFilter friendFilter = new RequestFilter(chans[i].get_id(),
                                                                       filter.start_time,
                                                                       filter.end_time);
                        friends[i] = loadSeismogram.retrieveSeismogram(friendFilter);
                    }
                }
                Organizer organizer = CommonAccess.getCommonAccess()
                        .getOrganizer();
                AuditInfo[] audit = new AuditInfo[1];
                audit[0] = new AuditInfo(System.getProperty("user.name", "GEE"),
                                         "loaded from Day Viewer");
                setStatus("Getting event");
                EventAccessOperations[] eao = display.getSelectedEvents();
                setStatus("Populating dataset");
                EventAccessOperations selectedEvent = null;
                if(eao.length > 0) {
                    selectedEvent = eao[0];
                    if(eao.length > 1) {
                        selectedEvent = pickEvent(eao);
                        if(selectedEvent == null)
                            return;
                    }
                }
                for(int i = 0; i < friends.length; i++) {
                    if(friends[i] != null) {
                        if(selectedEvent != null) {
                            organizer.addSeismogram(friends[i],
                                                    selectedEvent,
                                                    audit);
                            organizer.addChannel(chans[i], selectedEvent, audit);
                        } else {
                            organizer.addSeismogram(friends[i], audit);
                            organizer.addChannel(chans[i], audit);
                        }
                    }
                }
                setStatus("Adding Seismogram");
                colSeisTask.addSeismogram(seismogram);
                colSeisTaskAction.checkDisplayLocation(true);
                previousExtracts.put(filter, Boolean.TRUE);
            } catch(Exception ex) {
                GlobalExceptionHandler.handle(ex);
            }
            setFinished();
        }

        private Map previousExtracts = new HashMap();
    }

    private EventAccessOperations pickEvent(EventAccessOperations[] events) {
        String[] eventNames = new String[events.length];
        for(int i = 0; i < events.length; i++) {
            eventNames[i] = EventUtil.getEventInfo(events[i]);
        }
        String selection = (String)JOptionPane.showInputDialog(display,
                                                               "More than one event is selected.  Please choose the one you want",
                                                               "More than one event selected",
                                                               JOptionPane.QUESTION_MESSAGE,
                                                               null,
                                                               eventNames,
                                                               eventNames[0]);
        for(int i = 0; i < eventNames.length; i++) {
            if(eventNames[i].equals(selection)) {
                return events[i];
            }
        }
        return null;
    }

    public void mouseDragged(MouseEvent me) {
        if(active()) {
            display.addToSelection(me.getX(), me.getY());
            display.setCursor(Cursor.getPredefinedCursor(Cursor.E_RESIZE_CURSOR));
        }
    }

    public void mouseMoved(MouseEvent me) {
        if(active()) {
            display.setSelection(me.getX(), me.getY());
            if(display.bordersSelection(me.getX(), me.getY())) {
                display.setCursor(Cursor.getPredefinedCursor(Cursor.E_RESIZE_CURSOR));
            } else {
                display.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
            }
        }
    }

    private boolean active() {
        if(task.getPlottableTool() == this) {
            return true;
        }
        return false;
    }

    private PlottableDisplay display;

    private PlottableTask task;

    private LoadSeismogram loadSeismogram;

    private DataSetRealTimePlayerTask colSeisTask;

    private TaskAction colSeisTaskAction;

    private SeismogramExtractor extractor = new SeismogramExtractor();

    private static WorkerThreadPool extractorPool = new WorkerThreadPool("Day Viewer Extractor",
                                                                         1);
}