import logging

from cinp import client

MCP_API_VERSIONS = ( '0.10', '0.11', )


class MCP( object ):
  def __init__( self, host, proxy, job_id, instance_id, cookie, stop_event ):
    self.cinp = client.CInP( host, '/api/v1/', proxy, retry_event=stop_event )
    self.job_id = job_id
    self.instance_id = instance_id
    self.cookie = cookie

    root, _ = self.cinp.describe( '/api/v1/', retry_count=30 )  # very tollerant for the initial describe, let things settle

    if root[ 'api-version' ] not in MCP_API_VERSIONS:
      raise Exception( 'Expected API version (one of) "{0}" found "{1}"'.format( MCP_API_VERSIONS, root[ 'api-version' ] ) )

  def contractorInfo( self ):
    logging.info( 'MCP: Get Contractor Info' )
    return self.cinp.call( '/api/v1/config(getContractorInfo)', {}, retry_count=10 )

  def packratInfo( self ):
    logging.info( 'MCP: Get Packrat Info' )
    return self.cinp.call( '/api/v1/config(getPackratInfo)', {}, retry_count=10 )

  def confluenceInfo( self ):
    logging.info( 'MCP: Get Confluence Info' )
    return self.cinp.call( '/api/v1/config(getConfluenceInfo)', {}, retry_count=10 )

  def signalJobRan( self ):
    logging.info( 'MCP: Signal Job Ran' )
    self.cinp.call( '/api/v1/Processor/BuildJobResourceInstance:{0}:(jobRan)'.format( self.instance_id ), { 'cookie': self.cookie }, retry_count=20 )

  def sendMessage( self, message ):
    logging.info( 'MCP: Message "{0}"'.format( message ) )
    self.cinp.call( '/api/v1/Processor/BuildJobResourceInstance:{0}:(setMessage)'.format( self.instance_id ), { 'cookie': self.cookie, 'message': message }, retry_count=20 )

  def setSuccess( self, success ):
    logging.info( 'MCP: Success "{0}"'.format( success ) )
    self.cinp.call( '/api/v1/Processor/BuildJobResourceInstance:{0}:(setSuccess)'.format( self.instance_id ), { 'cookie': self.cookie, 'success': success }, retry_count=20 )

  def setResults( self, target, results ):
    if results is not None:
      logging.info( 'MCP: Results "{0}"'.format( results[ -100: ].strip() ) )
    else:
      logging.info( 'MCP: Results <empty>' )

    self.cinp.call( '/api/v1/Processor/BuildJobResourceInstance:{0}:(setResults)'.format( self.instance_id ), { 'cookie': self.cookie, 'target': target, 'results': results }, retry_count=20 )

  def setScore( self, target, score ):
    if score is not None:
      logging.info( 'MCP: Score "{0}"'.format( score ) )
    else:
      logging.info( 'MCP: Score <undefined>' )

    self.cinp.call( '/api/v1/Processor/BuildJobResourceInstance:{0}:(setScore)'.format( self.instance_id ), { 'cookie': self.cookie, 'target': target, 'score': score }, retry_count=20 )

  def uploadedPackages( self, package_file_map ):
    if not package_file_map:
      return

    self.cinp.call( '/api/v1/Processor/BuildJobResourceInstance:{0}:(addPackageFiles)'.format( self.instance_id ), { 'cookie': self.cookie, 'package_file_map': package_file_map }, retry_count=20 )

  def getInstanceState( self, name=None ):
    logging.info( 'MCP: Instance State for "{0}"'.format( name ) )
    args = {}
    if name is not None:
      args[ 'name' ] = name

    # json encoding turns the numeric dict keys into strings, this will undo that  # TODO:  this is fixed in CInP now??
    result = {}
    state_map = self.cinp.call( '/api/v1/Processor/BuildJob:{0}:(getInstanceState)'.format( self.job_id ), args, retry_count=10 )
    if name is None:
      for name in state_map:
        result[ name ] = {}
        for index, state in state_map[ name ].items():
          result[ name ][ int( index ) ] = state

    else:
      for index, state in state_map.items():
        result[ int( index ) ] = state

    return result

  def getInstanceStructureId( self, name=None ):
    logging.info( 'MCP: Instance Structure Id(s) for "{0}"'.format( name ) )
    args = {}
    if name is not None:
      args[ 'name' ] = name

    # json encoding turns the numeric dict keys into strings, this will undo that
    result = {}
    detail_map = self.cinp.call( '/api/v1/Processor/BuildJob:{0}:(getInstanceStructureId)'.format( self.job_id ), args, retry_count=10 )
    if name is None:
      for name in detail_map:
        result[ name ] = {}
        for index, detail in detail_map[ name ].items():
          result[ name ][ int( index ) ] = detail

    else:
      for index, detail in detail_map.items():
        result[ int( index ) ] = detail

    return result

  def updateValueMap( self, value_map  ):
    logging.info( 'MCP: Setting Value "{0}"'.format( value_map ) )

    self.cinp.call( '/api/v1/Processor/BuildJobResourceInstance:{0}:(updateValueMap)'.format( self.instance_id ), { 'cookie': self.cookie, 'value_map': value_map }, retry_count=20 )

    return True

  def getValueMap( self, name=None ):
    logging.info( 'MCP: Getting Value Map' )

    return self.cinp.call( '/api/v1/Processor/BuildJobResourceInstance:{0}:(getValueMap)'.format( self.instance_id ), { 'cookie': self.cookie }, retry_count=10 )
