def do_setup(self):
        try:
            localConfigPath = self._configPath
            configPath = VirtualPath.virtualize(localConfigPath, self._local)
            self.debug("Loading configuration from '%s'", localConfigPath)

            self._config = TranscodingConfig()
            loader = IniFile()
            loader.loadFromFile(self._config, localConfigPath)

            if self._inputPath:
                confInputFile = self._config.source.inputFile
                if not self._inputPath.endswith(confInputFile):
                    raise Exception("The source file path "
                                    + "doesn't match the configuration "
                                    + "source input-file property")
                altInputDir = self._inputPath[:-len(confInputFile)]
            else:
                altInputDir=None

            #TODO add cue points in report
            self._report = TranscodingReport()
            self._report.init(self._config)
            self._report.configPath = configPath

            if not self._diagnoseMode:
                moveInputFile = self._moveInputFile
            else:
                self.info("Entering diagnose mode")
                moveInputFile = False

            self._job = job.TranscodingJob(self, self, self._pathAttr)
            self._job.setup(self._local, self._config, self._report,
                            moveInputFile=moveInputFile,
                            altInputDir=altInputDir,
                            niceLevel=self._niceLevel)
            d = self._job.start()
            self._reportDefaultPath = self._job.getTempReportPath()
            self.__syncReport(self._report)
            d.addCallbacks(self.__cbJobDone, self.__ebJobFailed)
            return None
        except:
            self.__unexpectedError(task="component setup")
