/**
 * @file mega/filefingerprint.h
 * @brief Sparse file fingerprint
 *
 * (c) 2013-2014 by Mega Limited, Wellsford, New Zealand
 *
 * This file is part of the MEGA SDK - Client Access Engine.
 *
 * Applications using the MEGA API must present a valid application key
 * and comply with the the rules set forth in the Terms of Service.
 *
 * The MEGA SDK 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.
 *
 * @copyright Simplified (2-clause) BSD License.
 *
 * You should have received a copy of the license along with this
 * program.
 */

#pragma once

#include <array>

#include "types.h"

namespace mega {

struct MEGA_API InputStreamAccess
{
    virtual m_off_t size() = 0;
    virtual bool read(byte *, unsigned) = 0;
    virtual ~InputStreamAccess() { }
};

// Tolerance threshold (in seconds) for filesystem modification time comparisons
constexpr unsigned FS_MTIME_TOLERANCE_SECS = 2;

/* IMPORTANT:
 * In case we want to perform a `mtime` update, the new value must be greater than
 * `FS_MTIME_TOLERANCE_SECS` respect the previous one, otherwise it won't be detected
 */
constexpr unsigned MIN_ALLOW_MTIME_DIFFERENCE = FS_MTIME_TOLERANCE_SECS + 1;

// sparse file fingerprint, including size and mtime
struct MEGA_API FileFingerprint : public Cacheable
{
    m_off_t size = -1;
    m_time_t mtime = 0;
    FingerprintCrc crc{};

    // if true, represents actual file data
    // if false, is constructed from node ctime/key
    bool isvalid = false;

    // Generates a fingerprint by iterating through`fa`
    bool genfingerprint(FileAccess* fa, bool ignoremtime = false);

    // Generates a fingerprint by iterating through `is`
    bool genfingerprint(InputStreamAccess* is, m_time_t cmtime, bool ignoremtime = false);

    // Includes CRC and mtime
    // Be wary that these must be used in pair; do not mix with serialize pair
    void serializefingerprint(string* d) const;
    int unserializefingerprint(const string* d);

    FileFingerprint() = default;

    FileFingerprint(const FileFingerprint&);
    FileFingerprint& operator=(const FileFingerprint& other);

    // Includes size, CRC, mtime, and isvalid
    // Be wary that these must be used in pair; do not mix with serializefingerprint pair
    bool serialize(string* d) const override;

    // Includes size, CRC, and isvalid (mtime is not included)
    // This method can be used to serialize a file fingerprint without mtime, that could be used to
    // find nodes with same content but only differs in mtime.
    // Note: This method should not be used to serialize fingerprints that will be stored on Db
    bool serializeExcludingMtime(string* d) const;
    static unique_ptr<FileFingerprint> unserialize(const char*& ptr, const char* end);

    // convenience function for clear comparisons etc, referring to (this) base class
    const FileFingerprint& fingerprint() const { return *this; }

    string fingerprintDebugString() const;

    bool EqualExceptValidFlag(const FileFingerprint& rhs) const;
    bool equalExceptMtime(const FileFingerprint& rhs) const;
    bool equalExceptMtimeAndIsValid(const FileFingerprint& rhs) const;
};

// orders transfers by file fingerprints, ordered by size / mtime / sparse CRC
struct MEGA_API FileFingerprintCmp
{
    bool operator()(const FileFingerprint* a, const FileFingerprint* b) const;
    bool operator()(const FileFingerprint& a, const FileFingerprint& b) const;
};

struct MEGA_API FileFingerprintCmpNoMtime
{
    bool operator()(const FileFingerprint* a, const FileFingerprint* b) const;
    bool operator()(const FileFingerprint& a, const FileFingerprint& b) const;
};

bool operator==(const FileFingerprint& lhs, const FileFingerprint& rhs);
bool operator!=(const FileFingerprint& lhs, const FileFingerprint& rhs);


} // mega
