from concurrent.futures import ThreadPoolExecutor
from tornado.concurrent import run_on_executor
from API.handlers import APIHandler
from API.schema import api
import errors

class AudioAPI(APIHandler):
    """REST interface to the Box
    """
    executor = ThreadPoolExecutor(1)

    def __init__(self, extra):
        """Init
        """
        super(AudioAPI, self).__init__(extra)
        self.server = extra["server"]
        self.project_manager = extra["project_manager"]
        self.output_manager = extra["output_manager"]

    @api(name="ListSources",
         endpoint="audio.list_sources",
         description="Lists audio sources",
         result={
             "type": "object",
             "properties":
                 {
                     "audio_sources": {
                         "type": "array",
                         "items": {
                             "type": "object",
                             "properties": {
                                 "name": {
                                     "$ref": "AudioSourceName"
                                 },
                                 "support_delay": {
                                     "type": "boolean"
                                 },
                                 "layouts": {
                                     "type": "array",
                                     "items": {
                                        "$ref": "AudioSourceLayout"
                                    }
                                 }
                             }
                         }
                     }
                 },
             "minProperties": 1
         }
         )
    @run_on_executor
    def list_sources(self, parameters):
        sources = []
        project_audio_sources = self.project_manager.list_audio_sources()
        for source_name in project_audio_sources:
            sources.append({
                "name": source_name,
                "support_delay": project_audio_sources[source_name]["input"]
                                 in self.project_manager.AUDIO_INPUTS_SUPPORTING_DELAY,
                "layouts": project_audio_sources[source_name]["layouts"]})
        return {"audio_sources": sources}

    @api(name="GetSource",
         endpoint="audio.get_source",
         description="Gets current audio source",
         result={
             "type": "object",
             "properties":
                 {
                     "source": {
                         "$ref": "AudioSourceName"
                     },
                     "layout": {
                         "$ref": "AudioSourceLayout"
                     }
                 },
         }
         )
    @run_on_executor
    def get_source(self, parameters):
        return {"source": self.project_manager.get_audio_source(), "layout": self.project_manager.get_audio_layout()}

    @api(name="SetSource",
         endpoint="audio.set_source",
         description="Sets the current audio source",
         parameters={
             "type": "object",
             "properties":
                 {
                     "source": {
                         "$ref": "AudioSourceName"
                     },
                     "layout": {
                         "$ref": "AudioSourceLayout"
                     }
                 },
             "required": ["source", "layout"]
         }
         )
    @run_on_executor
    def set_source(self, parameters):
        # setting the video mode is forbidden while broadcasting or recording
        if self.output_manager.has_ongoing_critical_output():
            raise errors.AudioSourceChangeForbiddenError(
                "audio source cannot be changed (critical output is ongoing)")
        self.project_manager.set_audio_source(str(parameters.get("source")), str(parameters.get("layout")))
        self.server.reset()

    @api(name="GetAudioDelay",
         endpoint="audio.get_delay",
         description="Gets the current delay for the specified source",
         parameters={
             "type": "object",
             "properties":
                 {
                     "source": {
                         "$ref": "AudioSourceName"
                     }
                 },
             "minProperties": 1
         },
         result={
             "type": "object",
             "properties":
                 {
                     "delay": {
                         "type": "number",
                         "description": "The audio delay in seconds"
                     }
                 }
         }
         )
    @run_on_executor
    def get_delay(self, parameters):
        return {"delay": self.project_manager.get_audio_delay(str(parameters.get("source")))}

    @api(name="SetAudioDelay",
         endpoint="audio.set_delay",
         description="Sets the current audio delay for the specified source",
         parameters={
             "type": "object",
             "properties":
                 {
                     "source": {
                         "$ref": "AudioSourceName"
                     },
                     "delay": {
                         "type": "number",
                         "minimum": -1.0,
                         "maximum": 1.0,
                         "description": "The audio delay in seconds"
                     }
                 }
         }
         )
    @run_on_executor
    def set_delay(self, parameters):
        self.project_manager.set_audio_delay(str(parameters.get("source")), parameters.get("delay"))