/*
 * Copyright 2009- ECMWF.
 *
 * This software is licensed under the terms of the Apache Licence version 2.0
 * which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
 * In applying this licence, ECMWF does not waive the privileges and immunities
 * granted to it by virtue of its status as an intergovernmental organisation
 * nor does it submit to any jurisdiction.
 */

#ifndef ecflow_viewer_VInfo_HPP
#define ecflow_viewer_VInfo_HPP

#include <cstddef>
#include <memory>
#include <string>
#include <vector>

#include "ServerObserver.hpp"
#include "ecflow/attribute/Variable.hpp"

class ServerHandler;
class VAttribute;
class VNode;
class VItem;

class VInfoObserver;
class VInfoVisitor;

class VInfo;
typedef std::shared_ptr<VInfo> VInfo_ptr;

//==============================================================================
// For each selected item in any of the views a new VInfo object is created.
// This class offers the same interface to access information about any selected
// items: servers, nodes, attributes. The concrete implementation of
// these access methods are done in subclasses derived from VInfo.
//
// VInfo is regarded as a temporary object. We only need it while the selection
// is used in breadcrumbs, info panels or other widgets outside the main views.
//==============================================================================

class VInfo : public ServerObserver {
public:
    ~VInfo() override;

    virtual bool isServer() { return false; }
    virtual bool isNode() { return false; }
    virtual bool isAttribute() { return false; }
    virtual bool isEmpty() { return true; }
    virtual bool hasData() const = 0;

    ServerHandler* server() const { return server_; }
    VNode* node() const { return node_; }
    VAttribute* attribute() const { return attr_; }
    virtual VItem* item() const = 0;

    virtual std::string name() = 0;
    virtual std::string path() = 0;
    virtual std::string serverAlias() { return ""; }
    virtual std::string relativePath() { return ""; }
    virtual std::string nodePath() = 0;
    std::string storedNodePath() const;
    const std::string& storedPath() const { return storedPath_; }

    virtual void accept(VInfoVisitor*) = 0;

    void regainData();
    void addObserver(VInfoObserver*);
    void removeObserver(VInfoObserver*);

    // Form ServerObserver
    void notifyDefsChanged(ServerHandler*, const std::vector<ecf::Aspect::Type>&) override {}
    void notifyServerDelete(ServerHandler* server) override;
    void notifyBeginServerClear(ServerHandler* server) override;
    void notifyEndServerClear(ServerHandler* server) override;
    void notifyBeginServerScan(ServerHandler*, const VServerChange&) override {}
    void notifyEndServerScan(ServerHandler* server) override;
    void notifyServerConnectState(ServerHandler*) override {}
    void notifyServerActivityChanged(ServerHandler*) override {}
    void notifyServerSuiteFilterChanged(ServerHandler*) override {}
    void notifyServerRenamed(ServerHandler* server, const std::string& oldName) override;

    bool operator==(const VInfo&);

    static VInfo_ptr createParent(VInfo_ptr);
    static VInfo_ptr createFromPath(ServerHandler*, const std::string&);
    static VInfo_ptr createFromPath(const std::string& path);
    static VInfo_ptr createFromItem(VItem*);

protected:
    VInfo(ServerHandler* server, VNode* node, VAttribute* attr = nullptr);
    void dataLost();

    mutable ServerHandler* server_;
    mutable VNode* node_;
    mutable VAttribute* attr_;
    mutable std::string storedPath_;

    std::vector<VInfoObserver*> observers_;
};

// Implements the info object for server selections
class VInfoServer : public VInfo, public std::enable_shared_from_this<VInfo> {
public:
    bool isServer() override { return true; }
    bool isEmpty() override { return false; }
    bool hasData() const override;
    VItem* item() const override;

    void accept(VInfoVisitor*) override;
    std::string name() override;
    std::string path() override;
    std::string nodePath() override { return "/"; }
    static VInfo_ptr create(ServerHandler*);

protected:
    explicit VInfoServer(ServerHandler*);
};

// Implements the info object for node selections
class VInfoNode : public VInfo, public std::enable_shared_from_this<VInfo> {
public:
    bool isNode() override { return true; }
    bool isEmpty() override { return false; }
    bool hasData() const override;
    void accept(VInfoVisitor*) override;
    std::string path() override;
    std::string name() override;
    std::string serverAlias() override;
    std::string nodePath() override;
    std::string relativePath() override;
    VItem* item() const override;

    static VInfo_ptr create(VNode*);

protected:
    VInfoNode(ServerHandler*, VNode*);
};

// Implements the info  base class for attribute selections
class VInfoAttribute : public VInfo, public std::enable_shared_from_this<VInfo> {
public:
    ~VInfoAttribute() override;
    VAttribute* attribute() const { return attr_; }
    bool isAttribute() override { return true; }
    bool isEmpty() override { return false; }
    bool hasData() const override;
    void accept(VInfoVisitor*) override;
    std::string name() override;
    std::string path() override;
    std::string nodePath() override;
    VItem* item() const override;

    static VInfo_ptr create(VAttribute*);

protected:
    VInfoAttribute(ServerHandler*, VNode*, VAttribute*);
};

typedef std::shared_ptr<VInfoServer> VInfoServer_ptr;
typedef std::shared_ptr<VInfoNode> VInfoNode_ptr;
typedef std::shared_ptr<VInfoAttribute> VInfoAttribute_ptr;

class VInfoVisitor {
public:
    VInfoVisitor()          = default;
    virtual ~VInfoVisitor() = default;

    virtual void visit(VInfoServer*)    = 0;
    virtual void visit(VInfoNode*)      = 0;
    virtual void visit(VInfoAttribute*) = 0;
};

class VInfoObserver {
public:
    VInfoObserver()          = default;
    virtual ~VInfoObserver() = default;

    virtual void notifyDataLost(VInfo*) = 0;
    virtual void notifyDelete(VInfo*)   = 0;
};

#endif /* ecflow_viewer_VInfo_HPP */
