/*
!=======================================================================
!
!  PROGRAM  PHASE-Viewer  (PHASE-Viewer 2014.01 ver.3.3.0)
!
!  Created on 2006/11/15 15:41:25
!  AUTHOR(S): KOGA, Junichiro
!  File : SimpleMonitor.java
!  
!  Contact address :  Phase System Consortium
!                     E-mail: phase_system@nims.go.jp URL https://azuma.nims.go.jp
!
!
!   Since 2002, this program set had been intensively developed as a part of the following 
!  national projects supported by the Ministry of Education, Culture, Sports, Science and
!  Technology (MEXT) of Japan; "Frontier Simulation Software for Industrial Science
!  (FSIS)" from 2002 to 2005, "Revolutionary Simulation Software (RSS21)" from 2006 to
!  2008. "Research and Development of Innovative Simulation Software (RISS)" from 2008
!  to 2013. These projects is lead by the Center for Research on Innovative Simulation 
!  Software (CISS), the Institute of Industrial Science (IIS), the University of Tokyo.
!   Since 2013, this program set has been further developed centering on PHASE System
!  Consortium. 
!   The activity of development of this program set has been supervised by Takahisa Ohno.
!
!=======================================================================
 */
package ciss.phase_viewer.file;

import java.io.File;
import java.util.Timer;
import java.util.TimerTask;

import javax.swing.JTextArea;
import javax.swing.event.CaretEvent;
import javax.swing.event.CaretListener;
import javax.swing.event.InternalFrameEvent;
import javax.swing.event.InternalFrameListener;

import org.apache.log4j.Logger;
import org.jfree.chart.event.ChartProgressEvent;
import org.jfree.chart.event.ChartProgressListener;

import ciss.phase_viewer.common.Tail;
import ciss.phase_viewer.common.TextAreaBufferedOutputStream;
import ciss.phase_viewer.common.TextAreaOutputStream;
import ciss.phase_viewer.common.Utils;
import ciss.phase_viewer.graph.XYData;
import ciss.phase_viewer.jobcontrol.MonitorPanelInterface;
import ciss.phase_viewer.mainpanel.InternalFrameChase;
import ciss.phase_viewer.projectbrowser.ProjectInfo;
import ciss.phase_viewer.ssh.RemoteStdOut;
import ciss.phase_viewer.ssh.filechooser.RemoteFile;

import com.jcraft.jsch.Channel;
import com.jcraft.jsch.ChannelSftp;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.Session;

/**
 * シンプルなモニターのベースクラス.
 * 
 * @author KOGA, Junichiro
 */
