//========================================================================
//
// OptionalContent.h
//
// Copyright 2007 Brad Hards <bradh@kde.org>
// Copyright 2008 Carlos Garcia Campos <carlosgc@gnome.org>
// Copyright 2013, 2018, 2019 Albert Astals Cid <aacid@kde.org>
// Copyright 2018 Adam Reichold <adam.reichold@t-online.de>
// Copyright 2019 Oliver Sander <oliver.sander@tu-dresden.de>
//
// Released under the GPL (version 2, or later, at your option)
//
//========================================================================

#ifndef OPTIONALCONTENT_H
#define OPTIONALCONTENT_H

#include "Object.h"
#include "CharTypes.h"
#include <unordered_map>
#include <memory>

class GooString;
class XRef;

class OptionalContentGroup;

//------------------------------------------------------------------------

class OCGs
{
public:
    OCGs(Object *ocgObject, XRef *xref);

    OCGs(const OCGs &) = delete;
    OCGs &operator=(const OCGs &) = delete;

    // Is OCGS valid?
    bool isOk() const { return ok; }

    bool hasOCGs() const;
    const std::unordered_map<Ref, std::unique_ptr<OptionalContentGroup>> &getOCGs() const { return optionalContentGroups; }

    OptionalContentGroup *findOcgByRef(const Ref ref);

    Array *getOrderArray() { return (order.isArray() && order.arrayGetLength() > 0) ? order.getArray() : nullptr; }
    Array *getRBGroupsArray() { return (rbgroups.isArray() && rbgroups.arrayGetLength()) ? rbgroups.getArray() : nullptr; }

    bool optContentIsVisible(const Object *dictRef);

private:
    bool ok;

    bool evalOCVisibilityExpr(const Object *expr, int recursion);
    bool allOn(Array *ocgArray);
    bool allOff(Array *ocgArray);
    bool anyOn(Array *ocgArray);
    bool anyOff(Array *ocgArray);

    std::unordered_map<Ref, std::unique_ptr<OptionalContentGroup>> optionalContentGroups;

    Object order;
    Object rbgroups;
    XRef *m_xref;
};

//------------------------------------------------------------------------

class OptionalContentGroup
{
public:
    enum State
    {
        On,
        Off
    };

    // Values from the optional content usage dictionary.
    enum UsageState
    {
        ocUsageOn,
        ocUsageOff,
        ocUsageUnset
    };

    OptionalContentGroup(Dict *dict);

    OptionalContentGroup(GooString *label);

    ~OptionalContentGroup();

    OptionalContentGroup(const OptionalContentGroup &) = delete;
    OptionalContentGroup &operator=(const OptionalContentGroup &) = delete;

    const GooString *getName() const;

    Ref getRef() const;
    void setRef(const Ref ref);

    State getState() const { return m_state; };
    void setState(State state) { m_state = state; };

    UsageState getViewState() const { return viewState; }
    UsageState getPrintState() const { return printState; }

private:
    GooString *m_name;
    Ref m_ref;
    State m_state;
    UsageState viewState; // suggested state when viewing
    UsageState printState; // suggested state when printing
};

//------------------------------------------------------------------------

#endif
