/*
 * 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_SuiteFilter_HPP
#define ecflow_viewer_SuiteFilter_HPP

#include <string>
#include <vector>

#include "FlagSet.hpp"

class SuiteFilter;
class SuiteFilterObserver;
class VSettings;

#if 0
template <class T>
class FlagSet
{
public:
    FlagSet() : flags_(0) {}

    void clear() {flags_=0;}
    void set(T flag ) { flags_ |= (1 << flag); }
    void unset(T flag ) { flags_ &= ~ (1 << flag); }
    bool isSet(T flag) const { return (flags_ >> flag) & 1; }
    bool isEmpty() const {return flags_==0;}
    bool sameAs(T flag) const {return flags_ == flag;}

private:
    int flags_;

};

#endif

class SuiteFilterItem {
    friend class SuiteFilter;

public:
    SuiteFilterItem(const std::string& name, bool loaded, bool filtered)
        : name_(name),
          loaded_(loaded),
          filtered_(filtered) {}

    SuiteFilterItem(const SuiteFilterItem& other)            = default;
    SuiteFilterItem& operator=(const SuiteFilterItem& other) = default;

    bool operator!=(const SuiteFilterItem& rhs) const {
        return name_ != rhs.name_ || loaded_ != rhs.loaded_ || filtered_ != rhs.filtered_;
    }

    const std::string& name() const { return name_; }
    bool loaded() const { return loaded_; }
    bool filtered() const { return filtered_; }

protected:
    std::string name_;
    bool loaded_;
    bool filtered_;
};

class SuiteFilter {
public:
    SuiteFilter() = default;
    ~SuiteFilter();

    enum ChangeFlag { AutoAddChanged = 1, EnabledChanged = 2, ItemChanged = 4 };

    friend std::ostream& operator<<(std::ostream& aStream, const SuiteFilter& obj);

    SuiteFilter* clone();

    std::vector<std::string> filter() const;
    std::vector<std::string> loaded() const;
    const std::vector<SuiteFilterItem>& items() const { return items_; }

    int count() const { return static_cast<int>(items_.size()); }
    void setFiltered(int index, bool val);
    bool isOnlyOneFiltered(const std::string& oneSuite) const;
    bool isLoadedInitialised() const { return loadedInitialised_; }
    bool autoAddNewSuites() const { return autoAddNew_; }
    bool isEnabled() const { return enabled_; }

    void setLoadedInitialised(bool b) { loadedInitialised_ = b; }
    void setAutoAddNewSuites(bool b) { autoAddNew_ = b; }
    void setEnabled(bool b) { enabled_ = b; }
    void selectOnlyOne(const std::string& oneSuite);
    void selectAll();
    void unselectAll();
    bool removeUnloaded();
    bool hasUnloaded() const;

    bool sameAs(const SuiteFilter*) const;
    bool sameAsLoadedIgnored(const SuiteFilter*) const;
    bool merge(const SuiteFilter*);
    bool update(SuiteFilter*);
    bool setLoaded(const std::vector<std::string>& loaded, bool checkDiff = true);
    bool loadedSameAs(const std::vector<std::string>& loaded) const;
    const FlagSet<ChangeFlag>& changeFlags() { return changeFlags_; }

    bool hasObserver() const { return !observers_.empty(); }
    void addObserver(SuiteFilterObserver*);
    void removeObserver(SuiteFilterObserver*);

    void readSettings(VSettings* vs);
    void writeSettings(VSettings* vs);

    static const std::string dummySuite() { return dummySuite_; }

private:
    void clear();
    void adjust();
    void broadcastChange();
    bool adjustLoaded(const std::vector<std::string>& loaded);
    void adjustFiltered(const std::vector<std::string>& filtered);

    std::vector<SuiteFilterItem> items_;
    bool autoAddNew_{false};
    bool enabled_{false};
    bool loadedInitialised_{false};
    FlagSet<ChangeFlag> changeFlags_;
    std::vector<SuiteFilterObserver*> observers_;
    static std::string dummySuite_;
};

#endif /* ecflow_viewer_SuiteFilter_HPP */
