// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// 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 "decoder_impl_phash.h"
#include "common.h"
#include <mobius/core/log.h>
#include <mobius/decoder/data_decoder.h>

// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Constants
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
namespace
{
static constexpr int STATE_NO = 0;
static constexpr int STATE_YES = 1;
static constexpr int STATE_UNKNOWN = 2;
}

namespace mobius::extension::app::ares
{
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
//! \brief Decode file
//! \see ICH_loadPieces - helper_ICH.pas (line 528)
//! \see ICH_load_phash_index - helper_ICH.pas (line 1024)
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
void
decoder_impl_phash::decode (const mobius::io::reader& reader)
{
  if (!reader || reader.get_size () < 14)
    return;

  mobius::core::log log (__FILE__, __FUNCTION__);

  // =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  // Create main section
  // =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  auto decoder = mobius::decoder::data_decoder (reader);
  decoder.seek (0);

  section_ = mobius::core::file_decoder::section (reader, "File");

  // =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  // Decode header
  // =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  auto header_section = section_.new_child ("header");
  auto signature = decoder.get_bytearray_by_size (14);
  std::uint32_t version = 0;

  if (signature == "__ARESDBP102__")
    version = 2;

  else if (signature == "__ARESDBP103__")
    version = 3;

  else
    return;

  is_instance_ = true;
  metadata_.set_value ("general", "signature", signature.to_string ());
  metadata_.set_value ("general", "file_version", version);

  header_section.end ();

  // =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  // Decode entries
  // =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  std::uint64_t idx = 0;

  while (decoder)
    {
      auto entry_section = section_.new_child ("Entry #" + std::to_string (++idx));

      // =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
      // Decoder entry data
      // =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
      auto num64 = decoder.get_uint64_le ();
      auto pieces_data_size = decoder.get_uint32_le ();
      auto hash_sha1 = decoder.get_hex_string_by_size (20);
      auto num32 = decoder.get_uint32_le ();
      int is_entry_completed = STATE_UNKNOWN;
      std::uint64_t progress = 0;
      std::uint64_t piece_size = 0;
      std::uint64_t pieces_count = 0;
      std::uint64_t pieces_completed = 0;

      if (num64 != 1)
        log.development (__LINE__, "num64 = " + std::to_string (num64));

      if (num32 != 1)
        log.development (__LINE__, "num32 = " + std::to_string (num32));

      // =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
      // Decode pieces
      // =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
      std::vector <mobius::pod::data> pieces;

      while (pieces_data_size > 0)
        {
          ++pieces_count;

          int is_piece_completed = STATE_UNKNOWN;
          std::uint64_t piece_progress = 0;

          if (version == 3)
            {
              is_piece_completed = (decoder.get_uint8 () == 1) ? STATE_YES : STATE_NO;
              piece_progress = decoder.get_uint64_le ();
              progress += piece_progress;

              if (is_piece_completed == STATE_YES)
                {
                  piece_size = std::max (piece_size, piece_progress);
                  ++pieces_completed;

                  if (is_entry_completed == STATE_UNKNOWN)
                    is_entry_completed = STATE_YES;
                }

              else
                is_entry_completed = STATE_NO;

              pieces_data_size -= 9;
            }

          auto hash_sha1 = decoder.get_hex_string_by_size (20);
          pieces.emplace_back (mobius::pod::data {hash_sha1, piece_progress, is_piece_completed});
          pieces_data_size -= 20;
        }

      entry_section.end ();

      // =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
      // Create entry
      // =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
      mobius::core::file_decoder::entry e (idx, hash_sha1);
      e.set_metadata ("hash_sha1", hash_sha1);
      e.set_metadata ("pieces", pieces);
      e.set_metadata ("piece_size", piece_size);
      e.set_metadata ("pieces_count", pieces_count);
      e.set_metadata ("pieces_completed", pieces_completed);
      e.set_metadata ("pieces_to_go", pieces_count - pieces_completed);
      e.set_metadata ("is_completed", is_entry_completed);
      e.set_metadata ("progress", progress);

      entries_.push_back (e);
    }

  metadata_.set_value ("general", "entries", idx);
  section_.end ();
}

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