/*
!=======================================================================
!
!  PROGRAM  PHASE-Viewer  (PHASE-Viewer 2014.01 ver.3.3.0)
!
!  Created on 2006/01/27, 16:54
!  AUTHOR(S): KOGA, Junichiro
!  File : SftpClientPanel.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.ssh.sftp;

import javax.swing.BoxLayout;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.border.TitledBorder;

import ciss.phase_viewer.filebrowser.FileBrowserEvent;
import ciss.phase_viewer.filebrowser.FileBrowserTree;
import ciss.phase_viewer.filebrowser.FileBrowserTreeListener;
import ciss.phase_viewer.filebrowser.FileTransfer;
import ciss.phase_viewer.projectbrowser.ProjectInfo;
import ciss.phase_viewer.projectbrowser.projectdirbrowser.ProjectDirBrowser;
import ciss.phase_viewer.projectbrowser.projectdirbrowser.ProjectDirBrowserNode;
import ciss.phase_viewer.projectbrowser.projectdirbrowser.ProjectDirBrowserNodeChangeEvent;
import ciss.phase_viewer.projectbrowser.projectdirbrowser.ProjectDirBrowserNodeChangeListener;
import ciss.phase_viewer.settings.GlobalProperties;
import ciss.phase_viewer.settings.PropertiesManager;
import ciss.phase_viewer.ssh.SshClient;
import ciss.phase_viewer.ssh.filechooser.RemoteFile;
import ciss.phase_viewer.ssh.hosts.HostInfo;

import com.jcraft.jsch.ChannelSftp;
import com.jcraft.jsch.SftpException;

/**
 * Sftp機能などを備えたJPanel
 * 
 * @author
 */
