/*
 * Copyright 2009-present MongoDB, 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.
 */


#include <mongoc/mongoc-find-and-modify.h>

#include <mongoc/mongoc-find-and-modify-private.h>
#include <mongoc/mongoc-util-private.h>
#include <mongoc/mongoc-write-concern-private.h>

#include <mongoc/mongoc-write-concern.h>


/**
 * mongoc_find_and_modify_new:
 *
 * Create a new mongoc_find_and_modify_t.
 *
 * Returns: A newly allocated mongoc_find_and_modify_t. This should be freed
 *    with mongoc_find_and_modify_destroy().
 */
mongoc_find_and_modify_opts_t *
mongoc_find_and_modify_opts_new(void)
{
   mongoc_find_and_modify_opts_t *opts = NULL;

   opts = BSON_ALIGNED_ALLOC0(mongoc_find_and_modify_opts_t);
   bson_init(&opts->extra);
   opts->bypass_document_validation = false;

   return opts;
}

bool
mongoc_find_and_modify_opts_set_sort(mongoc_find_and_modify_opts_t *opts, const bson_t *sort)
{
   BSON_ASSERT(opts);

   if (sort) {
      bson_destroy(opts->sort);
      opts->sort = bson_copy(sort);
      return true;
   }

   return false;
}

void
mongoc_find_and_modify_opts_get_sort(const mongoc_find_and_modify_opts_t *opts, bson_t *sort)
{
   BSON_ASSERT(opts);
   BSON_ASSERT(sort);

   if (opts->sort) {
      bson_copy_to(opts->sort, sort);
   } else {
      bson_init(sort);
   }
}

bool
mongoc_find_and_modify_opts_set_update(mongoc_find_and_modify_opts_t *opts, const bson_t *update)
{
   BSON_ASSERT(opts);

   if (update) {
      bson_destroy(opts->update);
      opts->update = bson_copy(update);
      return true;
   }

   return false;
}

void
mongoc_find_and_modify_opts_get_update(const mongoc_find_and_modify_opts_t *opts, bson_t *update)
{
   BSON_ASSERT(opts);
   BSON_ASSERT(update);

   if (opts->update) {
      bson_copy_to(opts->update, update);
   } else {
      bson_init(update);
   }
}

bool
mongoc_find_and_modify_opts_set_fields(mongoc_find_and_modify_opts_t *opts, const bson_t *fields)
{
   BSON_ASSERT(opts);

   if (fields) {
      bson_destroy(opts->fields);
      opts->fields = bson_copy(fields);
      return true;
   }

   return false;
}

void
mongoc_find_and_modify_opts_get_fields(const mongoc_find_and_modify_opts_t *opts, bson_t *fields)
{
   BSON_ASSERT(opts);
   BSON_ASSERT(fields);

   if (opts->fields) {
      bson_copy_to(opts->fields, fields);
   } else {
      bson_init(fields);
   }
}

bool
mongoc_find_and_modify_opts_set_flags(mongoc_find_and_modify_opts_t *opts, const mongoc_find_and_modify_flags_t flags)
{
   BSON_ASSERT(opts);

   opts->flags = flags;
   return true;
}

mongoc_find_and_modify_flags_t
mongoc_find_and_modify_opts_get_flags(const mongoc_find_and_modify_opts_t *opts)
{
   BSON_ASSERT(opts);

   return opts->flags;
}

bool
mongoc_find_and_modify_opts_set_bypass_document_validation(mongoc_find_and_modify_opts_t *opts, bool bypass)
{
   BSON_ASSERT(opts);

   opts->bypass_document_validation = bypass;
   return true;
}

bool
mongoc_find_and_modify_opts_get_bypass_document_validation(const mongoc_find_and_modify_opts_t *opts)
{
   BSON_ASSERT(opts);

   return opts->bypass_document_validation;
}

bool
mongoc_find_and_modify_opts_set_max_time_ms(mongoc_find_and_modify_opts_t *opts, uint32_t max_time_ms)
{
   BSON_ASSERT(opts);

   opts->max_time_ms = max_time_ms;
   return true;
}

uint32_t
mongoc_find_and_modify_opts_get_max_time_ms(const mongoc_find_and_modify_opts_t *opts)
{
   BSON_ASSERT(opts);

   return opts->max_time_ms;
}

bool
mongoc_find_and_modify_opts_append(mongoc_find_and_modify_opts_t *opts, const bson_t *extra)
{
   BSON_ASSERT(opts);

   if (!extra) {
      return true;
   }

   return bson_concat(&opts->extra, extra);
}

void
mongoc_find_and_modify_opts_get_extra(const mongoc_find_and_modify_opts_t *opts, bson_t *extra)
{
   BSON_ASSERT(opts);
   BSON_ASSERT(extra);

   bson_copy_to(&opts->extra, extra);
}

/**
 * mongoc_find_and_modify_opts_destroy:
 * @opts: A mongoc_find_and_modify_opts_t.
 *
 * Releases a mongoc_find_and_modify_opts_t and all associated memory.
 */
void
mongoc_find_and_modify_opts_destroy(mongoc_find_and_modify_opts_t *opts)
{
   if (opts) {
      bson_destroy(opts->sort);
      bson_destroy(opts->update);
      bson_destroy(opts->fields);
      bson_destroy(&opts->extra);
      bson_free(opts);
   }
}
