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