// SPDX-License-Identifier: Apache-2.0
// Copyright Contributors to the OpenTimelineIO project

#pragma once

#include "opentimelineio/version.h"
#include <string>

namespace opentimelineio { namespace OPENTIMELINEIO_VERSION {

class SerializableObject;

struct ErrorStatus
{
    enum Outcome
    {
        OK = 0,
        NOT_IMPLEMENTED,
        UNRESOLVED_OBJECT_REFERENCE,
        DUPLICATE_OBJECT_REFERENCE,
        MALFORMED_SCHEMA,
        JSON_PARSE_ERROR,
        CHILD_ALREADY_PARENTED,
        FILE_OPEN_FAILED,
        FILE_WRITE_FAILED,
        SCHEMA_ALREADY_REGISTERED,
        SCHEMA_NOT_REGISTERED,
        SCHEMA_VERSION_UNSUPPORTED,
        KEY_NOT_FOUND,
        ILLEGAL_INDEX,
        TYPE_MISMATCH,
        INTERNAL_ERROR,
        NOT_AN_ITEM,
        NOT_A_CHILD_OF,
        NOT_A_CHILD,
        NOT_DESCENDED_FROM,
        CANNOT_COMPUTE_AVAILABLE_RANGE,
        INVALID_TIME_RANGE,
        OBJECT_WITHOUT_DURATION,
        CANNOT_TRIM_TRANSITION,
        OBJECT_CYCLE,
        CANNOT_COMPUTE_BOUNDS,
        MEDIA_REFERENCES_DO_NOT_CONTAIN_ACTIVE_KEY,
        MEDIA_REFERENCES_CONTAIN_EMPTY_KEY,
        NOT_A_GAP
    };

    ErrorStatus()
        : outcome(OK)
        , object_details(nullptr)
    {}

    ErrorStatus(Outcome in_outcome)
        : outcome(in_outcome)
        , details(outcome_to_string(in_outcome))
        , full_description(details)
        , object_details(nullptr)
    {}

    ErrorStatus(
        Outcome                   in_outcome,
        std::string const&        in_details,
        SerializableObject const* object = nullptr)
        : outcome(in_outcome)
        , details(in_details)
        , full_description(outcome_to_string(in_outcome) + ": " + in_details)
        , object_details(object)
    {}

    ErrorStatus& operator=(Outcome in_outcome)
    {
        *this = ErrorStatus(in_outcome);
        return *this;
    }

    Outcome                   outcome;
    std::string               details;
    std::string               full_description;
    SerializableObject const* object_details;

    static std::string outcome_to_string(Outcome);
};

// Check whether the given ErrorStatus is an error.
constexpr bool
is_error(const ErrorStatus& es) noexcept
{
    return ErrorStatus::Outcome::OK != es.outcome;
}

// Check whether the given ErrorStatus* is non-null and an error.
constexpr bool
is_error(const ErrorStatus* es) noexcept
{
    return es && ErrorStatus::Outcome::OK != es->outcome;
}

}} // namespace opentimelineio::OPENTIMELINEIO_VERSION
