package edu.sc.seis.gee.task;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.List;
import javax.swing.Timer;
import org.apache.log4j.Logger;
import edu.iris.Fissures.AuditInfo;
import edu.iris.Fissures.IfNetwork.Channel;
import edu.iris.Fissures.IfNetwork.ChannelId;
import edu.iris.Fissures.model.MicroSecondDate;
import edu.iris.Fissures.model.TimeInterval;
import edu.iris.Fissures.model.UnitImpl;
import edu.iris.Fissures.network.ChannelIdUtil;
import edu.sc.seis.fissuresUtil.cache.AbstractJob;
import edu.sc.seis.fissuresUtil.cache.JobTracker;
import edu.sc.seis.fissuresUtil.chooser.ClockUtil;
import edu.sc.seis.fissuresUtil.display.SeismogramDisplay;
import edu.sc.seis.fissuresUtil.exceptionHandler.GlobalExceptionHandler;
import edu.sc.seis.fissuresUtil.xml.DataSet;
import edu.sc.seis.fissuresUtil.xml.DataSetSeismogram;
import edu.sc.seis.fissuresUtil.xml.MemoryDataSet;
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.fissuresUtil.xml.StdDataSetParamNames;
import edu.sc.seis.gee.CommonAccess;
import edu.sc.seis.gee.NetworkGateKeeper;
import edu.sc.seis.gee.NoNetworkException;
import edu.sc.seis.gee.configurator.ConfigurationException;


/**
 * RTSeismogramDisplayTask.java
 *
 *
 * Created: Tue Jun  4 12:47:59 2002
 *
 * $Id@author <a href="mailto:">Srinivasa Telukutla</a>$Id
 * @author <a href="mailto:">Srinivasa Telukutla</a>
 * @version
 */
public class RTSeismogramDisplayTask extends DataSetRealTimePlayerTask {
    public RTSeismogramDisplayTask() {
        super();
        SeismogramDisplay.setCurrentTimeFlag(true);
    }

    public void configure(java.util.Map params)throws ConfigurationException {
        super.configure(params);
        CommonAccess commonAccess = CommonAccess.getCommonAccess();
        String taskId = (String)params.get("loadSeismogramTask");
        TaskAction loadSeisTaskAction = commonAccess.getTaskAction(taskId);
        loadSeismogramTask = (LoadSeismogram)loadSeisTaskAction.getTask();
        if (loadSeismogramTask == null) {
            throw new ConfigurationException("Invalid configuration, loadSeismogramTask must not be null");
        }
    }

        public void invoke() throws NoNetworkException, ConfigurationException {
        if (NetworkGateKeeper.accessAllowed()) {
            super.invoke();
        } else {
            throw new NoNetworkException();
        }
    }

    public void destroy() {
        super.destroy();
        if(reloadTimer != null) {
            reloadTimer.stop();
        }
    }

    public void addChannels(Channel[] channels){
        RealTimeLoader loader = new RealTimeLoader(channels);
        JobTracker.getTracker().add(loader);
        Thread t = new Thread(loader);
        t.start();
    }

    private class RealTimeLoader extends AbstractJob{

        public RealTimeLoader(Channel[] channels){
            super("Real Time Loader");
            this.channels = channels;
        }

        private Channel[] channels;

