/*
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public License
 * as published by the Free Software Foundation; either version 2.1
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 */

#include "./cwriter.h"

#include "../ipcs/sysv-shm.hpp"
#include "../shtype/shtype-from-gst-caps.hpp"
#include "../writer.hpp"
#include "./cshtype_internal.hpp"

namespace sh4lt {
struct CWriter {
  CWriter(const Sh4ltShType type_descr,
          size_t memsize,
          Sh4ltLogger log,
          void (*on_client_connected)(void* user_data, int id),
          void (*on_client_disconnected)(void* user_data, int id),
          void* user_data,
          mode_t unix_permission)
      : on_client_connected_(on_client_connected),
        on_client_disconnected_(on_client_disconnected),
        user_data_(user_data),
        writer_(
            static_cast<const sh4lt::CShType*>(type_descr)->shtype_,
            memsize,
            *static_cast<logger::Logger::ptr*>(log),
            [&](int id) {
              if (nullptr != on_client_connected_) on_client_connected_(user_data_, id);
            },
            [&](int id) {
              if (nullptr != on_client_disconnected_) on_client_disconnected_(user_data_, id);
            },
            unix_permission) {}
  void (*on_client_connected_)(void*, int);
  void (*on_client_disconnected_)(void*, int);
  void* user_data_;
  Writer writer_;
};

}  // namespace sh4lt

using namespace sh4lt;
Sh4ltWriter sh4lt_make_writer(const Sh4ltShType type_descr,
                              size_t memsize,
                              void (*on_client_connected)(void* user_data, int id),
                              void (*on_client_disconnected)(void* user_data, int id),
                              void* user_data,
                              Sh4ltLogger log,
                              mode_t unix_permission) {
  CWriter* res = new CWriter(type_descr,
                             memsize,
                             log,
                             on_client_connected,
                             on_client_disconnected,
                             user_data,
                             unix_permission);
  if (!res->writer_) {
    delete res;
    return nullptr;
  }
  return static_cast<void*>(res);
}

void sh4lt_delete_writer(Sh4ltWriter writer) { delete static_cast<CWriter*>(writer); }

int sh4lt_copy_to_shm(Sh4ltWriter writer,
                      const void* data,
                      size_t size,
                      int64_t buffer_date,
                      int64_t buffer_duration,
                      float speed) {
  return static_cast<CWriter*>(writer)->writer_.copy_to_shm(
      data, size, buffer_date, buffer_duration, speed);
}

int sh4lt_wait_readers_for(Sh4ltWriter writer, int64_t timeout_nsec) {
  return static_cast<CWriter*>(writer)->writer_.wait_readers_for(timeout_nsec);
}

Sh4ltWriterAccess sh4lt_get_one_write_access(Sh4ltWriter writer) {
  return static_cast<void*>(static_cast<CWriter*>(writer)->writer_.get_one_write_access_ptr());
}

Sh4ltWriterAccess sh4lt_get_one_write_access_resize(Sh4ltWriter writer, size_t new_size) {
  return static_cast<void*>(
      static_cast<CWriter*>(writer)->writer_.get_one_write_access_ptr_resize(new_size));
}

size_t sh4lt_shm_resize(Sh4ltWriterAccess access, size_t new_size) {
  return static_cast<OneWriteAccess*>(access)->shm_resize(new_size);
}

void* sh4lt_get_mem(Sh4ltWriterAccess access) {
  return static_cast<OneWriteAccess*>(access)->get_mem();
}

short sh4lt_notify_clients(Sh4ltWriterAccess access,
                           size_t size,
                           int64_t buffer_date,
                           int64_t buffer_duration,
                           float speed) {
  return static_cast<OneWriteAccess*>(access)->notify_clients(
      size, buffer_date, buffer_duration, speed);
}

void sh4lt_release_one_write_access(Sh4ltWriterAccess access) {
  delete static_cast<OneWriteAccess*>(access);
}

unsigned long sh4lt_get_shmmax(Sh4ltLogger log) {
  auto log_ptr = static_cast<logger::Logger::ptr*>(log);
  return sysVShm::get_shmmax(log_ptr ? log_ptr->get() : nullptr);
}

unsigned long sh4lt_get_shmmni(Sh4ltLogger log) {
  auto log_ptr = static_cast<logger::Logger::ptr*>(log);
  return sysVShm::get_shmmni(log_ptr ? log_ptr->get() : nullptr);
}
