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.Iterator;
8   import java.util.NoSuchElementException;
9   
10  import fi.jyu.mit.ohj2.Tiedosto;
11  
12  /**
13   * Kerhon jäsenistö joka osaa mm. lisätä uuden jäsenen
14   *
15   * @author Vesa Lappalainen
16   * @version 1.0, 22.02.2003
17   * @version 1.1, 19.02.2012 
18   */
19  public class Jasenet implements Iterable<Jasen> {
20      private boolean muutettu = false;
21      private static final int MAX_JASENIA = 5;
22      private String kokoNimi = "";
23      private String tiedostonPerusNimi = "";
24      private int lkm = 0;
25      private Jasen alkiot[] = new Jasen[MAX_JASENIA];
26  
27  
28      /**
29       * Oletusmuodostaja
30       */
31      public Jasenet() {
32          // Attribuuttien oma alustus riittää
33      }
34  
35  
36      /**
37       * Lisää uuden jäsenen tietorakenteeseen.  Ottaa jäsenen omistukseensa.
38       * @param jasen lisätäävän jäsenen viite.  Huom tietorakenne muuttuu omistajaksi
39       * @throws SailoException jos tietorakenne on jo täynnä
40       * @example
41       * <pre name="test">
42       * #THROWS SailoException 
43       * #PACKAGEIMPORT
44       * Jasenet jasenet = new Jasenet();
45       * Jasen aku1 = new Jasen(), aku2 = new Jasen();
46       * jasenet.getLkm() === 0;
47       * jasenet.lisaa(aku1); jasenet.getLkm() === 1;
48       * jasenet.lisaa(aku2); jasenet.getLkm() === 2;
49       * jasenet.lisaa(aku1); jasenet.getLkm() === 3;
50       * jasenet.anna(0) === aku1;
51       * jasenet.anna(1) === aku2;
52       * jasenet.anna(2) === aku1;
53       * jasenet.anna(1) == aku1 === false;
54       * jasenet.anna(1) == aku2 === true;
55       * jasenet.anna(3) === aku1; #THROWS IndexOutOfBoundsException 
56       * jasenet.lisaa(aku1); jasenet.getLkm() === 4;
57       * jasenet.lisaa(aku1); jasenet.getLkm() === 5;
58       * jasenet.lisaa(aku1);  #THROWS SailoException
59       * </pre>
60       */
61      public void lisaa(Jasen jasen) throws SailoException {
62          if (lkm >= alkiot.length) throw new SailoException("Liikaa alkioita");
63          alkiot[lkm] = jasen;
64          lkm++;
65          muutettu = true;
66      }
67  
68  
69      /**
70       * Palauttaa viitteen i:teen jäseneen.
71       * @param i monennenko jäsenen viite halutaan
72       * @return viite jäseneen, jonka indeksi on i
73       * @throws IndexOutOfBoundsException jos i ei ole sallitulla alueella  
74       */
75      public Jasen anna(int i) throws IndexOutOfBoundsException {
76          if (i < 0 || lkm <= i) throw new IndexOutOfBoundsException("Laiton indeksi: " + i);
77          return alkiot[i];
78      }
79  
80  
81      /**
82       * Lukee jäsenistön tiedostosta. 
83       * @param tied tiedoston nimen alkuosa
84       * @throws SailoException jos lukeminen epäonnistuu
85       * 
86       * @example
87       * <pre name="test">
88       * #THROWS SailoException 
89       * #import java.io.File;
90       * 
91       *  Jasenet jasenet = new Jasenet();
92       *  Jasen aku1 = new Jasen(), aku2 = new Jasen();
93       *  aku1.vastaaAkuAnkka();
94       *  aku2.vastaaAkuAnkka();
95       *  String tiedNimi = "testikelmit";
96       *  File ftied = new File(tiedNimi+".dat");
97       *  ftied.delete();
98       *  jasenet.lueTiedostosta(tiedNimi); #THROWS SailoException
99       *  jasenet.lisaa(aku1);
100      *  jasenet.lisaa(aku2);
101      *  jasenet.talleta();
102      *  jasenet = new Jasenet();           // Poistetaan vanhat luomalla uusi
103      *  jasenet.lueTiedostosta(tiedNimi);  // johon ladataan tiedot tiedostosta.
104      *  Iterator<Jasen> i = jasenet.iterator();
105      *  i.next().toString() === aku1.toString();
106      *  i.next().toString() === aku2.toString();
107      *  i.hasNext() === false;
108      *  jasenet.lisaa(aku2);
109      *  jasenet.talleta();
110      *  ftied.delete() === true;
111      *  File fbak = new File(tiedNimi+".bak");
112      *  fbak.delete() === true;
113      * </pre>
114      */
115     public void lueTiedostosta(String tied) throws SailoException {
116         setTiedostonPerusNimi(tied);
117         BufferedReader fi = Tiedosto.avaa_lukemista_varten(getTiedostonNimi());
118         if (fi == null) throw new SailoException("Tiedosto " + getTiedostonNimi() + " ei aukea");
119 
120         try {
121             kokoNimi = fi.readLine();
122             if (kokoNimi == null) throw new SailoException("Kerhon nimi puuttuu");
123             String rivi = fi.readLine();
124             if (rivi == null) throw new SailoException("Maksimikoko puuttuu");
125             // int maxKoko = Mjonot.erotaInt(rivi,10); // tehdään jotakin
126 
127             while ((rivi = fi.readLine()) != null) { 
128                 rivi = rivi.trim();
129                 if ("".equals(rivi) || rivi.charAt(0) == ';') continue;
130                 Jasen jasen = new Jasen(); 
131                 jasen.parse(rivi); // voisi olla virhekäsittely
132                 lisaa(jasen);
133             }
134             muutettu = false;
135 
136         } catch (IOException e) {
137             throw new SailoException("Ongelmia tiedoston kanssa: " + e.getMessage());
138         } finally {
139             try {
140                 fi.close();
141             } catch (IOException e) {
142                 throw new SailoException("Tiedoston sulkeminen ei onnistu: " + e.getMessage()); 
143             }
144         }
145     }
146 
147 
148     /**
149      * Tallentaa jäsenistän tiedostoon.  
150      * Tiedoston muoto:
151      * <pre>
152      * Kelmien kerho
153      * 20
154      * ; kommenttirivi
155      * 2|Ankka Aku|121103-706Y|Ankkakuja 6|12345|ANKKALINNA|12-1234|||1996|50.0|30.0|Velkaa Roopelle
156      * 3|Ankka Tupu|121153-706Y|Ankkakuja 6|12345|ANKKALINNA|12-1234|||1996|50.0|30.0|Velkaa Roopelle
157      * </pre>
158      * @throws SailoException jos talletus epäonnistuu
159      */
160     public void talleta() throws SailoException {
161         if (!muutettu) return;
162 
163         File fbak = new File(getBakNimi());
164         File ftied = new File(getTiedostonNimi());
165         fbak.delete(); // if .. System.err.println("Ei voi tuhota");
166         ftied.renameTo(fbak); // if .. System.err.println("Ei voi nimetä");
167 
168         PrintWriter fo = Tiedosto.avaa_kirjoittamista_varten(ftied.getName());
169         if (fo == null) throw new SailoException("Tiedosto " + ftied.getName() + " ei aukea");
170         try {
171             fo.println(getKokoNimi());
172             fo.println(alkiot.length);
173             for (Jasen jasen : this) {
174                 fo.println(jasen.toString());
175             }
176             //} catch ( IOException e ) { // ei heitä poikkeusta
177             //  throw new SailoException("Tallettamisessa ongelmia: " + e.getMessage());
178         } finally {
179             fo.close();
180         }
181 
182         muutettu = false;
183     }
184     
185     
186     /**
187      * Palauttaa Kerhon koko nimen
188      * @return Kerhon koko nimi merkkijononna
189      */
190     public String getKokoNimi() {
191         return kokoNimi;
192     }
193 
194 
195      /**
196      * Palauttaa kerhon jäsenten lukumäärän
197      * @return jäsenten lukumäärä
198      */
199     public int getLkm() {
200         return lkm;
201     }
202 
203 
204     /**
205      * Palauttaa tiedoston nimen, jota käytetään tallennukseen
206      * @return tallennustiedoston nimi
207      */
208     public String getTiedostonPerusNimi() {
209         return tiedostonPerusNimi;
210     }
211 
212 
213     /**
214      * Asettaa tiedoston perusnimen ilan tarkenninta
215      * @param tied tallennustiedoston perusnimi
216      */
217     public void setTiedostonPerusNimi(String tied) {
218         tiedostonPerusNimi = tied;
219     }
220 
221 
222     /**
223      * Palauttaa tiedoston nimen, jota käytetään tallennukseen
224      * @return tallennustiedoston nimi
225      */
226     public String getTiedostonNimi() {
227         return getTiedostonPerusNimi() + ".dat";
228     }
229 
230 
231     /**
232      * Palauttaa varakopiotiedoston nimen
233      * @return varakopiotiedoston nimi
234      */
235     public String getBakNimi() {
236         return tiedostonPerusNimi + ".bak";
237     }
238 
239 
240     /**
241      * Luokka jäsenten iteroimiseksi.
242      * @example
243      * <pre name="test">
244      * #THROWS SailoException 
245      * #PACKAGEIMPORT
246      * #import java.util.*;
247      * 
248      * Jasenet jasenet = new Jasenet();
249      * Jasen aku1 = new Jasen(), aku2 = new Jasen();
250      * aku1.rekisteroi(); aku2.rekisteroi();
251      *
252      * jasenet.lisaa(aku1); 
253      * jasenet.lisaa(aku2); 
254      * jasenet.lisaa(aku1); 
255      * 
256      * StringBuffer ids = new StringBuffer(30);
257      * for (Jasen jasen:jasenet)   // Kokeillaan for-silmukan toimintaa
258      *   ids.append(" "+jasen.getTunnusNro());           
259      * 
260      * String tulos = " " + aku1.getTunnusNro() + " " + aku2.getTunnusNro() + " " + aku1.getTunnusNro();
261      * 
262      * ids.toString() === tulos; 
263      * 
264      * ids = new StringBuffer(30);
265      * for (Iterator<Jasen>  i=jasenet.iterator(); i.hasNext(); ) { // ja iteraattorin toimintaa
266      *   Jasen jasen = i.next();
267      *   ids.append(" "+jasen.getTunnusNro());           
268      * }
269      * 
270      * ids.toString() === tulos;
271      * 
272      * Iterator<Jasen>  i=jasenet.iterator();
273      * i.next() == aku1  === true;
274      * i.next() == aku2  === true;
275      * i.next() == aku1  === true;
276      * 
277      * i.next();  #THROWS NoSuchElementException
278      *  
279      * </pre>
280      */
281     public class JasenetIterator implements Iterator<Jasen> {
282         private int kohdalla = -1;
283 
284 
285         /**
286          * Onko olemassa vielä seuraavaa jäsentä
287          * @see java.util.Iterator#hasNext()
288          * @return true jos on vielä jäseniä
289          */
290         @Override
291         public boolean hasNext() {
292             //       if ( kohdalla + 1 >= lkm )  return false;
293             //       return true;
294             return kohdalla + 1 < getLkm();
295         }
296 
297 
298         /**
299          * Annetaan seuraava jäsen
300          * @return seuraava jäsen
301          * @throws NoSuchElementException jos seuraava alkiota ei enää ole
302          * @see java.util.Iterator#next()
303          */
304         @Override
305         public Jasen next() throws NoSuchElementException {
306             if (!hasNext()) throw new NoSuchElementException("Ei oo");
307             kohdalla++;
308             return anna(kohdalla);
309         }
310 
311 
312         /**
313          * Tuhoamista ei ole toteutettu
314          * @throws UnsupportedOperationException aina
315          * @see java.util.Iterator#remove()
316          */
317         @Override
318         public void remove() throws UnsupportedOperationException {
319             throw new UnsupportedOperationException("Me ei poisteta");
320         }
321     }
322 
323 
324     /**
325      * Palautetaan iteraattori jäsenistään.
326      * @return jäsen iteraattori
327      */
328     @Override
329     public Iterator<Jasen> iterator() {
330         return new JasenetIterator();
331     }
332 
333 
334     /**
335      * Testiohjelma jäsenistölle
336      * @param args ei käytössä
337      */
338     public static void main(String args[]) {
339         Jasenet jasenet = new Jasenet();
340 
341         Jasen aku = new Jasen(), aku2 = new Jasen();
342         aku.rekisteroi();
343         aku.vastaaAkuAnkka();
344         aku2.rekisteroi();
345         aku2.vastaaAkuAnkka();
346 
347         try {
348             jasenet.lisaa(aku);
349             jasenet.lisaa(aku2);
350 
351             System.out.println("============= Jäsenet testi =================");
352 
353             for (int i = 0; i < jasenet.getLkm(); i++) {
354                 Jasen jasen = jasenet.anna(i);
355                 System.out.println("Jäsen nro: " + i);
356                 jasen.tulosta(System.out);
357             }
358 
359         } catch (SailoException ex) {
360             System.out.println(ex.getMessage());
361         }
362     }
363 
364 }
365