Opetushallitus/eperusteet-opintopolku

View on GitHub
eperusteet-opintopolku-app/yo/app/scripts/common/services/opsmenubuilders.ts

Summary

Maintainability
F
6 days
Test Coverage
/*
 * Copyright (c) 2013 The Finnish Board of Education - Opetushallitus
 *
 * This program is free software: Licensed under the EUPL, Version 1.1 or - as
 * soon as they will be approved by the European Commission - subsequent versions
 * of the EUPL (the "Licence");
 *
 * You may not use this work except in compliance with the Licence.
 * You may obtain a copy of the Licence at: http://ec.europa.eu/idabc/eupl
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * European Union Public Licence for more details.
 */

angular.module("app").factory("opsMenuBuilders", function(Algoritmit, $state, Kieli, Utils) {
    const createMenuByYear = vlk => {
        let menu = [];
        const createYears = (numbs, tunniste) => {
            let start = parseInt(numbs[0]);
            let stop = numbs[1] ? parseInt(numbs[1]) + 1 : start + 1;
            for (let i = start; i < stop; i++) {
                menu.push({
                    vuosi: "vuosiluokka_" + i,
                    _tunniste: tunniste,
                    vuosi_num: i
                });
            }
        };
        _.each(vlk, function(v) {
            menu.push(v);
            let nimi = v.nimi.fi || v.nimi.sv;
            let numbs = nimi.replace(/\D/g, "").split("");
            createYears(numbs, v._tunniste);
        });
        return menu;
    };

    var vlkMap = {};

    const rakennaVuosiluokkakokonaisuuksienMenu = (vlkt, aineet) => {
        vlkMap = _.indexBy(vlkt, "_tunniste");
        let vlkWithYears = createMenuByYear(vlkt);
        let arr = [];
        let lastVlk = null;
        let currentVuosi = null;

        _.each(vlkWithYears, function(vlk) {
            let vlkId = vlkMap[vlk._tunniste]["id"];
            if (!vlk.vuosi) {
                lastVlk = vlk;
                arr.push({
                    $vkl: vlk,
                    label: vlk.nimi,
                    depth: 0,
                    url: $state.href("root.ops.perusopetus.vuosiluokkakokonaisuus", { vlkId: vlk.id })
                });
                return arr;
            }
            arr.push({
                $vuosi: vlk.vuosi,
                label: vlk.vuosi,
                $vuosi_num: vlk.vuosi_num,
                $hidden: true,
                vlk: lastVlk.nimi,
                depth: 1,
                url: $state.href("root.ops.perusopetus.vuosiluokkakokonaisuus.vuosiluokka", {
                    vlkId: vlkId,
                    vuosi: vlk.vuosi_num
                })
            });
            currentVuosi = vlk.vuosi;
            traverseOppiaineet(aineet, arr, vlk._tunniste, 2, currentVuosi, null);
        });
        return arr;
    };

    //create an array of labels for the current vuosiloukat
    const createEachYearLabel = (arr, currentYears) => {
        let currentVlkt = [];
        let start = parseInt(currentYears[0]);
        let stop = currentYears[1] ? parseInt(currentYears[1]) + 1 : start + 1;
        for (let i = start; i < stop; i++) {
            currentVlkt.push("vuosiluokka_" + i);
        }
        return currentVlkt;
    };

    const oppiaineSort = (aineet, vlk = null) => {
        // Handle mixed jnro + no jnro situations
        const jnroSort = item => {
            let target = _(item.vuosiluokkakokonaisuudet)
                .filter(v => {
                    return v._vuosiluokkakokonaisuus === vlk;
                })
                .map("jnro")
                .first();
            return _.isNumber(target) ? target : 10000000;
        };
        return _(aineet)
            .sortBy(jnroSort)
            .sortBy(Utils.nameSort)
            .sortBy(jnroSort)
            .value();
    };

    function traverseOppiaineet(aineet, arr, vlk, startingDepth, currentVuosi, years) {
        let depth = startingDepth || 0;
        let currentYears =
            years ||
            arr[arr.length - 1].vlk.fi.replace(/\D/g, "").split("") ||
            arr[arr.length - 1].vlk.sv.replace(/\D/g, "").split("");

        let currentVlkt = createEachYearLabel(arr, currentYears);
        let isSisalto = depth === 0;

        /**
       * 1. include in a VLK, e.g. 'Vuosiluokat 1-2', if an oppiaine/oppimaara contains the TUNNISTE of that set of years
       * 2. then, include the oppiaine/maara in every year for that VLK if no vuosiluokat are specified for that VLK
       * 3. otherwise only include in the years specified in VUOSILUOKAT array on the oppiaine object
       */
        //NEW BUILDER
        let filteredAineet = _(aineet)
            .filter(oa => {
                return _.reduce(
                    oa.vuosiluokkakokonaisuudet,
                    (col, item: any, index, all) => {
                        if (item._vuosiluokkakokonaisuus === vlk) {
                            _.isEmpty(item.vuosiluokat) ? col.unshift("all") : col.unshift(item.vuosiluokat);
                        }
                        if (all.length - 1 === index) {
                            if (_.isEmpty(col)) return false;
                            return !!_.filter(_.flatten(col), function(item: any) {
                                return item === "all" ? true : item.vuosiluokka === currentVuosi;
                            }).length;
                        }
                        return col;
                    },
                    []
                );
            })
            .value();

        _.each(oppiaineSort(filteredAineet, vlk), function(oa) {
            buildOppiaineItem(arr, oa, vlk, depth, isSisalto, currentVuosi, { menuType: "vuosiluokittain" });
            if (oa.koosteinen && oa.oppimaarat.length > 0) {
                traverseOppiaineet(oa.oppimaarat, arr, vlk, 3, currentVuosi, currentYears);
            }
        });
    }

    function buildOppiaineItem(arr, oppiaine, vlk, depth, isSisalto, currentVuosi, opts) {
        if (!oppiaine.nimi[Kieli.getSisaltokieli()]) {
            return;
        }

        let piilotettu = false;
        const oaVlk: any = _.find(oppiaine.vuosiluokkakokonaisuudet, { _vuosiluokkakokonaisuus: vlk });
        if (oaVlk && oaVlk.piilotettu) {
            piilotettu = true;
        }

        let vlkId = vlk ? vlkMap[vlk]["id"] : null;
        let currentYear = currentVuosi ? currentVuosi[currentVuosi.length - 1] : null;
        let type = oppiaine.tyyppi === "yhteinen";
        let oppiaineUrl;
        if (opts["menuType"] === "vuosiluokittain") {
            oppiaineUrl = type
                ? $state.href("root.ops.perusopetus.vuosiluokkakokonaisuus.vuosiluokka.oppiaine", {
                      vlkId: vlkId,
                      vuosi: currentYear,
                      oppiaineId: oppiaine.id
                  })
                : $state.href("root.ops.perusopetus.vuosiluokkakokonaisuus.vuosiluokka.valinainenoppiaine", {
                      vlkId: vlkId,
                      vuosi: currentYear,
                      oppiaineId: oppiaine.id
                  });
        }
        if (opts["menuType"] === "oppiaineetMenu") {
            oppiaineUrl = type
                ? $state.href("root.ops.perusopetus.oppiaineet", {
                      oppiaineId: oppiaine.id
                  })
                : $state.href("root.ops.perusopetus.valinnaisetoppiaineet", {
                      oppiaineId: oppiaine.id
                  });
        }

        arr.push({
            depth: depth,
            $hidden: depth > 0,
            $oppiaine: oppiaine,
            $piilotettu: piilotettu,
            label: oppiaine.nimi,
            $parent_vuosi: currentVuosi,
            $tyyppi: oppiaine.tyyppi,
            url: oppiaineUrl
        });
    }

    const rakennaOppiaineetMenu = oppiaineet => {
        let menu = [];
        _.each(oppiaineSort(oppiaineet), function(oa) {
            buildOppiaineItem(menu, oa, null, 0, null, null, { menuType: "oppiaineetMenu" });
            if (oa.koosteinen && oa.oppimaarat.length > 0) {
                _.each(oppiaineSort(oa.oppimaarat), function(om) {
                    buildOppiaineItem(menu, om, null, 1, null, null, { menuType: "oppiaineetMenu" });
                });
            }
        });
        return menu;
    };

    const hasChild = (allChildren, id) => {
        return _.includes(allChildren, id);
    };

    interface Teksti {
        id: number;
        tunniste: string;
        lapset: Array<string>;
        tekstiKappale?: any;
        pakollinen: boolean;
        valmis: boolean;
    }

    interface hasChild {
        (id: number): boolean;
    }

    interface MenuItem {
        depth: number;
        $hidden: boolean;
        parent: number;
        $id: number;
        label: string;
        url: string;
    }

    interface MenuMaker {
        (
            current: Teksti,
            depth: number,
            menu: Array<MenuItem>,
            map: any,
            otsikot: Array<Teksti>,
            isChild: hasChild,
            parent?: number
        ): Array<MenuItem>;
    }

    let makeMenu: MenuMaker;

    makeMenu = (current, depth, menu, map, otsikot, isChild, parent) => {
        if (!otsikot.length) return menu;
        let teksti = map[current.id];
        if (parent) {
            menu.push({
                depth: depth,
                $hidden: depth > 0,
                parent: parent,
                $id: teksti.id,
                label: teksti.tekstiKappale.nimi,
                url: $state.href("root.amops.tekstikappale", { tekstikappaleId: teksti.id })
            });
        }
        if (current.lapset.length) {
            depth++;
            _.each(current.lapset, function(lapsiId: string) {
                otsikot.splice(_.indexOf(otsikot, map[lapsiId]), 1);
                return makeMenu(map[lapsiId], depth, menu, map, otsikot, isChild, current.id);
            });
        }
        let next = otsikot.shift();
        if (next && isChild(next.id)) return makeMenu(next, depth, menu, map, otsikot, isChild, parent);
        else return makeMenu(next, -1, menu, map, otsikot, isChild, null);
    };

    const rakennaAmopsTekstikappaleMenu = (otsikot: Array<Teksti>, rootInt: number): Array<MenuItem> => {
        const map = _.indexBy(otsikot, "id");
        const root = _.filter(otsikot, { id: rootInt })[0];
        let children = _.reduce(
            otsikot,
            (allChildren, teksti) => {
                return allChildren.concat(teksti.lapset);
            },
            []
        );
        let otsikotWithoutRoot = _.filter(otsikot, o => o.id != rootInt);
        return makeMenu(root, -1, [], map, otsikotWithoutRoot, _.partial(hasChild, children), null);
    };

    return {
        rakennaOppiaineetMenu: rakennaOppiaineetMenu,
        rakennaVuosiluokkakokonaisuuksienMenu: rakennaVuosiluokkakokonaisuuksienMenu,
        rakennaAmopsTekstikappaleMenu: rakennaAmopsTekstikappaleMenu
    };
});