import importlib
import inspect
import json
import logging
import pkgutil
from pathlib import Path
import subprocess
import types
from typing import Dict, Any, Optional

# Because I'm subprocessing myself, I need to do weird thing as import.
try:
    # If I'm started as a module __main__
    from .venvtools import create_venv_with_package
except ModuleNotFoundError:
    # If I'm started by my main directly
    from venvtools import create_venv_with_package

_LOGGER = logging.getLogger(__name__)

def parse_input(input_parameter):
    """From a syntax like package_name#submodule, build a package name
    and complete module name.
    """
    split_package_name = input_parameter.split('#')
    package_name = split_package_name[0]
    module_name = package_name.replace("-", ".")
    if len(split_package_name) >= 2:
        module_name = ".".join([module_name, split_package_name[1]])
    return package_name, module_name

def create_report(module_name: str) -> Dict[str, Any]:
    module_to_generate = importlib.import_module(module_name)

    report = {}
    report["models"] = {
        "enums": {},
        "exceptions": {},
        "models": {}
    }
    # Look for models first
    model_names = [model_name for model_name in dir(module_to_generate.models) if model_name[0].isupper()]
    for model_name in model_names:
        model_cls = getattr(module_to_generate.models, model_name)
        if hasattr(model_cls, "_attribute_map"):
            report["models"]["models"][model_name] = create_model_report(model_cls)
        elif issubclass(model_cls, Exception): # If not, might be an exception
            report["models"]["exceptions"][model_name] = create_model_report(model_cls)
        else:
            report["models"]["enums"][model_name] = create_model_report(model_cls)
    # Look for operation groups
    try:
        operations_classes = [op_name for op_name in dir(module_to_generate.operations) if op_name[0].isupper()]
    except AttributeError:
        # This guy has no "operations", this is possible (Cognitive Services). Just skip it then.
        operations_classes = []

    for op_name in operations_classes:
        op_content = {'name': op_name}
        op_cls = getattr(module_to_generate.operations, op_name)
        for op_attr_name in dir(op_cls):
            op_attr = getattr(op_cls, op_attr_name)
            if isinstance(op_attr, types.FunctionType) and not op_attr_name.startswith("_"):
                # Keep it
                func_content = create_report_from_func(op_attr)
                op_content.setdefault("functions", {})[op_attr_name] = func_content
        report.setdefault("operations", {})[op_name] = op_content

    return report

def create_model_report(model_cls):
    result = {
        'name': model_cls.__name__,
    }
    # If _attribute_map, it's a model
    if hasattr(model_cls, "_attribute_map"):
        result['type'] = "Model"
        for attribute, conf in model_cls._attribute_map.items():
            attribute_validation = getattr(model_cls, "_validation", {}).get(attribute, {})

            result.setdefault('parameters', {})[attribute] = {
                'name': attribute,
                'properties': {
                    'type': conf['type'],
                    'required': attribute_validation.get('required', False),
                    'readonly': attribute_validation.get('readonly', False)
                }
            }
    elif issubclass(model_cls, Exception): # If not, might be an exception
        result['type'] = "Exception"
    else: # If not, it's an enum
        result['type'] = "Enum"
        result['values'] = list(model_cls.__members__)

    return result

def create_report_from_func(function_attr):
    func_content = {
        'name': function_attr.__name__,
        'metadata': getattr(function_attr, "metadata", {}),
        'parameters': []
    }
    signature = inspect.signature(function_attr)
    for parameter_name in signature.parameters:
        if parameter_name == "self":
            continue
        if parameter_name =="custom_headers":
            break # We reach Autorest generic
        parameter = signature.parameters[parameter_name]
        func_content["parameters"].append({
            'name': parameter.name,
        })
    return func_content

def main(input_parameter: str, version: Optional[str] = None, no_venv: bool = False, pypi: bool = False, last_pypi: bool = False):
    package_name, module_name = parse_input(input_parameter)

    if (version or pypi or last_pypi) and not no_venv:
        if version:
            versions = [version]
        else:
            _LOGGER.info(f"Download versions of {package_name} on PyPI")
            from .pypi import PyPIClient
            client = PyPIClient()
            versions = [str(v) for v in client.get_ordered_versions(package_name)]
            _LOGGER.info(f"Got {versions}")
            if last_pypi:
                _LOGGER.info(f"Only keep last PyPI version")
                versions = [versions[-1]]

        for version in versions:
            _LOGGER.info(f"Installing version {version} of {package_name} in a venv")
            with create_venv_with_package([f"{package_name}=={version}"]) as venv:
                args = [
                    venv.env_exe,
                    __file__,
                    "--no-venv",
                    "--version",
                    version,
                    input_parameter
                ]
                try:
                    subprocess.check_call(args)
                except subprocess.CalledProcessError:
                    # If it fail, just assume this version is too old to get an Autorest report
                    _LOGGER.warning(f"Version {version} seems to be too old to build a report (probably not Autorest based)")
        # Files have been written by the subprocess
        return

    modules = find_autorest_generated_folder(module_name)
    result = []
    for module_name in modules:
        _LOGGER.info(f"Working on {module_name}")

        report = create_report(module_name)
        version = version or "latest"

        output_filename = Path(package_name) / Path("code_reports") / Path(version)

        module_for_path = get_sub_module_part(package_name, module_name)
        if module_for_path:
            output_filename /= Path(module_for_path+".json")
        else:
            output_filename /= Path("report.json")

        output_filename.parent.mkdir(parents=True, exist_ok=True)

        with open(output_filename, "w") as fd:
            json.dump(report, fd, indent=2)
            _LOGGER.info(f"Report written to {output_filename}")
        result.append(output_filename)
    return result

