1   package fi.jyu.mit.ohj2;
2   
3   import java.io.ByteArrayInputStream;
4   import java.io.ByteArrayOutputStream;
5   import java.io.FileInputStream;
6   import java.io.FileNotFoundException;
7   import java.io.FileOutputStream;
8   import java.io.IOException;
9   import java.io.InputStream;
10  import java.io.OutputStream;
11  import java.io.PrintStream;
12  
13  /**
14   * Luokka tietovirtojen uudelleen suuntaamiseksi
15   * @author vesal
16   * 
17   */
18  public class Suuntaaja { // NOPMD -luokkakirjasto
19  // #STATICIMPORT
20  // #import fi.jyu.mit.ohj2.*;
21      
22      /**
23       * Rajapinta suuntajalle
24       * @author vesal
25       *
26       */
27      public interface ISuuntaaja {
28          
29          /** 
30           * Palauttaa suuntauksen alkuperäiseen tilaan. 
31           */
32          void palauta();
33      }
34      
35      /**
36       * Käytössä olevan systeemin rivinvahdon merkkkijono
37       */
38      private static String NL = getNL(); // NOPMD - tarkoituksella lyhyt nimi
39      
40      
41      /**
42       * Palauttaa systeemin käytössä olevan newline jonon
43       * @return rivinvaihdon merkkiyhdistelmä käytetyssä järjestelmässä
44       */
45      public static String getNL() {
46          if ( NL != null ) return NL;
47          NL = "";
48          StringOutput so = new StringOutput();
49          System.out.println();
50          NL = so.toString();
51          so.palauta();
52          return NL;
53      }
54      
55      
56      /**
57       * Suuntaa inputin uudelleen ja kertoo Syotto-luokalle
58       * @param is uusi tietovirta syötölle
59       *  
60       */
61      protected static void setIn(InputStream is) {
62         System.setIn(is);
63         Syotto.alusta();
64         Readkey.init();
65      }
66      
67      /**
68       * Luokka jolla System.in otetaan tiedostosta
69       * @author vesal
70       * @version 11.3.2007
71       */
72      public static class Input implements ISuuntaaja {
73        private  static final InputStream origIn  = System.in; // NOPMD - ei ole vakio
74        private InputStream stdin = null;
75        
76        /**
77         * Asetetaan peruslukuvirta eri tiedostoon.
78         * Jos nimi on null, niin sitä virtaa ei suunnata uudelleen
79         * @param inNimi mistä tiedostosta System.in luetaan
80         * @throws FileNotFoundException jos tiedostoa ei saada käyttöön
81         * @example
82         * <pre name="test">
83         * #THROWS IOException
84         * #import java.io.*;
85         * #import java.util.*;
86         * #import static fi.jyu.mit.ohj2.VertaaTiedosto.*;
87         *   kirjoitaTiedosto("hiljaa1.txt", "33 hiljaa 1 hiipii\nhyvä 33 tulee\n");
88         *   Input in = new Input("hiljaa1.txt");
89         *   try ( Scanner sc = new Scanner(System.in) ) {
90         *   sc.nextLine() === "33 hiljaa 1 hiipii"; 
91         *   sc.nextLine() === "hyvä 33 tulee";
92         *   sc.hasNextLine() === false;
93         *   in.palauta();
94         *   tuhoaTiedosto("hiljaa1.txt"); 
95         *   in = new Input(null);
96         *   in.palauta();
97         *   }
98         * </pre>
99         */
100       public Input(String inNimi) throws FileNotFoundException {
101         // getNL();
102         if ( inNimi != null ) {
103           stdin = new FileInputStream(inNimi);
104           setIn(stdin);
105         }
106       }
107       
108       /**
109        * Palautetaan tietovirta takaisin alkuperäiseen tilaan
110        */
111       @Override
112       public void palauta() {
113         if ( stdin != null ) {
114           try {
115             stdin.close();
116           } catch (IOException e) { // NOPMD
117           }
118           setIn(origIn);
119         }
120       }
121       
122     }
123 
124     /**
125      * Luokka jolla System.out suunnataan toiseen tiedostoon
126      * @author vesal
127      * @version 11.3.2007
128      */
129     public static class Output  implements ISuuntaaja  {
130       private PrintStream origOut = System.out; 
131       private boolean syserr = false;
132       private PrintStream stdout = null;
133       
134       /**
135        * Asetetaan perustulostusvirta eri tiedostoon.
136        * Jos nimi on null, niin sitä virtaa ei suunnata uudelleen
137        * @param outNimi mihin System.out kirjoitetaan
138        * @throws FileNotFoundException jos tiedostoa ei saada käyttöön
139        * @example
140        * <pre name="test">
141        * #THROWS IOException
142        * #import java.io.*;
143        * #import java.util.*;
144        * #import static fi.jyu.mit.ohj2.VertaaTiedosto.*;
145        *   Output out = new Output("hiljaa1.txt");
146        *   System.out.println("eka");
147        *   System.out.println("toka");
148        *   out.palauta();
149        *   vertaaFileString("hiljaa1.txt","eka\ntoka\n") === null;
150        *   tuhoaTiedosto("hiljaa1.txt"); 
151        *   
152        *   out = new Output(null);
153        *   out.palauta();
154        * </pre>
155        */
156       public Output(String outNimi) throws FileNotFoundException {
157           this(outNimi,false);
158       }
159       
160       /**
161        * @param outNimi mihin suunnataan
162        * @param syserr suunnataanko error-virta 
163        * @throws FileNotFoundException jos tiedostoa ei saada auki
164        * <pre name="test">
165        * #THROWS IOException
166        * #import java.io.*;
167        * #import java.util.*;
168        * #import static fi.jyu.mit.ohj2.VertaaTiedosto.*;
169        *   Output out = new Output("koeOut.txt",false);
170        *   Output err = new Output("koeErr.txt",true);
171        *   System.out.println("eka");
172        *   System.err.println("toka");
173        *   out.palauta();
174        *   err.palauta();
175        *   vertaaFileString("koeOut.txt","eka\n") === null;
176        *   vertaaFileString("koeErr.txt","toka\n") === null;
177        *   tuhoaTiedosto("koeOut.txt"); 
178        *   tuhoaTiedosto("koeErr.txt"); 
179        * </pre>
180        */
181       public Output(String outNimi,boolean syserr) throws FileNotFoundException {
182           // getNL();
183           if ( outNimi != null ) {
184             stdout = new PrintStream(new FileOutputStream(outNimi));
185             if ( syserr ) { origOut = System.err; System.setErr(stdout); this.syserr = true; }
186             else { origOut = System.out; System.setOut(stdout); }
187           }
188         }
189         
190       /**
191        * Palautetaan tietovirta takaisin alkuperäiseen tilaan
192        */
193       @Override
194       public void palauta() {
195         if (stdout != null ) {
196           stdout.close();
197           if ( syserr ) System.setErr(origOut);
198           else System.setOut(origOut);
199         }
200       }
201       
202     }
203     
204     /**
205      * Luokka syötön lukemiseksi merkkijonosta
206      * @author vesal
207      * @version 2.2.2008
208      * @example
209      * <pre name="test">
210      *  StringInput si = new StringInput("kissa\nkoira");
211      *  StringOutput so = new StringOutput();
212      *  Syotto.kysy("Mikä") === "kissa";
213      *  Syotto.kysy("Mikä") === "koira";
214      *  Syotto.kysy("Mikä") === "";
215      *  si = new StringInput("12\n13");
216      *  Syotto.kysy("Luku",0) === 12;
217      *  Syotto.kysy("Luku",0) === 13;
218      *  Syotto.kysy("Luku",0) === 0;
219      *  si.palauta();
220      *  so.palauta();
221      * </pre>
222      *
223      */
224     public static class StringInput implements ISuuntaaja {
225         private static final InputStream origIn  = System.in; // NOPMD ei ole vakio
226         private ByteArrayInputStream byteinput;
227         
228 
229         /**
230          * Alustetataan lukutietovirta 
231          * @param inputString merkkijonojosta input otetaan
232          */
233         public StringInput(String inputString) {
234             byteinput = new ByteArrayInputStream(inputString.getBytes());
235             setIn(byteinput);
236         }
237 
238         /**
239          * Palautetaan tietovirta takaisin alkuperäiseen tilaan
240          */
241         @Override
242         public void palauta() {
243             setIn(origIn);
244         }
245         
246         /**
247          * Laitetaan syöttöön uusi merkkijono jota luetaan-
248          * @param inputString  merkkijonojosta input otetaan
249          * @example
250          * <pre name="test">
251          *  StringInput si = new StringInput("kissa\nkoira");
252          *  StringOutput so = new StringOutput();
253          *  Syotto.kysy("Mikä") === "kissa";
254          *  Syotto.kysy("Mikä") === "koira";
255          *  Syotto.kysy("Mikä") === "";
256          *  si.input("12\n13");
257          *  Syotto.kysy("Luku",0) === 12;
258          *  Syotto.kysy("Luku",0) === 13;
259          *  Syotto.kysy("Luku",0) === 0;
260          *  si.palauta();
261          *  so.palauta();
262          * </pre>
263              */
264         public void input(String inputString) {
265             byteinput = new ByteArrayInputStream(inputString.getBytes());
266             setIn(byteinput);
267         }
268     }
269     
270     
271     /**
272      * Luokka tulostuksen siirtämiseksi merkkijonoon
273      * @author vesal
274      * @version 2.2.2008
275      *
276      */
277     public static class StringOutput implements ISuuntaaja {
278         private PrintStream origOut = System.out; // NOPMD - ei ole vakio
279         private boolean syserr = false; 
280         private final ByteArrayOutputStream byteoutput;
281         
282         
283         /**
284          * Alustetataan kirjoitustietovirta 
285          */
286         public StringOutput() {
287             this(false);
288         }
289 
290         /**
291          * Alustetataan kirjoitustietovirta 
292          * @param syserr suunnattaanko System.err
293          * @example
294          * <pre name="test">
295          *   StringOutput se = new StringOutput(true);
296          *   StringOutput so = new StringOutput(false);
297          *   System.out.println("eka"); 
298          *   System.err.println("toka");
299          *   so.ero("eka\n") === null;
300          *   se.ero("toka\n") === null;
301          *   so.palauta();
302          *   se.palauta();
303          * </pre>
304          */
305         public StringOutput(boolean syserr) {
306             // if ( NL != null ) getNL();
307             byteoutput = new ByteArrayOutputStream();
308             PrintStream ps = new PrintStream(byteoutput); 
309             if ( syserr ) { origOut = System.err; System.setErr(ps); this.syserr = true; } 
310             else { origOut = System.out; System.setOut(ps); }
311         }
312 
313         /**
314          * Palautetaan tietovirta takaisin alkuperäiseen tilaan
315          */
316         @Override
317         public void palauta() {
318             if ( syserr ) System.setErr(origOut);
319             else System.setOut(origOut);
320         }
321         
322         /**
323          * Palautetaan toistaiseksi tulostettu tieto merkkijonona
324          * @return tulostettu tieto
325          * @example
326          * <pre name="test">
327          *   String NL = getNL();
328          *   StringOutput so = new StringOutput();
329          *   System.out.println("eka"); 
330          *   System.out.println("toka");
331          *   so.toString() === "eka"+NL+"toka"+NL; 
332          *   System.out.println("kolmas");
333          *   so.toStringReset() === "eka"+NL+"toka"+NL+"kolmas"+NL;
334          *   so.toString() === "";
335          *   System.out.println("neljäs");
336          *   so.toStringReset() === "neljäs"+NL;
337          *   System.out.print("viides\nkuudes");
338          *   so.toStringReset() === "viides\nkuudes";
339          *   System.out.printf("viides%nkuudes");
340          *   so.toStringReset() === "viides"+NL+"kuudes";
341          *   so.palauta();
342          * </pre>
343          */
344         @Override
345         public String toString() {
346             return byteoutput.toString();
347         }
348         
349         /**
350          * Palautetaan toistaiseksi tulostettu tieto merkkijonona
351          * ja tyhjennetään tietovirta
352          * @return tulostettu tieto
353          */
354         public String toStringReset() {
355             String result = byteoutput.toString();
356             reset();
357             return result;
358         }
359         
360         /**
361          * Tyhjentää toistaiseksi tulostetun osan
362          */
363         public void reset() {
364             byteoutput.reset();
365         }
366         
367         /**
368          * Kirjoittaa sisällön tietovirtaan 
369          * @param out virta johon kirjoitetaan
370          * @throws IOException jos joku menee pieleen
371          * @example
372          * <pre name="test">
373          * #THROWS IOException
374          * StringOutput so = new StringOutput();
375          * try ( PrintStream fs = Tiedosto.avaa_kirjoittamista_varten_stream("hiljaa1.txt") ) {
376          * System.out.println("eka"); 
377          * System.out.println("toka");
378          * so.writeTo(fs);
379          * }
380          * so.palauta();
381          * vertaaFileString("hiljaa1.txt","eka\ntoka\n") === null;
382          * tuhoaTiedosto("hiljaa1.txt"); 
383          * </pre>
384          */
385         public void writeTo(OutputStream out) throws IOException {
386            byteoutput.writeTo(out); 
387         }
388         
389         /**
390          * Palauttaa alkuperäisen tietovirran
391          * @return alkuperäinen tietovirta
392          */
393         @SuppressWarnings("static-method")
394         public PrintStream getOrigOut() {
395             return origOut;
396         }
397         
398         /**
399          * Vertaa tuloksen sisältöä jonoon ja palauttaa eron
400          * tai null jos samat.  Tyhjentää tulosteen.
401          * @param verrattava jono johon output-jonon sisältöä verrataan
402          * @return null jos samat, muuten 1. ero
403          * @example
404          * <pre name="test">
405          *   StringOutput so = new StringOutput();
406          *   System.out.println("eka"); 
407          *   System.out.println("toka");
408          *   so.ero("eka\ntoka\n")         === null; 
409          *   System.out.println("kolmas");
410          *   so.ero("eka\ntoka\nkolmas\n") === "Ero riveissä 1: kolmas ja eka";
411          *   so.toString()                 === "";
412          *   System.out.println("neljäs");
413          *   so.ero("neljäs\n")            === null;
414          *   System.out.print("viides\nkuudes");
415          *   so.ero("viides\nkuudes")      === null;
416          *   System.out.printf("viides%nkuudes");
417          *   so.ero("viides\nkuudes")      === null;
418          *   so.palauta();
419          *   so.getOrigOut() == System.out === true;
420          * </pre>
421          */
422         public String ero(String verrattava) {
423             return VertaaTiedosto.vertaaString(toStringReset(), verrattava);
424         }
425         
426     }
427     
428     
429     
430     /**
431      * Luokka jolla System.in ja System.out suunnataan toiseen tiedostoon
432      * @author vesal
433      * @version 11.3.2007
434      */
435     public static class InOut implements ISuuntaaja {
436       private final Input in;
437       private final Output out;
438       
439       /**
440        * Asetetaan perusluku- ja tulostusvirta eri tiedostoon.
441        * Jos jompikumpi nimi on null, niin sitä virtaa ei suunnata uudelleen
442        * @param inNimi mistä tiedostosta System.in luetaan
443        * @param outNimi mihin System.out kirjoitetaan
444        * @throws FileNotFoundException jos tiedostoa ei saada käyttöön
445        * @example
446        * <pre name="test">
447        * #THROWS IOException
448        *   kirjoitaTiedosto("hiljaa1.txt", "eka\ntoka\n");
449        *   InOut io = new InOut("hiljaa1.txt","hiljaa2.txt");
450        *   Syotto.kysy("1.") === "eka";
451        *   Syotto.kysy("2.") === "toka";
452        *   Syotto.kysy("3.") === "";
453        *   io.palauta();
454        *   tuhoaTiedosto("hiljaa1.txt"); 
455        *   vertaaFileString("hiljaa2.txt","1. >2. >3. >") === null;
456        *   tuhoaTiedosto("hiljaa2.txt"); 
457        * </pre>
458        */
459       public InOut(String inNimi, String outNimi) throws FileNotFoundException {
460           in = new Input(inNimi);
461           out = new Output(outNimi);
462       }
463       
464       /**
465        * Palautetaan tietovirrat takaisin alkuperäiseen tilaan
466        */
467       @Override
468       public void palauta() {
469           in.palauta();
470           out.palauta();
471       }
472       
473     }
474     
475     /** 
476      * Testataan suuntaamista
477      * @param args ei käytössä
478      */
479 /*    
480     public static void main(String[] args) {
481         StringInput si = new StringInput("kissa\nkoira\nkana");
482         StringOutput so = new StringOutput();
483         String s1 = Syotto.kysy("Mikä");
484         String so1 = so.toString();
485         so.getOrigOut().println("so1=" + so1);
486         si = new StringInput("12\n13\n15\n16\n17");
487         String s2 = Syotto.kysy("Kuka");
488         //si.palauta();
489         String s3 = Syotto.kysy("Mikä");
490         so.reset();
491         so.getOrigOut().println(s1 + "|" + s2 + "|" + s3);
492         String s4 = Syotto.kysy("Kuis");
493         System.out.println(s4);
494         si = new StringInput("12\n13\n15\n16\n17");
495         Scanner sc = new Scanner(System.in);
496         String s5 = sc.nextLine();
497         String s6 = Syotto.kysy("No");
498         si.palauta();
499         String so2 = so.toString();
500         so.palauta();
501         System.out.println(so1 + "|" + so2 + "|" + s5 + "|" + s6);
502     }
503 */    
504 }
505