class BuilderNewStyle(object, PropertiesMixin):

    bb_requests = None  # list of buildbot.process.buildrequest.BuildRequest
    bb_build = None  #: :type bb_build: buildbot.process.Build

    workdir = '.'

    factorySteps = None  # old-style static steps

    def __code_completion_helper__(self):
        if __debug__:
            self.bb_requests = BuildRequest()
            self.bb_build = Build()

    def __init__(self, **kwargs):
        if not hasattr(self, 'builderName'):
            self.builderName = kwargs.pop('builderName', None)
        if not hasattr(self, 'useSlave'):
            self.useSlave = kwargs.pop('useSlave', None)
        if not hasattr(self, 'tags'):
            self.tags = list(kwargs.pop('tags', []))
        if not hasattr(self, 'builder_properties'):
            self.builder_properties = kwargs.pop('builder_properties', {})
        self.locks = kwargs.pop('locks', [])
        assert len(kwargs.keys()) == 0, 'Unknown parameters: ' + ' '.join(kwargs.keys())


    def onNewBuild(self):
        '''
        It is called for cloned self object.

        Current build properties can be found via self.bb_requests

        Here we can populate "static" set of build steps
        '''
        self.fillStaticSteps()
        pass


    @defer.inlineCallbacks
    def run_(self):
        yield self.runPrepare()
        yield self.run()
        pass


    @defer.inlineCallbacks
    def runPrepare(self):
        yield None
        pass


    @defer.inlineCallbacks
    def run(self):
        yield None
        pass


    @defer.inlineCallbacks
    def runCleanup(self):
        yield None
        pass


    def fillStaticSteps(self):
        pass


    def initConstants(self):
        pass


    def getName(self):
        if self.builderName:
            raise Exception('implement getName() method or pass "builderName" ctor parameter')
        return self.builderName


    def getSlaves(self):
        if self.useSlave is None:
            raise Exception('implement getSlaves() method or pass "useSlave" ctor parameter')
        return [self.useSlave] if isinstance(self.useSlave, str) else self.useSlave


    def getFactory(self):
        return BuildFactoryWrapper(self)


    def getFactoryProperties(self, props):
        return props

    def getTags(self):
        return self.tags

    def canStartBuild(self, bldr, builder, breq):
        print('canStartBuild: {} on {}'.format(self.getName(), builder.slave.slavename))
        buildworker = None
        if 'buildworker' in breq.properties:
            buildworker = breq.properties['buildworker']
        elif 'buildworker' in bldr.config.properties:
            buildworker = bldr.config.properties['buildworker']
        if buildworker:
            if not isinstance(buildworker, (list, tuple)):
                buildworker = str(buildworker).split(',')
            return builder.slave.slavename in buildworker
        return True

    def register(self):
        self.initConstants()
        return BuilderConfig(
            name=self.getName(),
            slavenames=self.getSlaves(),
            factory=self.getFactory(),
            mergeRequests=False,
            tags=list(set(self.getTags())),
            properties=self.getFactoryProperties(props=self.builder_properties),
            canStartBuild = self.canStartBuild,
            locks=self.locks)

    #
    # Helpers
    #
    def addFactoryStep(self, step):
        assert self.bb_build is None, 'Build started, can\'t add factory step, use runtime step'
        self.factorySteps.append(step)


    def addStep(self, step, insertPosition=0, addToQueue=True):
        '''
        Add step into build.

        insertPosition=None - append
        insertPosition=0 - insert
        insertPosition=someStep - insert after specified step
        '''
        assert self.bb_build is not None, 'Build is not created, run this method only from run/runCleanup methods'
        return self.bb_build.addStep(step, insertPosition, addToQueue)


    def processStep(self, step):
        '''
        Process specified step

        It is Deferred call, use yield!

        Throws BuildFailed if step was failed (and build terminates)
        '''
        return self.bb_build.processStep(step)