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