def find_autorest_generated_folder(module_prefix="azure"):
    """Find all Autorest generated code in that module prefix.
    This actually looks for a "models" package only (not file). We could be smarter if necessary.
    """
    _LOGGER.info(f"Looking for Autorest generated package in {module_prefix}")

    # Manually skip some namespaces for now
    if module_prefix in ["azure.cli", "azure.storage", "azure.servicemanagement", "azure.servicebus"]:
        _LOGGER.info(f"Skip {module_prefix}")
        return []

    result = []
    try:
        _LOGGER.debug(f"Try {module_prefix}")
        model_module = importlib.import_module(".models", module_prefix)
        # If not exception, we MIGHT have found it, but cannot be a file.
        # Keep continue to try to break it, file module have no __path__
        model_module.__path__
        _LOGGER.info(f"Found {module_prefix}")
        result.append(module_prefix)
    except (ModuleNotFoundError, AttributeError):
        # No model, might dig deeper
        prefix_module = importlib.import_module(module_prefix)
        for _, sub_package, ispkg in pkgutil.iter_modules(prefix_module.__path__, module_prefix+"."):
            if ispkg:
                result += find_autorest_generated_folder(sub_package)
    return result

def get_sub_module_part(package_name, module_name):
    """Assuming package is azure-mgmt-compute and module name is azure.mgmt.compute.v2018-08-01
    will return v2018-08-01
    """
    sub_module_from_package = package_name.replace("-", ".")
    if not module_name.startswith(sub_module_from_package):
        _LOGGER.warning(f"Submodule {module_name} does not start with package name {package_name}")
        return
    return module_name[len(sub_module_from_package)+1:]

if __name__ == "__main__":
    import argparse

    parser = argparse.ArgumentParser(
        description='Code fingerprint building',
        formatter_class=argparse.RawTextHelpFormatter,
    )
    parser.add_argument('package_name',
                        help='Package name.')
    parser.add_argument('--version', '-v',
                        dest='version',
                        help='The version of the package you want. By default, latest and current branch.')
    parser.add_argument('--no-venv',
                        dest='no_venv', action="store_true",
                        help="If version is provided, this will assume the current accessible package is already this version. You should probably not use it.")
    parser.add_argument('--pypi',
                        dest='pypi', action="store_true",
                        help="If provided, build report for all versions on pypi of this package.")
    parser.add_argument('--last-pypi',
                        dest='last_pypi', action="store_true",
                        help="If provided, build report for last version on pypi of this package.")
    parser.add_argument("--debug",
                        dest="debug", action="store_true",
                        help="Verbosity in DEBUG mode")

    args = parser.parse_args()

    logging.basicConfig(level=logging.DEBUG if args.debug else logging.INFO)

    main(args.package_name, args.version, args.no_venv, args.pypi, args.last_pypi)


# coding=utf-8
# --------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License.txt in the project root for
# license information.
#
# Code generated by Microsoft (R) AutoRest Code Generator.
# Changes may cause incorrect behavior and will be lost if the code is
# regenerated.
# --------------------------------------------------------------------------

from msrest.service_client import SDKClient
from msrest import Serializer, Deserializer
from msrestazure import AzureConfiguration

from azure.profiles import KnownProfiles, ProfileDefinition
from azure.profiles.multiapiclient import MultiApiClientMixin
from ..version import VERSION

class ResourceManagementClientConfiguration(AzureConfiguration):
    """Configuration for ResourceManagementClient
    Note that all parameters used to create this instance are saved as instance
    attributes.

    :param credentials: Credentials needed for the client to connect to Azure.
    :type credentials: :mod:`A msrestazure Credentials
     object<msrestazure.azure_active_directory>`
    :param subscription_id: The ID of the target subscription.
    :type subscription_id: str
    :param str base_url: Service URL
    """

    def __init__(
            self, credentials, subscription_id, base_url=None):

        if credentials is None:
            raise ValueError("Parameter 'credentials' must not be None.")
        if subscription_id is None:
            raise ValueError("Parameter 'subscription_id' must not be None.")
        if not base_url:
            base_url = 'https://management.azure.com'

        super(ResourceManagementClientConfiguration, self).__init__(base_url)

        self.add_user_agent('resourcemanagementclient/{}'.format(VERSION))
        self.add_user_agent('Azure-SDK-For-Python')

        self.credentials = credentials
        self.subscription_id = subscription_id

