#
# Copyright 2017 the original author or authors.
#
# 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.
#
import os
from collections import OrderedDict

from google.protobuf import descriptor_pb2
from google.protobuf.descriptor import FieldDescriptor, Descriptor
from google.protobuf.message import Message


class InvalidDescriptorError(Exception):
    pass


class DescriptorParser(object):
    """
    Used to parse protobuf FileDescriptor objects into native Python
    data structures (nested dict/list/intrinsic values. Two of the typical
    sources of FileDescriptor objects are:
    1. CodeGeneratorRequest, used as binary input to any protoc plugin,
       contains a list of these FileDescriptor objects (under the
       proto_file attribute)
    2. FileDescriptorSet, as saved by protoc when using the -o option.

    An important feature of the parser is that it can process the source
    code annotations and can fold comments into the relevant defintions
    present in the proto file.

    Usage (in a protoc plugin):
    >>> request = plugin.CodeGeneratorRequest()
    >>> request.ParseFromString(sys.stdin.read())
    >>> parser = DescriptorParser()
    >>> for proto_file in request.proto_file:
    >>>     parsed_data = parser.parse_file_descriptor()
    >>>     print json.dumps(parsed_data, indent=4)
    """

    meta = None

    def __init__(self):
        if DescriptorParser.meta is None:
            DescriptorParser.meta = self.load_meta_descriptor()

    def load_meta_descriptor(self):
        """
        Load the protobuf version of descriptor.proto to use it in
        decoding protobuf paths.
        """
        fpath = os.path.abspath(os.path.join(os.path.dirname(__file__),
                                             'descriptor.desc'))
        with open(fpath, 'r') as f:
            blob = f.read()
        proto = descriptor_pb2.FileDescriptorSet()
        proto.ParseFromString(blob)
        assert len(proto.file) == 1
        return proto.file[0]

    parser_table = {
        unicode: lambda x: x,
        int: lambda x: x,
        bool: lambda x: x,
    }

    def parse(self, o, type_tag_name=None):
        if isinstance(o, Message):
            return self.parse_message(o, type_tag_name)
        else:
            return self.parser_table[type(o)](o)

    def parse_message(self, m, type_tag_name=None):
        assert isinstance(m, Message)
        d = OrderedDict()
        for field, value in m.ListFields():
            assert isinstance(field, FieldDescriptor)
            if field.label in (1, 2):
                d[field.name] = self.parse(value, type_tag_name)
            elif field.label == 3:
                d[field.name] = [self.parse(x, type_tag_name) for x in
                                 value]
            else:
                raise InvalidDescriptorError()

        if type_tag_name is not None:
            d[type_tag_name] = m.DESCRIPTOR.full_name.strip('.')

        return d

    def parse_file_descriptor(self, descriptor,
                              type_tag_name=None,
                              fold_comments=False):

        d = self.parse(descriptor, type_tag_name=type_tag_name)

        if fold_comments:
            locations = d.get('source_code_info', {}).get('location', [])
            for location in locations:
                path = location.get('path', [])
                comments = ''.join([
                    location.get('leading_comments', '').strip(' '),
                    location.get('trailing_comments', '').strip(' '),
                    ''.join(block.strip(' ') for block
                            in
                            location.get('leading_detached_comments', ''))
                ]).strip()

                # ignore locations with no comments
                if not comments:
                    continue

                # we ignore path with odd number of entries, since these do
                # not address our schema nodes, but rather the meta schema
                if (len(path) % 2 == 0):
                    node = self.find_node_by_path(
                        path, self.meta.DESCRIPTOR, d)
                    assert isinstance(node, dict)
                    node['_description'] = comments

            # remove source_code_info
            del d['source_code_info']

        return d

    def parse_file_descriptors(self, descriptors,
                               type_tag_name=None,
                               fold_comments=False):
        return [self.parse_file_descriptor(descriptor,
                                           type_tag_name=type_tag_name,
                                           fold_comments=fold_comments)
                for descriptor in descriptors]

    def find_node_by_path(self, path, meta, o):
        # stop recursion when path is empty
        if not path:
            return o

        # sanity check
        assert len(path) >= 2
        assert isinstance(meta, Descriptor)
        assert isinstance(o, dict)

        # find field name, then actual field
        field_number = path.pop(0)
        field_def = meta.fields_by_number[field_number]
        field = o[field_def.name]

        # field must be a list, extract entry with given index
        assert isinstance(field, list)  # expected to be a list field
        index = path.pop(0)
        child_o = field[index]

        child_meta = field_def.message_type
        return self.find_node_by_path(path, child_meta, child_o)
