/*
 * 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_attribute_LateAttr_HPP
#define ecflow_attribute_LateAttr_HPP

#include <string>
#include <utility> // for pair
#include <vector>

#include "ecflow/core/Chrono.hpp"
#include "ecflow/core/TimeSlot.hpp"

class NState;

namespace ecf {
class Calendar;
} // namespace ecf

namespace ecf {
/// ========================================================================
/// Use compiler,  destructor, assignment, copy constructor,
///
/// ************************************************************************
/// late attribute: Only applies to a task, it can be set on suite/family
///                 but this is treated as an inherited attribute.
///                 late attribute lower down the hierarchy overrides it.
/// ************************************************************************
/// The late _late_ attribute will not work correctly when the suites clock
/// start and stops with the server. Since the late relies on real time
/// for some of its functionality.
/// -s submitted: The time node can stay submitted (format [+]hh:mm). submitted is always
///               relative, so + is simply ignored, if present. If the node stays submitted
///               longer than the time specified, the late flag is set
/// -a Active   : The time of day the node must have become active (format hh:mm). If the node
///               is still queued or submitted, the late flag is set
/// -c Complete : The time node must become complete (format {+}hh:mm). If relative, time is
///               taken from the time the node became active, otherwise node must be complete by
///               the time given.
/// ========================================================================
class LateAttr {
public:
    LateAttr();

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

    void addSubmitted(const TimeSlot& s) { s_ = s; }
    void add_submitted(int hour, int minute) { s_ = TimeSlot(hour, minute); }
    void addActive(const TimeSlot& s) { a_ = s; }
    void add_active(int hour, int minute) { a_ = TimeSlot(hour, minute); }
    void addComplete(const TimeSlot& s, bool relative) {
        c_        = s;
        c_is_rel_ = relative;
    }
    void add_complete(int hour, int minute, bool relative) {
        c_        = TimeSlot(hour, minute);
        c_is_rel_ = relative;
    }

    const TimeSlot& submitted() const { return s_; }
    const TimeSlot& active() const { return a_; }
    const TimeSlot& complete() const { return c_; }
    bool complete_is_relative() const { return c_is_rel_; }

    /// i.e no time structs specified
    bool isNull() const;

    /// Given the state and time of state change, and calendar work out if we are late
    /// if we are sets the late flag
    void checkForLateness(const std::pair<NState, boost::posix_time::time_duration>& state, const ecf::Calendar& c);
    bool check_for_lateness(const std::pair<NState, boost::posix_time::time_duration>& state,
                            const ecf::Calendar& c) const;

    ///  To be used by GUI to inform used that a node is late
    bool isLate() const { return isLate_; }

    /// To be called at begin and re-queue time
    void reset() { setLate(false); }

    // Override this late attributes with the settings form the input.
    void override_with(LateAttr*);

    // The state_change_no is never reset. Must be incremented if it can affect equality
    unsigned int state_change_no() const { return state_change_no_; }

    /// set flag to be late
    void setLate(bool f);

    std::string toString() const;
    std::string name() const { return toString(); }

    static void parse(LateAttr&, const std::string& line, const std::vector<std::string>& lineTokens, size_t index);
    static LateAttr create(const std::string& lateString);

public:
    void write(std::string&) const;

private:
    TimeSlot s_; // relative by default
    TimeSlot a_;
    TimeSlot c_;
    unsigned int state_change_no_{0}; // *not* persisted, only used on server side
    bool c_is_rel_{false};
    bool isLate_{false};

private:
    friend class cereal::access;
    template <class Archive>
    void serialize(Archive& ar);
};

} // namespace ecf

#endif /* ecflow_attribute_LateAttr_HPP */
