package _VisualDVM.Passes.All;
import Common.Utils.Index;
import Common.Utils.Utils_;
import _VisualDVM.Current;
import _VisualDVM.Global;
import _VisualDVM.Passes.PassCode;
import _VisualDVM.Passes.Sapfor.SapforAnalysis;
import _VisualDVM.ProjectData.Files.DBProjectFile;
import _VisualDVM.ProjectData.SapforData.Functions.FuncCall;
import _VisualDVM.ProjectData.SapforData.Functions.FuncInfo;
import _VisualDVM.ProjectData.SapforData.Functions.FunctionType;
import _VisualDVM.Visual.UI;

import java.util.LinkedHashMap;
import java.util.Vector;
public class SPF_GetGraphFunctions extends SapforAnalysis {
    @Override
    protected void showPreparation() {
        if (Global.mainModule.HasFile())
            Global.mainModule.getFile().form.ShowNoFunctions();
        UI.getMainWindow().getProjectWindow().ShowNoFunctions();
        if (SPF_GetGraphFunctionPositions.showByCurrentFunction)
            UI.getMainWindow().getProjectWindow().getFunctionsWindow().ShowNoCurrentFunction();
    }
    @Override
    protected boolean alwaysCheck() {
        return true;
    }
    @Override
    protected boolean isAtomic() {
        return false;
    }
    @Override
    protected void performPreparation() throws Exception {
        super.performPreparation(); //удаление интеррупта.
        Global.mainModule.set(Current.Function, null);
        Global.mainModule.set(Current.SelectedFunction, null);
        target.main_function = null;
        target.main_functionH = null;
        target.allFunctions.clear();
        target.functionsGraph.Clear();
        target.inline_root.removeAllChildren();
        target.inline_root2.removeAllChildren();
        //-
        target.numFunctions = 0;
        for (DBProjectFile file : target.db.files.Data.values())
            file.function_decls.clear();
    }
    @Override
    protected void unpack(String packed) throws Exception {
        LinkedHashMap<String, FuncInfo> declarated_functions = new LinkedHashMap<>();
        String[] splited = packed.split("\\|");
        Index idx = new Index();
        // new version of function graph reading, availible from Sapfor version 156
        int numOfFiles = Integer.parseInt(splited[idx.Inc()]);
        Vector<String> done_programs = new Vector<>();
        for (int i = 0; i < numOfFiles; ++i) {
            String fileName = Utils_.toW(splited[idx.Inc()]);
            int functions_count = Integer.parseInt(splited[idx.Inc()]);
            DBProjectFile file = target.db.files.Data.get(fileName);
            if (!done_programs.contains(fileName)) {
                int call_count = 0;
                done_programs.add(fileName);
                for (int k = 0; k < functions_count; ++k) {
                    String f_name = splited[idx.Inc()];
                    Index calls_number = new Index();
                    //тело функции
                    FuncInfo nf = new FuncInfo(f_name, file, splited[idx.Inc()].split("#"), calls_number);
                    if (nf.isMain()) {
                        file.isMain = 1;
                        target.main_function = nf;
                        target.db.Update(file);
                    }
                    declarated_functions.put(nf.funcName, nf);
                    //--------------------------------
                    file.function_decls.put(nf.funcName, nf);
                    //--------------------------------
                    call_count += calls_number.getValue();
                    for (int j = 0; j < calls_number.getValue(); ++j) {
                        String call_name = splited[idx.Inc()];
                        int c_line = Integer.parseInt(splited[idx.Inc()]);
                        //-
                        FuncCall fc = new FuncCall(file, call_name, c_line);
                        fc.parent_offset = nf.line - fc.line;
                        nf.calls.add(fc);
                    }
                }
                file.CallGraphTitle = "Объявлений : " + file.function_decls.size() + "; Вызовов : " + call_count;
            }
        }
        //---
        //вторая фаза распаковки. дополняем список стандартными и не найденными функциями
        //------
        LinkedHashMap<String, FuncInfo> special_functions = new LinkedHashMap<>();
        for (FuncInfo funcInfo : declarated_functions.values()) {
            for (FuncCall funcCall : funcInfo.calls) {
                if (!declarated_functions.containsKey(funcCall.funcName) && (
                        !special_functions.containsKey(funcCall.funcName)
                )) {
                    //нет среди объявленных и еще не встречалась. значит это стандартная либо не найдено объявление.
                    special_functions.put(funcCall.funcName,
                            new FuncInfo(funcCall.funcName,
                                    sapfor.isIntrinsic(funcCall.funcName) ?
                                            FunctionType.Standard : FunctionType.NotFound
                            ));
                }
            }
        }
        //------
        //составляем единый список функций.
        LinkedHashMap<String, FuncInfo> all_functions = target.allFunctions;
        declarated_functions.values().forEach(funcInfo -> all_functions.put(funcInfo.funcName, funcInfo));
        special_functions.values().forEach(funcInfo -> all_functions.put(funcInfo.funcName, funcInfo));
        //------
        //теперь когда известны все объявления, ищем где они вызвались
        //<editor-fold desc="Функции и их вызовы по файлам">
        target.BuildInlineGraph();
        //</editor-fold>
        //<editor-fold desc="иерархический граф.">
        target.BuildInlineGraph2();
        //--
        //</editor-fold>
        target.numFunctions += target.allFunctions.size();
        target.UpdateFunctionsCount();
    }
    @Override
    public String phase() {
        return "CALL_GRAPH2";
    }
    @Override
    protected void FocusResult() {
        super.FocusResult();
        if (Global.mainModule.HasFile())
            Global.mainModule.getFile().form.FocusFunctions();
        UI.getMainWindow().getProjectWindow().FocusFunctions();
    }
    @Override
    protected void showDone() throws Exception {
        super.showDone();
        UI.getMainWindow().getProjectWindow().getAnalysisWindow().ShowFunctionsCount();
        UI.getMainWindow().getProjectWindow().getAnalysisWindow().ShowRegions();
        if (Global.mainModule.HasFile())
            Global.mainModule.getFile().form.ShowFunctions();
        Global.mainModule.getPass(PassCode.SPF_GetGraphFunctionPositions).Do();
    }
}