#-----------------------------------------------------------------------------
# Name:        SSHExplorer.py
# Purpose:
#
# Author:      Riaan Booysen
#
# Created:     2001
# RCS-ID:      $Id: SSHExplorer.py,v 1.25 2007/07/02 15:01:10 riaan Exp $
# Copyright:   (c) 2001 - 2007
# Licence:     GPL
#-----------------------------------------------------------------------------
print 'importing Explorers.SSHExplorer'

import os, sys

import wx

import Preferences, Utils
from Utils import _

import ExplorerNodes
from Models import Controllers, EditorHelper
from ProcessProgressDlg import ProcessProgressDlg

wxID_SSHOPEN = wx.NewId()

class SSHController(ExplorerNodes.Controller, ExplorerNodes.ClipboardControllerMix):
    def __init__(self, editor, list, inspector, controllers):
        ExplorerNodes.ClipboardControllerMix.__init__(self)
        ExplorerNodes.Controller.__init__(self, editor)

        self.list = list
        self.menu = wx.Menu()

        self.setupMenu(self.menu, self.list,
              [ (wxID_SSHOPEN, 'Open', self.OnOpenItems, '-'),
                (-1, '-', None, '') ] + self.clipMenuDef)
        self.toolbarMenus = [self.clipMenuDef]

    def destroy(self):
        ExplorerNodes.ClipboardControllerMix.destroy(self)
        self.toolbarMenus = []
        self.menu.Destroy()

class SSHCatNode(ExplorerNodes.CategoryNode):
    itemProtocol = 'ssh'
    defName = 'SSH'
    defaultStruct = {'username': '',
                     'cipher': '3des',
                     'host': '',
                     'root': '~'}
    def __init__(self, clipboard, config, parent, bookmarks):
        ExplorerNodes.CategoryNode.__init__(self, 'SSH', ('explorer', 'ssh'),
              clipboard, config, parent)
        self.bookmarks = bookmarks

    def createChildNode(self, name, props):
        root = props['root']
        #if root and root[0] != '/':
        #    root = '/'+root
        itm = SSHItemNode(name, props, root, self.clipboard, True,
              EditorHelper.imgNetDrive)
        itm.category = name
        itm.bookmarks = self.bookmarks
        return itm

    def createCatCompanion(self, catNode):
        comp = ExplorerNodes.CategoryDictCompanion(catNode.treename, self)
        return comp

class SSHItemNode(ExplorerNodes.ExplorerNode):
    protocol = 'ssh'
    connection = False
    def __init__(self, name, props, resourcepath, clipboard, isFolder, imgIdx):
        ExplorerNodes.ExplorerNode.__init__(self, name, resourcepath, clipboard,
              imgIdx, None, props)
        self.isFolder = isFolder

    def isFolderish(self):
        return self.isFolder

    def getURI(self):
