private function parseResource(array $modes, &$resource, &$root, $fullPropertyPath = '')
    {
        foreach ($modes as $relation => $mode) {
            $modeResolver = $this->resolveMode($mode);

            $steps = explode('.', $relation);

            // Get the first resource in the relation
            // TODO: Refactor
            $property = array_shift($steps);
            if (is_array($resource)) {
                if ($resource[$property] === null) {
                    continue;
                }

                $object = &$resource[$property];
            } else {
                if ($resource->{$property} === null) {
                    continue;
                }

                $object = &$resource->{$property};
            }

            if (empty($steps)) {
                // This is the deepest level. Resolve it.
                $fullPropertyPath .= $relation;
                $object = $this->modeResolvers[$mode]->resolve($relation, $object, $root, $fullPropertyPath);
            } else {
                // More levels exist in this relation.
                // We want a drill down and resolve the deepest level first.

                $path = implode('.', $steps);
                $modes = [
                    $path => $mode
                ];

                // Add the previous levels to the full path so it can be used
                // to populate the root level properly.
                $fullPropertyPath .= $property . '.';

                if (Utility::isCollection($object)) {
                    $object = $this->parseCollection($modes, $object, $root, $fullPropertyPath);
                } else {
                    $object = $this->parseResource($modes, $object, $root, $fullPropertyPath);
                }
            }

            // Reset the full property path after running a full relation
            $fullPropertyPath = '';
            Utility::setProperty($resource, $property, $object);
        }

        return $resource;
    }