#ifndef CODEINSTRUCTIONS_H
#define CODEINSTRUCTIONS_H

#include "ast.h"

#include "llvmlayer.h"
#include "pass/compilepass.h"
#include "compilation/advanced.h"

#include "query/context.h"
#include "query/containers.h"

namespace xreate {
    namespace containers {

using namespace llvm;

class Iterator{
public :
    virtual llvm::Value* begin() =0;
    virtual llvm::Value* end() = 0;
    virtual llvm::Value* get(llvm::Value* index,const std::string& hintRetVar="") = 0;
    virtual llvm::Value* advance(llvm::Value* index, const std::string& hintRetVar="")=0;
    virtual ~Iterator(){};

    static Iterator* create(xreate::compilation::Context context, const xreate::Symbol& var);
};

template<ImplementationType I>
class IteratorForward;

template<>
class IteratorForward<ON_THE_FLY> : public Iterator {
private:
    LLVMLayer* llvm;
    const xreate::Symbol current;
    const Symbol source;
    const ImplementationLinkedList linkedlist;
    CodeScope* const sourceScope;
            //TODO initialize and mark as const (three fields)
    compilation::CodeScopeUnit* sourceUnit;
    compilation::FunctionUnit* function; //TODO is used somewhere?
    const Expression& sourceDecl;
    compilation::Context context;
    llvm::Type* sourceRawType =nullptr;

public:
    IteratorForward(const compilation::Context& ctx, const xreate::Symbol& s, const ImplementationRec<ON_THE_FLY>& implementation)
    :   llvm(ctx.pass->man->llvm), 
        current(s), 
        source(implementation.source), 
        linkedlist(source), 
        sourceScope(source.scope),
        sourceUnit(new compilation::CodeScopeUnit(source.scope, ctx.function, ctx.pass)),
        sourceDecl(CodeScope::findDeclaration(source)),
        context(ctx)
    {}
    
    llvm::Value* begin() override;
    llvm::Value* end() override;
    llvm::Value* get(llvm::Value* index,const std::string& hintRetVar="") override;
    llvm::Value* advance(llvm::Value* index, const std::string& hintRetVar="") override;
};

template<>
class IteratorForward<SOLID>: public Iterator{
    size_t __length;
    llvm::Value* __container;
    LLVMLayer* llvm;
    
public:
    IteratorForward(const compilation::Context& ctx, const xreate::Symbol& symbolContainer, const ImplementationRec<SOLID>& implementation);
    llvm::Value* begin() override;
    llvm::Value* end() override;
    llvm::Value* get(llvm::Value* index,const std::string& hintRetVar="") override;
    llvm::Value* advance(llvm::Value* index, const std::string& hintRetVar="") override;
};
}}

#endif //CODEINSTRUCTIONS_H
