#pragma once

#include "../Distribution/Distribution.h"
#include "errors.h"
#include "graph_loops.h"
#include "types.h"

void createParallelDirectives(const std::map<LoopGraph*, std::map<DIST::Array*, ArrayInfo*>> &loopInfo,
                              const std::vector<ParallelRegion*>& regions, 
                              const std::map<DIST::Array*, std::set<DIST::Array*>> &arrayLinksByFuncCalls,
                              std::vector<Messages> &messagesForFile);

void selectParallelDirectiveForVariant(File* file,
                                       ParallelRegion* currReg,
                                       DIST::GraphCSR<int, double, attrType>& reducedG,
                                       DIST::Arrays<int>& allArrays,
                                       const std::vector<LoopGraph*>& loopGraph,
                                       const std::map<int, LoopGraph*>& mapLoopGraph,
                                       const std::map<std::string, FuncInfo*>& mapFuncInfo,
                                       const std::vector<std::pair<DIST::Array*, const DistrVariant*>>& distribution,
                                       std::vector<Directive*>& toInsert,
                                       const uint64_t regionId,
                                       const std::map<DIST::Array*, std::set<DIST::Array*>>& arrayLinksByFuncCalls,
                                       const std::map<LoopGraph*, void*>& depInfoForLoopGraph,
                                       std::vector<Messages>& messages);

void filterParallelDirectives(const std::map<std::string, std::vector<LoopGraph*>>& loopGraph,
                              std::map<std::string, std::vector<Directive*>>& createdDirectives);

bool analyzeLoopBody(LoopGraph* loopV,
                     std::map<DIST::Array*, std::vector<std::pair<bool, std::pair<std::string, int>>>>& leftValues,
                     std::map<DIST::Array*, std::vector<std::pair<bool, std::map<std::string, std::pair<int, int>>>>>& rightValues,
                     std::string& base,
                     const std::map<DIST::Array*, std::vector<bool>>& dimsNotMatch,
                     const std::map<std::string, FuncInfo*>& mapFuncInfo);

std::pair<std::vector<Directive*>, std::vector<Directive*>> createRealignRules(Statement* spStat, const uint64_t regId, File* file, const std::string& templClone,
                                                                               const std::map<DIST::Array*, std::set<DIST::Array*>>& arrayLinksByFuncCalls, 
                                                                               const std::set<DIST::Array*>& usedArrays,
                                                                               const std::pair<int, int>);

DIST::Array* getRealArrayRef(DIST::Array* in, const uint64_t regId, const std::map<DIST::Array*, std::set<DIST::Array*>>& arrayLinksByFuncCalls);

void shiftAlignRulesForTemplates(const std::set<DIST::Array*>& arrays, const uint64_t regId, DataDirective& dataDirectives, const std::map<DIST::Array*, std::set<DIST::Array*>>& arrayLinksByFuncCalls);

void createShadowSpec(const std::map<std::string, std::vector<LoopGraph*>>& loopGraph, const std::map<DIST::Array*, std::set<DIST::Array*>>& arrayLinksByFuncCalls, const std::set<DIST::Array*>& forArrays);

void addShadowFromAnalysis(ParallelDirective* dir, const std::map<DIST::Array*, ArrayInfo*>& currAccesses);

bool checkForConflict(const std::map<DIST::Array*, ArrayInfo*>& currAccesses,
                      const LoopGraph* currentLoop,
                      std::map<DIST::Array*, std::pair<int, std::pair<int, int>>, DIST::ArrayComparator>& arrayWriteAcc,
                      const std::vector<std::pair<std::pair<std::string, std::string>, std::vector<std::pair<int, int>>>>& acrossInfo,
                      std::set<DIST::Array*>& acrossOutArrays);

void createParallelDirs(File* file,
                        std::map<std::string, std::vector<Directive*>>& createdDirectives,
                        std::vector<Messages>& messages,
                        const std::vector<LoopGraph*>& loopsInFile,
                        const std::map<std::string, std::vector<FuncInfo*>>& allFuncInfo,
                        const std::vector<ParallelRegion*>& parallelRegions,
                        const std::map<LoopGraph*, void*>& depInfoForLoopGraph,
                        const std::map<DIST::Array*, std::set<DIST::Array*>>& arrayLinksByFuncCalls);