'use strict'; class LuokkaAste { #luokat = 1; luokat() { // Tee lista, jossa on #luokat ensimmäistä isoa kirjainta let luokat = []; for (let i = 0; i < this.#luokat; i++) { luokat.push(String.fromCharCode(65 + i)); } return luokat; } lisää() { this.#luokat++; } poista() { if (this.#luokat <= 1) { throw new Error('viimeistä luokkaa ei voi poistaa asteelta'); } this.#luokat--; } } class LuokkaAsteet { asteet = []; luokat() { let luokat = []; for (let aste = 0; aste < this.asteet.length; aste++) { if (this.asteet[aste] !== undefined) { for (let luokka of this.asteet[aste].luokat()) { luokat.push(`${aste}${luokka}`); } } } return luokat; } seuraavaAste() { // Seuraava aste on yksi suurinta listassa jo olevaa astetta isompi, tai // 1 jos listassa ei vielä ole asteita let aste = 1; for (let i = 0; i < this.asteet.length; i++) { if (this.asteet[i] !== undefined) { aste = i + 1; } } return aste; } lisää(aste) { aste ??= this.seuraavaAste() if (this.asteet[aste] !== undefined) { throw new Error(`luokka-aste ${aste} on jo olemassa`); } let asteObjekti = new LuokkaAste(); this.asteet[aste] = asteObjekti; return aste; } poista(aste) { if (this.asteet[aste] === undefined) { throw new Error(`luokka-astetta ${aste} ei ole olemassa`); } this.asteet[aste] = undefined; } muuta(vanha, uusi) { if (vanha === uusi) { return; } // Heitä poikkeus jo ennen poistoa, jotta asteet-taulukkoon ei tule // mitään muutoksia poikkeustilanteessa if (this.asteet[uusi] !== undefined) { throw new Error(`luokka-aste ${uusi} on jo olemassa`); } let aste = this.asteet[vanha]; this.poista(vanha); this.asteet[uusi] = aste; } } class Opettajat { #opettajat = new Map(); opettajat() { let lista = Array.from(this.#opettajat.entries()); lista.sort(); return lista; } lyhenne(lyhenne) { return this.#opettajat.get(lyhenne); } lisää(lyhenne, nimi) { if (this.#opettajat.has(lyhenne)) { throw new Error(`opettaja on jo olemassa lyhenteellä ${lyhenne}`); } this.#opettajat.set(lyhenne, nimi); } poista(lyhenne) { if (!this.#opettajat.delete(lyhenne)) { throw new Error(`ei opettajaa lyhenteellä ${lyhenne}`); } } } class Tilat { #tilat = new Map(); #seuraavaId = 0; tilat() { let tilat = []; for (let [id, tila] of this.#tilat) { tilat.push([id, tila]); } tilat.sort((a, b) => { return vertaa(a[1], b[1]); }); return tilat; } id(id) { if (!this.#tilat.has(id)) { throw new Error(`ei tilaa ID:llä ${id}`); } return this.#tilat.get(id); } lisää(tila) { let id = this.#seuraavaId++; this.#tilat.set(id, tila); return id; } poista(id) { if (!this.#tilat.delete(id)) { throw new Error(`ei tilaa ID:llä ${id}`); } } } function tilojenNimet(tilat, tilaIDt) { let nimet = []; for (let id of tilaIDt) { nimet.push(tilat.id(id)); } return nimet; } class Tunti { constructor(nimi, luokat, opettajaLyhenteet, tilat) { this.nimi = nimi; this.luokat = new Joukko(luokat); this.opettajaLyhenteet = new Joukko(opettajaLyhenteet); this.tilat = new Joukko(tilat); } } class Tunnit { tunnit = new Map(); #seuraavaId = 0; lisää(nimi, luokka, opettajaLyhenne, tila) { let id = this.#seuraavaId++; this.tunnit.set( id, new Tunti(nimi, [luokka], [opettajaLyhenne], [tila]) ); return id; } poista(id) { if (!this.tunnit.delete(id)) { throw new Error(`ei tuntia ID:llä ${id}`); } } järjestyksessä() { let tunnit = []; for (let [id, tunti] of this.tunnit) { tunnit.push([id, tunti]); } tunnit.sort((a, b) => { let tulos = vertaa(a[1].nimi, b[1].nimi); // TODO: Korjaa niin, että osaa verrata okein listoja if (tulos === 0) { tulos = vertaa(a[1].luokat.alkiot(), b[1].luokat.alkiot()); } // TODO: Korjaa niin, että osaa verrata okein listoja if (tulos === 0) { tulos = vertaa(a[1].opettajaLyhenteet.alkiot(), b[1].opettajaLyhenteet.alkiot()); } // TODO: Vertaa tilojen nimiä if (tulos === 0) { tulos = vertaa(a[0], b[0]); } return tulos; }); return tunnit; } } class Joukko { #alkiot = new Map(); constructor(alkiot) { if (alkiot !== undefined) { for (let alkio of alkiot) { this.#alkiot.set(alkio, true); } } } alkiot() { let alkiot = []; for (let [alkio, _] of this.#alkiot) { alkiot.push(alkio); } alkiot.sort(); return alkiot; } lisää(alkio) { this.#alkiot.set(alkio, true); } poista(alkio) { this.#alkiot.delete(alkio); } } function vertaa(a, b) { if (a < b) { return -1; } else if (a > b) { return 1; } else { return 0; } } testi('seuraava aste', () => { let luokkaAsteet = new LuokkaAsteet(); assertEq('aluksi', luokkaAsteet.seuraavaAste(), 1); luokkaAsteet.lisää(); assertEq('asteen 1 jälkeen', luokkaAsteet.seuraavaAste(), 2); luokkaAsteet.lisää(3); assertEq('asteiden 1 ja 3 jälkeen', luokkaAsteet.seuraavaAste(), 4); luokkaAsteet.lisää(); assertEq('asteiden 1, 3, 4 jälkeen', luokkaAsteet.seuraavaAste(), 5); luokkaAsteet.poista(4); luokkaAsteet.poista(3); assertEq('asteet 3 ja 4 poistettua', luokkaAsteet.seuraavaAste(), 2); luokkaAsteet.muuta(1, 5); assertEq('aste 1 muutettua 5:ksi', luokkaAsteet.seuraavaAste(), 6); }); testi('asteiden lisääminen', () => { let luokkaAsteet = new LuokkaAsteet(); assertEq('1. aste', luokkaAsteet.lisää(), 1); assertEq('2. aste', luokkaAsteet.lisää(), 2); assertEq('3. aste', luokkaAsteet.lisää(3), 3); assertThrow('3. aste uudelleen', 'luokka-aste 3 on jo olemassa', () => { luokkaAsteet.lisää(3); }); assertEq('lisättyä', luokkaAsteet.luokat(), ['1A', '2A', '3A']); }); testi('asteiden poistaminen', () => { let luokkaAsteet = new LuokkaAsteet(); luokkaAsteet.lisää(); luokkaAsteet.lisää(); luokkaAsteet.poista(1); luokkaAsteet.poista(2); assertThrow('3. asteen poisto', 'luokka-astetta 3 ei ole olemassa', () => { luokkaAsteet.poista(3); }); assertEq('poistettua', luokkaAsteet.luokat(), []); }); testi('asteiden muuttaminen', () => { let luokkaAsteet = new LuokkaAsteet(); assertEq('lisääminen', luokkaAsteet.lisää(), 1); luokkaAsteet.muuta(1, 5); assertEq('muutettua', luokkaAsteet.luokat(), ['5A']); assertThrow('poisto', 'luokka-astetta 1 ei ole olemassa', () => { luokkaAsteet.poista(1); }); luokkaAsteet.poista(5); }); testi('luokkien lisääminen', () => { let luokkaAsteet = new LuokkaAsteet(); let aste = luokkaAsteet.asteet[luokkaAsteet.lisää()]; assertEq('aluksi', aste.luokat(), ['A']); aste.lisää(); aste.lisää(); assertEq('lisättyä', aste.luokat(), ['A', 'B', 'C']); }); testi('luokkien poistaminen', () => { let luokkaAsteet = new LuokkaAsteet(); let aste = luokkaAsteet.asteet[luokkaAsteet.lisää()]; aste.lisää(); aste.lisää(); aste.poista(); aste.poista(); assertThrow('viimeisen poisto', 'viimeistä luokkaa ei voi poistaa asteelta', () => { aste.poista(); }); assertEq('poistettua', aste.luokat(), ['A']); }); testi('opettajien lisääminen', () => { let opettajat = new Opettajat(); assertEq('aluksi', opettajat.opettajat(), []); opettajat.lisää('MM', 'Maija Meikäläinen'); opettajat.lisää('AS', 'Aili Savolainen'); opettajat.lisää('KV', 'Kari Virtanen'); assertThrow('sama lyhenne', 'opettaja on jo olemassa lyhenteellä MM', () => { opettajat.lisää('MM', 'Matti Meikäläinen'); }); opettajat.lisää('MaM', 'Matti Meikäläinen'); assertEq('lisättyä', opettajat.opettajat(), [ ['AS', 'Aili Savolainen'], ['KV', 'Kari Virtanen'], ['MM', 'Maija Meikäläinen'], ['MaM', 'Matti Meikäläinen'], ]); }); testi('opettajien poistaminen', () => { let opettajat = new Opettajat(); opettajat.lisää('MM', 'Maija Meikäläinen'); opettajat.lisää('AS', 'Aili Savolainen'); opettajat.lisää('KV', 'Kari Virtanen'); opettajat.lisää('MaM', 'Matti Meikäläinen'); opettajat.poista('MM'); assertThrow('jo poistettu', 'ei opettajaa lyhenteellä MM', () => { opettajat.poista('MM'); }); assertEq('poistettua', opettajat.opettajat(), [ ['AS', 'Aili Savolainen'], ['KV', 'Kari Virtanen'], ['MaM', 'Matti Meikäläinen'], ]); }); testi('opettajien lyhenteen', () => { let opettajat = new Opettajat(); opettajat.lisää('MM', 'Maija Meikäläinen'); opettajat.lisää('AS', 'Aili Savolainen'); opettajat.lisää('KV', 'Kari Virtanen'); opettajat.lisää('MaM', 'Matti Meikäläinen'); assertEq('MM', opettajat.lyhenne('MM'), 'Maija Meikäläinen'); assertEq('AS', opettajat.lyhenne('AS'), 'Aili Savolainen'); assertEq('KV', opettajat.lyhenne('KV'), 'Kari Virtanen'); assertEq('MaM', opettajat.lyhenne('MaM'), 'Matti Meikäläinen'); assertEq('ZZ', opettajat.lyhenne('ZZ'), undefined); }); testi('tilojen lisääminen', () => { let tilat = new Tilat(); assertEq('käsityöluokka', tilat.lisää('Käsityöluokka'), 0); assertEq('1A', tilat.lisää('1A'), 1); assertEq('lisättyä', tilat.tilat(), [[1, '1A'], [0, 'Käsityöluokka']]); }); testi('tilojen poistaminen', () => { let tilat = new Tilat(); tilat.lisää('Käsityöluokka'); tilat.lisää('1A'); tilat.poista(0); tilat.poista(1); assertEq('poistettua', tilat.tilat(), []); assertThrow('jo poistettu', 'ei tilaa ID:llä 1', () => { tilat.poista(1); }); assertEq('Käsityöluokka uudestaan', tilat.lisää('Käsityöluokka'), 2); }); testi('tilojen nimet', () => { let tilat = new Tilat(); tilat.lisää('Käsityöluokka'); tilat.lisää('1A'); tilat.lisää('5A'); assertEq('', tilojenNimet(tilat, [1, 0, 2]), ['1A', 'Käsityöluokka', '5A']); }); testi('tuntien lisääminen', () => { let tunnit = new Tunnit(); assertEq('historia', tunnit.lisää('Historia', '5B', 'KV', 0), 0); assertEq('äidinkieli', tunnit.lisää('Äidinkieli', '1A', 'AS', 1), 1); assertEq('historia nimi', tunnit.tunnit.get(0).nimi, 'Historia'); assertEq('historia luokat', tunnit.tunnit.get(0).luokat.alkiot(), ['5B']); assertEq('historia opettajat', tunnit.tunnit.get(0).opettajaLyhenteet.alkiot(), ['KV']); assertEq('historia tilat', tunnit.tunnit.get(0).tilat.alkiot(), [0]); assertEq('äidinkieli nimi', tunnit.tunnit.get(1).nimi, 'Äidinkieli'); assertEq('äidinkieli luokat', tunnit.tunnit.get(1).luokat.alkiot(), ['1A']); assertEq('äidinkieli tilat', tunnit.tunnit.get(1).tilat.alkiot(), [1]); assertEq('äidinkieli opettajat', tunnit.tunnit.get(1).opettajaLyhenteet.alkiot(), ['AS']); }); testi('tuntien poistaminen', () => { let tunnit = new Tunnit(); tunnit.lisää('Historia', '5B', 'KV', 0); tunnit.lisää('Äidinkieli', '1B', 'AS', 1); tunnit.poista(0); tunnit.poista(1); assertThrow('jo poistettu', 'ei tuntia ID:llä 1', () => { tunnit.poista(1); }); assertEq('kuvataide', tunnit.lisää('Kuvataide', '6A', 'MM', 2), 2); }); testi('tuntien järjestys', () => { let tunnit = new Tunnit(); tunnit.lisää('Historia', '5B', 'KV', 0); tunnit.lisää('Äidinkieli', '1B', 'AS', 1); assertEq('aluksi', tunnit.järjestyksessä()[0][1].nimi, 'Historia'); tunnit.tunnit.get(1).nimi = 'Historia'; assertEq('sama nimi', tunnit.järjestyksessä()[0][1].luokat.alkiot(), ['1B']); tunnit.tunnit.get(0).luokat = new Joukko(['1B']); assertEq('sama luokka', tunnit.järjestyksessä()[0][1].opettajaLyhenteet.alkiot(), ['AS']); tunnit.tunnit.get(0).opettajaLyhenteet = new Joukko(['AS']); assertEq('sama opettaja', tunnit.järjestyksessä()[0][1].tilat.alkiot(), [0]); });