#        return ExplorerNodes.ExplorerNode.getURI(self) + (self.isFolder and '/' or '')
        title = self.getTitle()
        if title and title[0] != '/':
            title = '/' + title
        if self.isFolder:
            title = title + '/'
        return '%s://%s%s'%(self.protocol, self.category, title)

    def createChildNode(self, name, isFolder, props, respath=''):
        if not respath:
            respath = self.resourcepath+'/'+name
        item = SSHItemNode(name, props, respath, self.clipboard,
              isFolder, isFolder and EditorHelper.imgFolder or \
              EditorHelper.imgTextModel)
        if not isFolder:
            item.imgIdx = Controllers.identifyFile(name, localfs=False)[0].imgIdx
        item.category = self.category
        item.bookmarks = self.bookmarks
        return item

    def openList(self):
        res = []
        ls = self.execCmd("ls -la '%s'" % self.resourcepath)[1:]
        for line in ls:
            name = line.split(' ')[-1].strip()
            if name and name[-1] == '/':
                name = name[:-1]
            if name not in ('.', '..'):
                res.append(self.createChildNode(name, line[0] == 'd', self.properties))
        return res

    def execCmd(self, cmd):
        dlg = ProcessProgressDlg(None,
            self.sshCmd(cmd), _('SSH listing'), linesep = '\012')
        try:
            if dlg.ShowModal() == wx.OK:
                return dlg.output
        finally:
            dlg.Destroy()

        return []

    def sshCmd(self, command):
        return 'ssh -v -l %(username)s -c %(cipher)s %(host)s '% self.properties+\
                command

    def remotePath(self, filename):
        return '%(username)s@%(host)s:'%self.properties + self.resourcepath+\
               (filename and '/'+filename or '')

    def execSCP(self, cmd):
        dlg = ProcessProgressDlg(None, cmd, 'SCP copy', linesep = '\012')
        try:
            dlg.ShowModal()
        finally:
            dlg.Destroy()

    def copyFromFS(self, fsNode, fn=''):
        if not fn:
            fn = os.path.basename(fsNode.resourcepath)
        cwd = os.getcwd()
        os.chdir(os.path.dirname(fsNode.resourcepath))
        try:
            cmd = 'scp "%s" "%s"' % (os.path.basename(fsNode.resourcepath),
                                 self.remotePath(fn))
            self.execSCP(cmd)
        finally:
            os.chdir(cwd)

    def copyToFS(self, fsFolderNode, fn=''):
        if not fn:
            fn = os.path.basename(self.resourcepath)
        cwd = os.getcwd()
        os.chdir(fsFolderNode.resourcepath)
        try:
            cmd = 'scp "%s" "%s"' % (self.remotePath(''), fn)
            self.execSCP(cmd)
        finally:
            os.chdir(cwd)

    def moveFileFrom(self, other):
        fn = os.path.basename(other.resourcepath)
        self.execCmd("mv '%s' '%s'" % (other.resourcepath,
                                   self.resourcepath + '/' + fn))

    def copyFileFrom(self, other):
        fn = os.path.basename(other.resourcepath)
        self.execCmd("cp '%s' '%s'" % (other.resourcepath,
                                   self.resourcepath + '/' + fn))

    def deleteItems(self, names):
        absNames = []
        for name in names:
            absNames.append(self.resourcepath + '/' +name)
        self.execCmd("rm -rf '%s'" % ' '.join(absNames))

    def renameItem(self, name, newName):
        self.execCmd("mv '%s' '%s'" % (self.resourcepath + '/' + name,
                                   self.resourcepath + '/' + newName))

    def newFolder(self, name):
        self.execCmd("mkdir '%s'" % (self.resourcepath + '/' + name))

    def newBlankDocument(self, name):
        self.execCmd("echo \" \" > '%s'" % (self.resourcepath + '/' + name))

    def load(self, mode='rb'):
        from FileExplorer import FileSysNode
        import tempfile
        fn = tempfile.mktemp()
        p, n = os.path.split(fn)
        fn = os.path.join(p, 'X'+n)
        try:
            self.copyToFS(FileSysNode('', os.path.dirname(fn), None, -1, None, None), os.path.basename(fn))
            if os.path.exists(fn):
                try:
                    return open(fn, mode).read()
                finally:
                    os.remove(fn)
            else:
                raise ExplorerNodes.TransportLoadError(
                      _('File was not downloaded locally.'), self.resourcepath)
        except Exception, error:
            raise ExplorerNodes.TransportLoadError(error, self.resourcepath)

    def save(self, filename, data, mode='wb', overwriteNewer=False):
        from FileExplorer import FileSysNode
        import tempfile
        name = os.path.basename(self.resourcepath)
        fn = tempfile.mktemp()
        p, n = os.path.split(fn)
        fn = os.path.join(p, 'X'+n)
        try:
            open(fn, mode).write(data)
            try:
                parentDir = os.path.dirname(self.resourcepath)
                parentName = os.path.basename(parentDir)
                parentSSHNode = self.createChildNode(parentName, 1,
                      self.properties, parentDir)
                parentSSHNode.copyFromFS(FileSysNode('', fn, None, -1), name)
            finally:
                os.remove(fn)
        except Exception, error:
            raise ExplorerNodes.TransportSaveError(error, self.resourcepath)

##    def getNodeFromPath(self, respath):
##        if not respath: respath = '/'
##
##        isFolder = respath[-1] == '/'
##        if isFolder:
##            respath = respath[:-1]
##        return self.createChildNode(os.path.basename(respath), isFolder,
##              self.properties, '/'+respath)

    def getNodeFromPath(self, respath):
        if not respath: respath = '/'

        if not respath.startswith('~/'):
            respath = '/' + respath
        isFolder = respath[-1] == '/'
        if isFolder:
            respath = respath[:-1]
        return self.createChildNode(os.path.basename(respath), isFolder,
              self.properties, respath)

class SSHExpClipboard(ExplorerNodes.ExplorerClipboard):
    def clipPaste_FileSysExpClipboard(self, node, nodes, mode):
        for clipnode in nodes:
            if mode == 'cut':
                node.copyFromFS(clipnode)
                self.clipNodes = []
            elif mode == 'copy':
                node.copyFromFS(clipnode)

    def clipPaste_SSHExpClipboard(self, node, nodes, mode):
        for sshNode in nodes:
            if mode == 'cut':
                node.moveFileFrom(sshNode)
                self.clipNodes = []
            elif mode == 'copy':
                node.copyFileFrom(sshNode)

#-------------------------------------------------------------------------------
ExplorerNodes.register(SSHItemNode, clipboard=SSHExpClipboard,
      confdef=('explorer', 'ssh'), controller=SSHController, category=SSHCatNode)
ExplorerNodes.fileOpenDlgProtReg.append('ssh')