class ResourceManagementClient(MultiApiClientMixin, SDKClient):
    """Provides operations for working with resources and resource groups.

    :ivar config: Configuration for client.
    :vartype config: ResourceManagementClientConfiguration

    :param credentials: Credentials needed for the client to connect to Azure.
    :type credentials: :mod:`A msrestazure Credentials
     object<msrestazure.azure_active_directory>`
    :param subscription_id: The ID of the target subscription.
    :type subscription_id: str
    :param str api_version: API version to use if no profile is provided, or if
     missing in profile.
    :param str base_url: Service URL
    :param profile: A profile definition, from KnownProfiles to dict.
    :type profile: azure.profiles.KnownProfiles
    """

    DEFAULT_API_VERSION='2018-05-01'
    _PROFILE_TAG = "azure.mgmt.resource.resources.ResourceManagementClient"
    LATEST_PROFILE = ProfileDefinition({
        _PROFILE_TAG: {
            None: DEFAULT_API_VERSION
        }},
        _PROFILE_TAG + " latest"
    )

    def __init__(self, credentials, subscription_id, api_version=None, base_url=None, profile=KnownProfiles.default):
        self.config = ResourceManagementClientConfiguration(credentials, subscription_id, base_url)
        super(ResourceManagementClient, self).__init__(
            credentials,
            self.config,
            api_version=api_version,
            profile=profile
        )

