/*
 * 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_node_Alias_HPP
#define ecflow_node_Alias_HPP

#include "ecflow/node/Submittable.hpp"

class Alias final : public Submittable {
public:
    explicit Alias(const std::string& name, bool check = true);
    Alias();
    Alias(const Alias&);
    Alias& operator=(const Alias&);
    node_ptr clone() const override;

    ~Alias() override;

    static alias_ptr create(const std::string& name, bool check = true);

    void print(std::string&) const override;
    bool operator==(const Alias& rhs) const;

    /// Overridden to reset the try number
    /// The tasks job can be invoked multiple times. For each invocation we want to preserve
    /// the output. The try number is used in SMSJOB/SMSJOBOUT to preserve the output when
    /// there are multiple runs.  re-queue/begin() resets the try Number
    void begin() override;
    void requeue(Requeue_args&) override;

    Suite* suite() const override { return parent()->suite(); }
    Defs* defs() const override {
        return (parent()) ? parent()->defs() : nullptr;
    } // exposed to python hence check for NULL first
    Alias* isAlias() const override { return const_cast<Alias*>(this); }
    Submittable* isSubmittable() const override { return const_cast<Alias*>(this); }

    const std::string& debugType() const override;

    node_ptr removeChild(Node* child) override;
    bool addChild(const node_ptr& child, size_t position = std::numeric_limits<std::size_t>::max()) override;
    bool isAddChildOk(Node* child, std::string& errorMsg) const override;

    const std::string& script_extension() const override;

    void collateChanges(DefsDelta&) const override;
    void set_memento(const SubmittableMemento* m, std::vector<ecf::Aspect::Type>& aspects, bool f) {
        Submittable::set_memento(m, aspects, f);
    }

    node_ptr find_node_up_the_tree(const std::string& name) const override;

    // Pure node Functions that are not implemented for aliases
    node_ptr find_relative_node(const std::vector<std::string>&) override { return node_ptr(); }

    void get_all_nodes(std::vector<node_ptr>& nodes) const override;

    // Functions unique to aliases
    // Alias variable names by pass checking of valid names, allowing anything
    void add_alias_variable(const std::string& name, const std::string& value);

private:
    size_t child_position(const Node*) const override;

    /// Job creation checking is typically called from python API
    /// This has been disabled for Aliases
    void check_job_creation(job_creation_ctrl_ptr) override {}

    // Overridden from Node to increment/decrement limits only
    // i.e we do not update parent computed states for aliases
    void handleStateChange() override;

    // Pure node Functions that are not implemented for aliases
    void accept(ecf::NodeTreeVisitor&) override {}
    void acceptVisitTraversor(ecf::NodeTreeVisitor&) override {}
    void get_all_tasks(std::vector<task_ptr>&) const override {}
    void get_all_aliases(std::vector<alias_ptr>&) const override {}
    void getAllNodes(std::vector<Node*>&) const override {}
    void getAllTasks(std::vector<Task*>&) const override {}
    void getAllSubmittables(std::vector<Submittable*>&) const override {}
    void get_all_active_submittables(std::vector<Submittable*>&) const override {}

    friend class cereal::access;
    template <class Archive>
    void serialize(Archive& ar, std::uint32_t const version);
};

std::ostream& operator<<(std::ostream& os, const Alias&);

#endif /* ecflow_node_Alias_HPP */