        public void runJob(){
            setStatus("Getting selected channels");
            DataSetSeismogram[] currentSeis = display.getSeismograms();
            //System.out.println("size of currentSeis: " + currentSeis.length);
            //System.out.println("size of channels before pruning: " + channels.length);
            for (int i = 0; i < currentSeis.length; i++) {
                String seisChanId = ChannelIdUtil.toString(currentSeis[i].getRequestFilter().channel_id);
                //System.out.println("seisChanId: " + seisChanId);
                for (int j = 0; j < channels.length; j++) {
                    if (channels[j] != null){
                        String chanId = ChannelIdUtil.toString(channels[j].get_id());
                        //System.out.println("chanId: " + chanId);
                        if (seisChanId.equals(chanId)){
                            channels[j] = null;
                        }
                    }
                }
            }
            channels = pruneChannelArray(channels);
            boolean displayedAny = false;
            MicroSecondDate endDate = ClockUtil.now();
            MicroSecondDate beginDate = endDate.subtract(TWENTY_MINUTES);
            ChannelId[] ids = new ChannelId[channels.length];
            for(int i = 0; i < channels.length; i++) {
                ids[i] = channels[i].get_id();
                String channelParam =
                    StdDataSetParamNames.CHANNEL + ChannelIdUtil.toString(ids[i]);
                realTimeDataSet.addParameter(channelParam, channels[i], EMPTY_INFO);
            }
            DataSetSeismogram[] seis = new DataSetSeismogram[0];
            try {
                setStatus("Retrieving seismograms for channels");
                seis = loadSeismogramTask.retrieveSeismograms(beginDate.getFissuresTime(),
                                                              endDate.getFissuresTime(),
                                                              ids);
                for (int i = 0; i < seis.length; i++) {
                    realTimeDataSet.addDataSetSeismogram(seis[i], EMPTY_INFO);
                }
            }
            catch (Exception e){
                GlobalExceptionHandler.handle("Trouble Retrieving seismograms for real time", e);
            }
            setStatus("Displaying seismograms");
            for (int i = 0; i < seis.length; i++) {

                addSeismogram(seis[i]);
                SeismogramReloader loader =  new SeismogramReloader(seis[i], reloadTimer);
                reloadTimer.addActionListener(loader);
                displayedAny = true;
            }
            if(displayedAny) {
                reloadTimer.start();
                playButton.doClick();
            }
            setFinished();
        }
    }

    private Timer reloadTimer = new Timer(120*1000, new ActionListener() {
                public void actionPerformed(ActionEvent e) { }
            });

    class SeismogramReloader implements ActionListener {
        SeismogramReloader(DataSetSeismogram seis, Timer timer) {
            this.seis = seis;
            this.timer = timer;
        }

        public void actionPerformed(ActionEvent e){
            if(display.contains(seis)){
                MicroSecondDate endTime = ClockUtil.now();
                MicroSecondDate beginTime = endTime.subtract(TWENTY_MINUTES);
                seis.setEndTime(endTime.getFissuresTime());
                seis.setBeginTime(beginTime.getFissuresTime());
                seis.retrieveData(new SeisDataChangeListener() {
                            public void pushData(SeisDataChangeEvent sdce) {
                                //              logger.debug("got data for " + seis);
                            }

                            public void finished(SeisDataChangeEvent sdce) {
                                //            logger.debug("Done with data for " + seis);
                            }

                            public void error(SeisDataErrorEvent sdce) {
                                GlobalExceptionHandler.handle(sdce.getCausalException());
                            }

                        });
            }else{
                timer.removeActionListener(this);
            }
        }

        Timer timer;

        DataSetSeismogram seis;

    }

    public static Channel[] pruneChannelArray(Channel[] channels){
        //System.out.println("size of channel array: " + channels.length);
        List chanList = new ArrayList();
        for (int i = 0; i < channels.length; i++) {
            if (channels[i] != null){
                chanList.add(channels[i]);
            }
        }
        //System.out.println("size of channel list: " + chanList.size());
        return (Channel[])chanList.toArray(new Channel[0]);
    }

    private DataSet realTimeDataSet = new MemoryDataSet("Real Time Data", "Real Time Data", "me", EMPTY_INFO);

    private boolean guiInitialized = false;

    private static AuditInfo[] EMPTY_INFO = new AuditInfo[0];

    private LoadSeismogram loadSeismogramTask;

    private static final TimeInterval TWENTY_MINUTES =
        new TimeInterval(20,
                         UnitImpl.MINUTE);
    private static final TimeInterval TEN_MINUTES =
        new TimeInterval(10,
                         UnitImpl.MINUTE);
    private static final TimeInterval TWO_MINUTES =
        new TimeInterval(2,
                         UnitImpl.MINUTE);
    private static final TimeInterval TENTH_SECOND =
        new TimeInterval(100,
                         UnitImpl.MILLISECOND);

    private Logger logger = Logger.getLogger(RTSeismogramDisplayTask.class);
}// RTSeismogramDisplayTask

