// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Mobius Forensic Toolkit
// Copyright (C) 2008,2009,2010,2011,2012,2013,2014,2015,2016,2017,2018,2019,2020,2021,2022,2023,2024 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/>.
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
#include "common.h"
#include <mobius/core/log.h>
#include <mobius/decoder/data_decoder.h>
#include <mobius/pod/data.h>
#include <vector>

namespace mobius::extension::app::ares
{
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
//! \brief Decrypt data
//! \param enc_data Encrypted data
//! \return Decrypted data
//! \see helper_library_db.pas
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
mobius::bytearray
decrypt (const mobius::bytearray& enc_data, std::uint16_t seed)
{
  mobius::bytearray data (enc_data.size ());
  auto iter = data.begin ();

  for (auto c : enc_data)
    {
      *iter = (c ^ (seed >> 8));
      seed = (c + seed) * 23219 + 36126;
      ++iter;
    }

  return data;
}

// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
//! \brief Convert media type to string
//! \param t Media type
//! \see mediatype_to_str function (helper_mimetypes.pas)
//! \see const_ares.pas
//! \see vars_localiz.pas
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
std::string
media_type_to_string (std::uint8_t t)
{
  mobius::core::log log (__FILE__, __FUNCTION__);

  switch (t)
  {
    case 0: return "Other"; break;
    case 1: return "Audio"; break;
    case 2: return "Audio"; break;
    case 3: return "Software"; break;
    case 4: return "Audio"; break;
    case 5: return "Video"; break;
    case 6: return "Document"; break;
    case 7: return "Image"; break;

    default:
      log.development (__LINE__, "unhandled media type: " + std::to_string (t));
      return {};
  };
}

// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
//! \brief Decoder altsources
//! \param data Encoded data
//! \param is_new Set, if it is new format
//! \see add_sources function @helper_altsources (line 106)
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
std::vector <mobius::pod::data>
get_altsources (const mobius::bytearray& data, bool is_new)
{
  std::vector <mobius::pod::data> sources;

  auto decoder = mobius::decoder::data_decoder (data);

  while (decoder)
    {
      auto ip = decoder.get_ipv4_be ();
      auto port = decoder.get_uint16_le ();
      sources.emplace_back (mobius::pod::data {ip, port});

      decoder.skip (is_new ? 11 : 6);  // ip_server, port_server, ip_alt, dummy
    }

  return sources;
}

// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
//! \brief Get metadata from data
//! \param data Encoded data
//! \param type Metadata type
//! \see get_cached_metas@helper_library_db.pas
//! \see get_trusted_metas@helper_library_db.pas
//! \see read_details_DB_Download@helper_download_disk.pas
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
mobius::pod::map
get_metadata (const mobius::bytearray& data, bool is_arestra)
{
  mobius::core::log log (__FILE__, __FUNCTION__);

  auto decoder = mobius::decoder::data_decoder (data);
  mobius::pod::map metadata;

  while (decoder)
    {
      auto field_type = decoder.get_uint8 ();
      auto field_size = decoder.get_uint16_le ();

      switch (field_type)
      {
        case 1:
            if (is_arestra)
              metadata.set ("kwgenre", decoder.get_string_by_size (field_size));
            else
              metadata.set ("path", decoder.get_string_by_size (field_size));
            break;
        case 2:
            metadata.set ("title", decoder.get_string_by_size (field_size));
            break;
        case 3:
            metadata.set ("artist", decoder.get_string_by_size (field_size));
            break;
        case 4:
            metadata.set ("album", decoder.get_string_by_size (field_size));
            break;
        case 5:
            metadata.set ("category", decoder.get_string_by_size (field_size));
            break;
        case 6:
            metadata.set ("year", decoder.get_string_by_size (field_size));
            break;
        case 7:
            if (is_arestra)
              {
                auto data = decoder.get_bytearray_by_size (field_size);
                metadata.set ("sources", get_altsources (data, false));
              }
            else
              metadata.set ("vidinfo", decoder.get_string_by_size (field_size));
            break;
        case 8:
            metadata.set ("language", decoder.get_string_by_size (field_size));
            break;
        case 9:
            metadata.set ("url", decoder.get_string_by_size (field_size));
            break;
        case 10:
            metadata.set ("comments", decoder.get_string_by_size (field_size));
            break;
        case 11:
            metadata.set ("download_completed_time", decoder.get_unix_datetime ());
            break;
        case 13:
            {
              auto data = decoder.get_bytearray_by_size (field_size);
              metadata.set ("sources", get_altsources (data, true));
            }
            break;
        case 15:
            metadata.set ("hash_sha1", decoder.get_hex_string_by_size (field_size));
            break;
        case 17:
            metadata.set ("is_corrupted", true);
            decoder.skip (field_size);
            break;
        case 18:
            metadata.set ("hash_of_phash", decoder.get_hex_string_by_size (field_size));
            break;
        case 19:
            metadata.set ("subfolder", decoder.get_string_by_size (field_size));
            break;
        case 20:
            metadata.set ("phash_verified", decoder.get_uint64_le ());
            break;
        case 25:
            metadata.set ("download_started_time", decoder.get_unix_datetime ());
            break;

        default:
            log.development (__LINE__, "unhandled field_type: " + std::to_string (field_type));
            decoder.skip (field_size);
      }
    }

  return metadata;
}

} // namespace mobius::extension::app::ares
