#ifndef MOBIUS_EXTENSION_SEGMENT_DECODER_HPP
#define MOBIUS_EXTENSION_SEGMENT_DECODER_HPP

// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Mobius Forensic Toolkit
// Copyright (C)
// 2008,2009,2010,2011,2012,2013,2014,2015,2016,2017,2018,2019,2020,2021,2022,2023,2024,2025
// 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 "hash_section.hpp"
#include "header_section.hpp"
#include "section.hpp"
#include "table_section.hpp"
#include "volume_section.hpp"
#include <mobius/core/io/reader.hpp>

// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// @brief EWF segment file decoder
// @author Eduardo Aguiar
// @see https://github.com/libyal/libewf/blob/master/documentation/Expert%20
//       Witness%20Compression%20Format%20(EWF).asciidoc
//       (version 0.0.80, visited in 2016-08-25)
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
class segment_decoder
{
  public:
    using offset_type = mobius::core::io::reader::offset_type;

    // =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
    // @brief iterator for EWF sections
    // =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
    class const_iterator
    {
      public:
        using self_type = const_iterator;
        using value_type = section;
        using reference = section &;
        using pointer = section *;
        using difference_type = int;
        using iterator_category = std::forward_iterator_tag;

        // =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
        // constructors
        // =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
        const_iterator () = default;
        const_iterator (const_iterator &&) = default;
        const_iterator (const const_iterator &) = default;
        const_iterator (const segment_decoder *, offset_type);

        // =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
        // operators' prototypes
        // =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
        const_iterator &operator= (const const_iterator &) = default;
        const_iterator &operator= (const_iterator &&) = default;
        const_iterator &operator++ ();
        bool operator== (const const_iterator &);

        // =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
        // @brief check if two iterators are different
        // @param i iterator
        // @return true/false
        // =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
        bool
        operator!= (const_iterator &i)
        {
            return !(*this == i);
        }

        // =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
        // @brief get current section
        // @return section object
        // =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
        const section &
        operator* ()
        {
            return section_;
        }

      private:
        const segment_decoder *decoder_ = nullptr;
        section section_;
    };

    // =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
    // @brief check whether segment file is valid
    // @return true/false
    // =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
    operator bool () const { return is_valid_; }

    // =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
    // @brief get segment number
    // @return segment number, starting from 1
    // =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
    std::uint32_t
    get_segment_number () const
    {
        return segment_number_;
    }

    // =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
    // prototypes
    // =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
    explicit segment_decoder (mobius::core::io::reader reader);
    const_iterator begin () const;
    const_iterator end () const;

    section decode_section (offset_type) const;
    header_section decode_header_section (const section &) const;
    volume_section decode_volume_section (const section &) const;
    table_section decode_table_section (const section &) const;
    hash_section decode_hash_section (const section &) const;

  private:
    mobius::core::io::reader reader_;
    bool is_valid_ = false;
    std::uint32_t segment_number_ = 0;
};

#endif