public abstract class SimpleMonitor implements Monitorable, CaretListener,
        ChartProgressListener, InternalFrameListener {
    private Logger logger = Logger.getLogger(SimpleMonitor.class.getName());

    /*
     * (non-Javadoc)
     * 
     * @see
     * javax.swing.event.InternalFrameListener#internalFrameActivated(javax.
     * swing.event.InternalFrameEvent)
     */
    public void internalFrameActivated(InternalFrameEvent arg0) {
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * javax.swing.event.InternalFrameListener#internalFrameClosed(javax.swing
     * .event.InternalFrameEvent)
     */
    public void internalFrameClosed(InternalFrameEvent arg0) {
        monitorPanel.setGraphButtonSelected(false);
        destroyGraph();
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * javax.swing.event.InternalFrameListener#internalFrameClosing(javax.swing
     * .event.InternalFrameEvent)
     */
    public void internalFrameClosing(InternalFrameEvent arg0) {
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * javax.swing.event.InternalFrameListener#internalFrameDeactivated(javax
     * .swing.event.InternalFrameEvent)
     */
    public void internalFrameDeactivated(InternalFrameEvent arg0) {
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * javax.swing.event.InternalFrameListener#internalFrameDeiconified(javax
     * .swing.event.InternalFrameEvent)
     */
    public void internalFrameDeiconified(InternalFrameEvent arg0) {
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * javax.swing.event.InternalFrameListener#internalFrameIconified(javax.
     * swing.event.InternalFrameEvent)
     */
    public void internalFrameIconified(InternalFrameEvent arg0) {
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * javax.swing.event.InternalFrameListener#internalFrameOpened(javax.swing
     * .event.InternalFrameEvent)
     */
    public void internalFrameOpened(InternalFrameEvent arg0) {
    }

    protected ProjectInfo projectInfo;

    public SimpleMonitor(ProjectInfo projectInfo) {
        this.projectInfo = projectInfo;
    }

    protected boolean drawingChart = false;

    /*
     * (non-Javadoc)
     * 
     * @see
     * org.jfree.chart.event.ChartProgressListener#chartProgress(org.jfree.chart
     * .event.ChartProgressEvent)
     */
    public void chartProgress(ChartProgressEvent arg0) {
        if (arg0.getType() == ChartProgressEvent.DRAWING_STARTED) {
            drawingChart = true;
        } else {
            drawingChart = false;
        }
    }

    public boolean isMonitorable() {
        return true;
    }

    protected abstract String getFileToMonitor();

    protected Session session;

    protected JTextArea textArea;

    protected RemoteStdOut remoteStdOut;

    protected Tail localTail;

    protected boolean graph = false;

    protected String fileName = "";

    private File getMostRescent(String nam) {
        File mostRescent = null;
        ChannelSftp c = null;
        try {
            if (session != null) {
                if (!session.isConnected())
                    try {
                        session.connect();
                    } catch (JSchException e1) {
                        return null;
                    }
                Channel channel = session.openChannel("sftp");
                try {
                    channel.connect();
                } catch (JSchException e) {
                    return null;
                }
                c = (ChannelSftp) channel;
            }
            RemoteFile rf = new RemoteFile(projectInfo.getTargetDirectory(), c);
            File[] files = rf.listFiles();
            long date = -1;
            if (files == null || files.length == 0) {
                // logger.warn("no files!");
                return null;
            }
            for (int i = 0; i < files.length; i++) {
                if (files[i].getName().matches(nam)) {
                    if (date < files[i].lastModified()) {
                        mostRescent = files[i];
                        date = files[i].lastModified();
                    }
                }
            }
        } catch (Exception exc) {
            logger.error("failed to get remote-host info.");
            exc.printStackTrace();
            return null;
        }

        return mostRescent;
    }

    class MonitorMostRescent extends TimerTask {
        private String nam;

        public MonitorMostRescent(String nam) {
            this.nam = nam;
            Timer timer = new Timer();
            timer.schedule(this, 0L, 1000L);
        }

        @Override
        public void run() {
            File mRescent = getMostRescent(nam);
            if (mRescent == null)
                return;
            // System.out.println("fileName, mRes " + fileName + " "
            // + mRescent.getAbsolutePath() + this.toString());
            if (!fileName.equals(mRescent.getAbsolutePath())) {
                stopMonitor();
                cancel();
                monitor(session, textArea);
            }
        }
    }

    private MonitorMostRescent mmr;

    public void monitor(Session session, JTextArea textArea) {
        this.session = session;
        this.textArea = textArea;
        // CaretListener [] cl = this.textArea.getCaretListeners();
        // if(cl!=null)
        // for(int i=0 ; i<cl.length ; i++)
        // this.textArea.removeCaretListener(cl[i]);
        this.textArea.addCaretListener(this);
        String nam = getFileToMonitor();
        File mostRescent = getMostRescent(nam);
        if (mostRescent == null) {
            if (mmr != null)
                mmr.cancel();
            mmr = new MonitorMostRescent(nam);
            return;
        }

        fileName = mostRescent.getAbsolutePath();

        if (session == null) {
            TextAreaOutputStream taos = new TextAreaOutputStream(textArea);
            TextAreaBufferedOutputStream tbos = new TextAreaBufferedOutputStream(
                    taos);
            localTail = new Tail(mostRescent, tbos);
            localTail.doIt();
            if (mmr != null)
                mmr.cancel();
            mmr = new MonitorMostRescent(nam);
            return;
        }

        String fs = "/";
        String tail = "tail -f ";

        String fname = Utils.getPathDQ(projectInfo.getTargetDirectory() + fs
                + mostRescent.getName());
        String command = tail + fname;
        remoteStdOut = new RemoteStdOut(session, command, textArea);
        remoteStdOut.doIt();
        if (mmr != null)
            mmr.cancel();
        mmr = new MonitorMostRescent(nam);
    }

    public void stopMonitor() {
        if (remoteStdOut != null)
            remoteStdOut.terminate();
        if (localTail != null)
            localTail.cancel();

        graph = false;
    }

    public void createGraphFrom(JTextArea textArea) {
        graph = true;
        caretUpdate(null);
    }

    protected InternalFrameChase graphPanel;

    protected XYData[] xyData;

    private int prevTextIndex = 0;

    public void caretUpdate(CaretEvent arg0) {
        int caretPosNow = textArea.getCaretPosition();
        if (caretPosNow < prevTextIndex)
            return;
        String text = "";
        logger.debug("prevTextInde, caretPosNow: " + prevTextIndex + ", "
                + caretPosNow);
        try {
            text = textArea.getText(prevTextIndex, caretPosNow - prevTextIndex);
        } catch (Exception e) {
        }

        String[] lines = text.split(System.getProperty("line.separator"));

        doGraph(lines);

        prevTextIndex = caretPosNow;
    }

    protected abstract void doGraph(String[] lines);

    public void destroyGraph() {
        if (graphPanel != null && graphPanel.isVisible()) {
            graphPanel.dispose();
        }
        graphPanel = null;
        xyData = null;
        graph = false;
        prevTextIndex = 0;
    }

    public boolean isGraphCreatable(JTextArea textArea) {
        return xyData != null;
    }

    protected MonitorPanelInterface monitorPanel;

    /*
     * (non-Javadoc)
     * 
     * @see
     * ciss.phase_viewer.file.Monitorable#setMonitorPanel(ciss.phase_viewer.
     * jobcontrol.MonitorPanel)
     */
    public void setMonitorPanel(MonitorPanelInterface monitorPanel) {
        this.monitorPanel = monitorPanel;
    }

}
