import logging
import uuid

from buildman.component.basecomponent import BaseComponent
from buildman.component.buildcomponent import BuildComponent
from buildman.manager.basemanager import BaseManager

from trollius.coroutines import From

REGISTRATION_REALM = 'registration'
logger = logging.getLogger(__name__)

class DynamicRegistrationComponent(BaseComponent):
  """ Component session that handles dynamic registration of the builder components. """

  def onConnect(self):
    self.join(REGISTRATION_REALM)

  def onJoin(self, details):
    logger.debug('Registering registration method')
    yield From(self.register(self._worker_register, u'io.quay.buildworker.register'))

  def _worker_register(self):
    realm = self.parent_manager.add_build_component()
    logger.debug('Registering new build component+worker with realm %s', realm)
    return realm


class EnterpriseManager(BaseManager):
  """ Build manager implementation for the Enterprise Registry. """
  build_components = []
  shutting_down = False

  def initialize(self):
    # Add a component which is used by build workers for dynamic registration. Unlike
    # production, build workers in enterprise are long-lived and register dynamically.
    self.register_component(REGISTRATION_REALM, DynamicRegistrationComponent)

  def setup_time(self):
    # Builders are already registered, so the setup time should be essentially instant. We therefore
    # only return a minute here.
    return 60

  def add_build_component(self):
    """ Adds a new build component for an Enterprise Registry. """
    # Generate a new unique realm ID for the build worker.
    realm = str(uuid.uuid4())
    component = self.register_component(realm, BuildComponent, token="")
    self.build_components.append(component)
    return realm

  def schedule(self, build_job, loop):
    """ Schedules a build for an Enterprise Registry. """
    if self.shutting_down:
      return False

    for component in self.build_components:
      if component.is_ready():
        loop.call_soon(component.start_build, build_job)
        return True

    return False

  def shutdown(self):
    self.shutting_down = True

  def job_completed(self, build_job, job_status, build_component):
    self.job_complete_callback(build_job, job_status)

  def build_component_disposed(self, build_component, timed_out):
    self.build_components.remove(build_component)

  def num_workers(self):
    return len(self.build_components)