public class SftpClientPanel extends JPanel implements SshClient, SftpListener,
        FileBrowserTreeListener, FileTransfer,
        ProjectDirBrowserNodeChangeListener {
    private org.apache.log4j.Logger logger = org.apache.log4j.Logger
            .getLogger(SftpClientPanel.class.getName());

    private FileBrowserTree local;
    private FileBrowserTree remote;

    private HostInfo hostinfo;
    private Sftp sftp;

    private ChannelSftp c;
    private boolean isConnected = false;
    private GlobalProperties gp = PropertiesManager
            .getGlobalProperties(PropertiesManager.PROPERTIES_PVIEWER);
    private String localInitDir = System.getProperty("user.home");
    private String remoteInitDir;

    private boolean local_has_projbrowser = false;

    /**
     * 初期化のみ行うコンストラクター
     */
    public SftpClientPanel() {
        init();
        setVisible(true);
    }

    /**
     * 起動時、いきなり起動
     * 
     * @param hostinfo
     *            ホスト情報
     */
    public SftpClientPanel(HostInfo hostinfo) {
        this.hostinfo = hostinfo;
        init();
        connect(hostinfo);
    }

    /**
     * 起動時、いきなり起動; さらにProjectBrowserを付加できるかどうかも選べる.
     * 
     * @param hostinfo
     *            ホスト情報
     * @param local_has_proj_browser
     *            ProjectBrowserを付加するかどうか.
     */
    public SftpClientPanel(HostInfo hostinfo, boolean local_has_projbrowser) {
        this.hostinfo = hostinfo;
        this.local_has_projbrowser = local_has_projbrowser;
        init();
        connect(hostinfo);
    }

    /**
     * ローカルホストの初期ディレクトリーが選べる.
     * 
     * @param initDir
     *            ローカルホストの初期ディレクトリー
     */
    public SftpClientPanel(String initDir) {
        this.localInitDir = initDir;
        init();
    }

    /**
     * ローカルホストの初期ディレクトリーが選べる. また, ProjectDirBrowserを付加するかどうかも選べる.
     * 
     * @param initDir
     *            ローカルホストの初期ディレクトリー
     */
    public SftpClientPanel(String initDir, boolean local_has_projbrowser) {
        this.localInitDir = initDir;
        this.local_has_projbrowser = local_has_projbrowser;
        init();
    }

    /**
     * 「ローカル側のPaneにはProjectDirBrowserを付加したい場合」のコンストラクター
     * 
     * @param local_has_projbrowser
     */
    public SftpClientPanel(boolean local_has_projbrowser) {
        this.local_has_projbrowser = local_has_projbrowser;
        init();
    }

    public void uploadFinished(SftpEvent se) {
        reload(REMOTE_PANE);
    }

    public void downloadFinished(SftpEvent se) {
        reload(LOCAL_PANE);
    }

    public void setLocalInitialDir(String dir) {
        this.localInitDir = dir;
    }

    public void setRemoteInitialDir(String dir) {
        this.remoteInitDir = dir;
    }

    public void connect(HostInfo host) {
        hostinfo = host;
        logger.debug("connecting to host: " + host.getName());
        sftp = new Sftp(host);
        sftp.addSftpListener(this);
        sftp.addSftpListener(remote);
        sftp.connect();
        ((TitledBorder) remote.getBorder()).setTitle("connected to host: "
                + host.getName());
        c = sftp.getChannelSftp();
        remote.setChannelSftp(c);
        if (remoteInitDir == null || remoteInitDir.trim().length() == 0) {
            try {
                remoteInitDir = sftp.getChannelSftp().pwd();
            } catch (SftpException e) {
                e.printStackTrace();
            }
        }
        remote.init(remoteInitDir);
        this.setSize(this.getSize().width, this.getSize().height);
        isConnected = true;
    }

    public void disconnect() {
        if (sftp != null) {
            sftp.disconnect();
        }
        revalidate();
    }

    public void setHostInfo(HostInfo hostinfo) {
        this.hostinfo = hostinfo;
    }

    public HostInfo getHostInfo() {
        return hostinfo;
    }

    public Sftp getSftp() {
        return this.sftp;
    }

    public void directoryHasChanged(FileBrowserEvent fbe) {
        // pending ...
        FileBrowserTree tmp = (FileBrowserTree) fbe.getSource();
        boolean isremote = tmp.isRemote();
        RemoteFile cur = tmp.getCurrentDir();
        String curdir = new String();

        if (cur != null) {
            curdir = cur.getAbsolutePath();
        } else {
            curdir = RemoteFile.listRoots()[0].getAbsolutePath();
        }

        if (isremote) {
            logger.debug("remote directory has changed to " + curdir);
            if (sftp != null) {
                sftp.cd(curdir);
            }
        } else {
            logger.debug("local directory has changed to " + curdir);
            if (sftp != null) {
                sftp.lcd(curdir);
            }
        }

    }

    public boolean isConnected() {
        return this.isConnected;
    }

    protected void reload(int mode) {
        if (mode == LOCAL_PANE) {
            local.init();
        } else if (mode == REMOTE_PANE) {
            remote.init();
        }
    }

    private void init() {
        setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
        JPanel pane = createBrowsers();
        add(pane);
    }

    private JPanel createBrowsers() {
        int os = FileBrowserTree.WINDOWS;
        if (!System.getProperty("os.name").trim().toLowerCase()
                .startsWith("windows")) {
            os = FileBrowserTree.UNIX;
        }

        // local = new FileBrowserTree(os,
        // System.getProperty("user.home"),this,false,LOCAL_PANE);
        local = new FileBrowserTree(os, localInitDir, this,
                "ciss.phase_viewer.ssh.sftp.SftpNode", false);
        // local.setHasProjBrowser(local_has_projbrowser);
        local.init();
        local.setBorder(new TitledBorder("local"));
        local.addFileBrowserListener(this);
        local.setFileTransfer(this);

        // remote = new
        // FileBrowserTree(FileBrowserTree.UNIX,".",this,true,REMOTE_PANE);
        remote = new FileBrowserTree(FileBrowserTree.UNIX, ".", this,
                "ciss.phase_viewer.ssh.sftp.SftpNode", false);
        remote.setBorder(new TitledBorder("(not connected)"));
        remote.setRemote(true);
        remote.addFileBrowserListener(this);
        remote.setFileTransfer(this);

        JPanel p = new JPanel();
        JSplitPane split0 = new JSplitPane(JSplitPane.VERTICAL_SPLIT, true,
                local, remote);
        split0.setResizeWeight(0.5);
        split0.setDividerLocation(0.5);
        split0.setPreferredSize(getPreferredSize());
        p.setLayout(new BoxLayout(p, BoxLayout.X_AXIS));
        JScrollPane pan = new JScrollPane(split0);
        pan.setPreferredSize(split0.getPreferredSize());
        if (local_has_projbrowser) {
            ProjectDirBrowser dirBrowser = new ProjectDirBrowser("projects",
                    new ProjectDirBrowserNodeChangeListener[] { this });
            JSplitPane split1 = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT,
                    true, split0, dirBrowser);
            p.add(split1);
        } else {
            p.add(split0);
        }

        return p;
    }

    public void uploadFiles() {
        RemoteFile[] localFiles = local.getSelectedFiles();
        if (localFiles != null) {
            for (int i = 0; i < localFiles.length; i++) {
                logger.debug("selected file: "
                        + localFiles[i].getAbsolutePath());
            }
        }
        if (sftp == null) {
            logger.info("not connected");
            return;
        }
        String foo = localFiles[0].getParent();
        if (!foo.endsWith(System.getProperty("file.separator"))) {
            foo += System.getProperty("file.separator");
        }
        sftp.upload(localFiles, remote.getCurrentDir(), null);
    }

    public void downloadFiles() {
        RemoteFile[] remoteFiles = remote.getSelectedFiles();
        if (remoteFiles != null) {
            for (int i = 0; i < remoteFiles.length; i++) {
                logger.debug("selected file: "
                        + remoteFiles[i].getAbsolutePath());
            }
        }
        if (sftp == null) {
            logger.info("not connected");
            return;
        }
        sftp.download(remoteFiles, local.getCurrentDir());
    }

    public FileBrowserTree getBrowserTree(int mode) {
        if (mode == REMOTE_PANE) {
            return remote;
        } else if (mode == LOCAL_PANE) {
            return local;
        }
        logger.error("invalid specification of 'mode'");
        return null;
    }

    public static final int REMOTE_PANE = 0;
    public static final int LOCAL_PANE = 1;

    public void downloadToTmpFile() {
        String tmp = System.getProperty("java.io.tmpdir");
        RemoteFile[] remoteFiles = remote.getSelectedFiles();
        if (remoteFiles != null) {
            for (int i = 0; i < remoteFiles.length; i++) {
                logger.debug("selected file: "
                        + remoteFiles[i].getAbsolutePath());
            }
        }
        if (sftp == null) {
            logger.info("not connected");
            return;
        }
        for (int i = 0; i < remoteFiles.length; i++) {
            new java.io.File(tmp + System.getProperty("file.separator")
                    + remoteFiles[i].getName()).deleteOnExit();
        }
        RemoteFile tmpdir = new RemoteFile(tmp);
        sftp.download(remoteFiles, tmpdir);
    }

    public void nodeSelected(ProjectDirBrowserNodeChangeEvent e) {
        if (e == null || e.getSource() == null) {
            return;
        }
        ProjectDirBrowserNode node = (ProjectDirBrowserNode) e.getSource();
        ProjectInfo proj = node.getProjectInfo();
        String dir = proj.getProjectDirectory();
        logger.debug("dir: " + dir);
        local.setRoot(dir);
        if (hostinfo != null) {
            proj.setHostInfo(hostinfo);
            String targetDir = proj.getTargetDirectory();
            remote.setRoot(targetDir);
        }
    }

}
