from rest_framework import serializers
from rest_framework.schemas import SchemaGenerator as _SchemaGenerator
from rest_framework.compat import coreapi, urlparse


class SchemaGenerator(_SchemaGenerator):
    def get_link(self, path, method, view):
        """
        Return a `coreapi.Link` instance for the given endpoint.
        """
        fields = self.get_path_fields(path, method, view)
        fields += self.get_serializer_fields(path, method, view)
        fields += self.get_pagination_fields(path, method, view)
        fields += self.get_filter_fields(path, method, view)
        fields += self.get_query_fields(path, method, view)

        if fields and any([field.location in ('form', 'body') for field in fields]):
            encoding = self.get_encoding(path, method, view)
        else:
            encoding = None

        if self.url and path.startswith('/'):
            path = path[1:]

        return coreapi.Link(
            url=urlparse.urljoin(self.url, path),
            action=method.lower(),
            encoding=encoding,
            fields=fields
        )

    def get_query_fields(self, path, method, view):
        """
        Return a list of `coreapi.Field` instances corresponding to any
        request body input, as determined by the query serializer class.
        """
        if hasattr(view, 'query_serializer_class'):
            if view.query_serializer_class:
                serializer = view.query_serializer_class()
            else:
                return []
        else:
            return []

        if isinstance(serializer, serializers.ListSerializer):
            return [coreapi.Field(name='data', location='query', required=True)]

        if not isinstance(serializer, serializers.Serializer):
            return []

        fields = []
        for field in serializer.fields.values():
            if field.read_only or isinstance(field, serializers.HiddenField):
                continue

            required = field.required and method != 'PATCH'
            description = coreapi.force_text(field.help_text) if field.help_text else ''
            field = coreapi.Field(
                name=field.source,
                location='query',
                required=required,
                description=description
            )
            fields.append(field)

        return fields
