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