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      setTiedostonPerusNimi(tied);
85      BufferedReader fi = Tiedosto.avaa_lukemista_varten(getTiedostonNimi());
86      if ( fi == null ) throw new SailoException("Tiedosto " + getTiedostonNimi() + " ei aukea");
87  
88      String rivi;
89      try {
90        while ( ( rivi = fi.readLine() ) != null ) {
91          rivi = rivi.trim();
92          if ( "".equals(rivi) || rivi.charAt(0) == ';' ) continue;
93          Harrastus har = new Harrastus();  // NOPMD: pakko luoda silmukassa
94          har.parse(rivi);  // voisi olla virhekäsittely
95          lisaa(har);
96        }
97        muutettu = false;
98  
99      } catch ( IOException e ) {
100       throw new SailoException("Ongelmia tiedoston kanssa: " + e.getMessage()); // NOPMD
101     } finally {
102       try {
103         fi.close();
104       } catch (IOException e ) {
105         throw new SailoException("Tiedoston sulkeminen ei onnistu: " + e.getMessage()); // NOPMD
106       }
107     }
108   }
109 
110   
111   /**
112    * Tallentaa harrastukset tiedostoon.
113    * @throws SailoException jos talletus epäonnistuu
114    */
115   public void talleta() throws SailoException {
116     if ( !muutettu ) return;
117 
118     File fbak  = new File(getBakNimi());
119     File ftied = new File(getTiedostonNimi());
120     fbak.delete();            //  if ... System.err.println("Ei voi tuhota");
121     ftied.renameTo(fbak);     //  if ... System.err.println("Ei voi nimetä");
122 
123     PrintWriter fo = Tiedosto.avaa_kirjoittamista_varten(ftied.getName());
124     if ( fo == null ) throw new SailoException("Tiedosto " + ftied.getName() + "ei aukea");
125     try {
126       for (Harrastus har : this) {
127         fo.println(har.toString());
128       }
129     } finally {
130       fo.close();
131     }
132 
133     muutettu = false;
134   }
135 
136   
137   /**
138    * Palauttaa kerhon harrastusten lukumäärän
139    * @return harrastusten lukumäärä
140    */
141   public int getLkm()                    { return alkiot.size();              }
142 
143   
144   /**
145    * Asettaa tiedoston perusnimen ilan tarkenninta
146    * @param tied tallennustiedoston perusnimi
147    */
148   public void setTiedostonPerusNimi(String tied)  { tiedostonPerusNimi = tied;     }
149 
150   
151   /**
152    * Palauttaa tiedoston nimen, jota käytetään tallennukseen
153    * @return tallennustiedoston nimi
154    */
155   public String getTiedostonPerusNimi()  { return tiedostonPerusNimi;              }
156 
157   
158   /**
159    * Palauttaa tiedoston nimen, jota käytetään tallennukseen
160    * @return tallennustiedoston nimi
161    */
162   public String getTiedostonNimi()       { return tiedostonPerusNimi + ".har";     }
163 
164   
165   /**
166    * Palauttaa varakopiotiedoston nimen
167    * @return varakopiotiedoston nimi
168    */
169   public String getBakNimi()             { return tiedostonPerusNimi + ".hbak";    }
170 
171   
172   /**
173    * Iteraattori kaikkien harrastusten läpikäymiseen
174    * @return harrastusiteraattori
175    * 
176    * @example
177    * <pre name="test">
178    * #PACKAGEIMPORT
179    * #import java.util.*;
180    * 
181    *  Harrastukset harrasteet = new Harrastukset();
182    *  Harrastus pitsi21 = new Harrastus(2); harrasteet.lisaa(pitsi21);
183    *  Harrastus pitsi11 = new Harrastus(1); harrasteet.lisaa(pitsi11);
184    *  Harrastus pitsi22 = new Harrastus(2); harrasteet.lisaa(pitsi22);
185    *  Harrastus pitsi12 = new Harrastus(1); harrasteet.lisaa(pitsi12);
186    *  Harrastus pitsi23 = new Harrastus(2); harrasteet.lisaa(pitsi23);
187    * 
188    *  Iterator<Harrastus> i2=harrasteet.iterator();
189    *  i2.next() === pitsi21;
190    *  i2.next() === pitsi11;
191    *  i2.next() === pitsi22;
192    *  i2.next() === pitsi12;
193    *  i2.next() === pitsi23;
194    *  i2.next() === pitsi12;  #THROWS NoSuchElementException  
195    *  
196    *  int n = 0;
197    *  int jnrot[] = {2,1,2,1,2};
198    *  
199    *  for ( Harrastus har:harrasteet ) { 
200    *    har.getJasenNro() === jnrot[n]; n++;  
201    *  }
202    *  
203    *  n === 5;
204    *  
205    * </pre>
206    */
207   public Iterator<Harrastus> iterator() {
208     return alkiot.iterator();
209   }
210 
211   
212   /**
213    * Luokka tietyn jäsen harrastusten iteroimiseksi
214    * 
215    * @example
216    * <pre name="test">
217    * #PACKAGEIMPORT
218    * #import java.util.*;
219    * 
220    *  Harrastukset harrasteet = new Harrastukset();
221    *  Harrastus pitsi21 = new Harrastus(2); harrasteet.lisaa(pitsi21);
222    *  Harrastus pitsi11 = new Harrastus(1); harrasteet.lisaa(pitsi11);
223    *  Harrastus pitsi22 = new Harrastus(2); harrasteet.lisaa(pitsi22);
224    *  Harrastus pitsi12 = new Harrastus(1); harrasteet.lisaa(pitsi12);
225    *  Harrastus pitsi23 = new Harrastus(2); harrasteet.lisaa(pitsi23);
226    *  Harrastus pitsi51 = new Harrastus(5); harrasteet.lisaa(pitsi51);
227    * 
228    *  Iterator<Harrastus> i2=harrasteet.iterator(2);
229    *  i2.next() === pitsi21;
230    *  i2.next() === pitsi22;
231    *  i2.next() === pitsi23;
232    *  i2.next() === pitsi12;  #THROWS NoSuchElementException  
233    *  
234    *  int n = 0;
235    *  for (Iterator<Harrastus> i = harrasteet.iterator(2); i.hasNext(); ) {
236    *    i.next().getJasenNro() === 2; n++;
237    *  }
238    *  
239    *  n === 3;
240    *  
241    *  Iterator<Harrastus> i3=harrasteet.iterator(3);
242    *  i3.hasNext() === false;
243    *  i3.next()    === pitsi12;  #THROWS NoSuchElementException  
244    *  
245    *  Iterator<Harrastus> i4=harrasteet.iterator(4);
246    *  i4.next()    === pitsi12;  #THROWS NoSuchElementException  
247    *  
248    *  Iterator<Harrastus> i5=harrasteet.iterator(5);
249    *  i5.next()    === pitsi51;    
250    *  i5.next()    === pitsi51;  #THROWS NoSuchElementException  
251    * </pre>
252    * 
253    * @example
254    * <pre name="test">
255    * // Testataan erikoistapauksia
256    *  Harrastukset harrasteet = new Harrastukset();
257    *  Iterator<Harrastus> i;
258    *  
259    *  i = harrasteet.iterator(2); // Iteroidaan tyhjään joukoon
260    *  i.next()    === null;       #THROWS NoSuchElementException  
261    *  i = harrasteet.iterator(2);
262    *  i.hasNext() === false;
263    *  
264    *  Harrastus pitsi21 = new Harrastus(2); harrasteet.lisaa(pitsi21);
265    *  i = harrasteet.iterator(1); // Iteroidaan harrastusta jota ei ole
266    *  i.next()    === null;       #THROWS NoSuchElementException  
267    *  i = harrasteet.iterator(1);
268    *  i.hasNext() === false;
269    *  
270    *  i = harrasteet.iterator(2); // Iteroidaan 1. olevaa
271    *  i.next()    === pitsi21;  
272    *  i.next()    === null;       #THROWS NoSuchElementException  
273    *  
274    *  i = harrasteet.iterator(2); // Iteroidaan 1. olevaa hasNext():in kanssa
275    *  i.hasNext() === true;       // hasNext ekalla kertaa 
276    *  i.next()    === pitsi21;  
277    *  i.hasNext() === false; 
278    *  i.next()    === null;       #THROWS NoSuchElementException
279    *    
280    *  Harrastus pitsi31 = new Harrastus(3); harrasteet.lisaa(pitsi31);
281    *  i = harrasteet.iterator(1); // Iteroidaan 2. alkion joukosta olematonta
282    *  i.next()    === null;       #THROWS NoSuchElementException  
283    *  i = harrasteet.iterator(1); // Kokeillaan olematonta hasNext():in kanssa
284    *  i.hasNext() === false;
285    *  
286    *  i = harrasteet.iterator(2); // Iteroidaan ei viimeisenä olevaa
287    *  i.next()    === pitsi21;  
288    *  i.next()    === null;       #THROWS NoSuchElementException  
289    *  
290    *  i = harrasteet.iterator(2); // 1. hasNext():in avulla
291    *  i.hasNext() === true; 
292    *  i.next()    === pitsi21;  
293    *  i.hasNext() === false; 
294    *  i.next()    === null;       #THROWS NoSuchElementException
295    *    
296    *  i=harrasteet.iterator(3);   // Iteroidaan viimeisenä olevaa
297    *  i.hasNext() === true; 
298    *  i.next()    === pitsi31;  
299    *  i.hasNext() === false; 
300    *  // i.next()    === null;       #THROWS NoSuchElementException // NOPMD ei tykkää
301    * </pre>
302    */
303   public class HarrastuksetIterator implements Iterator<Harrastus> {
304     private final int jasenNro;
305     private final Iterator<Harrastus> iter = alkiot.iterator();
306     private Harrastus har;
307 
308     
309     /**
310      * Alustetaan iteraattori käymään läpi tietyn jäsenen harrastukset
311      * @param vnro viitenumero jäseneen
312      */
313     public HarrastuksetIterator(int vnro) {
314       jasenNro = vnro;
315     }
316 
317     
318     /**
319      * Tutkitaan onko vielä halutun jäsenen harrastuksia jäljellä.
320      * @return true jos jäsenen harrastuksia on vielä 
321      * @see java.util.Iterator#hasNext()
322      */
323     public boolean hasNext() {
324       while ( true ) {
325         har = null;                // NOPMD: tarkoituksella null 
326         if ( !iter.hasNext() ) return false;
327         har = iter.next();
328         if ( har.getJasenNro()== jasenNro ) return true;
329       }
330     }
331 
332     
333     /**
334      * Palautetaan jäsenen seuraava harrastus.
335      * @return jäsenen seuraava harrastus
336      * @throws NoSuchElementException jos harrastuksia ei enää ole
337      * @see java.util.Iterator#next()
338      */
339     public Harrastus next() throws NoSuchElementException {
340       if ( har != null ) {
341         Harrastus pal = har;
342         har = null;              // NOPMD: tarkoituksella null
343         return pal;
344       }
345       while ( true ) {
346         Harrastus har = iter.next();
347         if ( har.getJasenNro() == jasenNro ) return har;
348       }
349     }
350 
351     
352     /**
353      * Tuhoamista ei ole toteutettu
354      * @throws UnsupportedOperationException aina
355      * @see java.util.Iterator#remove()
356      */
357     public void remove() throws UnsupportedOperationException {
358       throw new UnsupportedOperationException("Me ei poisteta");
359     }
360 
361   }
362 
363   
364   /**
365    * Palautetaan tietyn jäsenen harrastuksia käsittelevä iteraattori
366    * @param vnro tutkittavan jäsenen viitenumero
367    * @return valitun jäsenen harrastusten iteraattori
368    */
369   public Iterator<Harrastus> iterator(int vnro) {
370     return new HarrastuksetIterator(vnro);
371   }
372   
373 
374   /**
375    * Testiohjelma harrastuksille
376    * @param args ei käytössä
377    */
378   public static void main(String[] args) {
379     Harrastukset harrasteet = new Harrastukset();
380     Harrastus pitsi1 = new Harrastus();
381     pitsi1.vastaaPitsinNyplays(2);
382     Harrastus pitsi2 = new Harrastus();
383     pitsi2.vastaaPitsinNyplays(1);
384     Harrastus pitsi3 = new Harrastus();
385     pitsi3.vastaaPitsinNyplays(2);
386     Harrastus pitsi4 = new Harrastus();
387     pitsi4.vastaaPitsinNyplays(2);
388 
389     harrasteet.lisaa(pitsi1);
390     harrasteet.lisaa(pitsi2);
391     harrasteet.lisaa(pitsi3);
392     harrasteet.lisaa(pitsi2);
393     harrasteet.lisaa(pitsi4);
394 
395     System.out.println("============= Harrastukset testi =================");
396 
397     { // Testataan toimiiko iteraattori ilman hasNextiä
398     Iterator<Harrastus> i2=harrasteet.iterator(2);
399     Harrastus har = i2.next();
400     System.out.print(har.getJasenNro() + " ");
401     har.tulosta(System.out);
402     har = i2.next();
403     System.out.print(har.getJasenNro() + " ");
404     har.tulosta(System.out);
405     har = i2.next();
406     System.out.print(har.getJasenNro() + " ");
407     har.tulosta(System.out);
408     }
409 
410     for (Iterator<Harrastus> i=harrasteet.iterator(2); i.hasNext(); ) {
411       Harrastus har = i.next();
412       System.out.print(har.getJasenNro() + " ");
413       har.tulosta(System.out);
414     }
415 
416   }
417 
418 
419   /**
420    * Palautetana lista jäsenen harrastuksia
421    * @param tunnusnro minkä id:n mukaisia harrastuksia etsitään.
422    * @return lista jäsenen harrastuksia
423    */
424   public List<Harrastus> annaHarrastukset(int tunnusnro) {
425       List<Harrastus> jasenenHarrastukset = new ArrayList<Harrastus>();
426       for (Harrastus har : this) {
427           if ( har.getJasenNro() == tunnusnro ) jasenenHarrastukset.add(har);
428       }
429       return jasenenHarrastukset;
430   }
431 
432 }
433 
434 
435