// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Mobius Forensic Toolkit
// Copyright (C) 2008,2009,2010,2011,2012,2013,2014,2015,2016,2017,2018 Eduardo Aguiar
//
// This program is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the
// Free Software Foundation; either version 2, 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 General
// Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=

// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
//!\brief  C++ API module wrapper
//!\author Eduardo Aguiar
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
#include "api.h"
#include <Python.h>
#include <datetime.h>
#include "api_dataholder.h"

#include "core/module.h"
#include "crypt/module.h"
#include "disk/module.h"
#include "filesystem/module.h"
#include "forensics/module.h"
#include "imagefile/module.h"
#include "io/module.h"
#include "partition/module.h"
#include "system/module.h"

// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
//!\brief module methods
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
static PyMethodDef module_methods[] =
{
  {
    NULL,
    NULL,
    0,
    NULL
  } // sentinel
};

// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
//!\brief module initialisation function
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
PyMODINIT_FUNC
initmobius ()
{
  // build types
  if (PyType_Ready (&api_dataholder_t) < 0)
    return;

  // initialize module
  PyObject* mobius_module = Py_InitModule3 (
    "mobius",
    module_methods,
    "Mobius Forensic Toolkit API wrapper"
  );

  if (mobius_module == nullptr)
    return;

  // add types  
  PyDateTime_IMPORT;

  // build submodules
  PyObject *core_module = new_core_module ();
  PyModule_AddObject (mobius_module, "core", core_module);

  PyObject *crypt_module = new_crypt_module ();
  PyModule_AddObject (mobius_module, "crypt", crypt_module);

  PyObject *disk_module = new_disk_module ();
  PyModule_AddObject (mobius_module, "disk", disk_module);

  PyObject *filesystem_module = new_filesystem_module ();
  PyModule_AddObject (mobius_module, "filesystem", filesystem_module);

  PyObject *forensics_module = new_forensics_module ();
  PyModule_AddObject (mobius_module, "forensics", forensics_module);

  PyObject *imagefile_module = new_imagefile_module ();
  PyModule_AddObject (mobius_module, "imagefile", imagefile_module);

  PyObject *io_module = new_io_module ();
  PyModule_AddObject (mobius_module, "io", io_module);

  PyObject *partition_module = new_partition_module ();
  PyModule_AddObject (mobius_module, "partition", partition_module);

  PyObject *system_module = new_system_module ();
  PyModule_AddObject (mobius_module, "system", system_module);

  // deprecated: this types must be enclosed in submodules
  Py_INCREF (&api_dataholder_t);
  PyModule_AddObject (mobius_module, "dataholder", (PyObject *) &api_dataholder_t);
}

// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// These three PyDateTime functions must be located here, because PyDateTime_IMPORT
// creates a static variable, and as so, with local scope to this file only.
// These functions are declared into "api_datetime.h" header file and can
// be used throughout the api_xxx.cc source files.
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=

// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
//!\brief create PyDateTime from mobius::datetime::datetime
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
PyObject *
PyDateTime_from_datetime (const mobius::datetime::datetime& dt)
{
  auto ret_date = dt.get_date ();
  auto ret_time = dt.get_time ();

  return PyDateTime_FromDateAndTime (ret_date.get_year (), ret_date.get_month (), ret_date.get_day (), ret_time.get_hour (), ret_time.get_minute (), ret_time.get_second (), 0);
}

// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
//!\brief create mobius::datetime::datetime from PyDateTime
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
const mobius::datetime::datetime
PyDateTime_as_datetime (PyObject *obj)
{
  return mobius::datetime::datetime (
    PyDateTime_GET_YEAR (obj),
    PyDateTime_GET_MONTH (obj),
    PyDateTime_GET_DAY (obj),
    PyDateTime_DATE_GET_HOUR (obj),
    PyDateTime_DATE_GET_MINUTE (obj),
    PyDateTime_DATE_GET_SECOND (obj));
}

// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
//!\brief check if object is PyDateTime
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
bool
check_PyDateTime (PyObject *obj)
{
  return PyDateTime_Check (obj);
}

// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
//!\brief create PyString from mobius::bytearray
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
PyObject *
PyString_from_bytearray (const mobius::bytearray& array)
{
  return PyString_FromStringAndSize ((const char *) array.data (), array.size ());
}