class FileTranscoder(component.BaseComponent, job.JobEventSink):

    componentMediumClass = FileTranscoderMedium
    logCategory = compconsts.TRANSCODER_LOG_CATEGORY


    ## Public Methods ##

    def getStatus(self):
        return self._status

    def do_acknowledge(self):
        self.onAcknowledged()
        d = self._job.acknowledge()
        d.addCallback(self.__cbJobTerminated)
        d.addErrback(self.__ebAcknowledgeError)
        return d


    ## Overriden Methods ##

    def init(self):
        log.setDefaultCategory(compconsts.TRANSCODER_LOG_CATEGORY)
        log.setDebugNotifier(self.__notifyDebug)
        self.logName = None
        self._diagnoseMode = False
        self._waitAcknowledge = False
        self._moveInputFile = True
        self._niceLevel = None
        self._job = None
        self._report = None
        self._reportDefaultPath = None
        self._reportForcedPath = None
        self._configPath = None
        self._config = None
        self._inputPath = None
        self._local = None
        self._status = TranscoderStatusEnum.pending
        self._pathAttr = None
        self.uiState.addDictKey('job-data', {})
        self.uiState.addDictKey('source-data', {})
        self.uiState.addDictKey('targets-data', {})
        self.uiState.setitem('job-data', "progress", 0.0)
        self.uiState.setitem('job-data', "job-state", JobStateEnum.pending)
        self.uiState.setitem('job-data', "acknowledged", False)
        self.uiState.setitem('job-data', "status", self._status)

    def check_properties(self, props, addMessage):
        #TODO: Add directories/files right checks
        if props.has_key("config"):
            if props.has_key("diagnose"):
                msg = ("Component properties 'config' "
                       + "and 'diagnose' should not be "
                       + "specified at the same time")
                raise TranscoderConfigError(msg)
            local = Local.createFromComponentProperties(props)
            configPath = VirtualPath(props["config"])
            localConfigPath = configPath.localize(local)
            if not os.path.exists(localConfigPath):
                msg = "Config file not found ('%s')" % localConfigPath
                raise TranscoderConfigError(msg)
        elif props.has_key("diagnose"):
            localReportPath = props["diagnose"]
            if not os.path.exists(localReportPath):
                msg = "Report file not found ('%s')" % localReportPath
                raise TranscoderConfigError(msg)
        else:
            msg = ("One of the component properties "
                   + "'config' and 'diagnose' "
                   + "should be specified")
            raise TranscoderConfigError(msg)
        if props.has_key("report"):
            localRealPath = os.path.realpath(props["report"])
            localReportDir = os.path.dirname(localRealPath)
            if not os.path.exists(localReportDir):
                msg = "Output report directory not found ('%s')" % localReportDir
                raise TranscoderConfigError(msg)


    def do_check(self):

        def transcoder_checks(result):
            # PyChecker doesn't like dynamic attributes
            __pychecker__ = "no-objattrs"
            props = self.config["properties"]
            #FIXME: Better checks for path roots
            self._waitAcknowledge = props.get("wait-acknowledge", False)
            self._moveInputFile = props.get("move-input-file", True)
            self._niceLevel = props.get("nice-level", None)
            self._pathAttr = fileutils.PathAttributes.createFromComponentProperties(props)
            localRepPath = props.get("report", None)
            self._reportForcedPath = localRepPath and os.path.realpath(localRepPath)
            if props.has_key("config"):
                self._local = Local.createFromComponentProperties(props)
                configPath = VirtualPath(props["config"])
                localConfigPath = configPath.localize(self._local)
                self.debug("Loading configuration from '%s'",
                           localConfigPath)
                self._configPath = localConfigPath
                self._inputPath = None
                self._diagnoseMode = False
            else:
                localReportPath = props["diagnose"]
                self.debug("Loading report from '%s'", localReportPath)
                baseReport = TranscodingReport()
                loader = IniFile()
                loader.loadFromFile(baseReport, localReportPath)
                self.info("Using local '%s' from report file",
                          baseReport.local.name)
                self._local = baseReport.local.getLocal()
                self._local.updateFromComponentProperties(props)
                configPath = baseReport.configPath
                localConfigPath = configPath.localize(self._local)
                if not os.path.exists(localConfigPath):
                    msg = "Config file not found ('%s')" % localConfigPath
                    raise TranscoderConfigError(msg)
                self._configPath = localConfigPath
                alternatives = [baseReport.source.lastPath,
                                baseReport.source.failedPath,
                                baseReport.source.donePath,
                                baseReport.source.inputPath]
                for virtAltPath in alternatives:
                    self._inputPath = virtAltPath.localize(self._local)
                    if os.path.isfile(self._inputPath):
                        break
                self._diagnoseMode = True
            return result

        try:
            self._fireStatusChanged(TranscoderStatusEnum.checking)
            d = component.BaseComponent.do_check(self)
            d.addCallback(transcoder_checks)
            d.addErrback(self.__ebErrorFilter, "component checking")
            return d
        except:
            self.__unexpectedError(task="component checks")

    def do_setup(self):
        try:
            localConfigPath = self._configPath
            configPath = VirtualPath.virtualize(localConfigPath, self._local)
            self.debug("Loading configuration from '%s'", localConfigPath)

            self._config = TranscodingConfig()
            loader = IniFile()
            loader.loadFromFile(self._config, localConfigPath)

            if self._inputPath:
                confInputFile = self._config.source.inputFile
                if not self._inputPath.endswith(confInputFile):
                    raise Exception("The source file path "
                                    + "doesn't match the configuration "
                                    + "source input-file property")
                altInputDir = self._inputPath[:-len(confInputFile)]
            else:
                altInputDir=None

            #TODO add cue points in report
            self._report = TranscodingReport()
            self._report.init(self._config)
            self._report.configPath = configPath

            if not self._diagnoseMode:
                moveInputFile = self._moveInputFile
            else:
                self.info("Entering diagnose mode")
                moveInputFile = False

            self._job = job.TranscodingJob(self, self, self._pathAttr)
            self._job.setup(self._local, self._config, self._report,
                            moveInputFile=moveInputFile,
                            altInputDir=altInputDir,
                            niceLevel=self._niceLevel)
            d = self._job.start()
            self._reportDefaultPath = self._job.getTempReportPath()
            self.__syncReport(self._report)
            d.addCallbacks(self.__cbJobDone, self.__ebJobFailed)
            return None
        except:
            self.__unexpectedError(task="component setup")

    def do_stop(self, *args, **kwargs):

        def component_stop(result):
            return component.BaseComponent.do_stop(self)

        try:
            if self._job:
                d = self._job.stop()
            else:
                d = defer.succeed(None)
            d.addCallback(component_stop)
            d.addErrback(self.__ebStopErrorFilter)
            return d
        except:
            self.__unexpectedError(task="component stopping")

    ## Overriden Methods ##

    def onJobInfo(self, info):
        for key, value in info.iteritems():
            self.uiState.setitem('job-data', key, value)

    def onAcknowledged(self):
        self.uiState.setitem('job-data', "acknowledged", True)

    def onJobError(self, error):
        self.uiState.setitem('job-data', "job-error", error)

    def onJobWarning(self, warning):
        self.uiState.setitem('job-data', "job-warning", warning)

    def onProgress(self, percent):
        if percent == None:
            self.info("Progression not supported")
        elif self._diagnoseMode:
            self.info("Progress: %d %%" % int(percent))
        else:
            self.log("Progress: %d %%" % int(percent))
        self.uiState.setitem('job-data', "progress", percent)

    def onJobStateChanged(self, state):
        self.uiState.setitem('job-data', "job-state", state)

    def onSourceInfo(self, info):
        inputFile = info["input-file"]
        virtFile = VirtualPath.virtualize(inputFile, self._local)
        info["input-file"] = str(virtFile)
        for key, value in info.iteritems():
            self.uiState.setitem('source-data', key, value)

    def onTargetStateChanged(self, label, state):
        self.uiState.setitem('targets-data', (label, "target-state"), state)

    def onTargetInfo(self, label, info):
        for key, value in info.iteritems():
            self.uiState.setitem('targets-data', (label, key), value)

    def onTargetError(self, label, error):
        self.uiState.setitem('targets-data', (label, "target-error"), error)

    def onTargetWarning(self, label, warning):
        self.uiState.setitem('targets-data', (label, "target-warning"), warning)

    def onSyncReport(self, report):
        self.__syncReport(report)


    ## Protected/Friend Methods ##

    def _getReportPath(self):
        if self._reportDefaultPath:
            virtPath = VirtualPath.virtualize(self._reportDefaultPath,
                                              self._local)
            return virtPath
        return None

    def _fireStatusChanged(self, status):
        self._status = status
        self.uiState.setitem('job-data', "status", status)

    def _fireTranscodingReport(self, reportPath):
        virtPath = VirtualPath.virtualize(reportPath, self._local)
        self.uiState.setitem('job-data', "transcoding-report", virtPath)


    ## Private Methods ##

    def __notifyDebug(self, msg, info=None, debug=None, failure=None,
                      exception=None, documents=None):
        infoMsg = ["File Transcoder Debug Notification: %s" % msg]
        debugMsg = []
        if info:
            infoMsg.append("Information:\n\n%s" % info)
        if debug:
            debugMsg.append("Additional Debug Info:\n\n%s" % debug)
        if failure:
            debugMsg.append("Failure Message: %s\nFailure Traceback:\n%s"
                            % (log.getFailureMessage(failure),
                               log.getFailureTraceback(failure)))
        if exception:
            debugMsg.append("Exception Message: %s\n\nException Traceback:\n%s"
                            % (log.getExceptionMessage(exception),
                               log.getExceptionTraceback(exception)))
        m = messages.Warning(T_("\n\n".join(infoMsg)),
                             debug="\n\n".join(debugMsg))
        self.addMessage(m)

    def __ebErrorFilter(self, failure, task=None):
        if failure.check(FlumotionError, PropertyError):
            return self.__transcodingError(failure, task)
        return self.__unexpectedError(failure, task)

    def __ebStopErrorFilter(self, failure):
        self.__unexpectedError(failure)
        return component.BaseComponent.do_stop(self)

    def __transcodingError(self, failure=None, task=None):
        self._fireStatusChanged(TranscoderStatusEnum.error)
        if not failure:
            failure = Failure()
        self.onJobError(failure.getErrorMessage())
        log.notifyFailure(self, failure,
                          "Transocding error%s",
                          (task and " during %s" % task) or "",
                          cleanTraceback=True)
        self.setMood(moods.sad)
        return failure

    def __unexpectedError(self, failure=None, task=None):
        self._fireStatusChanged(TranscoderStatusEnum.unexpected_error)
        if not failure:
            failure = Failure()
        self.onJobError(failure.getErrorMessage())
        log.notifyFailure(self, failure,
                          "Unexpected error%s",
                          (task and " during %s" % task) or "",
                          cleanTraceback=True)
        m = messages.Error(T_(failure.getErrorMessage()),
                           debug=log.getFailureMessage(failure))
        self.addMessage(m)
        return failure

    def __syncReport(self, report):
        report.reportPath = self._getReportPath()
        self.debug("Report path is: %s", report.reportPath)
        self.__writeReport(report)
        self._fireTranscodingReport(self._reportDefaultPath)

    def __deleteTempReport(self):
        if self._reportForcedPath:
            return
        current = self._reportDefaultPath
        temp = self._job.getTempReportPath()
        if ((current != temp)
            and os.path.isfile(current)
            and os.path.isfile(temp)):
            try:
                os.remove(temp)
            except OSError, e:
                msg = "Fail to delete temporary report"
                self.warning("%s '%s'", msg, temp)
                info = "File path: '%s'" % temp
                debug = log.getExceptionMessage(e)
                self.__notifyDebug(msg, info=info, debug=debug, exception=e)