# -*- coding: utf-8 -*-

# Copyright (c) 2002, 2003 Detlev Offenbach <detlev@die-offenbachs.de>
#

"""
Module implementing an abstract base class to be subclassed by all specific VCS interfaces.
"""

import os

from qt import *

class VersionControl(QObject):
    """
    Class implementing an abstract base class to be subclassed by all specific VCS interfaces.
    
    It defines the vcs interface to be implemented by subclasses
    and the common methods.
    """
    
    canBeCommitted = 1
    """ Indicates that a file/directory is in the vcs."""
    canBeAdded = 2
    """ Indicates that a file/directory is not in vcs."""
    
    def __init__(self, parent=None, name=None):
        """
        Constructor
        
        Arguments
        
            parent -- parent widget (QWidget)
            
            name -- name of this object (string or QString)
        """
        QObject.__init__(self, parent, name)
        self.defaultOptions = {
            'global' : [''],
            'commit' : [''],
            'update' : [''],
            'add' : [''],
            'remove' : [''],
            'diff' : [''],
            'log' : [''],
            'history' : [''],
            'status' : [''],
            'tag' : [''],
            'export' : ['']
        }
        
    def vcsExists(self):
        """
        Public method used to test for the presence of the vcs.
        
        It must return a bool to indicate the existance.
        """
        raise RuntimeError, 'Not implemented'
        
    def vcsInit(self, vcsDir, noDialog=0):
        """
        Public method used to initialize the vcs.
        
        It must return a boolean to indicate an execution without errors.
        
        Arguments
        
            vcsDir -- name of the VCS directory (string)
            
            noDialog -- flag indicating quiet operations (boolean)
        """
        raise RuntimeError, 'Not implemented'
        
    def vcsImport(self, vcsDir, message, project, vendor, release, projectDir, noDialog=0):
        """
        Public method used to import the project into the vcs.
        
        It must return a boolean to indicate an execution without errors.
        
        Arguments
        
            vcsDir -- name of the VCS directory (string)
            
            message -- message for this operation (string)
            
            project -- reference to the project object
            
            vendor -- vendor string (string)
            
            release -- release version string (string)
            
            projectDir -- project directory to create (string)
            
            noDialog -- flag indicating quiet operations
        """
        raise RuntimeError, 'Not implemented'
        
    def vcsCheckout(self, vcsDir, project, projectDir, noDialog=0, tag=None):
        """
        Public method used to check the project out of the vcs.
        
        It must return a boolean to indicate an execution without errors.
        
        Arguments
        
            vcsDir -- name of the VCS directory (string)
            
            project -- reference to the project object
            
            projectDir -- project directory to create (string)
            
            noDialog -- flag indicating quiet operations
            
            tag -- tag of version to check out (string)
        """
        raise RuntimeError, 'Not implemented'
        
    def vcsExport(self, vcsDir, project, projectDir, tag=None):
        """
        Public method used to export a directory from the vcs.
        
        It must return a boolean to indicate an execution without errors.
        
        Arguments
        
            vcsDir -- name of the VCS directory (string)
            
            project -- reference to the project object
            
            projectDir -- project directory to create (string)
            
            tag -- tag of version to check out (string)
        """
        raise RuntimeError, 'Not implemented'
        
    def vcsCommit(self, name, message, noDialog=0):
        """
        Public method used to make the change of a file/directory permanent in the vcs.
        
        It must return a boolean to indicate an execution without errors.
        
        Arguments
        
            name -- file/directory name to be committed (string)
            
            message -- message for this operation (string)
            
            noDialog -- flag indicating quiet operations
        """
        raise RuntimeError, 'Not implemented'
        
    def vcsUpdate(self, name):
        """
        Public method used to update a file/directory in the vcs.
        
        It must not return anything.
        
        Arguments
        
            name -- file/directory name to be updated (string)
        """
        raise RuntimeError, 'Not implemented'
        
    def vcsAdd(self, name, isDir=0):
        """
        Public method used to add a file/directory in the vcs.
        
        It must not return anything.
        
        Arguments
        
            name -- file/directory name to be added (string)
            
            isDir -- flag indicating name is a directory (boolean)
        """
        raise RuntimeError, 'Not implemented'
        
    def vcsAddBinary(self, name, isDir=0):
        """
        Public method used to add a file/directory in binary mode in the vcs.
        
        It must not return anything.
        
        Arguments
        
            name -- file/directory name to be added (string)
            
            isDir -- flag indicating name is a directory (boolean)
        """
        raise RuntimeError, 'Not implemented'
        
    def vcsAddTree(self, path):
        """
        Public method to add a directory tree rooted at path in the vcs.
        
        It must not return anything.
        
        Arguments
        
            path -- root directory of the tree to be added (string)
        """
        raise RuntimeError, 'Not implemented'
        
    def vcsRemove(self, name, project=0):
        """
        Public method used to add a file/directory in the vcs.
        
        Arguments
        
            name -- file/directory name to be removed (string)
            
            project -- flag indicating deletion of a project tree (boolean)
            
        Returns
        
            flag indicating successfull operation (boolean)
        """
        raise RuntimeError, 'Not implemented'
        
    def vcsLog(self, name):
        """
        Public method used to view the log of a file/directory in the vcs.
        
        It must not return anything.
        
        Arguments
        
            name -- file/directory name to show the log for (string)
        """
        raise RuntimeError, 'Not implemented'
        
    def vcsDiff(self, name):
        """
        Public method used to view the diff of a file/directory in the vcs.
        
        It must not return anything.
        
        Arguments
        
            name -- file/directory name to be diffed (string)
        """
        raise RuntimeError, 'Not implemented'
        
    def vcsHistory(self, name):
        """
        Public method used to view the history of a file/directory in the vcs.
        
        It must not return anything.
        
        Arguments
        
            name -- file/directory name to show the history for (string)
        """
        raise RuntimeError, 'Not implemented'
        
    def vcsStatus(self, name):
        """
        Public method used to view the status of a file/directory in the vcs.
        
        It must not return anything.
        
        Arguments
        
            name -- file/directory name to show the status for (string)
        """
        raise RuntimeError, 'Not implemented'
        
    def vcsTag(self, name):
        """
        Public method used to set the tag of a file/directory in the vcs.
        
        It must not return anything.
        
        Arguments
        
            name -- file/directory name to be tagged (string)
        """
        raise RuntimeError, 'Not implemented'
        
    def vcsRevert(self, name):
        """
        Public method used to revert changes made to a file/directory.
        
        It must not return anything.
        
        Arguments
        
            name -- file/directory name to be reverted (string)
        """
        raise RuntimeError, 'Not implemented'
        
    def vcsSwitch(self, name):
        """
        Public method used to switch a directory to a different tag/branch.
        
        It must not return anything.
        
        Arguments
        
            name -- directory name to be switched (string)
        """
        raise RuntimeError, 'Not implemented'
        
    def vcsMerge(self, name):
        """
        Public method used to merge a tag/branch into the local project.
        
        It must not return anything.
        
        Arguments
        
            name -- file/directory name to be merged (string)
        """
        raise RuntimeError, 'Not implemented'
        
    def vcsLogin(self, user, passwd, host, repository):
        """
        Public method used to login to the remote repository.
        
        It must not return anything.
        
        Arguments
        
            user -- user name (string)
            
            passwd -- password (string)
            
            host -- hostname (string)
            
            repository -- repository name (string)
        """
        raise RuntimeError, 'Not implemented'
        
    def vcsLogout(self, user, host, repository):
        """
        Public method used to logout from the remote repository.
        
        It must not return anything.
        
        Arguments
        
            user -- user name (string)
            
            host -- hostname (string)
            
            repository -- repository name (string)
        """
        raise RuntimeError, 'Not implemented'
        
    def vcsRegisteredState(self, name):
        """
        Public method used to get the registered state of a file in the vcs.
        
        Arguments
        
            name -- filename to check (string)
            
        Returns
        
            a combination of canBeCommited and canBeAdded or
            0 in order to signal an error
        """
        raise RuntimeError, 'Not implemented'
        
    def vcsAllRegisteredStates(self, names, dname):
        """
        Public method used to get the registered states of a number of files in the vcs.
        
        Arguments
        
            names -- dictionary with all filenames to be checked as keys
            
            dname -- directory to check in (string)
            
        Returns
        
            the received dictionary completed with a combination of 
            canBeCommited and canBeAdded or None in order to signal an error
        """
        raise RuntimeError, 'Not implemented'
        
    def vcsName(self):
        """
        Public method returning the name of the vcs.
        
        Returns
        
            name of the vcs (string)
        """
        raise RuntimeError, 'Not implemented'
        
    def vcsCleanup(self, name):
        """
        Public method used to cleanup the local copy.
        
        Arguments
        
            name -- directory name to be cleaned up (string)
        """
        raise RuntimeError, 'Not implemented'
        
    def vcsCommandLine(self, name):
        """
        Public method used to execute arbitrary vcs commands.
        
        Arguments
        
            name -- directory name of the working directory (string)
        """
        raise RuntimeError, 'Not implemented'
        
    #####################################################################
    ## methods above need to be implemented by a subclass
    #####################################################################
    
    def vcsDefaultOptions(self):
        """
        Public method used to retrieve the default options for the vcs.
        
        Returns
        
            a dictionary with the vcs operations as key and
            the respective options as values. The key 'global' must contain
            the global options. The other keys must be 'commit', 'update',
            'add', 'remove', 'diff', 'log', 'history', 'tag', 'status' and 'export'.
        """
        return self.defaultOptions
        
    def vcsSetOptions(self, options):
        """
        Public method used to set the options for the vcs.
        
        Arguments
        
            options -- a dictionary of option strings with keys as
                defined by the default options
        """
        for key in options.keys():
            try:
                self.options[key] = options[key]
            except:
                pass
        
    def vcsGetOptions(self):
        """
        Public method used to retrieve the options of the vcs.
        
        Returns
        
            a dictionary of option strings that can be passed to
            vcsSetOptions.
        """
        return self.options
        
    #####################################################################
    ## below are some utility methods
    #####################################################################
    
    def startSynchronizedProcess(self, proc):
        """
        Private method to start a synchroneous process
        
        This method starts a process and waits
        for its end while still serving the Qt event loop.
        
        Arguments
        
            proc -- process to start (QProcess)
        """
        if proc is None:
            return
            
        if not proc.start():
            arg0 = proc.arguments()[0]
            QMessageBox.critical(None,
                self.trUtf8('Process Generation Error'),
                self.trUtf8(
                    'The process %1 could not be started.'
                    'Ensure, that it is in the search path.'
                ).arg(arg0),
                self.trUtf8('OK'))
        else:
            while proc.isRunning():
                qApp.processEvents()
                QThread.msleep(300)
                qApp.processEvents()
            return proc.normalExit()
        
    def splitPath(self, name):
        """
        Private method splitting name into a directory part and a file part.
        
        Arguments
        
            name -- path name (string)
            
        Returns 
        
            a tuple of 2 strings (dirname, filename).
        """
        fi = str(name)
        if os.path.isdir(fi):
            dn = os.path.abspath(fi)
            fn = "."
        else:
            dn, fn = os.path.split(fi)
        return (dn, fn)

    def addArguments(self, proc, arglist):
        """
        Private method to add an argument list to the process proc.
        
        Arguments
        
            proc -- the process object (QProcess)
            
            arglist -- list of arguments (list of strings or QStrings or a QStringList)
        """
        for arg in arglist:
            if arg != '':
                proc.addArgument(arg)
