# Copyright (c) 2014 Baidu.com, Inc. All Rights Reserved
#
# 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 probe.
"""

import copy
import json
import logging
import uuid
import sys

from baidubce import bce_base_client
from baidubce.auth import bce_v1_signer
from baidubce.http import bce_http_client
from baidubce.http import handler
from baidubce.http import http_methods
from baidubce import utils
from baidubce.utils import required
from baidubce import compat

_logger = logging.getLogger(__name__)

if sys.version < '3':
    reload(sys)
    sys.setdefaultencoding('utf-8')

class ProbeClient(bce_base_client.BceBaseClient):
    """
    Probe base sdk client
    """
    version = b'/v1'

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

    def _merge_config(self, config=None):
        """
        :param config:
        :type config: baidubce.BceClientConfiguration
        :return:
        """
        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(config)
        if body_parser is None:
            body_parser = handler.parse_json
        if headers is None:
            headers = {b'Accept': b'*/*', b'Content-Type':
                b'application/json;charset=utf-8'}

        return bce_http_client.send_request(
            config, bce_v1_signer.sign, [handler.parse_error, body_parser],
            http_method, path, body, headers, params)

    @required(name=(bytes, str),
              vpc_id=(bytes, str),
              subnet_id=(bytes, str),
              protocol=(bytes, str),
              frequency=int,
              source_ips=list,
              source_ip_num=int)
    def create_probe(self, name, vpc_id, subnet_id, protocol,
                     frequency, dst_ip, dst_port=None,
                     source_ips=None, source_ip_num=None,
                     description=None,
                     payload=None, client_token=None, config=None):
        """
        The method to create a probe.

        :param name:
            The name of the probe.
            The name must be 1 to 64 characters in length,
            and can contain numbers, letters and underscores (_).
        :type name: string

        :param vpc_id:
            The id of the vpc to create the probe in.
        :type vpc_id: string

        :param subnet_id:
            The id of the subnet to create the probe in.
        :type subnet_id: string

        :param protocol:
            The protocol of the probe, TCP, UDP, ICMP or DNS.
        :type protocol: string

        :param frequency:
            The number of the probing per minute, 10, 20 or 30.
            Default value is 20.
        :type frequency: int

        :param dst_ip:
            The destination ip of the probe.
        :type dst_ip: string

        :param dst_port:
            The destination port of the probe.
            Must be specified when the protocol is TCP, UDP or DNS.
        :type dst_port: string

        :param source_ips:
            The specified list of source ips of the probe.
        :type source_ips: list

        :param source_ip_num:
            The number of the source ips to be auto generated.
            When source_ip_num is not specified,
            source_ips must at least contain one ip.
        :type source_ip_num: int

        :param description:
            The description of the probe.
        :type description: string

        :param payload:
            The probe string of the UDP probe
            or the domain of the DNS probe.
            Must be specified when the protocol is TCP, UDP or DNS.
        :type payload: string

        :param client_token:
            If the clientToken is not specified by the user, a random String
            generated by default algorithm will be used.
        :type client_token: string

        :param config:
        :type config: baidubce.BceClientConfiguration

        :return:
        :rtype: baidubce.bce_response.BceResponse
        """
        path = utils.append_uri(self.version, b'probe')
        if client_token is None:
            client_token = generate_client_token()
        params = {b'clientToken': client_token}
        if source_ips is None:
            source_ips = []
        body = {
            'name': name,
            'vpcId': vpc_id,
            'subnetId': subnet_id,
            'protocol': protocol,
            'frequency': frequency,
            'sourceIps': source_ips,
            'sourceIpNum': source_ip_num,
        }
        if description is not None:
            body['description'] = description
        if dst_ip is not None:
            body['destIp'] = dst_ip
        if dst_port is not None:
            body['destPort'] = dst_port
        if payload is not None:
            body['payload'] = payload
        return self._send_request(http_methods.POST, path,
                                  body=json.dumps(body), params=params,
                                  config=config)

    def list_probes(self, marker=None, max_keys=None, config=None):
        """
        The method to list all probes owned by the authenticated user.

        :param marker:
            The optional parameter marker specified in the original request to specify
            where in the results to begin listing.
            Together with the marker, specifies the list result which listing should begin.
            If the marker is not specified, the list result will listing from the first one.
        :type marker: string

        :param max_Keys:
            The optional parameter to specifies the max number of list result to return.
            The default value is 1000.
        :type max_Keys: int

        :param config:
        :type config: baidubce.BceClientConfiguration

        :return:
        :rtype baidubce.bce_response.BceResponse
        """
        path = utils.append_uri(self.version, b'probe')
        params = {}
        if marker is not None:
            params[b'marker'] = marker
        if max_keys is not None:
            params[b'maxKeys'] = max_keys
        return self._send_request(http_methods.GET, path, params=params,
                                  config=config)

    @required(probe_id=(bytes, str))
    def get_probe(self, probe_id, config=None):
        """
        The method to get the detail informations of a probe.

        :param probe_id:
            The id of the probe.
        :type probe_id: string

        :param config:
        :type config: baidubce.BceClientConfiguration

        :return:
        :rtype baidubce.bce_response.BceResponse
        """
        path = utils.append_uri(self.version, b'probe', probe_id)
        return self._send_request(http_methods.GET, path, config=config)

    def update_probe(self, probe_id, name=None, description=None,
                     dst_ip=None, dst_port=None, frequency=None,
                     payload=None, client_token=None, config=None):
        """
        The method to update a probe.

        :param probe_id:
            The id of the probe.
        :type probe_id: string

        :param name:
            The name of the probe.
        :type name: string

        :param description:
            The description of the probe.
        :type description: string

        :param dst_ip:
            The destination ip of the probe.
        :type dst_ip: string

        :param dst_port:
            The destination port of the probe.
        :type dst_port: string

        :param frequency:
            The number of the probing per minute, 10, 20 or 30.
        :type frequency: int

        :param payload:
            The probe string of the UDP probe and the TCP probe,
            or the domain of the DNS probe.
        :type payload:string

        :param client_token:
            If the clientToken is not specified by the user, a random String
            generated by default algorithm will be used.
        :type client_token: string

        :param config:
        :type config: baidubce.BceClientConfiguration

        :return:
        :rtype: baidubce.bce_response.BceResponse
        """
        path = utils.append_uri(self.version, b'probe', probe_id)
        if client_token is None:
            client_token = generate_client_token()
        params = {b'clientToken': client_token}
        body = {}
        if name is not None:
            body['name'] = name
        if description is not None:
            body['description'] = description
        if dst_ip is not None:
            body['destIp'] = dst_ip
        if dst_port is not None:
            body['destPort'] = dst_port
        if frequency is not None:
            body['frequency'] = frequency
        if payload is not None:
            body['payload'] = payload
        return self._send_request(http_methods.PUT, path, body=json.dumps(body),
                                  params=params, config=config)

    @required(probe_id=(bytes, str))
    def delete_probe(self, probe_id, client_token=None, config=None):
        """
        The method to delete a probe.

        :param probe_id:
            The id of the probe.
        :type probe_id: string

        :param client_token:
            If the clientToken is not specified by the user, a random String
            generated by default algorithm will be used.
        :type client_token: string

        :param config:
        :type config: baidubce.BceClientConfiguration

        :return:
        :rtype: baidubce.bce_response.BceResponse
        """
        path = utils.append_uri(self.version, b'probe', probe_id)
        if client_token is None:
            client_token = generate_client_token()
        params = {b'clientToken': client_token}
        return self._send_request(http_methods.DELETE, path,
                                  params=params, config=config)


def generate_client_token_by_uuid():
    """
    The default method to generate the random string for client_token
    if the optional parameter client_token is not specified by the user.

    :return:
    :rtype string
    """
    return str(uuid.uuid4())


generate_client_token = generate_client_token_by_uuid