# Copyright 2016 Google 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.

"""Annotations management for Vision API responses."""


from google.cloud.vision.color import ImagePropertiesAnnotation
from google.cloud.vision.entity import EntityAnnotation
from google.cloud.vision.face import Face
from google.cloud.vision.safe import SafeSearchAnnotation


class Annotations(object):
    """Helper class to bundle annotation responses.

    :type faces: list
    :param faces: List of :class:`~google.cloud.vision.face.Face`.

    :type properties: list
    :param properties:
        List of :class:`~google.cloud.vision.color.ImagePropertiesAnnotation`.

    :type labels: list
    :param labels: List of
                   :class:`~google.cloud.vision.entity.EntityAnnotation`.

    :type landmarks: list
    :param landmarks: List of
                      :class:`~google.cloud.vision.entity.EntityAnnotation.`

    :type logos: list
    :param logos: List of
                  :class:`~google.cloud.vision.entity.EntityAnnotation`.

    :type safe_searches: list
    :param safe_searches:
        List of :class:`~google.cloud.vision.safe.SafeSearchAnnotation`

    :type texts: list
    :param texts: List of
                  :class:`~google.cloud.vision.entity.EntityAnnotation`.
    """
    def __init__(self, faces=None, properties=None, labels=None,
                 landmarks=None, logos=None, safe_searches=None, texts=None):
        self.faces = faces or ()
        self.properties = properties or ()
        self.labels = labels or ()
        self.landmarks = landmarks or ()
        self.logos = logos or ()
        self.safe_searches = safe_searches or ()
        self.texts = texts or ()

    @classmethod
    def from_api_repr(cls, response):
        """Factory: construct an instance of ``Annotations`` from a response.

        :type response: dict
        :param response: Vision API response object.

        :rtype: :class:`~google.cloud.vision.annotations.Annotations`
        :returns: An instance of ``Annotations`` with detection types loaded.
        """
        annotations = {}
        key_map = {
            'faceAnnotations': 'faces',
            'imagePropertiesAnnotation': 'properties',
            'labelAnnotations': 'labels',
            'landmarkAnnotations': 'landmarks',
            'logoAnnotations': 'logos',
            'safeSearchAnnotation': 'safe_searches',
            'textAnnotations': 'texts'
        }

        for feature_type, annotation in response.items():
            curr_feature = annotations.setdefault(key_map[feature_type], [])
            curr_feature.extend(
                _entity_from_response_type(feature_type, annotation))
        return cls(**annotations)


def _entity_from_response_type(feature_type, results):
    """Convert a JSON result to an entity type based on the feature.

    :rtype: list
    :returns: List containing any of
              :class:`~google.cloud.vision.color.ImagePropertiesAnnotation`,
              :class:`~google.cloud.vision.entity.EntityAnnotation`,
              :class:`~google.cloud.vision.face.Face`,
              :class:`~google.cloud.vision.safe.SafeSearchAnnotation`.
    """
    detected_objects = []
    if feature_type == 'faceAnnotations':
        detected_objects.extend(
            Face.from_api_repr(face) for face in results)
    elif feature_type == 'imagePropertiesAnnotation':
        detected_objects.append(
            ImagePropertiesAnnotation.from_api_repr(results))
    elif feature_type == 'safeSearchAnnotation':
        detected_objects.append(SafeSearchAnnotation.from_api_repr(results))
    else:
        for result in results:
            detected_objects.append(EntityAnnotation.from_api_repr(result))
    return detected_objects

@@ -848,16 +848,437 @@
 ation%0A%0A%0A
+FACE_ANNOTATIONS = 'faceAnnotations'%0AIMAGE_PROPERTIES_ANNOTATION = 'imagePropertiesAnnotation'%0ASAFE_SEARCH_ANNOTATION = 'safeSearchAnnotation'%0A%0A_KEY_MAP = %7B%0A    FACE_ANNOTATIONS: 'faces',%0A    IMAGE_PROPERTIES_ANNOTATION: 'properties',%0A    'labelAnnotations': 'labels',%0A    'landmarkAnnotations': 'landmarks',%0A    'logoAnnotations': 'logos',%0A    SAFE_SEARCH_ANNOTATION: 'safe_searches',%0A    'textAnnotations': 'texts'%0A%7D%0A%0A%0A
 class An
@@ -2237,20 +2237,18 @@
 , faces=
-None
+()
 , proper
@@ -2252,20 +2252,18 @@
 perties=
-None
+()
 , labels
@@ -2263,20 +2263,32 @@
  labels=
-None
+(), landmarks=()
 ,%0A      
@@ -2301,35 +2301,17 @@
     
- landmarks=None,
  logos=
-None
+()
 , sa
@@ -2326,20 +2326,18 @@
 hes=
-None
+()
 , texts=
 None
@@ -2336,12 +2336,10 @@
 xts=
-None
+()
 ):%0A 
@@ -2363,22 +2363,16 @@
  = faces
- or ()
 %0A       
@@ -2400,22 +2400,16 @@
 operties
- or ()
 %0A       
@@ -2429,22 +2429,16 @@
 = labels
- or ()
 %0A       
@@ -2464,22 +2464,16 @@
 andmarks
- or ()
 %0A       
@@ -2491,22 +2491,16 @@
  = logos
- or ()
 %0A       
@@ -2534,22 +2534,16 @@
 searches
- or ()
 %0A       
@@ -2565,14 +2565,8 @@
 exts
- or ()
 %0A%0A  
@@ -2969,356 +2969,8 @@
  %7B%7D%0A
-        key_map = %7B%0A            'faceAnnotations': 'faces',%0A            'imagePropertiesAnnotation': 'properties',%0A            'labelAnnotations': 'labels',%0A            'landmarkAnnotations': 'landmarks',%0A            'logoAnnotations': 'logos',%0A            'safeSearchAnnotation': 'safe_searches',%0A            'textAnnotations': 'texts'%0A        %7D%0A%0A
     
@@ -3077,15 +3077,16 @@
 ult(
-key_map
+_KEY_MAP
 %5Bfea
@@ -3748,33 +3748,32 @@
 type == 
-'faceAnnotations'
+FACE_ANNOTATIONS
 :%0A      
@@ -3886,35 +3886,35 @@
  == 
-'imagePropertiesAnnotation'
+IMAGE_PROPERTIES_ANNOTATION
 :%0A  
@@ -4031,38 +4031,38 @@
 type == 
-'safeSearchAnnotation'
+SAFE_SEARCH_ANNOTATION
 :%0A      

Make __init__ defaults immutable tuples, move key_map to modual constant, make duplicated response keys constants.