#pragma once

#include <yandex/maps/wiki/diffalert/object.h>

#include <set>
#include <string>

namespace maps {
namespace wiki {
namespace diffalert {

class Object;
class Snapshot;

class OptionalObject
{
public:
    OptionalObject();
    explicit OptionalObject(Object* object);

    explicit operator bool() const;

    Object& operator*();
    const Object& operator*() const;

    Object* operator->();
    const Object* operator->() const;

private:
    Object* checkAndGet() const;

    Object* object_;
};


class DiffContext
{
public:
    virtual ~DiffContext() {}

    virtual TId objectId() const = 0;
    virtual const std::string& categoryId() const = 0;

    // nullptr means object is deleted or not yet created
    // at least one of the objects must be non-null
    virtual OptionalObject oldObject() const = 0;
    virtual OptionalObject newObject() const = 0;

    virtual Snapshot& oldSnapshot() const = 0;
    virtual Snapshot& newSnapshot() const = 0;

    bool stateChanged() const;
    // behaviour for created/deleted objects: always true
    virtual bool categoryChanged() const = 0;
    // behaviour for created/deleted objects: always true
    virtual bool attrsChanged() const = 0;
    // behaviour for created/deleted objects: true if object has/had
    // geom or geom parts
    virtual bool geomChanged() const = 0;
    virtual const Relations& relationsAdded() const = 0;
    virtual const Relations& relationsDeleted() const = 0;
    bool relationsChanged() const;

    virtual const Relations& tableAttrsAdded() const = 0;
    virtual const Relations& tableAttrsDeleted() const = 0;
    bool tableAttrsChanged() const;

    bool changed() const;
};

struct ChangesPrinter { const DiffContext& diffContext; };
std::ostream& operator<<(std::ostream& os, const ChangesPrinter& p);

} // namespace diffalert
} // namespace wiki
} // namespace maps
