# Copyright 2014 Baidu, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
# except in compliance with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software distributed under the
# License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
# either express or implied. See the License for the specific language governing permissions
# and limitations under the License.

"""
This module provides a client class for Media.
"""

import copy
import json
import logging
#from baidubce import bce_base_client
from baidubce.bce_base_client import BceBaseClient
from baidubce.auth import bce_v1_signer
from baidubce.bce_response import BceResponse
from baidubce.http import bce_http_client
from baidubce.http import handler
from baidubce.http import http_content_types
from baidubce.http import http_headers
from baidubce.http import http_methods
from baidubce.exception import BceClientError
from baidubce.exception import BceServerError
from baidubce.services.media import media_handler
from baidubce.utils import required

_logger = logging.getLogger(__name__)


class MediaClient(BceBaseClient):
    """
    sdk client
    """

    prefix = '/v3'

    def __init__(self, config=None):
        BceBaseClient.__init__(self, config)

    @required(pipeline_name=(bytes, str))
    def list_jobs(self,
                  pipeline_name,
                  job_status=None,
                  begin=None,
                  end=None,
                  config=None):
        """
        List jobs by pipelineName and jobStatus

        :param pipelineName: The pipeline name
        :type  pipelineName: string or unicode
        :param job_status: The job status, will not filter if None
        :type  job_status: string or unicode
        :param begin: The createTime should be later than or equals with begin, will not check if None
        :type  begin: string or unicode
        :param end: The createTime should be earlier than or equals with end, will not check if None
        :type  end: string or unicode
        :param config: None
        :type config: BceClientConfiguration
        :returns:
        :rtype: baidubce.bce_response.BceResponse
        """
        if pipeline_name == '':
            raise BceClientError('pipeline_name can\'t be empty string')
        my_params={
                'pipelineName': pipeline_name
        }
        if job_status is not None:
            my_params["jobStatus"] = job_status
        if begin is not None:
            my_params["begin"] = begin
        if end is not None:
            my_params["end"] = end
        return self._send_request(
            http_methods.GET, 
            '/job/transcoding',
            params=my_params,
            config=config)

    @required(pipeline_name=(bytes, str), source=dict, target=dict)
    def create_job(self, pipeline_name, source, target, config=None):
        """
        Create a job

        :param pipelineName: The pipeline name
        :type pipelineName: string or unicode
        :param source: source
        :type source: array
        :param target: source
        :type target: array
        :param config: None
        :type config: BceClientConfiguration
        :returns:
        :rtype: baidubce.bce_response.BceResponse
        """
        if pipeline_name == '':
            raise BceClientError('pipeline_name can\'t be empty string')
        return self._send_request(
            http_methods.POST,
            '/job/transcoding',
            body=json.dumps({
                'pipelineName': pipeline_name,
                'source': source,
                'target': target}),
            headers={http_headers.CONTENT_TYPE: http_content_types.JSON},
            config=config)

    @required(job_id=(bytes, str))
    def get_job(self, job_id, config=None):
        """
        Get the specific job information

        :param pipelineName: The pipeline name
        :type pipelineName: string or unicode
        :param config: None
        :type config: BceClientConfiguration
        :returns:
        :rtype: baidubce.bce_response.BceResponse
        """
        if job_id == '':
            raise BceClientError('job_id can\'t be empty string')
        return self._send_request(
            http_methods.GET, 
            '/job/transcoding/' + job_id,
            config=config)

    @required(job_id=(bytes, str))
    def get_transcoding_encryption_key(self, job_id, config=None):
        """
        Get transcoding job encryption key

        :param job_id: The job Id want to query transcoding encryption key.
        :type job_id: string
        :param config: None
        :type config: BceClientConfiguration
        :returns: Response Object contains transcoding encryption Aes key.
        :rtype: baidubce.bce_response.BceResponse
        """
        if job_id == '':
            raise BceClientError('job_id can\'t be empty string')
        return self._send_request(
            http_methods.GET, 
            '/transcoding/key/' + job_id,
            body_parser=media_handler.parse_secret_key_response,
            config=config)

    @required(bucket=(bytes, str), key=(bytes, str))
    def get_mediainfo_of_file(self, bucket, key, config=None):
        """
        Get the media info of media information

        :param pipelineName: The pipeline name
        :type pipelineName: string or unicode
        :param config: None
        :type config: BceClientConfiguration
        :returns:
        :rtype: baidubce.bce_response.BceResponse
        """
        if bucket == '':
            raise BceClientError('bucket can\'t be empty string')
        if key == '':
            raise BceClientError('key can\'t be empty string')
        return self._send_request(
            http_methods.GET,
            '/mediainfo',
            params={
                'bucket': bucket,
                'key': key},
            config=config)

    def list_pipelines(self, config=None):
        """
        List pipelines

        :param pipelineName: The pipeline name
        :type pipelineName: string or unicode
        :param config: None
        :type config: BceClientConfiguration
        :returns:
        :rtype: baidubce.bce_response.BceResponse
        """
        return self._send_request(http_methods.GET, '/pipeline', config=config)

    @required(
        pipeline_name=(bytes, str),
        source_bucket=(bytes, str),
        target_bucket=(bytes, str))
    def create_pipeline(
            self,
            pipeline_name,
            source_bucket,
            target_bucket,
            description=None,
            pipeline_config=None,
            config=None):
        """
        Create a pipeline

        :param pipelineName: The pipeline name
        :type pipelineName: string or unicode
        :param config: None
        :type config: BceClientConfiguration
        :returns:
        :rtype: baidubce.bce_response.BceResponse
        """
        body_content = {}
        if description is not None:
            body_content['description'] = description
        else:
            body_content['description'] = ""
        if pipeline_config is not None:
            body_content['config'] = pipeline_config
        if pipeline_name == '':
            raise BceClientError('pipeline_name can\'t be empty string')
        if source_bucket == '':
            raise BceClientError('source_bucket can\'t be empty string')
        if target_bucket == '':
            raise BceClientError('target_bucket can\'t be empty string')
        body_content['pipelineName'] = pipeline_name
        body_content['sourceBucket'] = source_bucket
        body_content['targetBucket'] = target_bucket
        return self._send_request(
            http_methods.POST,
            '/pipeline',
            body=json.dumps(body_content),
            headers={http_headers.CONTENT_TYPE: http_content_types.JSON},
            config=config)

    @required(pipeline_name=(bytes, str), pipeline=(BceResponse, dict))
    def update_pipeline(
            self,
            pipeline_name,
            pipeline,
            config=None):
        """
        Update a pipeline

        :param pipeline_name: the preset name
        :type pipeline_name: string
        :param pipeline: the update body
        :type pipeline: Object
        :returns:
        :param config: None
        :type config: BceClientConfiguration
        :returns:
        :rtype: baidubce.bce_response.BceResponse
        """
        return self._send_request(
            http_methods.PUT,
            '/pipeline/' + pipeline_name,
            body=json.dumps(pipeline, default=lambda o: o.__dict__),
            headers={http_headers.CONTENT_TYPE: http_content_types.JSON},
            config=config)

    @required(pipelien_name=(bytes, str))
    def get_pipeline_for_update(self, pipeline_name, config=None):
        """
        Get the specific pipeline information without converting camel key to a "pythonic" name

        :param pipeline_name: The pipeline name
        :type pipeline_name: string or unicode
        :param config: None
        :type config: BceClientConfiguration
        :returns:
        :rtype: baidubce.bce_response.BceResponse
        """
        if pipeline_name == '':
            raise BceClientError('pipeline_name can\'t be empty string')
        return self._send_request(http_methods.GET, '/pipeline/' + pipeline_name,
                                  config=config, body_parser=media_handler.parse_json)

    @required(pipeline_name=(bytes, str))
    def get_pipeline(self, pipeline_name, config=None):
        """
        Get the specific pipeline information

        :param pipelineName: The pipeline name
        :type pipelineName: string or unicode
        :param config: None
        :type config: BceClientConfiguration
        :returns:
        :rtype: baidubce.bce_response.BceResponse
        """
        if pipeline_name == '':
            raise BceClientError('pipeline_name can\'t be empty string')
        return self._send_request(http_methods.GET, '/pipeline/' + pipeline_name, config=config)

    @required(pipeline_name=(bytes, str))
    def delete_pipeline(self, pipeline_name, config=None):
        """
        Delete the specific pipeline

        :param pipelineName: The pipeline name
        :type pipelineName: string or unicode
        :param config: None
        :type config: BceClientConfiguration
        :returns:
        :rtype: baidubce.bce_response.BceResponse
        """
        if pipeline_name == '':
            raise BceClientError('pipeline_name can\'t be empty string')
        return self._send_request(http_methods.DELETE, '/pipeline/' + pipeline_name, config=config)

    def list_presets(self, config=None):
        """
        List presets

        :param config: None
        :type config: BceClientConfiguration
        :returns:
        :rtype: baidubce.bce_response.BceResponse
        """
        return self._send_request(http_methods.GET, '/preset', config=config)

    @required(preset_name=(bytes, str), container=(bytes, str))
    def create_preset(
            self,
            preset_name,
            container,
            transmux=None,
            description=None,
            clip=None,
            audio=None,
            video=None,
            encryption=None,
            watermark_id=None,
            extra_config=None,
            trans_config=None,
            config=None):
        """
        Create a preset

        :param config: None
        :type config: BceClientConfiguration
        :returns:
        :rtype: baidubce.bce_response.BceResponse
        """

        body_content = dict()
        if preset_name == '':
            raise BceClientError('preset_name can\'t be empty string')
        if container == '':
            raise BceClientError('container can\'t be empty string')
        body_content['presetName'] = preset_name
        body_content['container'] = container
        if description is None:
            body_content['description'] = ''
        else:
            body_content['description'] = description
        if transmux is not None:
            body_content['transmux'] = transmux
        if clip is not None:
            body_content['clip'] = clip
        if audio is not None:
            body_content['audio'] = audio
        if video is not None:
            body_content['video'] = video
        if encryption is not None:
            body_content['encryption'] = encryption
        if watermark_id is not None:
            body_content['watermarkId'] = watermark_id
        if extra_config is not None:
            body_content['extraCfg'] = extra_config
        if trans_config is not None:
            body_content['transCfg'] = trans_config
        return self._send_request(
            http_methods.POST,
            '/preset',
            body=json.dumps(body_content),
            headers={http_headers.CONTENT_TYPE: http_content_types.JSON},
            config=config)

    @required(preset_name=(bytes, str), preset=(BceResponse, dict))
    def update_preset(
            self,
            preset_name,
            preset,
            config=None):
        """
        Update a preset

        :param preset_name: the preset name
        :type preset_name: string
        :param preset: the update body
        :type preset: Object
        :returns:
        :param config: None
        :type config: BceClientConfiguration
        :returns:
        :rtype: baidubce.bce_response.BceResponse
        """
        return self._send_request(
            http_methods.PUT,
            '/preset/' + preset_name,
            body=json.dumps(preset, default=lambda o: o.__dict__),
            headers={http_headers.CONTENT_TYPE: http_content_types.JSON},
            config=config)

    @required(preset_name=(bytes, str))
    def get_preset(self, preset_name, config=None):
        """
        Get the specific preset information

        :param pipelineName: The pipeline name
        :type pipelineName: string or unicode
        :param config: None
        :type config: BceClientConfiguration
        :returns:
        :rtype: baidubce.bce_response.BceResponse
        """
        if preset_name == '':
            raise BceClientError('preset_name can\'t be empty string')
        return self._send_request(http_methods.GET, '/preset/' + preset_name, config=config)

    @required(preset_name=(bytes, str))
    def get_preset_for_update(self, preset_name, config=None):
        """
        Get the specific preset information without converting camel key to a "pythonic" name

        :param preset_name: The preset name
        :type preset_name: string or unicode
        :param config: None
        :type config: BceClientConfiguration
        :returns:
        :rtype: baidubce.bce_response.BceResponse
        """
        if preset_name == '':
            raise BceClientError('preset_name can\'t be empty string')
        return self._send_request(http_methods.GET, '/preset/' + preset_name,
                                  config=config, body_parser=media_handler.parse_json)

    @required(preset_name=(bytes, str))
    def delete_preset(self, preset_name, config=None):
        """
        Delete a preset

        :param pipelineName: The pipeline name
        :type pipelineName: string or unicode
        :param config: None
        :type config: BceClientConfiguration
        :returns:
        :rtype: baidubce.bce_response.BceResponse
        """
        if preset_name == '':
            raise BceClientError('preset_name can\'t be empty string')
        return self._send_request(http_methods.DELETE, '/preset/' + preset_name, config=config)

    @required(pipeline_name=(bytes, str), source=dict)
    def create_thumbnail_job(self, pipeline_name, source, target=None, capture=None, config=None):
        """
        Create thumbnail job

        :param pipelineName: The pipeline name
        :type pipelineName: string or unicode
        :param config: None
        :type config: BceClientConfiguration
        :returns:
        :rtype: baidubce.bce_response.BceResponse
        """
        body_content = {}
        if pipeline_name == '':
            raise BceClientError('pipeline_name can\'t be empty string')
        if target is not None:
            body_content['target'] = target
        if capture is not None:
            body_content['capture'] = capture
        body_content['pipelineName'] = pipeline_name
        body_content['source'] = source
        return self._send_request(
            http_methods.POST,
            '/job/thumbnail',
            body=json.dumps(body_content),
            headers={http_headers.CONTENT_TYPE: http_content_types.JSON},
            config=config)

    @required(job_id=(bytes, str))
    def get_thumbnail_job(self, job_id, config=None):
        """
        Get thumbnail job

        :param pipelineName: The pipeline name
        :type pipelineName: string or unicode
        :param config: None
        :type config: BceClientConfiguration
        :returns:
        :rtype: baidubce.bce_response.BceResponse
        """
        if job_id == '':
            raise BceClientError('job_id can\'t be empty string')
        return self._send_request(http_methods.GET, '/job/thumbnail/' + job_id, config=config)

    @required(pipeline_name=(bytes, str))
    def list_thumbnail_jobs_by_pipeline(self,
                                        pipeline_name,
                                        job_status=None,
                                        begin=None,
                                        end=None,
                                        config=None):
        """
        List thumbnail jobs by pipelineName

        :param pipelineName: The pipeline name
        :type pipelineName: string or unicode
        :param job_status: The thumbnail job status, will not filter if None
        :type  job_status: string or unicode
        :param begin: The createTime should be later than or equals with begin, will not check if None
        :type  begin: string or unicode
        :param end: The createTime should be earlier than or equals with end, will not check if None
        :type  end: string or unicode
        :param config: None
        :type config: BceClientConfiguration
        :returns:
        :rtype: baidubce.bce_response.BceResponse
        """
        
        if pipeline_name == '':
            raise BceClientError('pipeline_name can\'t be empty string')
        my_params={
                'pipelineName': pipeline_name
        }
        if job_status is not None:
            my_params["jobStatus"] = job_status
        if begin is not None:
            my_params["begin"] = begin
        if end is not None:
            my_params["end"] = end
        return self._send_request(
            http_methods.GET,
            '/job/thumbnail',
            params=my_params,
            config=config)

    @required(
        bucket=(bytes, str),
        key=(bytes, str),
        vertical_offset_in_pixel=int,
        hori_offset_in_pixel=int)
    def create_watermark(
            self,
            bucket,
            key,
            vertical_alignment=None,
            horizontal_alignment=None,
            vertical_offset_in_pixel=None,
            hori_offset_in_pixel=None,
            config=None):
        """
        Create watermark

        :param pipelineName: The pipeline name
        :type pipelineName: string or unicode
        :param config: None
        :type config: BceClientConfiguration
        :returns:
        :rtype: baidubce.bce_response.BceResponse
        """
        if bucket == '':
            raise BceClientError('bucket can\'t be empty string')
        if key == '':
            raise BceClientError('key can\'t be empty string')
        body_content = {}
        body_content['bucket'] = bucket
        body_content['key'] = key
        if vertical_alignment is not None:
            body_content['verticalAlignment'] = vertical_alignment
        if horizontal_alignment is not None:
            body_content['horizontalAlignment'] = horizontal_alignment
        if vertical_offset_in_pixel is not None:
            body_content['verticalOffsetInPixel'] = vertical_offset_in_pixel
        if hori_offset_in_pixel is not None:
            body_content['horizontalOffsetInPixel'] = hori_offset_in_pixel
        return self._send_request(
            http_methods.POST,
            '/watermark',
            body=json.dumps(body_content),
            headers={http_headers.CONTENT_TYPE: http_content_types.JSON},
            config=config)

    @required(watermark_id=(bytes, str))
    def get_watermark(self, watermark_id, config=None):
        """
        Get the specific watermark information

        :param pipelineName: The pipeline name
        :type pipelineName: string or unicode
        :param config: None
        :type config: BceClientConfiguration
        :returns:
        :rtype: baidubce.bce_response.BceResponse
        """
        if watermark_id == '':
            raise BceClientError('watermark_id can\'t be empty string')
        return self._send_request(http_methods.GET, '/watermark/' + watermark_id, config=config)

    def list_watermarks(self, config=None):
        """
        List watermarks

        :param pipelineName: The pipeline name
        :type pipelineName: string or unicode
        :param config: None
        :type config: BceClientConfiguration
        :returns:
        :rtype: baidubce.bce_response.BceResponse
        """
        return self._send_request(http_methods.GET, '/watermark', config=config)

    @required(watermark_id=(bytes, str))
    def delete_watermark(self, watermark_id, config=None):
        """
        Delete the specific watermark

        :param pipelineName: The pipeline name
        :type pipelineName: string or unicode
        :param config: None
        :type config: BceClientConfiguration
        :returns:
        :rtype: baidubce.bce_response.BceResponse
        """
        if watermark_id == '':
            raise BceClientError('watermark_id can\'t be empty string')
        return self._send_request(http_methods.DELETE, '/watermark/' + watermark_id, config=config)

    def list_notifications(self, config=None):
        """
        List notifications

        :param config: None
        :type config: BceClientConfiguration
        :returns:
        :rtype: baidubce.bce_response.BceResponse
        """
        return self._send_request(http_methods.GET, '/notification', config=config)

    @required(
        name=(bytes, str),
        endpoint=(bytes, str))
    def create_notification(
            self,
            name,
            endpoint,
            config=None):
        """
        Create a notification

        :param name: The notification name
        :type name: string or unicode
        :param endpoint: The endpoint
        :type endpoint: string or unicode
        :param config: None
        :type config: BceClientConfiguration
        :returns:
        :rtype: baidubce.bce_response.BceResponse
        """
        if name == '':
            raise BceClientError('name can\'t be empty string')
        if endpoint == '':
            raise BceClientError('endpoint can\'t be empty string')
        body_content = {'name': name,
                        'endpoint': endpoint}
        return self._send_request(
            http_methods.POST,
            '/notification',
            body=json.dumps(body_content),
            headers={http_headers.CONTENT_TYPE: http_content_types.JSON},
            config=config)

    @required(name=(bytes, str))
    def get_notification(self, name, config=None):
        """
        Get the specific notification information

        :param name: The notification name
        :type name: string or unicode
        :param config: None
        :type config: BceClientConfiguration
        :returns:
        :rtype: baidubce.bce_response.BceResponse
        """
        if name == '':
            raise BceClientError('name can\'t be empty string')
        return self._send_request(http_methods.GET, '/notification/' + name, config=config)

    @required(name=(bytes, str))
    def delete_notification(self, name, config=None):
        """
        Delete the specific notification

        :param name: The notification name
        :type name: string or unicode
        :param config: None
        :type config: BceClientConfiguration
        :returns:
        :rtype: baidubce.bce_response.BceResponse
        """
        if name == '':
            raise BceClientError('name can\'t be empty string')
        return self._send_request(http_methods.DELETE, '/notification/' + name, config=config)

    def _get_config_parameter(self, config, attr):
        result = None
        if config is not None:
            result = getattr(config, attr)
        if result is not None:
            return result
        return getattr(self.config, attr)

    @staticmethod
    def _merge_config(self, config):
        if config is None:
            return self.config
        else:
            new_config = copy.copy(self.config)
            new_config.merge_non_none_values(config)
            return new_config

    def _send_request(
            self, http_method, path,
            body=None, headers=None, params=None,
            config=None,
            body_parser=None):
        config = self._merge_config(self, config)
        if body_parser is None:
            body_parser = handler.parse_json
        realpath = MediaClient.prefix + path
        return bce_http_client.send_request(
            config, bce_v1_signer.sign, [handler.parse_error, body_parser],
            http_method, str.encode(realpath), body, headers, params)
