public function save($collection, $document, array $options = [])
    {
        $collection     = $this->makeCollection($collection);
        $_documentClass = $this->_documentClass;

        $params = $this->includeOptionsInParams(
            $options, [
                'waitForSync'      => null,
                'silent'           => false,
                'createCollection' => $this->getConnection()->getOption(ConnectionOptions::OPTION_CREATE),
                'overwrite'        => (bool) @$options[self::OPTION_OVERWRITE],
                'returnOld'        => (bool) @$options[self::OPTION_RETURN_OLD],
                'returnNew'        => (bool) @$options[self::OPTION_RETURN_NEW],
            ]
        );

        $this->createCollectionIfOptions($collection, $params);

        $url = UrlHelper::appendParamsUrl(Urls::URL_DOCUMENT . '/' . $collection, $params);

        if (is_array($document)) {
            $data = $document;
        } else {
            $data = $document->getAllForInsertUpdate();
        }

        $response = $this->getConnection()->post($url, $this->json_encode_wrapper($data));
        $json     = $response->getJson();

        // This makes sure that if we're in batch mode, it will not go further and choke on the checks below.
        // Caution: Instead of a document ID, we are returning the batchpart object
        // The Id of the BatchPart can be retrieved by calling getId() on it.
        // We're basically returning an object here, in order not to accidentally use the batch part id as the document id
        if ($batchPart = $response->getBatchPart()) {
            return $batchPart;
        }
                
        if (@$options[self::OPTION_RETURN_OLD] || @$options[self::OPTION_RETURN_NEW]) {
            return $json;
        }

        if (is_array($document)) {
            return $json[$_documentClass::ENTRY_KEY];
        }

        $location = $response->getLocationHeader();
        if (!$location) {
            throw new ClientException('Did not find location header in server response');
        }

        $id = UrlHelper::getDocumentIdFromLocation($location);

        $document->setInternalId($json[$_documentClass::ENTRY_ID]);
        $document->setRevision($json[$_documentClass::ENTRY_REV]);

        if ($id !== $document->getId()) {
            throw new ClientException('Got an invalid response from the server');
        }

        $document->setIsNew(false);

        return $document->getId();
    }