############ Generated from here ############

    @classmethod
    def _models_dict(cls, api_version):
        return {k: v for k, v in cls.models(api_version).__dict__.items() if isinstance(v, type)}

    @classmethod
    def models(cls, api_version=DEFAULT_API_VERSION):
        """Module depends on the API version:

           * 2016-02-01: :mod:`v2016_02_01.models<azure.mgmt.resource.resources.v2016_02_01.models>`
           * 2016-09-01: :mod:`v2016_09_01.models<azure.mgmt.resource.resources.v2016_09_01.models>`
           * 2017-05-10: :mod:`v2017_05_10.models<azure.mgmt.resource.resources.v2017_05_10.models>`
           * 2018-02-01: :mod:`v2018_02_01.models<azure.mgmt.resource.resources.v2018_02_01.models>`
           * 2018-05-01: :mod:`v2018_05_01.models<azure.mgmt.resource.resources.v2018_05_01.models>`
        """
        if api_version == '2016-02-01':
            from .v2016_02_01 import models
            return models
        elif api_version == '2016-09-01':
            from .v2016_09_01 import models
            return models
        elif api_version == '2017-05-10':
            from .v2017_05_10 import models
            return models
        elif api_version == '2018-02-01':
            from .v2018_02_01 import models
            return models
        elif api_version == '2018-05-01':
            from .v2018_05_01 import models
            return models
        raise NotImplementedError("APIVersion {} is not available".format(api_version))

    @property
    def deployment_operations(self):
        """Instance depends on the API version:

           * 2016-02-01: :class:`DeploymentOperations<azure.mgmt.resource.resources.v2016_02_01.operations.DeploymentOperations>`
           * 2016-09-01: :class:`DeploymentOperations<azure.mgmt.resource.resources.v2016_09_01.operations.DeploymentOperations>`
           * 2017-05-10: :class:`DeploymentOperations<azure.mgmt.resource.resources.v2017_05_10.operations.DeploymentOperations>`
           * 2018-02-01: :class:`DeploymentOperations<azure.mgmt.resource.resources.v2018_02_01.operations.DeploymentOperations>`
           * 2018-05-01: :class:`DeploymentOperations<azure.mgmt.resource.resources.v2018_05_01.operations.DeploymentOperations>`
        """
        api_version = self._get_api_version('deployment_operations')
        if api_version == '2016-02-01':
            from .v2016_02_01.operations import DeploymentOperations as OperationClass
        elif api_version == '2016-09-01':
            from .v2016_09_01.operations import DeploymentOperations as OperationClass
        elif api_version == '2017-05-10':
            from .v2017_05_10.operations import DeploymentOperations as OperationClass
        elif api_version == '2018-02-01':
            from .v2018_02_01.operations import DeploymentOperations as OperationClass
        elif api_version == '2018-05-01':
            from .v2018_05_01.operations import DeploymentOperations as OperationClass
        else:
            raise NotImplementedError("APIVersion {} is not available".format(api_version))
        return OperationClass(self._client, self.config, Serializer(self._models_dict(api_version)), Deserializer(self._models_dict(api_version)))

    @property
    def deployments(self):
        """Instance depends on the API version:

           * 2016-02-01: :class:`DeploymentsOperations<azure.mgmt.resource.resources.v2016_02_01.operations.DeploymentsOperations>`
           * 2016-09-01: :class:`DeploymentsOperations<azure.mgmt.resource.resources.v2016_09_01.operations.DeploymentsOperations>`
           * 2017-05-10: :class:`DeploymentsOperations<azure.mgmt.resource.resources.v2017_05_10.operations.DeploymentsOperations>`
           * 2018-02-01: :class:`DeploymentsOperations<azure.mgmt.resource.resources.v2018_02_01.operations.DeploymentsOperations>`
           * 2018-05-01: :class:`DeploymentsOperations<azure.mgmt.resource.resources.v2018_05_01.operations.DeploymentsOperations>`
        """
        api_version = self._get_api_version('deployments')
        if api_version == '2016-02-01':
            from .v2016_02_01.operations import DeploymentsOperations as OperationClass
        elif api_version == '2016-09-01':
            from .v2016_09_01.operations import DeploymentsOperations as OperationClass
        elif api_version == '2017-05-10':
            from .v2017_05_10.operations import DeploymentsOperations as OperationClass
        elif api_version == '2018-02-01':
            from .v2018_02_01.operations import DeploymentsOperations as OperationClass
        elif api_version == '2018-05-01':
            from .v2018_05_01.operations import DeploymentsOperations as OperationClass
        else:
            raise NotImplementedError("APIVersion {} is not available".format(api_version))
        return OperationClass(self._client, self.config, Serializer(self._models_dict(api_version)), Deserializer(self._models_dict(api_version)))

    @property
    def operations(self):
        """Instance depends on the API version:

           * 2018-05-01: :class:`Operations<azure.mgmt.resource.resources.v2018_05_01.operations.Operations>`
        """
        api_version = self._get_api_version('operations')
        if api_version == '2018-05-01':
            from .v2018_05_01.operations import Operations as OperationClass
        else:
            raise NotImplementedError("APIVersion {} is not available".format(api_version))
        return OperationClass(self._client, self.config, Serializer(self._models_dict(api_version)), Deserializer(self._models_dict(api_version)))

    @property
    def providers(self):
        """Instance depends on the API version:

           * 2016-02-01: :class:`ProvidersOperations<azure.mgmt.resource.resources.v2016_02_01.operations.ProvidersOperations>`
           * 2016-09-01: :class:`ProvidersOperations<azure.mgmt.resource.resources.v2016_09_01.operations.ProvidersOperations>`
           * 2017-05-10: :class:`ProvidersOperations<azure.mgmt.resource.resources.v2017_05_10.operations.ProvidersOperations>`
           * 2018-02-01: :class:`ProvidersOperations<azure.mgmt.resource.resources.v2018_02_01.operations.ProvidersOperations>`
           * 2018-05-01: :class:`ProvidersOperations<azure.mgmt.resource.resources.v2018_05_01.operations.ProvidersOperations>`
        """
        api_version = self._get_api_version('providers')
        if api_version == '2016-02-01':
            from .v2016_02_01.operations import ProvidersOperations as OperationClass
        elif api_version == '2016-09-01':
            from .v2016_09_01.operations import ProvidersOperations as OperationClass
        elif api_version == '2017-05-10':
            from .v2017_05_10.operations import ProvidersOperations as OperationClass
        elif api_version == '2018-02-01':
            from .v2018_02_01.operations import ProvidersOperations as OperationClass
        elif api_version == '2018-05-01':
            from .v2018_05_01.operations import ProvidersOperations as OperationClass
        else:
            raise NotImplementedError("APIVersion {} is not available".format(api_version))
        return OperationClass(self._client, self.config, Serializer(self._models_dict(api_version)), Deserializer(self._models_dict(api_version)))

    @property
    def resource_groups(self):
        """Instance depends on the API version:

           * 2016-02-01: :class:`ResourceGroupsOperations<azure.mgmt.resource.resources.v2016_02_01.operations.ResourceGroupsOperations>`
           * 2016-09-01: :class:`ResourceGroupsOperations<azure.mgmt.resource.resources.v2016_09_01.operations.ResourceGroupsOperations>`
           * 2017-05-10: :class:`ResourceGroupsOperations<azure.mgmt.resource.resources.v2017_05_10.operations.ResourceGroupsOperations>`
           * 2018-02-01: :class:`ResourceGroupsOperations<azure.mgmt.resource.resources.v2018_02_01.operations.ResourceGroupsOperations>`
           * 2018-05-01: :class:`ResourceGroupsOperations<azure.mgmt.resource.resources.v2018_05_01.operations.ResourceGroupsOperations>`
        """
        api_version = self._get_api_version('resource_groups')
        if api_version == '2016-02-01':
            from .v2016_02_01.operations import ResourceGroupsOperations as OperationClass
        elif api_version == '2016-09-01':
            from .v2016_09_01.operations import ResourceGroupsOperations as OperationClass
        elif api_version == '2017-05-10':
            from .v2017_05_10.operations import ResourceGroupsOperations as OperationClass
        elif api_version == '2018-02-01':
            from .v2018_02_01.operations import ResourceGroupsOperations as OperationClass
        elif api_version == '2018-05-01':
            from .v2018_05_01.operations import ResourceGroupsOperations as OperationClass
        else:
            raise NotImplementedError("APIVersion {} is not available".format(api_version))
        return OperationClass(self._client, self.config, Serializer(self._models_dict(api_version)), Deserializer(self._models_dict(api_version)))

    @property
    def resources(self):
        """Instance depends on the API version:

           * 2016-02-01: :class:`ResourcesOperations<azure.mgmt.resource.resources.v2016_02_01.operations.ResourcesOperations>`
           * 2016-09-01: :class:`ResourcesOperations<azure.mgmt.resource.resources.v2016_09_01.operations.ResourcesOperations>`
           * 2017-05-10: :class:`ResourcesOperations<azure.mgmt.resource.resources.v2017_05_10.operations.ResourcesOperations>`
           * 2018-02-01: :class:`ResourcesOperations<azure.mgmt.resource.resources.v2018_02_01.operations.ResourcesOperations>`
           * 2018-05-01: :class:`ResourcesOperations<azure.mgmt.resource.resources.v2018_05_01.operations.ResourcesOperations>`
        """
        api_version = self._get_api_version('resources')
        if api_version == '2016-02-01':
            from .v2016_02_01.operations import ResourcesOperations as OperationClass
        elif api_version == '2016-09-01':
            from .v2016_09_01.operations import ResourcesOperations as OperationClass
        elif api_version == '2017-05-10':
            from .v2017_05_10.operations import ResourcesOperations as OperationClass
        elif api_version == '2018-02-01':
            from .v2018_02_01.operations import ResourcesOperations as OperationClass
        elif api_version == '2018-05-01':
            from .v2018_05_01.operations import ResourcesOperations as OperationClass
        else:
            raise NotImplementedError("APIVersion {} is not available".format(api_version))
        return OperationClass(self._client, self.config, Serializer(self._models_dict(api_version)), Deserializer(self._models_dict(api_version)))

    @property
    def tags(self):
        """Instance depends on the API version:

           * 2016-02-01: :class:`TagsOperations<azure.mgmt.resource.resources.v2016_02_01.operations.TagsOperations>`
           * 2016-09-01: :class:`TagsOperations<azure.mgmt.resource.resources.v2016_09_01.operations.TagsOperations>`
           * 2017-05-10: :class:`TagsOperations<azure.mgmt.resource.resources.v2017_05_10.operations.TagsOperations>`
           * 2018-02-01: :class:`TagsOperations<azure.mgmt.resource.resources.v2018_02_01.operations.TagsOperations>`
           * 2018-05-01: :class:`TagsOperations<azure.mgmt.resource.resources.v2018_05_01.operations.TagsOperations>`
        """
        api_version = self._get_api_version('tags')
        if api_version == '2016-02-01':
            from .v2016_02_01.operations import TagsOperations as OperationClass
        elif api_version == '2016-09-01':
            from .v2016_09_01.operations import TagsOperations as OperationClass
        elif api_version == '2017-05-10':
            from .v2017_05_10.operations import TagsOperations as OperationClass
        elif api_version == '2018-02-01':
            from .v2018_02_01.operations import TagsOperations as OperationClass
        elif api_version == '2018-05-01':
            from .v2018_05_01.operations import TagsOperations as OperationClass
        else:
            raise NotImplementedError("APIVersion {} is not available".format(api_version))
        return OperationClass(self._client, self.config, Serializer(self._models_dict(api_version)), Deserializer(self._models_dict(api_version)))


