import { round, zipWith, orderBy } from "lodash";



export default {
    state: {
        wanted_loops: [],
        removed_loops: [],

        sorted_by: null
    },
    getters: {
        all: (state, getters) => ({
            colorName: {
                selector: (l) => l.id,
                title: "Name",
                censor: true,
                colorSelector: (l) => l.color
            },
            name: {
                selector: (l) => l.id,
                censor: true,
                title: "Name",
            },
            source: {
                selector: (l) => l.source,
                title: "Source"
            },
            from: {
                selector: (l) => l.start,
                title: "From"
            },
            to: {
                selector: (l) => l.end,
                title: "To"
            },
            distance: {
                selector: (l) => round(l.distance, 2),
                title: "D"
            },
            delta: {
                selector: (l) => round(l.delta, 2),
                title: "δ"
            },
            theta: {
                selector: (l) => round(l.theta, 2),
                title: "θ"
            },
            rho: {
                selector: (l) => round(l.rho, 2),
                title: "ϱ"
            },
            flexibility: {
                multiple: true,
                selectors: (p) => p.availableBfactors.map((flex) => (l) => l.flexibility[flex]),
                titles: (p) => p.availableBfactors
            },
            maxLoopCcorWithActive: {
                selector: (l) => {
                    let value = -getters.getMaxCcorWithActive(l.id, (l, l2id) => l.loopCorrelationWith(l2id));
                    if (isNaN(value)) {
                        return "-";
                    } else {
                        return value;
                    }
                },
                title: "Max. L-L"
            },
            maxCoilCcorWithActive: {
                selector: (l) => {
                    let value = -getters.getMaxCcorWithActive(l.id, (l, l2id) => l.maximumSubCorrelationWith(l2id));
                    if (isNaN(value)) {
                        return "-";
                    } else {
                        return value;
                    }
                },                title: "Max. SS-C"
            },
            replacementLoop: {
                selector: (l) => l.replacement?.id,
                censor: true,
                title: "Replacement"
            },
            id: {
                selector: (l) => l.id,
                title: "ID"
            }

        }),

        concrete_state_properties: (state, getters) => ({
            "protein-selection": [getters.all.name, getters.all.source, getters.all.from, getters.all.to],
            "loop-exploration": [getters.all.colorName, getters.all.source, getters.all.from, getters.all.to],
            "flexibility-filter": [getters.all.name, getters.all.from, getters.all.to, getters.all.flexibility],
            "crosscorelation-filter": [getters.all.name, getters.all.from, getters.all.to, getters.all.maxLoopCcorWithActive, getters.all.maxCoilCcorWithActive],
            "loop-pairing": [getters.all.name, getters.all.from, getters.all.to, getters.all.replacementLoop],
            "grafting": [getters.all.name, getters.all.from, getters.all.to, getters.all.replacementLoop]

        }),

        isLoopWanted: (state) => (loop_id) => {

            return state.wanted_loops.find((l) => l.id == loop_id) !== undefined;
        },

        getWantedLoops(state) {
            return state.wanted_loops;
        },
        getRemovedLoops(state) {
            return state.removed_loops;
        },
        getInterestingLoops(state) {
            return state.wanted_loops.concat(state.removed_loops)
        },
        getDisplayedStateProperties(state, getters) {
            if (getters.concrete_state_properties[getters.getCurrentWorkflowStep.id] == null) {
                throw "Unknown loops step"
            }
            let concrete_properties = [...getters.concrete_state_properties[getters.getCurrentWorkflowStep.id].filter(prop => !prop.multiple)]
            let scaffoldProtein = getters.getScaffold;

            if (scaffoldProtein != null) {
                let unresolvedProperties = getters.concrete_state_properties[getters.getCurrentWorkflowStep.id].filter(prop => prop.multiple);
                for (let prop of unresolvedProperties) {
                    let selectors = prop.selectors(scaffoldProtein);
                    let titles = prop.titles(scaffoldProtein);
                    concrete_properties = concrete_properties.concat(
                        zipWith(selectors, titles, (s, t) => {
                            return {
                                selector: s,
                                title: t
                            }
                        }))
                }
            }
            return concrete_properties;
        }
    },
    mutations: {
        addInterestingLoop(state, loop) {
            state.removed_loops.push(loop);
            state.sorted_by = null;

        },



        deleteInterestingLoop(state, loop) {
            state.removed_loops = state.removed_loops.filter(l => l.id != loop.id);
            state.wanted_loops = state.wanted_loops.filter(l => l.id != loop.id);

        },

        mutateWantedLoops(state, wanted_loops) {
            state.wanted_loops = wanted_loops;
            state.sorted_by = null;
        },

        mutateRemovedLoops(state, removed_loops) {
            state.removed_loops = removed_loops;
            state.sorted_by = null;
        },

        makeWanted(state, loop) {
            let wanted_loop = state.removed_loops.find(l => l.id == loop.id)
            if (wanted_loop == null) {
                throw new Error("Toggling an unknown loop");
            }
            state.removed_loops = state.removed_loops.filter(l => l.id != loop.id);
            state.wanted_loops.push(wanted_loop);
        },


        makeRemoved(state, loop) {
            let removed_loop = state.wanted_loops.find(l => l.id == loop.id)
            if (removed_loop == null) {
                throw new Error("Toggling an unknown loop");
            }
            state.wanted_loops = state.wanted_loops.filter(l => l.id != loop.id);
            state.removed_loops.push(removed_loop);
        },
        sortInterestingLoops(state, selector) {
            let order = state.sorted_by == null || (state.sorted_by.selector == selector && state.sorted_by.order == "desc")
                ? "asc"
                : "desc";
            state.sorted_by = {
                selector,
                order
            }
            state.wanted_loops = orderBy(state.wanted_loops, selector, order);
            state.removed_loops = orderBy(state.removed_loops, selector, order);

        }

    },
    actions: {
        makeInterestingLoop(context, { rawLoop }) {
            if (context.getters.getScaffold.name.toLowerCase() != rawLoop.pdb.toLowerCase()) {
                return;
            }
            if (!context.getters.getInterestingLoops.map(l => l.name).includes(rawLoop.id)) {
                context.commit("addInterestingLoop", rawLoop)
            }
        },
        deleteInterestingLoops(context, protein_name) {
            for (let loop of context.state.wanted_loops) {
                if (loop.protein.toLowerCase() == protein_name.toLowerCase()) {
                    context.commit("deleteInterestingLoop", loop);
                }
            }
        },
        toggleLoopWanted(context, loop) {
            if (!context.getters.isLoopWanted(loop.id)) {
                context.commit("makeWanted", loop);
            } else {
                context.commit("makeRemoved", loop);
            }
        }
    }
}