'use strict'; const tapahtumaTyypit = { lisääAste: 'lisääAste', poistaAste: 'poistaAste', muutaAste: 'muutaAste', lisääLuokka: 'lisääLuokka', poistaLuokka: 'poistaLuokka', lisääOpettaja: 'lisääOpettaja', poistaOpettaja: 'poistaOpettaja', lisääTila: 'lisääTila', poistaTila: 'poistaTila', lisääTunti: 'lisääTunti', poistaTunti: 'poistaTunti', lisääTuntiLuokka: 'lisääTuntiLuokka', poistaTuntiLuokka: 'poistaTuntiLuokka', lisääTuntiOpettaja: 'lisääTuntiOpettaja', poistaTuntiOpettaja: 'poistaTuntiOpettaja', lisääTuntiTila: 'lisääTuntiTila', poistaTuntiTila: 'poistaTuntiTila', }; class Tapahtuma { constructor(tyyppi, argumentit) { this.tyyppi = tyyppi; this.argumentit = argumentit; } } let historia, tulevaisuus; let luokkaAsteet, opettajat, tilat, tunnit; alustaMalli(); function alustaMalli() { historia = []; tulevaisuus = []; luokkaAsteet = new LuokkaAsteet(); opettajat = new Opettajat(); tilat = new Tilat(); tunnit = new Tunnit(); } function suorita(tyyppi, ...argumentit) { let paluuarvo = undefined; switch (tyyppi) { case tapahtumaTyypit.lisääAste: assertRange('lisääAste argumentit', argumentit.length, 0, 1); paluuarvo = luokkaAsteet.lisää(...argumentit) break; case tapahtumaTyypit.poistaAste: assertEq('poistaAste argumentit', argumentit.length, 1); let [poistettuAste] = argumentit; luokkaAsteet.poista(poistettuAste); // Poista poistettujen luokka-asteiden luokat tunneista for (let [_, tunti] of tunnit.tunnit) { for (let luokka of tunti.luokat.alkiot()) { let luokanAste = parseInt(luokka[0]); if (luokanAste === poistettuAste) { tunti.luokat.poista(luokka); } } } break; case tapahtumaTyypit.muutaAste: assertEq('muutaAste argumentit', argumentit.length, 2); let [vanhaAste, uusiAste] = argumentit; luokkaAsteet.muuta(vanhaAste, uusiAste); // Muuta muutetut luokka-asteet tunneissa for (let [_, tunti] of tunnit.tunnit) { for (let luokka of tunti.luokat.alkiot()) { let luokanAste = parseInt(luokka[0]); if (luokanAste === vanhaAste) { let uusiLuokka = `${uusiAste}${luokka.slice(1)}`; tunti.luokat.poista(luokka); tunti.luokat.lisää(uusiLuokka); } } } break; case tapahtumaTyypit.lisääLuokka: assertEq('lisääLuokka argumentit', argumentit.length, 1); luokkaAsteet.asteet[argumentit[0]].lisää(); break; case tapahtumaTyypit.poistaLuokka: assertEq('poistaLuokka argumentit', argumentit.length, 1); let [aste] = argumentit; luokkaAsteet.asteet[aste].poista(); // Poista luokka jota ei enää ole asteella tunneista for (let [_, tunti] of tunnit.tunnit) { for (let luokka of tunti.luokat.alkiot()) { if (luokkaAsteet.luokat().indexOf(luokka) === -1) { tunti.luokat.poista(luokka); } } } break; case tapahtumaTyypit.lisääOpettaja: assertEq('lisääOpettaja argumentit', argumentit.length, 2); opettajat.lisää(...argumentit); break; case tapahtumaTyypit.poistaOpettaja: assertEq('poistaOpettaja argumentit', argumentit.length, 1); let [poistettuOpettaja] = argumentit; opettajat.poista(poistettuOpettaja); // Poista opettaja joita ei enää ole tunneista for (let [_, tunti] of tunnit.tunnit) { tunti.opettajaLyhenteet.poista(poistettuOpettaja); } break; case tapahtumaTyypit.lisääTila: assertEq('lisääTila argumentit', argumentit.length, 1); paluuarvo = tilat.lisää(...argumentit); break; case tapahtumaTyypit.poistaTila: assertEq('poistaTila argumentit', argumentit.length, 1); let [poistettuTila] = argumentit; tilat.poista(poistettuTila); for (let [_, tunti] of tunnit.tunnit) { tunti.tilat.poista(poistettuTila); } break; case tapahtumaTyypit.lisääTunti: assertEq('lisääTunti argumentit', argumentit.length, 4); paluuarvo = tunnit.lisää(...argumentit); break; case tapahtumaTyypit.poistaTunti: assertEq('poistaTunti argumentit', argumentit.length, 1); tunnit.poista(...argumentit); break; case tapahtumaTyypit.lisääTuntiLuokka: assertEq('lisääTuntiLuokka argumentit', argumentit.length, 2); tunnit.tunnit.get(argumentit[0]).luokat.lisää(argumentit[1]); break; case tapahtumaTyypit.poistaTuntiLuokka: assertEq('poistaTuntiLuokka argumentit', argumentit.length, 2); tunnit.tunnit.get(argumentit[0]).luokat.poista(argumentit[1]); break; case tapahtumaTyypit.lisääTuntiOpettaja: assertEq('lisääTuntiOpettaja argumentit', argumentit.length, 2); tunnit.tunnit.get(argumentit[0]).opettajaLyhenteet.lisää(argumentit[1]); break; case tapahtumaTyypit.poistaTuntiOpettaja: assertEq('poistaTuntiOpettajat argumentit', argumentit.length, 2); tunnit.tunnit.get(argumentit[0]).opettajaLyhenteet.poista(argumentit[1]); break; case tapahtumaTyypit.lisääTuntiTila: assertEq('lisääTuntiTila argumentit', argumentit.length, 2); tunnit.tunnit.get(argumentit[0]).tilat.lisää(argumentit[1]); break; case tapahtumaTyypit.poistaTuntiTila: assertEq('poistaTuntiTila argumentit', argumentit.length, 2); tunnit.tunnit.get(argumentit[0]).tilat.poista(argumentit[1]); break; default: throw new Error(`tuntematon tapahtumatyyppi ${tyyppi}`); } historia.push(new Tapahtuma(tyyppi, argumentit)); tulevaisuus = []; return paluuarvo; } function kumoa() { if (historia.length === 0) { return; } // Kumoaminen tapahtuu ottamalla historia uusinta tapahtumaa lukuun // ottamatta ja suorittamalla se siihen asti uudestaan tyhjältä mallilta let kumottu = historia.pop(); let uusi_tulevaisuus = tulevaisuus.concat(kumottu); let vanha_historia = historia; alustaMalli(); for (let {tyyppi, argumentit} of vanha_historia) { suorita(tyyppi, ...argumentit); } tulevaisuus = uusi_tulevaisuus; } function teeUudelleen() { if (tulevaisuus.length === 0) { return; } let {tyyppi, argumentit} = tulevaisuus.pop(); // Tulevaisuus tulee tallentaa, sillä suorita() tuhoaa sen let uusi_tulevaisuus = tulevaisuus; suorita(tyyppi, ...argumentit); tulevaisuus = uusi_tulevaisuus; } testi('mallin alustaminen', () => { historia = undefined; tulevaisuus = undefined; luokkaAsteet = undefined; opettajat = undefined; tilat = undefined; tunnit = undefined; alustaMalli(); assertNe('historia', historia, undefined); assertNe('tulevaisuus', tulevaisuus, undefined); assertNe('luokkaAsteet', luokkaAsteet, undefined); assertNe('opettajat', opettajat, undefined); assertNe('tilat', tilat, undefined); assertNe('tunnit', tunnit, undefined); }); testi('tapahtumahistoria', () => { alustaMalli(); suorita(tapahtumaTyypit.lisääAste); suorita(tapahtumaTyypit.poistaAste, 1); assertEq('historia.length', historia.length, 2); assertEq('historia[0].tyyppi', historia[0].tyyppi, tapahtumaTyypit.lisääAste); assertEq('historia[0].argumentit.length', historia[0].argumentit.length, 0); assertEq('historia[1].tyyppi', historia[1].tyyppi, tapahtumaTyypit.poistaAste); assertEq('historia[1].argumentit.length', historia[1].argumentit.length, 1); assertEq('historia[1].argumentit[0]', historia[1].argumentit[0], 1); assertThrow('poistaAste 1', 'luokka-astetta 1 ei ole olemassa', () => { suorita(tapahtumaTyypit.poistaAste, 1); }); assertEq('historia.length poikkeuksen jälkeen', historia.length, 2); alustaMalli(); }); testi('kumoamiminen', () => { alustaMalli(); kumoa(); suorita(tapahtumaTyypit.lisääAste); suorita(tapahtumaTyypit.lisääLuokka, 1); suorita(tapahtumaTyypit.lisääAste); suorita(tapahtumaTyypit.lisääLuokka, 2); suorita(tapahtumaTyypit.lisääLuokka, 1); assertEq('aluksi 1. aste', luokkaAsteet.asteet[1].luokat(), ['A', 'B', 'C']); assertEq('aluksi 2. aste', luokkaAsteet.asteet[2].luokat(), ['A', 'B']); kumoa(); assertEq('kerran 1. aste', luokkaAsteet.asteet[1].luokat(), ['A', 'B']); assertEq('kerran 2. aste', luokkaAsteet.asteet[2].luokat(), ['A', 'B']); kumoa(); assertEq('kahdesti 1. aste', luokkaAsteet.asteet[1].luokat(), ['A', 'B']); assertEq('kahdesti 2. aste', luokkaAsteet.asteet[2].luokat(), ['A']); kumoa(); assertEq('kolmesti 1. aste', luokkaAsteet.asteet[1].luokat(), ['A', 'B']); assertEq('kolmesti 2. aste', luokkaAsteet.asteet[2], undefined); kumoa(); assertEq('neljästi 1. aste', luokkaAsteet.asteet[1].luokat(), ['A']); kumoa(); assertEq('viidesti 1. aste', luokkaAsteet.asteet[1], undefined); alustaMalli(); }); testi('uudelleen tekeminen', () => { alustaMalli(); teeUudelleen(); suorita(tapahtumaTyypit.lisääAste); suorita(tapahtumaTyypit.lisääAste); suorita(tapahtumaTyypit.lisääLuokka, 1); suorita(tapahtumaTyypit.lisääLuokka, 2); suorita(tapahtumaTyypit.lisääLuokka, 2); kumoa(); kumoa(); kumoa(); assertEq('aluksi 1. aste', luokkaAsteet.asteet[1].luokat(), ['A']); assertEq('aluksi 2. aste', luokkaAsteet.asteet[2].luokat(), ['A']); teeUudelleen(); assertEq('kerran 1. aste', luokkaAsteet.asteet[1].luokat(), ['A', 'B']); assertEq('kerran 2. aste', luokkaAsteet.asteet[2].luokat(), ['A']); teeUudelleen(); assertEq('kahdesti 1. aste', luokkaAsteet.asteet[1].luokat(), ['A', 'B']); assertEq('kahdesti 2. aste', luokkaAsteet.asteet[2].luokat(), ['A', 'B']); suorita(tapahtumaTyypit.lisääLuokka, 1); teeUudelleen(); assertEq('kolmesti 1. aste', luokkaAsteet.asteet[1].luokat(), ['A', 'B', 'C']); assertEq('kolmesti 2. aste', luokkaAsteet.asteet[2].luokat(), ['A', 'B']); alustaMalli(); }); testi('asteiden käsittely', () => { alustaMalli(); assertEq('lisää', suorita(tapahtumaTyypit.lisääAste), 1); suorita(tapahtumaTyypit.muutaAste, 1, 2); assertEq('muutettua seuraava aste', luokkaAsteet.seuraavaAste(), 3); suorita(tapahtumaTyypit.poistaAste, 2); assertEq('lopuksi seuraava aste', luokkaAsteet.seuraavaAste(), 1); alustaMalli(); }); testi('luokkien käsittely', () => { alustaMalli(); suorita(tapahtumaTyypit.lisääAste); assertEq('aluksi', luokkaAsteet.asteet[1].luokat(), ['A']); suorita(tapahtumaTyypit.lisääLuokka, 1); assertEq('lisättyä', luokkaAsteet.asteet[1].luokat(), ['A', 'B']); suorita(tapahtumaTyypit.poistaLuokka, 1); assertEq('poistettua', luokkaAsteet.asteet[1].luokat(), ['A']); alustaMalli(); }); testi('opettajien käsittely', () => { alustaMalli(); assertEq('aluksi', opettajat.opettajat(), []); suorita(tapahtumaTyypit.lisääOpettaja, 'MM', 'Maija Meikäläinen'); assertEq('lisättyä', opettajat.opettajat(), [['MM', 'Maija Meikäläinen']]); suorita(tapahtumaTyypit.poistaOpettaja, 'MM'); assertEq('poistettua', opettajat.opettajat(), []); }); testi('tilojen käsittely', () => { alustaMalli(); assertEq('aluksi', tilat.tilat(), []); assertEq('1A', suorita(tapahtumaTyypit.lisääTila, '1A'), 0); assertEq('lisättyä', tilat.tilat(), [[0, '1A']]); suorita(tapahtumaTyypit.poistaTila, 0); assertEq('poistettua', tilat.tilat(), []); alustaMalli(); }); testi('tuntien käsittely', () => { alustaMalli(); suorita(tapahtumaTyypit.lisääAste); suorita(tapahtumaTyypit.lisääAste); suorita(tapahtumaTyypit.lisääAste, 5); suorita(tapahtumaTyypit.lisääLuokka, 5); suorita(tapahtumaTyypit.lisääOpettaja, 'KV', 'Kari Virtanen'); suorita(tapahtumaTyypit.lisääOpettaja, 'AS', 'Aili Savolainen'); suorita(tapahtumaTyypit.lisääOpettaja, 'MM', 'Maija Meikäläinen'); suorita(tapahtumaTyypit.lisääOpettaja, 'MaM', 'Matti Meikäläinen'); suorita(tapahtumaTyypit.lisääTila, '1A'); suorita(tapahtumaTyypit.lisääTila, '5B'); suorita(tapahtumaTyypit.lisääTila, 'Käsityöluokka'); suorita(tapahtumaTyypit.lisääTila, '5A'); assertEq('aluksi', tunnit.järjestyksessä(), []); assertEq('historia', suorita(tapahtumaTyypit.lisääTunti, ['Historia'], ['5B'], ['KV'], [1]), 0 ); assertEq('äidinkieli', suorita(tapahtumaTyypit.lisääTunti, ['Äidinkieli'], ['1A'], ['AS'], [0]), 1 ); assertEq('kuvataide', suorita(tapahtumaTyypit.lisääTunti, ['Kuvataide'], ['5A'], ['MM'], [2]), 2 ); assertEq('lisättyä pituus', tunnit.järjestyksessä().length, 3); suorita(tapahtumaTyypit.poistaAste, 1); assertEq('aste poistettua 0', tunnit.järjestyksessä()[0][1].luokat.alkiot(), ['5B']); assertEq('aste poistettua 1', tunnit.järjestyksessä()[1][1].luokat.alkiot(), ['5A']); assertEq('aste poistettua 2', tunnit.järjestyksessä()[2][1].luokat.alkiot(), []); suorita(tapahtumaTyypit.muutaAste, 5, 6); assertEq('aste muutettua 0', tunnit.järjestyksessä()[0][1].luokat.alkiot(), ['6B']); assertEq('aste muutettua 1', tunnit.järjestyksessä()[1][1].luokat.alkiot(), ['6A']); assertEq('aste muutettua 2', tunnit.järjestyksessä()[2][1].luokat.alkiot(), []); suorita(tapahtumaTyypit.poistaLuokka, 6); assertEq('luokka poistettua 0', tunnit.järjestyksessä()[0][1].luokat.alkiot(), []); assertEq('luokka poistettua 1', tunnit.järjestyksessä()[1][1].luokat.alkiot(), ['6A']); assertEq('luokka poistettua 1', tunnit.järjestyksessä()[2][1].luokat.alkiot(), []); suorita(tapahtumaTyypit.poistaOpettaja, 'KV'); assertEq('opettaja poistettua 0', tunnit.järjestyksessä()[0][1].opettajaLyhenteet.alkiot(), []); assertEq('opettaja poistettua 1', tunnit.järjestyksessä()[1][1].opettajaLyhenteet.alkiot(), ['MM']); assertEq('opettaja poistettua 2', tunnit.järjestyksessä()[2][1].opettajaLyhenteet.alkiot(), ['AS']); suorita(tapahtumaTyypit.poistaTila, 1); assertEq('tila poistettua 0', tunnit.järjestyksessä()[0][1].tilat.alkiot(), []); assertEq('tila poistettua 1', tunnit.järjestyksessä()[1][1].tilat.alkiot(), [2]); assertEq('tila poistettua 2', tunnit.järjestyksessä()[2][1].tilat.alkiot(), [0]); suorita(tapahtumaTyypit.lisääTuntiLuokka, 0, '2A'); assertEq('luokka lisättyä tunnille 0', tunnit.järjestyksessä()[0][1].luokat.alkiot(), ['2A']); assertEq('luokka lisättyä tunnille 1', tunnit.järjestyksessä()[1][1].luokat.alkiot(), ['6A']); assertEq('luokka lisättyä tunnille 2', tunnit.järjestyksessä()[2][1].luokat.alkiot(), []); suorita(tapahtumaTyypit.poistaTuntiLuokka, 2, '6A'); assertEq('luokka poistettua tunnilta 0', tunnit.järjestyksessä()[0][1].luokat.alkiot(), ['2A']); assertEq('luokka poistettua tunnilta 1', tunnit.järjestyksessä()[1][1].luokat.alkiot(), []); assertEq('luokka poistettua tunnilta 2', tunnit.järjestyksessä()[2][1].luokat.alkiot(), []); suorita(tapahtumaTyypit.lisääTuntiOpettaja, 0, 'MaM'); assertEq('opettaja lisättyä tunnille 0', tunnit.järjestyksessä()[0][1].opettajaLyhenteet.alkiot(), ['MaM']); assertEq('opettaja lisättyä tunnille 1', tunnit.järjestyksessä()[1][1].opettajaLyhenteet.alkiot(), ['MM']); assertEq('opettaja lisättyä tunnille 2', tunnit.järjestyksessä()[2][1].opettajaLyhenteet.alkiot(), ['AS']); suorita(tapahtumaTyypit.poistaTuntiOpettaja, 2, 'MM'); assertEq('opettaja poistettua tunnilta 0', tunnit.järjestyksessä()[0][1].opettajaLyhenteet.alkiot(), ['MaM']); assertEq('opettaja poistettua tunnilta 1', tunnit.järjestyksessä()[1][1].opettajaLyhenteet.alkiot(), []); assertEq('opettaja poistettua tunnilta 2', tunnit.järjestyksessä()[2][1].opettajaLyhenteet.alkiot(), ['AS']); suorita(tapahtumaTyypit.lisääTuntiTila, 0, 3); assertEq('tila lisäätyä tunnille 0', tunnit.järjestyksessä()[0][1].tilat.alkiot(), [3]); assertEq('tila lisäätyä tunnille 1', tunnit.järjestyksessä()[1][1].tilat.alkiot(), [2]); assertEq('tila lisäätyä tunnille 2', tunnit.järjestyksessä()[2][1].tilat.alkiot(), [0]); suorita(tapahtumaTyypit.poistaTuntiTila, 1, 0); assertEq('tila poistettua tunnilta 0', tunnit.järjestyksessä()[0][1].tilat.alkiot(), [3]); assertEq('tila poistettua tunnilta 1', tunnit.järjestyksessä()[1][1].tilat.alkiot(), [2]); assertEq('tila poistettua tunnilta 2', tunnit.järjestyksessä()[2][1].tilat.alkiot(), []); suorita(tapahtumaTyypit.poistaTunti, 0); assertEq('poistettua pituus', tunnit.järjestyksessä().length, 2); alustaMalli(); });