/**
  * @param MessageInterface $object
  * @param array $data
  *
  * @return MessageInterface
  */
 private function _doHydrate(MessageInterface $object, $data)
 {
     $reflected = new \ReflectionClass($object);
     if ($object instanceof MessageCollectionInterface && $object instanceof ArrayCollectionInterface) {
         foreach ($data->{$object->getDataMemberName()} as $singleData) {
             $class = $object->createChildClass();
             $object->add($this->_doHydrate($class, $singleData));
         }
     }
     foreach ($data as $key => $value) {
         if ($reflected->hasProperty($key)) {
             $property = $reflected->getProperty($key);
             $setter = $this->generateSetter($key);
             $doc = new DocBlock($property);
             if ($doc->hasTag('var')) {
                 $tags = $doc->getTagsByName('var');
                 if (count($tags) !== 1) {
                     throw new RuntimeException('Property "' . $property->getName() . '" of class ' . $property->getDeclaringClass() . 'has more @var tags. Only one is allowed.');
                 }
                 $type = $tags[0]->getType();
                 switch (true) {
                     /**
                      * Internal type Enum
                      */
                     /*case $type === '\\Enum':
                       $getter = $this->generateGetter($key);
                       $object->{$getter}()->setValue($value);
                       break;*/
                     /**
                      * All basic types
                      */
                     case in_array(strtolower($type), $this->basicTypes, false):
                         $object->{$setter}($value);
                         break;
                         /**
                          * Object types - special cases first
                          */
                     /**
                      * Object types - special cases first
                      */
                     case $type === '\\DateTime':
                         $class = new \DateTime($value);
                         $object->{$setter}($class);
                         break;
                     case $type === '\\DateTimeZone':
                         if (empty($value)) {
                             continue;
                         }
                         $class = new \DateTimeZone($value);
                         $object->{$setter}($class);
                         break;
                     case !is_array($value) && class_exists($type, true):
                         $class = new $type($value);
                         $object->{$setter}($class);
                         break;
                         /**
                          * Try to find class and hydrate object
                          */
                     /**
                      * Try to find class and hydrate object
                      */
                     default:
                         $possibleClassNames = [];
                         $possibleClassNames[] = $this->baseNS . $type;
                         $possibleClassNames[] = $reflected->getNamespaceName() . $type;
                         $possibleClassNames[] = $type;
                         foreach ($possibleClassNames as $className) {
                             if (class_exists($className, true)) {
                                 $class = new $className();
                                 $hydrated = $this->_doHydrate($class, $value);
                                 $object->{$setter}($hydrated);
                                 continue 2;
                             }
                         }
                         /**
                          * Class not found, we use raw $value.
                          */
                         $object->{$setter}($value);
                         break;
                 }
             }
         } elseif ($key === '_links') {
             foreach ($value as $link) {
                 $object->addMethod($link->method, $link->rel, $link->href);
             }
         }
     }
     return $object;
 }
 /**
  * @param $object
  * @param $options
  * @return Uri
  * @throws Exception
  */
 private function prepareEndpointUri(MessageInterface $object, array $options)
 {
     $endpoint = $object->getEndpoint();
     $defaultParams = $object->getDefaultParams();
     $params = array_key_exists('params', $options) ? $options['params'] : [];
     if (substr($endpoint, 0, 4) !== 'http') {
         $endpoint = $this->apiUri . $endpoint;
     }
     $params = array_merge($params, $defaultParams);
     foreach ($params as $key => $value) {
         $endpoint = str_replace('{' . $key . '}', $value, $endpoint);
     }
     if (preg_match('/.*{.*}.*/', $endpoint)) {
         throw new Exception('Not all endpoint parameters was replaced: ' . $endpoint);
     }
     $uri = new Uri($endpoint);
     if (array_key_exists('paging', $options)) {
         $paging = $options['paging'];
         if (array_key_exists('offset', $paging)) {
             if (!is_numeric($paging['offset']) || $paging['offset'] < 0) {
                 throw new RuntimeException('Paging offset cam be only positive number and 0.');
             }
             $uri = Uri::withQueryValue($uri, 'offset', $paging['offset']);
         }
         if (array_key_exists('count', $paging)) {
             if (!is_numeric($paging['count']) || $paging['count'] < 1) {
                 throw new RuntimeException('Paging count cam be only positive number.');
             }
             $uri = Uri::withQueryValue($uri, 'count', $paging['count']);
         }
     }
     if (array_key_exists('fields', $options)) {
         if (is_array($options['fields'])) {
             $fields = implode(',', $options['fields']);
         } else {
             $fields = $options['fields'];
         }
         $uri = Uri::withQueryValue($uri, 'fields', $fields);
     }
     if (array_key_exists('exclude_fields', $options)) {
         if (array_key_exists('fields', $options)) {
             throw new RuntimeException('You can not use "fields" and "exclude_fields" in one API query.');
         }
         if (is_array($options['exclude_fields'])) {
             $exclude_fields = implode(',', $options['exclude_fields']);
         } else {
             $exclude_fields = $options['exclude_fields'];
         }
         $uri = Uri::withQueryValue($uri, 'exclude_fields', $exclude_fields);
     }
     return $uri;
 }