# coding=utf-8
# --------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License.txt in the project root for
# license information.
#
# Code generated by Microsoft (R) AutoRest Code Generator.
# Changes may cause incorrect behavior and will be lost if the code is
# regenerated.
# --------------------------------------------------------------------------

from msrest.service_client import SDKClient
from msrest import Serializer, Deserializer
from msrestazure import AzureConfiguration

from azure.profiles import KnownProfiles, ProfileDefinition
from azure.profiles.multiapiclient import MultiApiClientMixin
from ..version import VERSION

class PolicyClientConfiguration(AzureConfiguration):
    """Configuration for PolicyClient
    Note that all parameters used to create this instance are saved as instance
    attributes.

    :param credentials: Credentials needed for the client to connect to Azure.
    :type credentials: :mod:`A msrestazure Credentials
     object<msrestazure.azure_active_directory>`
    :param subscription_id: The ID of the target subscription.
    :type subscription_id: str
    :param str base_url: Service URL
    """

    def __init__(
            self, credentials, subscription_id, base_url=None):

        if credentials is None:
            raise ValueError("Parameter 'credentials' must not be None.")
        if subscription_id is None:
            raise ValueError("Parameter 'subscription_id' must not be None.")
        if not base_url:
            base_url = 'https://management.azure.com'

        super(PolicyClientConfiguration, self).__init__(base_url)

        self.add_user_agent('policyclient/{}'.format(VERSION))
        self.add_user_agent('Azure-SDK-For-Python')

        self.credentials = credentials
        self.subscription_id = subscription_id

