1   package kerho;
2   
3   import java.io.*;
4   import java.util.Comparator;
5   
6   import kanta.HetuKentta;
7   import kanta.HetuTarkistus;
8   import kanta.IntKentta;
9   import kanta.JonoKentta;
10  import kanta.Kentta;
11  import kanta.PuhelinKentta;
12  import kanta.RahaKentta;
13  import kanta.RegExpTarkistaja;
14  import kanta.SisaltaaTarkistaja;
15  
16  import fi.jyu.mit.ohj2.Mjonot;
17  
18  import static kanta.HetuTarkistus.*;
19  
20  /**
21   * Kerhon jäsen joka osaa mm. itse huolehtia tunnusNro:staan.
22   *
23   * @author Vesa Lappalainen
24   * @version 1.0, 22.02.2003
25   * @version 2.0, 09.01.2011 - kentät indeksoituna
26   */
27  public class Jasen implements Cloneable {
28      private Kentta     kentat[]    = { // valitettavasti ei voi olla final
29                                         // vaikka pitäisi, clone estää tämän :-(
30              new IntKentta("id"),
31              new JonoKentta("nimi"),
32              new HetuKentta("hetu", new HetuTarkistus()),
33              new JonoKentta("katuosoite"),
34              new JonoKentta("postinumero", new SisaltaaTarkistaja(SisaltaaTarkistaja.NUMEROT)),
35              new JonoKentta("postiosoite"),
36              new PuhelinKentta("kotipuhelin"),
37              new PuhelinKentta("työpuhelin"),
38              new JonoKentta("autopuhelin", new RegExpTarkistaja("[- 0-9]*")),
39              new IntKentta("liittymisvuosi"),
40              new RahaKentta("jäsenmaksu"),
41              new RahaKentta("maksettumaksu"),
42              new JonoKentta("lisätietoja")
43      };
44  
45      private static int seuraavaNro    = 1;
46  
47      /**
48       * Luokka joka vertaa kahta jäsentä keskenään 
49       */
50      public static class Vertailija implements Comparator<Jasen> {
51  
52          private final int kenttanro;
53  
54  
55          /**
56           * Alustetaan vertailija vertailemaan tietyn kentän perusteella
57           * @param k vertailtavan kentän indeksi.
58           */
59          public Vertailija(int k) {
60              this.kenttanro = k;
61          }
62  
63  
64          /**
65           * Verrataana kahta jäsentä keskenään.
66           * @param j1 1. verrattava jäsen
67           * @param j2 2. verrattava jäsen
68           * @return <0 jos j1 < j2, == 0 jos j1 == j2 ja muuten >0
69           */
70          @Override
71          public int compare(Jasen j1, Jasen j2) {
72              String s1 = j1.getAvain(kenttanro);
73              String s2 = j2.getAvain(kenttanro);
74  
75              return s1.compareTo(s2);
76  
77          }
78  
79      }
80  
81      /**
82       * Palauttaa jäsenen kenttien lukumäärän
83       * @return kenttien lukumäärä
84       */
85      public int getKenttia() {
86          return kentat.length;
87      }
88  
89  
90      /**
91       * Eka kenttä joka on mielekäs kysyttäväksi
92       * @return eknn kentän indeksi
93       */
94      public int ekaKentta() {
95          return 1;
96      }
97  
98      
99      /**
100      * Alustetaan jäsenen merkkijono-attribuuti tyhjiksi jonoiksi
101      * ja tunnusnro = 0.
102      */
103     public Jasen() {
104         // Toistaiseksi ei tarvita mitään
105     }
106 
107 
108     /**
109      * @return jäsenen nimi
110      * @example
111      * <pre name="test">
112      *   Jasen aku = new Jasen();
113      *   aku.vastaaAkuAnkka();
114      *   aku.getNimi() =R= "Ankka Aku .*";
115      * </pre>
116      */
117     public String getNimi() {
118         return anna(1);
119     }
120 
121     
122     /**
123      * Antaa k:n kentän sisällön merkkijonona
124      * @param k monenenko kentän sisältö palautetaan
125      * @return kentän sisältö merkkijonona
126      */
127     public String anna(int k) { 
128         try {
129             return kentat[k].toString();
130         } catch (Exception ex) {
131             return "";
132         }
133     }
134 
135 
136     /**
137      * Antaa k:n kentän sisällön avain-merkkijonona
138      * jonka perusteella voi lajitella
139      * @param k monenenko kentän sisältö palautetaan
140      * @return kentän sisältö merkkijonona
141      *
142      * @example
143      * <pre name="test">
144      *   Jasen aku = new Jasen();
145      *   aku.parse("   1  |  Ankka Aku   | 030201-111C");
146      *   aku.getAvain(0) === "         1";
147      *   aku.getAvain(1) === "ANKKA AKU";
148      *   aku.getAvain(2) === "010203-111C";
149      *   aku.getAvain(20) === "";
150      * </pre>
151      */
152     public String getAvain(int k) {
153         try {
154             return kentat[k].getAvain();
155         } catch (Exception ex) {
156             return "";
157         }
158     }
159 
160 
161     /**
162      * Asettaa k:n kentän arvoksi parametrina tuodun merkkijonon arvon
163      * @param k kuinka monennen kentän arvo asetetaan
164      * @param jono jonoa joka asetetaan kentän arvoksi
165      * @return null jos asettaminen onnistuu, muuten vastaava virheilmoitus.
166      * @example
167      * <pre name="test">
168      *   Jasen jasen = new Jasen();
169      *   jasen.aseta(1,"Ankka Aku") === null;
170      *   jasen.aseta(2,"kissa") =R= "Hetu liian lyhyt"
171      *   jasen.aseta(2,"030201-1111") === "Tarkistusmerkin kuuluisi olla C"; 
172      *   jasen.aseta(2,"030201-111C") === null; 
173      *   jasen.aseta(9,"kissa") === "Virhe: jono = \"kissa\"";
174      *   jasen.aseta(9,"1940") === null;
175      * </pre>
176      */
177     public String aseta(int k, String jono) { 
178         try {
179             String virhe = kentat[k].aseta(jono.trim());
180             if ( virhe == null && k == 0 ) setTunnusNro(getTunnusNro());
181             return virhe;
182         } catch (Exception ex) {
183             return "Virhe: " + ex.getMessage();
184         }
185     }
186 
187 
188     /**
189      * Palauttaa k:tta jäsenen kenttää vastaavan kysymyksen
190      * @param k kuinka monennen kentän kysymys palautetaan (0-alkuinen)
191      * @return k:netta kenttää vastaava kysymys
192      */
193     public String getKysymys(int k) { 
194         try {
195             return kentat[k].getKysymys();
196         } catch (Exception ex) {
197             return "Ääliö";
198         }
199     }
200 
201     /**
202      * Apumetodi, jolla saadaan täytettyä testiarvot jäsenelle.
203      * @param apuhetu hetu joka annetaan henkilölle 
204      */
205     public void vastaaAkuAnkka(String apuhetu) {
206         aseta(1,"Ankka Aku " + kanta.HetuTarkistus.rand(1000, 9999));
207         aseta(2,apuhetu);                                            
208         aseta(3,"Ankkakuja 6");                                      
209         aseta(4,"12345");                                            
210         aseta(5,"ANKKALINNA");                                       
211         aseta(6,"12-1234");                                          
212         aseta(7,"");                                                 
213         aseta(8,"");                                                 
214         aseta(9,"1996");                                             
215         aseta(10,"50");                                              
216         aseta(11,"30");                                              
217         aseta(12,"Velkaa Roopelle");                                 
218     }
219 
220 
221     /**
222      * Apumetodi, jolla saadaan täytettyä testiarvot jäsenelle.
223      * Henkilötunnus arvotaan, jotta kahdella jäsenellä ei olisi
224      * samoja tietoja.
225      */
226     public void vastaaAkuAnkka() {
227         String apuhetu = arvoHetu();
228         vastaaAkuAnkka(apuhetu);
229     }
230 
231 
232     /**
233      * Tulostetaan henkilön tiedot
234      * @param out tietovirta johon tulostetaan
235      */
236     public void tulosta(PrintStream out) {
237         int pisin = 0;
238         for (Kentta kentta : kentat)
239             if (kentta.getKysymys().length() > pisin)
240                 pisin = kentta.getKysymys().length();
241 
242         for (Kentta kentta : kentat)
243             out.println(Mjonot.fmt(kentta.getKysymys(), -pisin - 1) +
244                     ": " + kentta.toString());
245     }
246 
247 
248     /**
249      * Tulostetaan henkilön tiedot
250      * @param os tietovirta johon tulostetaan
251      */
252     public void tulosta(OutputStream os) {
253         tulosta(new PrintStream(os));
254     }
255 
256 
257     /**
258      * Antaa jäsenelle seuraavan rekisterinumeron.
259      * @return jäsenen uusi tunnusNro
260      * @example
261      * <pre name="test">
262      *   Jasen aku1 = new Jasen();
263      *   aku1.getTunnusNro() === 0;
264      *   aku1.rekisteroi();
265      *   Jasen aku2 = new Jasen();
266      *   aku2.rekisteroi();
267      *   int n1 = aku1.getTunnusNro();
268      *   int n2 = aku2.getTunnusNro();
269      *   n1 === n2-1;
270      * </pre>
271      */
272     public int rekisteroi() {
273         return setTunnusNro(seuraavaNro);
274     }
275 
276 
277     /**
278      * Palauttaa jäsenen tunnusnumeron.
279      * @return jäsenen tunnusnumero
280      */
281     public int getTunnusNro() {
282         return ((IntKentta)(kentat[0])).getValue();
283     }
284 
285 
286     /**
287      * Asettaa tunnusnumeron ja samalla varmistaa että
288      * seuraava numero on aina suurempi kuin tähän mennessä suurin.
289      * @param nr asetettava tunnusnumero
290      */
291     private int setTunnusNro(int nr) {
292         IntKentta k = ((IntKentta)(kentat[0]));
293         k.setValue(nr);
294         if (nr >= seuraavaNro) seuraavaNro = nr + 1;
295         return k.getValue();
296     }
297     
298 
299     /**
300      * Palauttaa jäsenen tiedot merkkijonona jonka voi tallentaa tiedostoon.
301      * @return jäsen tolppaeroteltuna merkkijonona 
302      * @example
303      * <pre name="test">
304      *   Jasen jasen = new Jasen();
305      *   jasen.parse("   3  |  Ankka Aku   | 030201-111C");
306      *   jasen.toString().startsWith("3|Ankka Aku|030201-111C|") === true; // on enemmäkin kuin 3 kenttää, siksi loppu |
307      * </pre>  
308      */
309     @Override
310     public String toString() {
311         StringBuffer sb = new StringBuffer("");
312         String erotin = "";
313         for (int k = 0; k < getKenttia(); k++) {
314             sb.append(erotin);
315             sb.append(anna(k));
316             erotin = "|";
317         }
318         return sb.toString();
319     }
320 
321 
322     /**
323      * Selvitää jäsenen tiedot | erotellusta merkkijonosta
324      * Pitää huolen että seuraavaNro on suurempi kuin tuleva tunnusNro.
325      * @param rivi josta jäsenen tiedot otetaan
326      * 
327      * @example
328      * <pre name="test">
329      *   Jasen jasen = new Jasen();
330      *   jasen.parse("   3  |  Ankka Aku   | 030201-111C");
331      *   jasen.getTunnusNro() === 3;
332      *   jasen.toString().startsWith("3|Ankka Aku|030201-111C|") === true; // on enemmäkin kuin 3 kenttää, siksi loppu |
333      *
334      *   jasen.rekisteroi();
335      *   int n = jasen.getTunnusNro();
336      *   jasen.parse(""+(n+20));       // Otetaan merkkijonosta vain tunnusnumero
337      *   jasen.rekisteroi();           // ja tarkistetaan että seuraavalla kertaa tulee yhtä isompi
338      *   jasen.getTunnusNro() === n+20+1;
339      *     
340      * </pre>
341      */
342     public void parse(String rivi) {
343         StringBuffer sb = new StringBuffer(rivi);
344         for (int k = 0; k < getKenttia(); k++)
345             aseta(k, Mjonot.erota(sb, '|'));
346     }
347     
348     
349     /**
350      * Tehdään identtinen klooni jäsenestä
351      * @return Object kloonattu jäsen
352      * @example
353      * <pre name="test">
354      * #THROWS CloneNotSupportedException 
355      *   Jasen jasen = new Jasen();
356      *   jasen.parse("   3  |  Ankka Aku   | 123");
357      *   Jasen kopio = jasen.clone();
358      *   kopio.toString() === jasen.toString();
359      *   jasen.parse("   4  |  Ankka Tupu   | 123");
360      *   kopio.toString().equals(jasen.toString()) === false;
361      * </pre>
362      */
363     @Override
364     public Jasen clone() throws CloneNotSupportedException { // NOPMD
365         Jasen uusi;
366         uusi = (Jasen)super.clone();
367         uusi.kentat = kentat.clone();
368 
369         for (int k = 0; k < getKenttia(); k++)
370             uusi.kentat[k] = kentat[k].clone();
371         return uusi;
372     }
373 
374 
375     /**
376      * Tutkii onko jäsenen tiedot samat kuin parametrina tuodun jäsenen tiedot
377      * @param jasen jäsen johon verrataan
378      * @return true jos kaikki tiedot samat, false muuten
379      * @example
380      * <pre name="test">
381      *   Jasen jasen1 = new Jasen();
382      *   jasen1.parse("   3  |  Ankka Aku   | 030201-111C");
383      *   Jasen jasen2 = new Jasen();
384      *   jasen2.parse("   3  |  Ankka Aku   | 030201-111C");
385      *   Jasen jasen3 = new Jasen();
386      *   jasen3.parse("   3  |  Ankka Aku   | 030201-115H");
387      *   
388      *   jasen1.equals(jasen2) === true;
389      *   jasen2.equals(jasen1) === true;
390      *   jasen1.equals(jasen3) === false;
391      *   jasen3.equals(jasen2) === false;
392      * </pre>
393      */
394     public boolean equals(Jasen jasen) { // NOPMD
395         for (int k = 0; k < getKenttia(); k++)
396             if (!anna(k).equals(jasen.anna(k))) return false;
397         return true;
398     }
399 
400     
401     /**
402      * Testiohjelma jäsenelle.
403      * @param args ei käytössä
404      */
405     public static void main(String args[]) {
406         Jasen aku = new Jasen(), aku2 = new Jasen();
407         aku.rekisteroi();
408         aku2.rekisteroi();
409         aku.tulosta(System.out);
410         aku.vastaaAkuAnkka();
411         aku.tulosta(System.out);
412 
413         aku2.vastaaAkuAnkka();
414         aku2.tulosta(System.out);
415 
416         aku2.vastaaAkuAnkka();
417         aku2.tulosta(System.out);
418     }
419 
420 }
421