1   package kerho;
2   
3   import java.io.*;
4   import java.util.*;
5   import fi.jyu.mit.ohj2.*;
6   
7   /**
8    * Kerhon harrastukset, joka osaa mm. lisätä uuden harrastuksen
9    *
10   * @author Vesa Lappalainen
11   * @version 1.0, 22.02.2003
12   */
13  public class Harrastukset implements Iterable<Harrastus> {
14      private boolean                     muutettu           = false;
15      private String                      tiedostonPerusNimi = "";
16  
17      /**
18       * Taulukko harrastuksista
19       */
20      private final Collection<Harrastus> alkiot             = new ArrayList<Harrastus>();
21  
22  
23      /**
24       * Harrastusten alustaminen
25       */
26      public Harrastukset() {
27          // toistaiseksi ei tarvitse tehdä mitään
28      }
29  
30  
31      /**
32       * Lisää uuden harrastuksen tietorakenteeseen.  Ottaa harrastuksen omistukseensa.
33       * @param har lisättävä harrastus.  Huom tietorakenne muuttuu omistajaksi
34       */
35      public void lisaa(Harrastus har) {
36          muutettu = true;
37          alkiot.add(har);
38      }
39  
40  
41      /**
42       * Poistaa valitun harrastuksen
43       * @param harrastus poistettava harrastus
44       * @return tosi jos löytyi poistettava harrastus 
45       * <pre name="test">
46       * #THROWS SailoException 
47       * #import java.io.File;
48       *  Harrastukset harrasteet = new Harrastukset();
49       *  Harrastus pitsi21 = new Harrastus(); pitsi21.vastaaPitsinNyplays(2);
50       *  Harrastus pitsi11 = new Harrastus(); pitsi11.vastaaPitsinNyplays(1);
51       *  Harrastus pitsi22 = new Harrastus(); pitsi22.vastaaPitsinNyplays(2); 
52       *  Harrastus pitsi12 = new Harrastus(); pitsi12.vastaaPitsinNyplays(1); 
53       *  Harrastus pitsi23 = new Harrastus(); pitsi23.vastaaPitsinNyplays(2); 
54       *  harrasteet.lisaa(pitsi21);
55       *  harrasteet.lisaa(pitsi11);
56       *  harrasteet.lisaa(pitsi22);
57       *  harrasteet.lisaa(pitsi12);
58       *  harrasteet.poista(pitsi23) === false ; harrasteet.getLkm() === 4;
59       *  harrasteet.poista(pitsi11) === true;   harrasteet.getLkm() === 3;
60       *  List<Harrastus> h = harrasteet.annaHarrastukset(1);
61       *  h.size() === 1; 
62       *  h = harrasteet.annaHarrastukset(1);
63       *  h.get(0) === pitsi12;
64       * </pre>
65       */
66      public boolean poista(Harrastus harrastus) {
67          boolean ret = alkiot.remove(harrastus);
68          if (ret) muutettu = true;
69          return ret;
70      }
71  
72  
73      /**
74       * Poistaa kaikki tietyn jäsenen harrastukset
75       * @param jasenNro viite siihen, minkä jäsenen harrastukset poistetaan
76       * @return montako poistettiin 
77       * @example
78       * <pre name="test">
79       * #THROWS SailoException 
80       * #import java.io.File;
81       *  Harrastukset harrasteet = new Harrastukset();
82       *  Harrastus pitsi21 = new Harrastus(); pitsi21.vastaaPitsinNyplays(2);
83       *  Harrastus pitsi11 = new Harrastus(); pitsi11.vastaaPitsinNyplays(1);
84       *  Harrastus pitsi22 = new Harrastus(); pitsi22.vastaaPitsinNyplays(2); 
85       *  Harrastus pitsi12 = new Harrastus(); pitsi12.vastaaPitsinNyplays(1); 
86       *  Harrastus pitsi23 = new Harrastus(); pitsi23.vastaaPitsinNyplays(2); 
87       *  harrasteet.lisaa(pitsi21);
88       *  harrasteet.lisaa(pitsi11);
89       *  harrasteet.lisaa(pitsi22);
90       *  harrasteet.lisaa(pitsi12);
91       *  harrasteet.lisaa(pitsi23);
92       *  harrasteet.poista(2) === 3;  harrasteet.getLkm() === 2;
93       *  harrasteet.poista(3) === 0;  harrasteet.getLkm() === 2;
94       *  List<Harrastus> h = harrasteet.annaHarrastukset(2);
95       *  h.size() === 0; 
96       *  h = harrasteet.annaHarrastukset(1);
97       *  h.get(0) === pitsi11;
98       *  h.get(1) === pitsi12;
99       * </pre>
100      */
101     public int poista(int jasenNro) {
102         int n = 0;
103         for (Iterator<Harrastus> it = alkiot.iterator(); it.hasNext();) {
104             Harrastus har = it.next();
105             if (har.getJasenNro() == jasenNro) {
106                 it.remove();
107                 n++;
108             }
109         }
110         if (n > 0) muutettu = true;
111         return n;
112     }
113 
114 
115     /**
116      * Lukee harrastukset tiedostosta.
117      * @param tied tiedoston nimen alkuosa
118      * @throws SailoException jos lukeminen epäonnistuu
119      * 
120      * @example
121      * <pre name="test">
122      * #THROWS SailoException 
123      * #import java.io.File;
124      *  Harrastukset harrasteet = new Harrastukset();
125      *  Harrastus pitsi21 = new Harrastus(); pitsi21.vastaaPitsinNyplays(2);
126      *  Harrastus pitsi11 = new Harrastus(); pitsi11.vastaaPitsinNyplays(1);
127      *  Harrastus pitsi22 = new Harrastus(); pitsi22.vastaaPitsinNyplays(2); 
128      *  Harrastus pitsi12 = new Harrastus(); pitsi12.vastaaPitsinNyplays(1); 
129      *  Harrastus pitsi23 = new Harrastus(); pitsi23.vastaaPitsinNyplays(2); 
130      *  String tiedNimi = "testikelmit";
131      *  File ftied = new File(tiedNimi+".har");
132      *  ftied.delete();
133      *  harrasteet.lueTiedostosta(tiedNimi); #THROWS SailoException
134      *  harrasteet.lisaa(pitsi21);
135      *  harrasteet.lisaa(pitsi11);
136      *  harrasteet.lisaa(pitsi22);
137      *  harrasteet.lisaa(pitsi12);
138      *  harrasteet.lisaa(pitsi23);
139      *  harrasteet.talleta();
140      *  harrasteet = new Harrastukset();
141      *  harrasteet.lueTiedostosta(tiedNimi);
142      *  Iterator<Harrastus> i = harrasteet.iterator();
143      *  i.next().toString() === pitsi21.toString();
144      *  i.next().toString() === pitsi11.toString();
145      *  i.next().toString() === pitsi22.toString();
146      *  i.next().toString() === pitsi12.toString();
147      *  i.next().toString() === pitsi23.toString();
148      *  i.hasNext() === false;
149      *  harrasteet.lisaa(pitsi23);
150      *  harrasteet.talleta();
151      *  ftied.delete() === true;
152      *  File fbak = new File(tiedNimi+".hbak");
153      *  fbak.delete() === true;
154      * </pre>
155      */
156     public void lueTiedostosta(String tied) throws SailoException {
157         muutettu = true;
158         setTiedostonPerusNimi(tied);
159         BufferedReader fi = Tiedosto.avaa_lukemista_varten(getTiedostonNimi());
160         if (fi == null) throw new SailoException("Tiedosto " + getTiedostonNimi() + " ei aukea");
161 
162         String rivi;
163         try {
164             while ((rivi = fi.readLine()) != null) { // NOPMD
165                 rivi = rivi.trim();
166                 if ("".equals(rivi) || rivi.charAt(0) == ';') continue;
167                 Harrastus har = new Harrastus(); // NOPMD: pakko luoda silmukassa
168                 har.parse(rivi); // voisi olla virhekäsittely
169                 lisaa(har);
170             }
171             muutettu = false;
172 
173         } catch (IOException e) {
174             throw new SailoException("Ongelmia tiedoston kanssa: " + e.getMessage()); // NOPMD
175         } finally {
176             try {
177                 fi.close();
178             } catch (IOException e) {
179                 throw new SailoException("Tiedoston sulkeminen ei onnistu: " + e.getMessage()); // NOPMD
180             }
181         }
182     }
183 
184 
185     /**
186      * Tallentaa harrastukset tiedostoon.
187      * @throws SailoException jos talletus epäonnistuu
188      */
189     public void talleta() throws SailoException {
190         if (!muutettu) return;
191 
192         File fbak = new File(getBakNimi());
193         File ftied = new File(getTiedostonNimi());
194         fbak.delete(); //  if ... System.err.println("Ei voi tuhota");
195         ftied.renameTo(fbak); //  if ... System.err.println("Ei voi nimetä");
196 
197         PrintWriter fo = Tiedosto.avaa_kirjoittamista_varten(ftied.getName());
198         if (fo == null) throw new SailoException("Tiedosto " + ftied.getName() + " ei aukea");
199         try {
200             for (Harrastus har : this) {
201                 fo.println(har.toString());
202             }
203         } finally {
204             fo.close();
205         }
206 
207         muutettu = false;
208     }
209 
210 
211     /**
212      * Palauttaa kerhon harrastusten lukumäärän
213      * @return harrastusten lukumäärä
214      */
215     public int getLkm() {
216         return alkiot.size();
217     }
218 
219 
220     /**
221      * Asettaa tiedoston perusnimen ilan tarkenninta
222      * @param tied tallennustiedoston perusnimi
223      */
224     public void setTiedostonPerusNimi(String tied) {
225         tiedostonPerusNimi = tied;
226     }
227 
228 
229     /**
230      * Palauttaa tiedoston nimen, jota käytetään tallennukseen
231      * @return tallennustiedoston nimi
232      */
233     public String getTiedostonPerusNimi() {
234         return tiedostonPerusNimi;
235     }
236 
237 
238     /**
239      * Palauttaa tiedoston nimen, jota käytetään tallennukseen
240      * @return tallennustiedoston nimi
241      */
242     public String getTiedostonNimi() {
243         return tiedostonPerusNimi + ".har";
244     }
245 
246 
247     /**
248      * Palauttaa varakopiotiedoston nimen
249      * @return varakopiotiedoston nimi
250      */
251     public String getBakNimi() {
252         return tiedostonPerusNimi + ".hbak";
253     }
254 
255 
256     /**
257      * Iteraattori kaikkien harrastusten läpikäymiseen
258      * @return harrastusiteraattori
259      * 
260      * @example
261      * <pre name="test">
262      * #PACKAGEIMPORT
263      * #import java.util.*;
264      * 
265      *  Harrastukset harrasteet = new Harrastukset();
266      *  Harrastus pitsi21 = new Harrastus(2); harrasteet.lisaa(pitsi21);
267      *  Harrastus pitsi11 = new Harrastus(1); harrasteet.lisaa(pitsi11);
268      *  Harrastus pitsi22 = new Harrastus(2); harrasteet.lisaa(pitsi22);
269      *  Harrastus pitsi12 = new Harrastus(1); harrasteet.lisaa(pitsi12);
270      *  Harrastus pitsi23 = new Harrastus(2); harrasteet.lisaa(pitsi23);
271      * 
272      *  Iterator<Harrastus> i2=harrasteet.iterator();
273      *  i2.next() === pitsi21;
274      *  i2.next() === pitsi11;
275      *  i2.next() === pitsi22;
276      *  i2.next() === pitsi12;
277      *  i2.next() === pitsi23;
278      *  i2.next() === pitsi12;  #THROWS NoSuchElementException  
279      *  
280      *  int n = 0;
281      *  int jnrot[] = {2,1,2,1,2};
282      *  
283      *  for ( Harrastus har:harrasteet ) { 
284      *    har.getJasenNro() === jnrot[n]; n++;  
285      *  }
286      *  
287      *  n === 5;
288      *  
289      * </pre>
290      */
291     @Override
292     public Iterator<Harrastus> iterator() {
293         return alkiot.iterator();
294     }
295 
296     /**
297      * Luokka tietyn jäsen harrastusten iteroimiseksi
298      * 
299      * @example
300      * <pre name="test">
301      * #PACKAGEIMPORT
302      * #import java.util.*;
303      * 
304      *  Harrastukset harrasteet = new Harrastukset();
305      *  Harrastus pitsi21 = new Harrastus(2); harrasteet.lisaa(pitsi21);
306      *  Harrastus pitsi11 = new Harrastus(1); harrasteet.lisaa(pitsi11);
307      *  Harrastus pitsi22 = new Harrastus(2); harrasteet.lisaa(pitsi22);
308      *  Harrastus pitsi12 = new Harrastus(1); harrasteet.lisaa(pitsi12);
309      *  Harrastus pitsi23 = new Harrastus(2); harrasteet.lisaa(pitsi23);
310      *  Harrastus pitsi51 = new Harrastus(5); harrasteet.lisaa(pitsi51);
311      * 
312      *  Iterator<Harrastus> i2=harrasteet.iterator(2);
313      *  i2.next() === pitsi21;
314      *  i2.next() === pitsi22;
315      *  i2.next() === pitsi23;
316      *  i2.next() === pitsi12;  #THROWS NoSuchElementException  
317      *  
318      *  int n = 0;
319      *  for (Iterator<Harrastus> i = harrasteet.iterator(2); i.hasNext(); ) {
320      *    i.next().getJasenNro() === 2; n++;
321      *  }
322      *  
323      *  n === 3;
324      *  
325      *  Iterator<Harrastus> i3=harrasteet.iterator(3);
326      *  i3.hasNext() === false;
327      *  i3.next()    === pitsi12;  #THROWS NoSuchElementException  
328      *  
329      *  Iterator<Harrastus> i4=harrasteet.iterator(4);
330      *  i4.next()    === pitsi12;  #THROWS NoSuchElementException  
331      *  
332      *  Iterator<Harrastus> i5=harrasteet.iterator(5);
333      *  i5.next()    === pitsi51;    
334      *  i5.next()    === pitsi51;  #THROWS NoSuchElementException  
335      * </pre>
336      * 
337      * @example
338      * <pre name="test">
339      * // Testataan erikoistapauksia
340      *  Harrastukset harrasteet = new Harrastukset();
341      *  Iterator<Harrastus> i;
342      *  
343      *  i = harrasteet.iterator(2); // Iteroidaan tyhjään joukoon
344      *  i.next()    === null;       #THROWS NoSuchElementException  
345      *  i = harrasteet.iterator(2);
346      *  i.hasNext() === false;
347      *  
348      *  Harrastus pitsi21 = new Harrastus(2); harrasteet.lisaa(pitsi21);
349      *  i = harrasteet.iterator(1); // Iteroidaan harrastusta jota ei ole
350      *  i.next()    === null;       #THROWS NoSuchElementException  
351      *  i = harrasteet.iterator(1);
352      *  i.hasNext() === false;
353      *  
354      *  i = harrasteet.iterator(2); // Iteroidaan 1. olevaa
355      *  i.next()    === pitsi21;  
356      *  i.next()    === null;       #THROWS NoSuchElementException  
357      *  
358      *  i = harrasteet.iterator(2); // Iteroidaan 1. olevaa hasNext():in kanssa
359      *  i.hasNext() === true;       // hasNext ekalla kertaa 
360      *  i.next()    === pitsi21;  
361      *  i.hasNext() === false; 
362      *  i.next()    === null;       #THROWS NoSuchElementException
363      *    
364      *  Harrastus pitsi31 = new Harrastus(3); harrasteet.lisaa(pitsi31);
365      *  i = harrasteet.iterator(1); // Iteroidaan 2. alkion joukosta olematonta
366      *  i.next()    === null;       #THROWS NoSuchElementException  
367      *  i = harrasteet.iterator(1); // Kokeillaan olematonta hasNext():in kanssa
368      *  i.hasNext() === false; 
369      *  
370      *  i = harrasteet.iterator(2); // Iteroidaan ei viimeisenä olevaa
371      *  i.next()    === pitsi21;  
372      *  i.next()    === null;       #THROWS NoSuchElementException  
373      *  
374      *  i = harrasteet.iterator(2); // 1. hasNext():in avulla
375      *  i.hasNext() === true; 
376      *  i.next()    === pitsi21;  
377      *  i.hasNext() === false; 
378      *  i.next()    === null;       #THROWS NoSuchElementException
379      *    
380      *  i=harrasteet.iterator(3);   // Iteroidaan viimeisenä olevaa
381      *  i.hasNext() === true; 
382      *  i.hasNext() === true;       // Ei saa siirtyä ohi 
383      *  i.next()    === pitsi31;  
384      *  i.hasNext() === false; 
385      *  // i.next()    === null;       #THROWS NoSuchElementException // NOPMD ei tykkää
386      * </pre>
387      */
388     public class HarrastuksetIterator implements Iterator<Harrastus> {
389         private final int                 jasenNro;
390         private final Iterator<Harrastus> iter = iterator();
391         private Harrastus                 harrastus;
392 
393 
394         /**
395          * Alustetaan iteraattori käymään läpi tietyn jäsenen harrastukset
396          * @param vnro viitenumero jäseneen
397          */
398         public HarrastuksetIterator(int vnro) {
399             jasenNro = vnro;
400         }
401 
402 
403         /**
404          * Tutkitaan onko vielä halutun jäsenen harrastuksia jäljellä.
405          * @return true jos jäsenen harrastuksia on vielä 
406          * @see java.util.Iterator#hasNext()
407          */
408         @Override
409         public boolean hasNext() {
410             while (true) {
411                 if (harrastus != null && harrastus.getJasenNro() == jasenNro) return true; // 
412                 harrastus = null; // NOPMD: tarkoituksella null 
413                 if (!iter.hasNext()) return false;
414                 harrastus = iter.next();
415                 if (harrastus.getJasenNro() == jasenNro) return true;
416             }
417         }
418 
419 
420         /**
421          * Palautetaan jäsenen seuraava harrastus.
422          * @return jäsenen seuraava harrastus
423          * @throws NoSuchElementException jos harrastuksia ei enää ole
424          * @see java.util.Iterator#next()
425          */
426         @Override
427         public Harrastus next() throws NoSuchElementException {
428             if (harrastus != null) {
429                 Harrastus pal = harrastus;
430                 harrastus = null; // NOPMD: tarkoituksella null
431                 return pal;
432             }
433             while (true) {
434                 Harrastus har = iter.next();
435                 if (har.getJasenNro() == jasenNro) return har;
436             }
437         }
438 
439 
440         /**
441          * Tuhoamista ei ole toteutettu
442          * @throws UnsupportedOperationException aina
443          * @see java.util.Iterator#remove()
444          */
445         @Override
446         public void remove() throws UnsupportedOperationException {
447             throw new UnsupportedOperationException("Me ei poisteta");
448         }
449 
450     }
451 
452 
453     /**
454      * Haetaan kaikki jäsen harrastukset
455      * @param tunnusnro jäsenen tunnusnumero jolle harrastuksia haetaan
456      * @return tietorakenne jossa viiteet löydetteyihin harrastuksiin
457      * @example
458      * <pre name="test">
459      * #import java.util.*;
460      * 
461      *  Harrastukset harrasteet = new Harrastukset();
462      *  Harrastus pitsi21 = new Harrastus(2); harrasteet.lisaa(pitsi21);
463      *  Harrastus pitsi11 = new Harrastus(1); harrasteet.lisaa(pitsi11);
464      *  Harrastus pitsi22 = new Harrastus(2); harrasteet.lisaa(pitsi22);
465      *  Harrastus pitsi12 = new Harrastus(1); harrasteet.lisaa(pitsi12);
466      *  Harrastus pitsi23 = new Harrastus(2); harrasteet.lisaa(pitsi23);
467      *  Harrastus pitsi51 = new Harrastus(5); harrasteet.lisaa(pitsi51);
468      *  
469      *  List<Harrastus> loytyneet;
470      *  loytyneet = harrasteet.annaHarrastukset(3);
471      *  loytyneet.size() === 0; 
472      *  loytyneet = harrasteet.annaHarrastukset(1);
473      *  loytyneet.size() === 2; 
474      *  loytyneet.get(0) == pitsi11 === true;
475      *  loytyneet.get(1) == pitsi12 === true;
476      *  loytyneet = harrasteet.annaHarrastukset(5);
477      *  loytyneet.size() === 1; 
478      *  loytyneet.get(0) == pitsi51 === true;
479      * </pre> 
480      */
481     public List<Harrastus> annaHarrastukset(int tunnusnro) {
482         List<Harrastus> loydetyt = new ArrayList<Harrastus>();
483         for (Harrastus har : alkiot)
484             if (har.getJasenNro() == tunnusnro) loydetyt.add(har);
485         return loydetyt;
486     }
487 
488 
489     /**
490      * Palautetaan tietyn jäsenen harrastuksia käsittelevä iteraattori
491      * @param vnro tutkittavan jäsenen viitenumero
492      * @return valitun jäsenen harrastusten iteraattori
493      */
494     public Iterator<Harrastus> iterator(int vnro) {
495         return new HarrastuksetIterator(vnro);
496     }
497 
498 
499     /**
500      * Laitetaan muutos, jolloin pakotetaan tallentamaan.  
501      */
502     public void setMuutos() {
503         muutettu = true;
504     }
505 
506 
507     /**
508      * Testiohjelma harrastuksille
509      * @param args ei käytössä
510      */
511     public static void main(String[] args) {
512         Harrastukset harrasteet = new Harrastukset();
513         Harrastus pitsi1 = new Harrastus();
514         pitsi1.vastaaPitsinNyplays(2);
515         Harrastus pitsi2 = new Harrastus();
516         pitsi2.vastaaPitsinNyplays(1);
517         Harrastus pitsi3 = new Harrastus();
518         pitsi3.vastaaPitsinNyplays(2);
519         Harrastus pitsi4 = new Harrastus();
520         pitsi4.vastaaPitsinNyplays(2);
521 
522         harrasteet.lisaa(pitsi1);
523         harrasteet.lisaa(pitsi2);
524         harrasteet.lisaa(pitsi3);
525         harrasteet.lisaa(pitsi2);
526         harrasteet.lisaa(pitsi4);
527 
528         System.out.println("============= Harrastukset testi =================");
529 
530         { // Testataan toimiiko iteraattori ilman hasNextiä
531             Iterator<Harrastus> i2 = harrasteet.iterator(2);
532             Harrastus har = i2.next();
533             System.out.print(har.getJasenNro() + " ");
534             har.tulosta(System.out);
535             har = i2.next();
536             System.out.print(har.getJasenNro() + " ");
537             har.tulosta(System.out);
538             har = i2.next();
539             System.out.print(har.getJasenNro() + " ");
540             har.tulosta(System.out);
541         }
542 
543         for (Iterator<Harrastus> i = harrasteet.iterator(2); i.hasNext();) {
544             Harrastus har = i.next();
545             System.out.print(har.getJasenNro() + " ");
546             har.tulosta(System.out);
547         }
548 
549     }
550 
551 }
552