| Jasenet.java |
1 package kerho;
2
3 import java.io.BufferedReader;
4 import java.io.File;
5 import java.io.IOException;
6 import java.io.PrintWriter;
7 import java.util.ArrayList;
8 import java.util.Arrays;
9 import java.util.Collection;
10 import java.util.Collections;
11 import java.util.Iterator;
12 import java.util.List;
13 import java.util.NoSuchElementException;
14
15 import fi.jyu.mit.ohj2.Tiedosto;
16 import fi.jyu.mit.ohj2.WildChars;
17
18 /**
19 * Kerhon jäsenistö joka osaa mm. lisätä uuden jäsenen
20 *
21 * @author Vesa Lappalainen
22 * @version 1.0, 22.02.2003
23 * @version 1.1, 19.02.2012
24 * @version 1.2, 15.03.2012
25 */
26 public class Jasenet implements Iterable<Jasen> {
27 private boolean muutettu = false;
28 private int MAX_JASENIA = Integer.MAX_VALUE;
29 private String kokoNimi = "";
30 private String tiedostonPerusNimi = "";
31 private int lkm = 0;
32 private Jasen alkiot[] = new Jasen[5];
33
34
35 /**
36 * Oletusmuodostaja jolla tulee täysin dynaaminen koko.
37 */
38 public Jasenet() {
39 // Attribuuttien oma alustus riittää
40 }
41
42
43 /**
44 * Muodostaja jolla maxkoko voidaan asettaa.
45 * Tällöin ei koskaan lisätä enempää kuin maksimi.
46 * @param koko jäsenistön maxkoko
47 *
48 */
49 public Jasenet(int koko) {
50 MAX_JASENIA = koko;
51 alkiot = new Jasen[MAX_JASENIA];
52 }
53
54
55 /**
56 * Lisää uuden jäsenen tietorakenteeseen. Ottaa jäsenen omistukseensa.
57 * @param jasen lisättävän jäsenen viite. Huom tietorakenne muuttuu omistajaksi
58 * @throws SailoException jos määrä ylittää pyydetyn maksimirajan
59 * @example
60 * <pre name="test">
61 * #THROWS SailoException
62 * #PACKAGEIMPORT
63 * Jasenet jasenet = new Jasenet(5);
64 * Jasen aku1 = new Jasen(), aku2 = new Jasen();
65 * jasenet.getLkm() === 0;
66 * jasenet.lisaa(aku1); jasenet.getLkm() === 1;
67 * jasenet.lisaa(aku2); jasenet.getLkm() === 2;
68 * jasenet.lisaa(aku1); jasenet.getLkm() === 3;
69 * jasenet.anna(0) === aku1;
70 * jasenet.anna(1) === aku2;
71 * jasenet.anna(2) === aku1;
72 * jasenet.anna(1) == aku1 === false;
73 * jasenet.anna(1) == aku2 === true;
74 * jasenet.anna(3) === aku1; #THROWS IndexOutOfBoundsException
75 * jasenet.lisaa(aku1); jasenet.getLkm() === 4;
76 * jasenet.lisaa(aku1); jasenet.getLkm() === 5;
77 * jasenet.lisaa(aku1); #THROWS SailoException
78 *
79 * jasenet = new Jasenet();
80 * for (int i=0; i<200; i++) {
81 * jasenet.lisaa(aku1); jasenet.getLkm() === 2*i+1;
82 * jasenet.lisaa(aku2); jasenet.getLkm() === 2*i+2;
83 * }
84 * </pre>
85 */
86 public void lisaa(Jasen jasen) throws SailoException {
87 if (lkm >= MAX_JASENIA) throw new SailoException("Liikaa alkioita");
88 if (lkm >= alkiot.length) alkiot = Arrays.copyOf(alkiot, lkm+20);
89 alkiot[lkm] = jasen;
90 lkm++;
91 muutettu = true;
92 }
93
94
95 /**
96 * Poistaa jäsenen jolla on valittu tunnusnumero
97 * @param id poistettavan jäsenen tunnusnumero
98 * @return 1 jos poistettiin, 0 jos ei löydy
99 * @example
100 * <pre name="test">
101 * #THROWS SailoException
102 * Jasenet jasenet = new Jasenet(5);
103 * Jasen aku1 = new Jasen(), aku2 = new Jasen(), aku3 = new Jasen();
104 * aku1.rekisteroi(); aku2.rekisteroi(); aku3.rekisteroi();
105 * int id1 = aku1.getTunnusNro();
106 * jasenet.lisaa(aku1); jasenet.lisaa(aku2); jasenet.lisaa(aku3);
107 * jasenet.poista(id1+1) === 1;
108 * jasenet.etsiId(id1+1) === -1; jasenet.getLkm() === 2;
109 * jasenet.poista(id1) === 1; jasenet.getLkm() === 1;
110 * jasenet.poista(id1+3) === 0; jasenet.getLkm() === 1;
111 * </pre>
112 *
113 */
114 public int poista(int id) {
115 int ind = etsiId(id);
116 if (ind < 0) return 0;
117 lkm--;
118 for (int i = ind; i < lkm; i++)
119 alkiot[i] = alkiot[i + 1];
120 alkiot[lkm] = null;
121 muutettu = true;
122 return 1;
123 }
124
125
126 /**
127 * Korvaa jäsenen tietorakenteessa. Ottaa jäsenen omistukseensa.
128 * Etsitään samalla tunnusnumerolla oleva jäsen. Jos ei läydy,
129 * niin lisätään uutena jäsenenä.
130 * @param jasen lisätäävän jäsenen viite. Huom tietorakenne muuttuu omistajaksi
131 * @throws SailoException jos tietorakennen on jo täynnä
132 * <pre name="test">
133 * #THROWS SailoException,CloneNotSupportedException
134 * #PACKAGEIMPORT
135 * Jasenet jasenet = new Jasenet();
136 * Jasen aku1 = new Jasen(), aku2 = new Jasen();
137 * aku1.rekisteroi(); aku2.rekisteroi();
138 * jasenet.getLkm() === 0;
139 * jasenet.korvaaTaiLisaa(aku1); jasenet.getLkm() === 1;
140 * jasenet.korvaaTaiLisaa(aku2); jasenet.getLkm() === 2;
141 * Jasen aku3 = aku1.clone();
142 * aku3.aseta(3,"kkk");
143 * jasenet.anna(0) == aku1 === true;
144 * jasenet.korvaaTaiLisaa(aku3); jasenet.getLkm() === 2;
145 * jasenet.anna(0) === aku3;
146 * jasenet.anna(0) == aku3 === true;
147 * jasenet.anna(0) == aku1 === false;
148 * </pre>
149 */
150 public void korvaaTaiLisaa(Jasen jasen) throws SailoException {
151 int id = jasen.getTunnusNro();
152 for (int i = 0; i < lkm; i++) {
153 if (alkiot[i].getTunnusNro() == id) {
154 alkiot[i] = jasen;
155 muutettu = true;
156 return;
157 }
158 }
159 lisaa(jasen);
160 }
161
162
163 /**
164 * Palauttaa viitteen i:teen jäseneen.
165 * @param i monennenko jäsenen viite halutaan
166 * @return viite jäseneen, jonka indeksi on i
167 * @throws IndexOutOfBoundsException jos i ei ole sallitulla alueella
168 */
169 public Jasen anna(int i) throws IndexOutOfBoundsException {
170 if (i < 0 || lkm <= i) throw new IndexOutOfBoundsException("Laiton indeksi: " + i);
171 return alkiot[i];
172 }
173
174
175 /**
176 * Lukee jäsenistön tiedostosta.
177 * @param tied tiedoston nimen alkuosa
178 * @throws SailoException jos lukeminen epäonnistuu
179 *
180 * @example
181 * <pre name="test">
182 * #THROWS SailoException
183 * #import java.io.File;
184 *
185 * Jasenet jasenet = new Jasenet();
186 * Jasen aku1 = new Jasen(), aku2 = new Jasen();
187 * aku1.vastaaAkuAnkka();
188 * aku2.vastaaAkuAnkka();
189 * String tiedNimi = "testikelmit";
190 * File ftied = new File(tiedNimi+".dat");
191 * ftied.delete();
192 * jasenet.lueTiedostosta(tiedNimi); #THROWS SailoException
193 * jasenet.lisaa(aku1);
194 * jasenet.lisaa(aku2);
195 * jasenet.talleta();
196 * jasenet = new Jasenet(); // Poistetaan vanhat luomalla uusi
197 * jasenet.lueTiedostosta(tiedNimi); // johon ladataan tiedot tiedostosta.
198 * Iterator<Jasen> i = jasenet.iterator();
199 * i.next().toString() === aku1.toString();
200 * i.next().toString() === aku2.toString();
201 * i.hasNext() === false;
202 * jasenet.lisaa(aku2);
203 * jasenet.talleta();
204 * ftied.delete() === true;
205 * File fbak = new File(tiedNimi+".bak");
206 * fbak.delete() === true;
207 * </pre>
208 */
209 public void lueTiedostosta(String tied) throws SailoException {
210 setTiedostonPerusNimi(tied);
211 BufferedReader fi = Tiedosto.avaa_lukemista_varten(getTiedostonNimi());
212 if (fi == null) throw new SailoException("Tiedosto " + getTiedostonNimi() + " ei aukea");
213
214 try {
215 kokoNimi = fi.readLine();
216 if (kokoNimi == null) throw new SailoException("Kerhon nimi puuttuu");
217 String rivi = fi.readLine();
218 if (rivi == null) throw new SailoException("Maksimikoko puuttuu");
219 // int maxKoko = Mjonot.erotaInt(rivi,10); // tehdään jotakin
220
221 while ((rivi = fi.readLine()) != null) {
222 rivi = rivi.trim();
223 if ("".equals(rivi) || rivi.charAt(0) == ';') continue;
224 Jasen jasen = new Jasen();
225 jasen.parse(rivi); // voisi olla virhekäsittely
226 lisaa(jasen);
227 }
228 muutettu = false;
229
230 } catch (IOException e) {
231 throw new SailoException("Ongelmia tiedoston kanssa: " + e.getMessage());
232 } finally {
233 try {
234 fi.close();
235 } catch (IOException e) {
236 throw new SailoException("Tiedoston sulkeminen ei onnistu: " + e.getMessage());
237 }
238 }
239 }
240
241
242 /**
243 * Tallentaa jäsenistän tiedostoon.
244 * Tiedoston muoto:
245 * <pre>
246 * Kelmien kerho
247 * 20
248 * ; kommenttirivi
249 * 2|Ankka Aku|121103-706Y|Ankkakuja 6|12345|ANKKALINNA|12-1234|||1996|50.0|30.0|Velkaa Roopelle
250 * 3|Ankka Tupu|121153-706Y|Ankkakuja 6|12345|ANKKALINNA|12-1234|||1996|50.0|30.0|Velkaa Roopelle
251 * </pre>
252 * @throws SailoException jos talletus epäonnistuu
253 */
254 public void talleta() throws SailoException {
255 if (!muutettu) return;
256
257 File fbak = new File(getBakNimi());
258 File ftied = new File(getTiedostonNimi());
259 fbak.delete(); // if .. System.err.println("Ei voi tuhota");
260 ftied.renameTo(fbak); // if .. System.err.println("Ei voi nimetä");
261
262 PrintWriter fo = Tiedosto.avaa_kirjoittamista_varten(ftied.getName());
263 if (fo == null) throw new SailoException("Tiedosto " + ftied.getName() + " ei aukea");
264 try {
265 fo.println(getKokoNimi());
266 fo.println(alkiot.length);
267 for (Jasen jasen : this) {
268 fo.println(jasen.toString());
269 }
270 //} catch ( IOException e ) { // ei heitä poikkeusta
271 // throw new SailoException("Tallettamisessa ongelmia: " + e.getMessage());
272 } finally {
273 fo.close();
274 }
275
276 muutettu = false;
277 }
278
279
280 /**
281 * Palauttaa Kerhon koko nimen
282 * @return Kerhon koko nimi merkkijononna
283 */
284 public String getKokoNimi() {
285 return kokoNimi;
286 }
287
288
289 /**
290 * Palauttaa kerhon jäsenten lukumäärän
291 * @return jäsenten lukumäärä
292 */
293 public int getLkm() {
294 return lkm;
295 }
296
297
298 /**
299 * Palauttaa tiedoston nimen, jota käytetään tallennukseen
300 * @return tallennustiedoston nimi
301 */
302 public String getTiedostonPerusNimi() {
303 return tiedostonPerusNimi;
304 }
305
306
307 /**
308 * Asettaa tiedoston perusnimen ilan tarkenninta
309 * @param tied tallennustiedoston perusnimi
310 */
311 public void setTiedostonPerusNimi(String tied) {
312 tiedostonPerusNimi = tied;
313 }
314
315
316 /**
317 * Palauttaa tiedoston nimen, jota käytetään tallennukseen
318 * @return tallennustiedoston nimi
319 */
320 public String getTiedostonNimi() {
321 return getTiedostonPerusNimi() + ".dat";
322 }
323
324
325 /**
326 * Palauttaa varakopiotiedoston nimen
327 * @return varakopiotiedoston nimi
328 */
329 public String getBakNimi() {
330 return tiedostonPerusNimi + ".bak";
331 }
332
333
334 /**
335 * Luokka jäsenten iteroimiseksi.
336 * @example
337 * <pre name="test">
338 * #THROWS SailoException
339 * #PACKAGEIMPORT
340 * #import java.util.*;
341 *
342 * Jasenet jasenet = new Jasenet();
343 * Jasen aku1 = new Jasen(), aku2 = new Jasen();
344 * aku1.rekisteroi(); aku2.rekisteroi();
345 *
346 * jasenet.lisaa(aku1);
347 * jasenet.lisaa(aku2);
348 * jasenet.lisaa(aku1);
349 *
350 * StringBuffer ids = new StringBuffer(30);
351 * for (Jasen jasen:jasenet) // Kokeillaan for-silmukan toimintaa
352 * ids.append(" "+jasen.getTunnusNro());
353 *
354 * String tulos = " " + aku1.getTunnusNro() + " " + aku2.getTunnusNro() + " " + aku1.getTunnusNro();
355 *
356 * ids.toString() === tulos;
357 *
358 * ids = new StringBuffer(30);
359 * for (Iterator<Jasen> i=jasenet.iterator(); i.hasNext(); ) { // ja iteraattorin toimintaa
360 * Jasen jasen = i.next();
361 * ids.append(" "+jasen.getTunnusNro());
362 * }
363 *
364 * ids.toString() === tulos;
365 *
366 * Iterator<Jasen> i=jasenet.iterator();
367 * i.next() == aku1 === true;
368 * i.next() == aku2 === true;
369 * i.next() == aku1 === true;
370 *
371 * i.next(); #THROWS NoSuchElementException
372 *
373 * </pre>
374 */
375 public class JasenetIterator implements Iterator<Jasen> {
376 private int kohdalla = -1;
377
378
379 /**
380 * Onko olemassa vielä seuraavaa jäsentä
381 * @see java.util.Iterator#hasNext()
382 * @return true jos on vielä jäseniä
383 */
384 @Override
385 public boolean hasNext() {
386 // if ( kohdalla + 1 >= lkm ) return false;
387 // return true;
388 return kohdalla + 1 < getLkm();
389 }
390
391
392 /**
393 * Annetaan seuraava jäsen
394 * @return seuraava jäsen
395 * @throws NoSuchElementException jos seuraava alkiota ei enää ole
396 * @see java.util.Iterator#next()
397 */
398 @Override
399 public Jasen next() throws NoSuchElementException {
400 if (!hasNext()) throw new NoSuchElementException("Ei oo");
401 kohdalla++;
402 return anna(kohdalla);
403 }
404
405
406 /**
407 * Tuhoamista ei ole toteutettu
408 * @throws UnsupportedOperationException aina
409 * @see java.util.Iterator#remove()
410 */
411 @Override
412 public void remove() throws UnsupportedOperationException {
413 throw new UnsupportedOperationException("Me ei poisteta");
414 }
415 }
416
417
418 /**
419 * Palautetaan iteraattori jäsenistään.
420 * @return jäsen iteraattori
421 */
422 @Override
423 public Iterator<Jasen> iterator() {
424 return new JasenetIterator();
425 }
426
427
428 /**
429 * Palauttaa "taulukossa" hakuehtoon vastaavien jäsenten viitteet
430 * @param hakuehto hakuehto
431 * @param k etsittävän kentän indeksi
432 * @return tietorakenteen löytyneistä jäsenistä
433 * @example
434 * <pre name="test">
435 * #THROWS SailoException
436 * Jasenet jasenet = new Jasenet();
437 * Jasen jasen1 = new Jasen(); jasen1.parse("1|Ankka Aku|030201-115H|Ankkakuja 6|");
438 * Jasen jasen2 = new Jasen(); jasen2.parse("2|Ankka Tupu||030552-123B|");
439 * Jasen jasen3 = new Jasen(); jasen3.parse("3|Susi Sepe|121237-121V||131313|Perämetsä");
440 * Jasen jasen4 = new Jasen(); jasen4.parse("4|Ankka Iines|030245-115V|Ankkakuja 9");
441 * Jasen jasen5 = new Jasen(); jasen5.parse("5|Ankka Roope|091007-408U|Ankkakuja 12");
442 * jasenet.lisaa(jasen1); jasenet.lisaa(jasen2); jasenet.lisaa(jasen3); jasenet.lisaa(jasen4); jasenet.lisaa(jasen5);
443 * List<Jasen> loytyneet;
444 * loytyneet = (List<Jasen>)jasenet.etsi("*s*",1);
445 * loytyneet.size() === 2;
446 * loytyneet.get(0) == jasen4 === true;
447 * loytyneet.get(1) == jasen3 === true;
448 *
449 * loytyneet = (List<Jasen>)jasenet.etsi("*7-*",2);
450 * loytyneet.size() === 2;
451 * loytyneet.get(0) == jasen5 === true;
452 * loytyneet.get(1) == jasen3 === true;
453 * </pre>
454 */
455 public Collection<Jasen> etsi(String hakuehto, int k) {
456 List<Jasen> loytyneet = new ArrayList<Jasen>();
457 for (Jasen jasen : this) {
458 // if ( jasen.anna(k).toUpperCase().startsWith(hakuehto.toUpperCase()) ) loytyneet.add(jasen); // NOPMD
459 if (WildChars.onkoSamat(jasen.anna(k), hakuehto)) loytyneet.add(jasen); // NOPMD
460 }
461 Collections.sort(loytyneet, new Jasen.Vertailija(k));
462 return loytyneet;
463 }
464
465
466 /**
467 * Etsii jäsenen id:n perusteella
468 * @param id tunnusnumero, jonka mukaan etsitään
469 * @return jäsen jolla etsittävä id tai null
470 * <pre name="test">
471 * #THROWS SailoException
472 * Jasenet jasenet = new Jasenet(5);
473 * Jasen aku1 = new Jasen(), aku2 = new Jasen(), aku3 = new Jasen();
474 * aku1.rekisteroi(); aku2.rekisteroi(); aku3.rekisteroi();
475 * int id1 = aku1.getTunnusNro();
476 * jasenet.lisaa(aku1); jasenet.lisaa(aku2); jasenet.lisaa(aku3);
477 * jasenet.annaId(id1 ) == aku1 === true;
478 * jasenet.annaId(id1+1) == aku2 === true;
479 * jasenet.annaId(id1+2) == aku3 === true;
480 * </pre>
481 */
482 public Jasen annaId(int id) {
483 for (Jasen jasen : this) {
484 if (id == jasen.getTunnusNro()) return jasen;
485 }
486 return null;
487 }
488
489
490 /**
491 * Etsii jäsenen id:n perusteella
492 * @param id tunnusnumero, jonka mukaan etsitään
493 * @return löytyneen jäsenen indeksi tai -1 jos ei löydy
494 * <pre name="test">
495 * #THROWS SailoException
496 * Jasenet jasenet = new Jasenet(5);
497 * Jasen aku1 = new Jasen(), aku2 = new Jasen(), aku3 = new Jasen();
498 * aku1.rekisteroi(); aku2.rekisteroi(); aku3.rekisteroi();
499 * int id1 = aku1.getTunnusNro();
500 * jasenet.lisaa(aku1); jasenet.lisaa(aku2); jasenet.lisaa(aku3);
501 * jasenet.etsiId(id1+1) === 1;
502 * jasenet.etsiId(id1+2) === 2;
503 * </pre>
504 */
505 public int etsiId(int id) {
506 for (int i = 0; i < lkm; i++)
507 if (id == alkiot[i].getTunnusNro()) return i;
508 return -1;
509 }
510
511
512 /**
513 * Testiohjelma jäsenistölle
514 * @param args ei käytössä
515 */
516 public static void main(String args[]) {
517 Jasenet jasenet = new Jasenet();
518
519 Jasen aku = new Jasen(), aku2 = new Jasen();
520 aku.rekisteroi();
521 aku.vastaaAkuAnkka();
522 aku2.rekisteroi();
523 aku2.vastaaAkuAnkka();
524
525 try {
526 jasenet.lisaa(aku);
527 jasenet.lisaa(aku2);
528
529 System.out.println("============= Jäsenet testi =================");
530
531 for (int i = 0; i < jasenet.getLkm(); i++) {
532 Jasen jasen = jasenet.anna(i);
533 System.out.println("Jäsen nro: " + i);
534 jasen.tulosta(System.out);
535 }
536
537 } catch (SailoException ex) {
538 System.out.println(ex.getMessage());
539 }
540 }
541
542 }
543