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

# Copyright (c) 2006 - 2007 Detlev Offenbach <detlev@die-offenbachs.de>
#

"""
Module implementing the VCS status monitor thread base class.
"""

import os

from PyQt4.QtCore import QThread, QMutex, QWaitCondition, QString, QStringList, SIGNAL

class VcsStatusMonitorThread(QThread):
    """
    Class implementing the VCS status monitor thread base class.
    
    @signal vcsStatusMonitorData(QStringList) emitted to update the VCS status
    @signal vcsStatusMonitorStatus(QString, QString) emitted to signal the status of the
        monitoring thread (ok, nok, op) and a status message
    """
    def __init__(self, interval, projectDir, parent = None):
        """
        Constructor
        
        @param interval new interval in seconds (integer)
        @param projectDir project directory to monitor (string or QString)
        @param parent reference to the parent object (QObject)
        """
        QThread.__init__(self, parent)
        self.setObjectName("VcsStatusMonitorThread")
        
        self.projectDir = QString(projectDir)
        
        self.interval = interval
        
        self.statusList = QStringList()
        self.reportedStates = {}
        
        self.monitorMutex = QMutex()
        self.monitorCondition = QWaitCondition()
        self.__stopIt = False
    
    def run(self):
        """
        Protected method implementing the tasks action.
        """
        while not self.__stopIt:
            # perform the checking task
            self.statusList.clear()
            self.emit(SIGNAL("vcsStatusMonitorStatus(QString, QString)"), 
                      QString("op"), self.trUtf8("Checking repository status"))
            res, statusMsg = self._performMonitor()
            if res:
                status = QString("ok")
            else:
                status = QString("nok")
            self.emit(SIGNAL("vcsStatusMonitorStatus(QString, QString)"), 
                      status, statusMsg)
            self.emit(SIGNAL("vcsStatusMonitorData(QStringList)"), self.statusList)
            
            # wait until interval has expired checking for a stop condition
            self.monitorMutex.lock()
            if not self.__stopIt:
                self.monitorCondition.wait(self.monitorMutex, self.interval * 1000)
            self.monitorMutex.unlock()
        
        self.exit()
    
    def setInterval(self, interval):
        """
        Public method to change the monitor interval.
        
        @param interval new interval in seconds (integer)
        """
        locked = self.monitorMutex.tryLock()
        self.interval = interval
        self.monitorCondition.wakeAll()
        if locked:
            self.monitorMutex.unlock()
    
    def getInterval(self):
        """
        Public method to get the monitor interval.
        
        @return interval in seconds (integer)
        """
        return self.interval
    
    def checkStatus(self):
        """
        Public method to wake up the status monitor thread.
        """
        locked = self.monitorMutex.tryLock()
        self.monitorCondition.wakeAll()
        if locked:
            self.monitorMutex.unlock()
    
    def stop(self):
        """
        Public method to stop the monitor thread.
        """
        locked = self.monitorMutex.tryLock()
        self.__stopIt = True
        self.monitorCondition.wakeAll()
        if locked:
            self.monitorMutex.unlock()

    def _performMonitor(self):
        """
        Protected method implementing the real monitoring action.
        
        This method must be overridden and populate the statusList member variable
        with a list of strings giving the status in the first column and the
        path relative to the project directory starting with the third column.
        The allowed status flags are:
        <li>
            <ul>"A" path was added but not yet comitted</ul>
            <ul>"M" path has local changes</ul>
            <ul>"U" path needs an update</ul>
            <ul>"Z" path contains a conflict</ul>
            <ul>" " path is back at normal</ul>
        </li>
        
        @return tuple of flag indicating successful operation (boolean) and 
            a status message in case of non successful operation (QString)
        """
        raise RuntimeError, 'Not implemented'

    def clearCachedState(self, name):
        """
        Public method to clear the cached VCS state of a file/directory.
        
        @param name name of the entry to be cleared (QString or string)
        """
        key = unicode(name).replace(unicode(self.projectDir) + os.sep, '')
        try:
            del self.reportedStates[key]
        except KeyError:
            pass
