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         *   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         * </pre>
98         */
99        public Input(String inNimi) throws FileNotFoundException {
100         // getNL();
101         if ( inNimi != null ) {
102           stdin = new FileInputStream(inNimi);
103           setIn(stdin);
104         }
105       }
106       
107       /**
108        * Palautetaan tietovirta takaisin alkuperäiseen tilaan
109        */
110       public void palauta() {
111         if ( stdin != null ) {
112           try {
113             stdin.close();
114           } catch (IOException e) { // NOPMD
115           }
116           setIn(origIn);
117         }
118       }
119       
120     }
121 
122     /**
123      * Luokka jolla System.out suunnataan toiseen tiedostoon
124      * @author vesal
125      * @version 11.3.2007
126      */
127     public static class Output  implements ISuuntaaja  {
128       private static final PrintStream origOut = System.out; // NOPMD - ei ole vakio
129       private PrintStream stdout = null;
130       
131       /**
132        * Asetetaan perustulostusvirta eri tiedostoon.
133        * Jos nimi on null, niin sitä virtaa ei suunnata uudelleen
134        * @param outNimi mihin System.out kirjoitetaan
135        * @throws FileNotFoundException jos tiedostoa ei saada käyttöön
136        * @example
137        * <pre name="test">
138        * #THROWS IOException
139        * #import java.io.*;
140        * #import java.util.*;
141        * #import static fi.jyu.mit.ohj2.VertaaTiedosto.*;
142        *   Output out = new Output("hiljaa1.txt");
143        *   System.out.println("eka");
144        *   System.out.println("toka");
145        *   out.palauta();
146        *   vertaaFileString("hiljaa1.txt","eka\ntoka\n") === null;
147        *   tuhoaTiedosto("hiljaa1.txt"); 
148        *   
149        *   out = new Output(null);
150        *   out.palauta();
151        * </pre>
152        */
153       public Output(String outNimi) throws FileNotFoundException {
154         // getNL();
155         if ( outNimi != null ) {
156           stdout = new PrintStream(new FileOutputStream(outNimi));
157           System.setOut(stdout);
158         }
159       }
160       
161       /**
162        * Palautetaan tietovirta takaisin alkuperäiseen tilaan
163        */
164       public void palauta() {
165         if (stdout != null ) {
166           stdout.close();
167           System.setOut(origOut);
168         }
169       }
170       
171     }
172     
173     /**
174      * Luokka syötön lukemiseksi merkkijonosta
175      * @author vesal
176      * @version 2.2.2008
177      * @example
178      * <pre name="test">
179      *  StringInput si = new StringInput("kissa\nkoira");
180      *  StringOutput so = new StringOutput();
181      *  Syotto.kysy("Mikä") === "kissa";
182      *  Syotto.kysy("Mikä") === "koira";
183      *  Syotto.kysy("Mikä") === "";
184      *  si = new StringInput("12\n13");
185      *  Syotto.kysy("Luku",0) === 12;
186      *  Syotto.kysy("Luku",0) === 13;
187      *  Syotto.kysy("Luku",0) === 0;
188      *  si.palauta();
189      *  so.palauta();
190      * </pre>
191      *
192      */
193     public static class StringInput implements ISuuntaaja {
194         private static final InputStream origIn  = System.in; // NOPMD ei ole vakio
195         private ByteArrayInputStream byteinput;
196         
197 
198         /**
199          * Alustetataan lukutietovirta 
200          * @param inputString merkkijonojosta input otetaan
201          */
202         public StringInput(String inputString) {
203             byteinput = new ByteArrayInputStream(inputString.getBytes());
204             setIn(byteinput);
205         }
206 
207         /**
208          * Palautetaan tietovirta takaisin alkuperäiseen tilaan
209          */
210         public void palauta() {
211             setIn(origIn);
212         }
213         
214         /**
215          * Laitetaan syöttöön uusi merkkijono jota luetaan-
216          * @param inputString  merkkijonojosta input otetaan
217          * @example
218          * <pre name="test">
219          *  StringInput si = new StringInput("kissa\nkoira");
220          *  StringOutput so = new StringOutput();
221          *  Syotto.kysy("Mikä") === "kissa";
222          *  Syotto.kysy("Mikä") === "koira";
223          *  Syotto.kysy("Mikä") === "";
224          *  si.input("12\n13");
225          *  Syotto.kysy("Luku",0) === 12;
226          *  Syotto.kysy("Luku",0) === 13;
227          *  Syotto.kysy("Luku",0) === 0;
228          *  si.palauta();
229          *  so.palauta();
230          * </pre>
231              */
232         public void input(String inputString) {
233             byteinput = new ByteArrayInputStream(inputString.getBytes());
234             setIn(byteinput);
235         }
236     }
237     
238     
239     /**
240      * Luokka tulostuksen siirtämiseksi merkkijonoon
241      * @author vesal
242      * @version 2.2.2008
243      *
244      */
245     public static class StringOutput implements ISuuntaaja {
246         private static final PrintStream origOut = System.out; // NOPMD - ei ole vakio
247         private final ByteArrayOutputStream byteoutput;
248         
249         /**
250          * Alutetataan kirjoitustietovirta 
251          */
252         public StringOutput() {
253             // if ( NL != null ) getNL();
254             byteoutput = new ByteArrayOutputStream();
255             PrintStream ps = new PrintStream(byteoutput); 
256             System.setOut(ps);
257         }
258 
259         /**
260          * Palautetaan tietovirta takaisin alkuperäiseen tilaan
261          */
262         public void palauta() {
263             System.setOut(origOut);
264         }
265         
266         /**
267          * Palautetaan toistaiseksi tulostettu tieto merkkijonona
268          * @return tulostettu tieto
269          * @example
270          * <pre name="test">
271          *   String NL = getNL();
272          *   StringOutput so = new StringOutput();
273          *   System.out.println("eka"); 
274          *   System.out.println("toka");
275          *   so.toString() === "eka"+NL+"toka"+NL; 
276          *   System.out.println("kolmas");
277          *   so.toStringReset() === "eka"+NL+"toka"+NL+"kolmas"+NL;
278          *   so.toString() === "";
279          *   System.out.println("neljäs");
280          *   so.toStringReset() === "neljäs"+NL;
281          *   System.out.print("viides\nkuudes");
282          *   so.toStringReset() === "viides\nkuudes";
283          *   System.out.printf("viides%nkuudes");
284          *   so.toStringReset() === "viides"+NL+"kuudes";
285          *   so.palauta();
286          * </pre>
287          */
288         @Override
289         public String toString() {
290             return byteoutput.toString();
291         }
292         
293         /**
294          * Palautetaan toistaiseksi tulostettu tieto merkkijonona
295          * ja tyhjennetään tietovirta
296          * @return tulostettu tieto
297          */
298         public String toStringReset() {
299             String result = byteoutput.toString();
300             reset();
301             return result;
302         }
303         
304         /**
305          * Tyhjentää toistaiseksi tulostetun osan
306          */
307         public void reset() {
308             byteoutput.reset();
309         }
310         
311         /**
312          * Kirjoittaa sisällön tietovirtaan 
313          * @param out virta johon kirjoitetaan
314          * @throws IOException jos joku menee pieleen
315          * @example
316          * <pre name="test">
317          * #THROWS IOException
318          * PrintStream fs = Tiedosto.avaa_kirjoittamista_varten_stream("hiljaa1.txt");
319          * StringOutput so = new StringOutput();
320          * System.out.println("eka"); 
321          * System.out.println("toka");
322          * so.writeTo(fs);
323          * fs.close();
324          * so.palauta();
325          * vertaaFileString("hiljaa1.txt","eka\ntoka\n") === null;
326          * tuhoaTiedosto("hiljaa1.txt"); 
327          * </pre>
328          */
329         public void writeTo(OutputStream out) throws IOException {
330            byteoutput.writeTo(out); 
331         }
332         
333         /**
334          * Palauttaa alkuperäisen tietovirran
335          * @return alkuperäinen tietovirta
336          */
337         public PrintStream getOrigOut() {
338             return origOut;
339         }
340         
341         /**
342          * Vertaa tuloksen sisältöä jonoon ja palauttaa eron
343          * tai null jos samat.  Tyhjentää tulosteen.
344          * @param verrattava jono johon output-jonon sisältöä verrataan
345          * @return null jos samat, muuten 1. ero
346          * @example
347          * <pre name="test">
348          *   StringOutput so = new StringOutput();
349          *   System.out.println("eka"); 
350          *   System.out.println("toka");
351          *   so.ero("eka\ntoka\n")         === null; 
352          *   System.out.println("kolmas");
353          *   so.ero("eka\ntoka\nkolmas\n") === "Ero riveissä 1: kolmas ja eka";
354          *   so.toString()                 === "";
355          *   System.out.println("neljäs");
356          *   so.ero("neljäs\n")            === null;
357          *   System.out.print("viides\nkuudes");
358          *   so.ero("viides\nkuudes")      === null;
359          *   System.out.printf("viides%nkuudes");
360          *   so.ero("viides\nkuudes")      === null;
361          *   so.palauta();
362          *   so.getOrigOut() == System.out === true;
363          * </pre>
364          */
365         public String ero(String verrattava) {
366             return VertaaTiedosto.vertaaString(toStringReset(), verrattava);
367         }
368         
369     }
370     
371     
372     
373     /**
374      * Luokka jolla System.in ja System.out suunnataan toiseen tiedostoon
375      * @author vesal
376      * @version 11.3.2007
377      */
378     public static class InOut implements ISuuntaaja {
379       private final Input in;
380       private final Output out;
381       
382       /**
383        * Asetetaan perusluku- ja tulostusvirta eri tiedostoon.
384        * Jos jompikumpi nimi on null, niin sitä virtaa ei suunnata uudelleen
385        * @param inNimi mistä tiedostosta System.in luetaan
386        * @param outNimi mihin System.out kirjoitetaan
387        * @throws FileNotFoundException jos tiedostoa ei saada käyttöön
388        * @example
389        * <pre name="test">
390        * #THROWS IOException
391        *   kirjoitaTiedosto("hiljaa1.txt", "eka\ntoka\n");
392        *   InOut io = new InOut("hiljaa1.txt","hiljaa2.txt");
393        *   Syotto.kysy("1.") === "eka";
394        *   Syotto.kysy("2.") === "toka";
395        *   Syotto.kysy("3.") === "";
396        *   io.palauta();
397        *   tuhoaTiedosto("hiljaa1.txt"); 
398        *   vertaaFileString("hiljaa2.txt","1. >2. >3. >") === null;
399        *   tuhoaTiedosto("hiljaa2.txt"); 
400        * </pre>
401        */
402       public InOut(String inNimi, String outNimi) throws FileNotFoundException {
403           in = new Input(inNimi);
404           out = new Output(outNimi);
405       }
406       
407       /**
408        * Palautetaan tietovirrat takaisin alkuperäiseen tilaan
409        */
410       public void palauta() {
411           in.palauta();
412           out.palauta();
413       }
414       
415     }
416     
417     /** 
418      * Testataan suuntaamista
419      * @param args ei käytössä
420      */
421 /*    
422     public static void main(String[] args) {
423         StringInput si = new StringInput("kissa\nkoira\nkana");
424         StringOutput so = new StringOutput();
425         String s1 = Syotto.kysy("Mikä");
426         String so1 = so.toString();
427         so.getOrigOut().println("so1=" + so1);
428         si = new StringInput("12\n13\n15\n16\n17");
429         String s2 = Syotto.kysy("Kuka");
430         //si.palauta();
431         String s3 = Syotto.kysy("Mikä");
432         so.reset();
433         so.getOrigOut().println(s1 + "|" + s2 + "|" + s3);
434         String s4 = Syotto.kysy("Kuis");
435         System.out.println(s4);
436         si = new StringInput("12\n13\n15\n16\n17");
437         Scanner sc = new Scanner(System.in);
438         String s5 = sc.nextLine();
439         String s6 = Syotto.kysy("No");
440         si.palauta();
441         String so2 = so.toString();
442         so.palauta();
443         System.out.println(so1 + "|" + so2 + "|" + s5 + "|" + s6);
444     }
445 */    
446 }
447