class PolicyClient(MultiApiClientMixin, SDKClient):
    """To manage and control access to your resources, you can define customized policies and assign them at a scope.

    :ivar config: Configuration for client.
    :vartype config: PolicyClientConfiguration

    :param credentials: Credentials needed for the client to connect to Azure.
    :type credentials: :mod:`A msrestazure Credentials
     object<msrestazure.azure_active_directory>`
    :param subscription_id: The ID of the target subscription.
    :type subscription_id: str
    :param str api_version: API version to use if no profile is provided, or if
     missing in profile.
    :param str base_url: Service URL
    :param profile: A profile definition, from KnownProfiles to dict.
    :type profile: azure.profiles.KnownProfiles
    """

    DEFAULT_API_VERSION='2018-03-01'
    _PROFILE_TAG = "azure.mgmt.resource.policy.PolicyClient"
    LATEST_PROFILE = ProfileDefinition({
        _PROFILE_TAG: {
            None: DEFAULT_API_VERSION
        }},
        _PROFILE_TAG + " latest"
    )

    def __init__(self, credentials, subscription_id, api_version=None, base_url=None, profile=KnownProfiles.default):
        self.config = PolicyClientConfiguration(credentials, subscription_id, base_url)
        super(PolicyClient, self).__init__(
            credentials,
            self.config,
            api_version=api_version,
            profile=profile
        )

############ Generated from here ############

    @classmethod
    def _models_dict(cls, api_version):
        return {k: v for k, v in cls.models(api_version).__dict__.items() if isinstance(v, type)}

    @classmethod
    def models(cls, api_version=DEFAULT_API_VERSION):
        """Module depends on the API version:

           * 2015-10-01-preview: :mod:`v2015_10_01_preview.models<azure.mgmt.resource.policy.v2015_10_01_preview.models>`
           * 2016-04-01: :mod:`v2016_04_01.models<azure.mgmt.resource.policy.v2016_04_01.models>`
           * 2016-12-01: :mod:`v2016_12_01.models<azure.mgmt.resource.policy.v2016_12_01.models>`
           * 2017-06-01-preview: :mod:`v2017_06_01_preview.models<azure.mgmt.resource.policy.v2017_06_01_preview.models>`
           * 2018-03-01: :mod:`v2018_03_01.models<azure.mgmt.resource.policy.v2018_03_01.models>`
           * 2018-05-01: :mod:`v2018_05_01.models<azure.mgmt.resource.policy.v2018_05_01.models>`
        """
        if api_version == '2015-10-01-preview':
            from .v2015_10_01_preview import models
            return models
        elif api_version == '2016-04-01':
            from .v2016_04_01 import models
            return models
        elif api_version == '2016-12-01':
            from .v2016_12_01 import models
            return models
        elif api_version == '2017-06-01-preview':
            from .v2017_06_01_preview import models
            return models
        elif api_version == '2018-03-01':
            from .v2018_03_01 import models
            return models
        elif api_version == '2018-05-01':
            from .v2018_05_01 import models
            return models
        raise NotImplementedError("APIVersion {} is not available".format(api_version))

    @property
    def policy_assignments(self):
        """Instance depends on the API version:

           * 2015-10-01-preview: :class:`PolicyAssignmentsOperations<azure.mgmt.resource.policy.v2015_10_01_preview.operations.PolicyAssignmentsOperations>`
           * 2016-04-01: :class:`PolicyAssignmentsOperations<azure.mgmt.resource.policy.v2016_04_01.operations.PolicyAssignmentsOperations>`
           * 2016-12-01: :class:`PolicyAssignmentsOperations<azure.mgmt.resource.policy.v2016_12_01.operations.PolicyAssignmentsOperations>`
           * 2017-06-01-preview: :class:`PolicyAssignmentsOperations<azure.mgmt.resource.policy.v2017_06_01_preview.operations.PolicyAssignmentsOperations>`
           * 2018-03-01: :class:`PolicyAssignmentsOperations<azure.mgmt.resource.policy.v2018_03_01.operations.PolicyAssignmentsOperations>`
           * 2018-05-01: :class:`PolicyAssignmentsOperations<azure.mgmt.resource.policy.v2018_05_01.operations.PolicyAssignmentsOperations>`
        """
        api_version = self._get_api_version('policy_assignments')
        if api_version == '2015-10-01-preview':
            from .v2015_10_01_preview.operations import PolicyAssignmentsOperations as OperationClass
        elif api_version == '2016-04-01':
            from .v2016_04_01.operations import PolicyAssignmentsOperations as OperationClass
        elif api_version == '2016-12-01':
            from .v2016_12_01.operations import PolicyAssignmentsOperations as OperationClass
        elif api_version == '2017-06-01-preview':
            from .v2017_06_01_preview.operations import PolicyAssignmentsOperations as OperationClass
        elif api_version == '2018-03-01':
            from .v2018_03_01.operations import PolicyAssignmentsOperations as OperationClass
        elif api_version == '2018-05-01':
            from .v2018_05_01.operations import PolicyAssignmentsOperations as OperationClass
        else:
            raise NotImplementedError("APIVersion {} is not available".format(api_version))
        return OperationClass(self._client, self.config, Serializer(self._models_dict(api_version)), Deserializer(self._models_dict(api_version)))

    @property
    def policy_definitions(self):
        """Instance depends on the API version:

           * 2015-10-01-preview: :class:`PolicyDefinitionsOperations<azure.mgmt.resource.policy.v2015_10_01_preview.operations.PolicyDefinitionsOperations>`
           * 2016-04-01: :class:`PolicyDefinitionsOperations<azure.mgmt.resource.policy.v2016_04_01.operations.PolicyDefinitionsOperations>`
           * 2016-12-01: :class:`PolicyDefinitionsOperations<azure.mgmt.resource.policy.v2016_12_01.operations.PolicyDefinitionsOperations>`
           * 2017-06-01-preview: :class:`PolicyDefinitionsOperations<azure.mgmt.resource.policy.v2017_06_01_preview.operations.PolicyDefinitionsOperations>`
           * 2018-03-01: :class:`PolicyDefinitionsOperations<azure.mgmt.resource.policy.v2018_03_01.operations.PolicyDefinitionsOperations>`
           * 2018-05-01: :class:`PolicyDefinitionsOperations<azure.mgmt.resource.policy.v2018_05_01.operations.PolicyDefinitionsOperations>`
        """
        api_version = self._get_api_version('policy_definitions')
        if api_version == '2015-10-01-preview':
            from .v2015_10_01_preview.operations import PolicyDefinitionsOperations as OperationClass
        elif api_version == '2016-04-01':
            from .v2016_04_01.operations import PolicyDefinitionsOperations as OperationClass
        elif api_version == '2016-12-01':
            from .v2016_12_01.operations import PolicyDefinitionsOperations as OperationClass
        elif api_version == '2017-06-01-preview':
            from .v2017_06_01_preview.operations import PolicyDefinitionsOperations as OperationClass
        elif api_version == '2018-03-01':
            from .v2018_03_01.operations import PolicyDefinitionsOperations as OperationClass
        elif api_version == '2018-05-01':
            from .v2018_05_01.operations import PolicyDefinitionsOperations as OperationClass
        else:
            raise NotImplementedError("APIVersion {} is not available".format(api_version))
        return OperationClass(self._client, self.config, Serializer(self._models_dict(api_version)), Deserializer(self._models_dict(api_version)))

    @property
    def policy_set_definitions(self):
        """Instance depends on the API version:

           * 2017-06-01-preview: :class:`PolicySetDefinitionsOperations<azure.mgmt.resource.policy.v2017_06_01_preview.operations.PolicySetDefinitionsOperations>`
           * 2018-03-01: :class:`PolicySetDefinitionsOperations<azure.mgmt.resource.policy.v2018_03_01.operations.PolicySetDefinitionsOperations>`
           * 2018-05-01: :class:`PolicySetDefinitionsOperations<azure.mgmt.resource.policy.v2018_05_01.operations.PolicySetDefinitionsOperations>`
        """
        api_version = self._get_api_version('policy_set_definitions')
        if api_version == '2017-06-01-preview':
            from .v2017_06_01_preview.operations import PolicySetDefinitionsOperations as OperationClass
        elif api_version == '2018-03-01':
            from .v2018_03_01.operations import PolicySetDefinitionsOperations as OperationClass
        elif api_version == '2018-05-01':
            from .v2018_05_01.operations import PolicySetDefinitionsOperations as OperationClass
        else:
            raise NotImplementedError("APIVersion {} is not available".format(api_version))
        return OperationClass(self._client, self.config, Serializer(self._models_dict(api_version)), Deserializer(self._models_dict(api_version)))


