package ru.yandex.autotests.direct.analyzer.perl;

import ru.yandex.autotests.direct.analyzer.perl.PerlUse;
import ru.yandex.autotests.direct.analyzer.lexer.Lexem;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Created by alexey-n on 18.11.14.
 */
public class PerlModule {

    private Map<String, PerlFunction> declaredFunctions;
    private List<PerlUse> declaredUse;
    private String perlPackage;
    private List<Lexem> outOfFunctionLexem;
    private List<PerlFunction> calledFunction;

    public PerlModule() {
        declaredFunctions = new HashMap<String, PerlFunction>();
        declaredUse = new ArrayList<PerlUse>();
        outOfFunctionLexem = new ArrayList<Lexem>();
        calledFunction = new ArrayList<PerlFunction>();
    }

    public PerlFunction getFunction(String name) {
        return declaredFunctions.get(name);
    }

    public void putFunction(String name, PerlFunction function) {
        function.setPerlModule(this);
        declaredFunctions.put(name, function);
    }

    public List<PerlUse> getUse() {
        return declaredUse;
    }

    public void addUse(PerlUse use) {
        declaredUse.add(use);
    }

    public List<Lexem> getOutOfFunctionLexem() {
        return outOfFunctionLexem;
    }

    public void addOutOfFunctionLexem(Lexem lexem) {
        outOfFunctionLexem.add(lexem);
    }

    public String getPerlPackage() {
        return perlPackage;
    }

    public void setPerlPackage(String perlPackage) {
        this.perlPackage = perlPackage;
    }

    public Map<String, PerlFunction> getDeclaredFunctions() {
        return declaredFunctions;
    }

    public int getDeclaredFunctionsCount() {
        return declaredFunctions.size();
    }

    public void initCalledFunction() {
        for(Lexem lexem:outOfFunctionLexem) {
            if(lexem.getName().equals("Call") || lexem.getName().equals("Key") || lexem.getName().equals("Namespace")) {
                if (lexem.getData().equals("new")
                        || lexem.getData().equals("usage")
                        || lexem.getData().equals("options")
                        || lexem.getData().equals("type")
                        || lexem.getData().equals("strategy")
                        || lexem.getData().equals("error")
                        || lexem.getData().equals("data")
                        || lexem.getData().equals("Cmd")
                        || lexem.getData().equals("Description")) {
                    continue;
                }
                List<PerlFunction> functions = PerlScope.getFunction(lexem.getData());
                if (functions != null && functions.size() > 0) {
                    boolean collision = false, finded = false;
                    if (functions.size() == 1) {
                        if(!calledFunction.contains(functions.get(0))) {
                            calledFunction.add(functions.get(0));
                        }
                        finded = true;
                    } else {
                        for (PerlFunction function : functions) {
                            if (function.getPerlModule().getPerlPackage().equals(perlPackage)) {
                                finded = true;
                                if (!calledFunction.contains(function)) {
                                    calledFunction.add(function);
                                }
                                break;
                            }
                        }
                        if (!finded) {
                            for (PerlFunction function : functions) {
                                for (PerlUse perlUse : declaredUse) {
                                    if (function.getPerlModule().getPerlPackage().toLowerCase()
                                            .contains(perlUse.getUseString().toLowerCase())
                                            && perlUse.getUseString().length() >= 2) {
                                        if (finded == true && !calledFunction.contains(function)) {
                                            collision = true;
                                        }
                                        if (!calledFunction.contains(function) && !finded) {
                                            calledFunction.add(function);
                                        }
                                        finded = true;
                                    }
                                }
                            }
                        }
                    }
                    if (collision) {
                        calledFunction.remove(calledFunction.get(calledFunction.size() - 1));
                    }
                }
            }
        }
        for (PerlFunction perlFunction:declaredFunctions.values()) {
            perlFunction.initCalledFunction();
        }
    }

    public List<PerlFunction> getCalledFunction() {
        return calledFunction;
    }
}
