#pragma once

#include <vector>
#include <map>
#include <set>
#include <string>
#include <cstdint>

#include "SgUtils.h"

struct ArrayDimension
{
    uint64_t start, step, tripCount;
    SgArrayRefExp* array;
};

class AccessingSet {
private:
    std::vector<std::vector<ArrayDimension>> allElements;

public:
    AccessingSet(std::vector<std::vector<ArrayDimension>> input) : allElements(input) {};
    AccessingSet() {};
    AccessingSet(const AccessingSet& a) { allElements = a.GetElements(); };
    const std::vector<std::vector<ArrayDimension>>& GetElements() const;
    void Insert(const std::vector<ArrayDimension>& element);
    AccessingSet Union(const AccessingSet& source);
    AccessingSet Intersect(const AccessingSet& secondSet) const;
    AccessingSet Diff(const AccessingSet& secondSet) const;
    bool ContainsElement(const std::vector<ArrayDimension>& element) const;
    void FindCoveredBy(const std::vector<ArrayDimension>& element, std::vector<std::vector<ArrayDimension>>& result) const;
    void FindUncovered(const std::vector<ArrayDimension>& element, std::vector<std::vector<ArrayDimension>>& result) const;
    friend bool operator!=(const AccessingSet& lhs, const AccessingSet& rhs);
};

using arrayAccessingIndexes = std::map<std::string, AccessingSet>;

bool operator!=(const ArrayDimension& lhs, const ArrayDimension& rhs);
bool operator!=(const AccessingSet& lhs, const AccessingSet& rhs);
bool operator!=(const arrayAccessingIndexes& lhs, const arrayAccessingIndexes& rhs);