# coding=utf-8
# --------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License.txt in the project root for
# license information.
#
# Code generated by Microsoft (R) AutoRest Code Generator.
# Changes may cause incorrect behavior and will be lost if the code is
# regenerated.
# --------------------------------------------------------------------------

from msrest.pipeline import ClientRawResponse

from .. import models

class TextModerationOperations(object):
    """TextModerationOperations operations.

    :param client: Client for service requests.
    :param config: Configuration of service client.
    :param serializer: An object model serializer.
    :param deserializer: An object model deserializer.
    """

    models = models

    def __init__(self, client, config, serializer, deserializer):

        self._client = client
        self._serialize = serializer
        self._deserialize = deserializer

        self.config = config

    def screen_text(
            self, text_content_type, text_content, language=None, autocorrect=False, pii=False, list_id=None, classify=False, custom_headers=None, raw=False, callback=None, **operation_config):
        """Detect profanity and match against custom and shared blacklists.

        Detects profanity in more than 100 languages and match against custom
        and shared blacklists.

        :param text_content_type: The content type. Possible values include:
         'text/plain', 'text/html', 'text/xml', 'text/markdown'
        :type text_content_type: str
        :param text_content: Content to screen.
        :type text_content: Generator
        :param language: Language of the text.
        :type language: str
        :param autocorrect: Autocorrect text.
        :type autocorrect: bool
        :param pii: Detect personal identifiable information.
        :type pii: bool
        :param list_id: The list Id.
        :type list_id: str
        :param classify: Classify input.
        :type classify: bool
        :param dict custom_headers: headers that will be added to the request
        :param bool raw: returns the direct response alongside the
         deserialized response
        :param callback: When specified, will be called with each chunk of
         data that is streamed. The callback should take two arguments, the
         bytes of the current chunk of data and the response object. If the
         data is uploading, response will be None.
        :type callback: Callable[Bytes, response=None]
        :param operation_config: :ref:`Operation configuration
         overrides<msrest:optionsforoperations>`.
        :return: Screen or ClientRawResponse if raw=true
        :rtype: ~azure.cognitiveservices.vision.contentmoderator.models.Screen
         or ~msrest.pipeline.ClientRawResponse
        :raises:
         :class:`APIErrorException<azure.cognitiveservices.vision.contentmoderator.models.APIErrorException>`
        """
        # Construct URL
        url = self.screen_text.metadata['url']
        path_format_arguments = {
            'Endpoint': self._serialize.url("self.config.endpoint", self.config.endpoint, 'str', skip_quote=True)
        }
        url = self._client.format_url(url, **path_format_arguments)

        # Construct parameters
        query_parameters = {}
        if language is not None:
            query_parameters['language'] = self._serialize.query("language", language, 'str')
        if autocorrect is not None:
            query_parameters['autocorrect'] = self._serialize.query("autocorrect", autocorrect, 'bool')
        if pii is not None:
            query_parameters['PII'] = self._serialize.query("pii", pii, 'bool')
        if list_id is not None:
            query_parameters['listId'] = self._serialize.query("list_id", list_id, 'str')
        if classify is not None:
            query_parameters['classify'] = self._serialize.query("classify", classify, 'bool')

        # Construct headers
        header_parameters = {}
        header_parameters['Accept'] = 'application/json'
        header_parameters['Content-Type'] = 'text/plain'
        if custom_headers:
            header_parameters.update(custom_headers)
        header_parameters['Content-Type'] = self._serialize.header("text_content_type", text_content_type, 'str')

        # Construct body
        body_content = self._client.stream_upload(text_content, callback)

        # Construct and send request
        request = self._client.post(url, query_parameters, header_parameters, body_content)
        response = self._client.send(request, stream=False, **operation_config)

        if response.status_code not in [200]:
            raise models.APIErrorException(self._deserialize, response)

        deserialized = None

        if response.status_code == 200:
            deserialized = self._deserialize('Screen', response)

        if raw:
            client_raw_response = ClientRawResponse(deserialized, response)
            return client_raw_response

        return deserialized
    screen_text.metadata = {'url': '/contentmoderator/moderate/v1.0/ProcessText/Screen/'}

    def detect_language(
            self, text_content_type, text_content, custom_headers=None, raw=False, callback=None, **operation_config):
        """This operation will detect the language of given input content. Returns
        the ISO 639-3
        code for the predominant language comprising the submitted text.
        Over 110 languages supported.

        :param text_content_type: The content type. Possible values include:
         'text/plain', 'text/html', 'text/xml', 'text/markdown'
        :type text_content_type: str
        :param text_content: Content to screen.
        :type text_content: Generator
        :param dict custom_headers: headers that will be added to the request
        :param bool raw: returns the direct response alongside the
         deserialized response
        :param callback: When specified, will be called with each chunk of
         data that is streamed. The callback should take two arguments, the
         bytes of the current chunk of data and the response object. If the
         data is uploading, response will be None.
        :type callback: Callable[Bytes, response=None]
        :param operation_config: :ref:`Operation configuration
         overrides<msrest:optionsforoperations>`.
        :return: DetectedLanguage or ClientRawResponse if raw=true
        :rtype:
         ~azure.cognitiveservices.vision.contentmoderator.models.DetectedLanguage
         or ~msrest.pipeline.ClientRawResponse
        :raises:
         :class:`APIErrorException<azure.cognitiveservices.vision.contentmoderator.models.APIErrorException>`
        """
        # Construct URL
        url = self.detect_language.metadata['url']
        path_format_arguments = {
            'Endpoint': self._serialize.url("self.config.endpoint", self.config.endpoint, 'str', skip_quote=True)
        }
        url = self._client.format_url(url, **path_format_arguments)

        # Construct parameters
        query_parameters = {}

        # Construct headers
        header_parameters = {}
        header_parameters['Accept'] = 'application/json'
        header_parameters['Content-Type'] = 'text/plain'
        if custom_headers:
            header_parameters.update(custom_headers)
        header_parameters['Content-Type'] = self._serialize.header("text_content_type", text_content_type, 'str')

        # Construct body
        body_content = self._client.stream_upload(text_content, callback)

        # Construct and send request
        request = self._client.post(url, query_parameters, header_parameters, body_content)
        response = self._client.send(request, stream=False, **operation_config)

        if response.status_code not in [200]:
            raise models.APIErrorException(self._deserialize, response)

        deserialized = None

        if response.status_code == 200:
            deserialized = self._deserialize('DetectedLanguage', response)

        if raw:
            client_raw_response = ClientRawResponse(deserialized, response)
            return client_raw_response

        return deserialized
    detect_language.metadata = {'url': '/contentmoderator/moderate/v1.0/ProcessText/DetectLanguage'}