package com.macfaq.io;

import java.io.*;

public class SourceReader extends FilterReader {

  public SourceReader(InputStream in) {
    this(new InputStreamReader(in));
  }

  public SourceReader(Reader in) {
    super(in);
  }

  private int buffer = -1;

  public int read() throws IOException {
  
    if (this.buffer != -1) {
      int c = this.buffer;
      this.buffer = -1; 
      return c;
    }
    
    int c = in.read();
    if (c != '\\') return c;
   
   int next = in.read();
   if (next != 'u' ) { // This is not a Unicode escape
     this.buffer = next;
     return c;
   }
   
   // read next 4 hex digits
   // If the next four chars do not make a valid hex digit
   // this is not a valid .java file and you need 
   // a compiler error
   StringBuffer sb = new StringBuffer();
   sb.append((char) in.read());
   sb.append((char) in.read());
   sb.append((char) in.read());
   sb.append((char) in.read());
   String hex = sb.toString();  
   try {
     return Integer.valueOf(hex, 16).intValue();
   }
   catch (NumberFormatException e) {
     throw new IOException("Bad Unicode escape: \\u" + hex);  
   }
   
  }
 
  
  private boolean endOfStream = false;
  
  public int read(char[] text, int offset, int length) throws IOException {
  
    if (endOfStream) return -1;
    int numRead = 0;
    
    for (int i = offset; i < offset+length; i++) {
      int temp = this.read();
      if (temp == -1) {
        this.endOfStream = true;
        break;
      }
      text[i] = (char) temp;
      numRead++;
    }
    return numRead;
  
  }

  public long skip(long n) throws IOException {

    char[] c = new char[(int) n];
    int numSkipped = this.read(c);
    return numSkipped;
    
  }
  
  // test
  public static void main(String[] args) {
   
   for (int i = 0; i < args.length; i++) {
    
     try {
       InputStream in = new FileInputStream(args[i]);
       Reader r = new SourceReader(in);
       char[] text = new char[128];
       while (true) {
         int n = r.read(text);
         if (n == -1) {
           System.out.println("End of file");
           System.out.flush();
           break;
         }
         for (int j = 0; j < n; j++) {
           System.out.print(text[j]);
         }
       }
     }
     catch (IOException e) {
       System.err.println(e);
     }
    
   } 
    
// generate test data
/*   
   for (int i = 32; i < 127; i++) {
     System.out.println("// " + (char) i + "\t\\\\u00" 
      + Integer.toHexString(i) + "\t\\u00" + Integer.toHexString(i)); 
   }
*/   
    
  }

}


// For testing some Unicode escapes when this program is run on itself:
//      \\u0020 \u0020
// !    \\u0021 \u0021
// "    \\u0022 \u0022
// #    \\u0023 \u0023
// $    \\u0024 \u0024
// %    \\u0025 \u0025
// &    \\u0026 \u0026
// '    \\u0027 \u0027
// (    \\u0028 \u0028
// )    \\u0029 \u0029
// *    \\u002a \u002a
// +    \\u002b \u002b
// ,    \\u002c \u002c
// -    \\u002d \u002d
// .    \\u002e \u002e
// /    \\u002f \u002f
// 0    \\u0030 \u0030
// 1    \\u0031 \u0031
// 2    \\u0032 \u0032
// 3    \\u0033 \u0033
// 4    \\u0034 \u0034
// 5    \\u0035 \u0035
// 6    \\u0036 \u0036
// 7    \\u0037 \u0037
// 8    \\u0038 \u0038
// 9    \\u0039 \u0039
// :    \\u003a \u003a
// ;    \\u003b \u003b
// <    \\u003c \u003c
// =    \\u003d \u003d
// >    \\u003e \u003e
// ?    \\u003f \u003f
// @    \\u0040 \u0040
// A    \\u0041 \u0041
// B    \\u0042 \u0042
// C    \\u0043 \u0043
// D    \\u0044 \u0044
// E    \\u0045 \u0045
// F    \\u0046 \u0046
// G    \\u0047 \u0047
// H    \\u0048 \u0048
// I    \\u0049 \u0049
// J    \\u004a \u004a
// K    \\u004b \u004b
// L    \\u004c \u004c
// M    \\u004d \u004d
// N    \\u004e \u004e
// O    \\u004f \u004f
// P    \\u0050 \u0050
// Q    \\u0051 \u0051
// R    \\u0052 \u0052
// S    \\u0053 \u0053
// T    \\u0054 \u0054
// U    \\u0055 \u0055
// V    \\u0056 \u0056
// W    \\u0057 \u0057
// X    \\u0058 \u0058
// Y    \\u0059 \u0059
// Z    \\u005a \u005a
// [    \\u005b \u005b
// \    \\u005c \u005c
// ]    \\u005d \u005d
// ^    \\u005e \u005e
// _    \\u005f \u005f
// `    \\u0060 \u0060
// a    \\u0061 \u0061
// b    \\u0062 \u0062
// c    \\u0063 \u0063
// d    \\u0064 \u0064
// e    \\u0065 \u0065
// f    \\u0066 \u0066
// g    \\u0067 \u0067
// h    \\u0068 \u0068
// i    \\u0069 \u0069
// j    \\u006a \u006a
// k    \\u006b \u006b
// l    \\u006c \u006c
// m    \\u006d \u006d
// n    \\u006e \u006e
// o    \\u006f \u006f
// p    \\u0070 \u0070
// q    \\u0071 \u0071
// r    \\u0072 \u0072
// s    \\u0073 \u0073
// t    \\u0074 \u0074
// u    \\u0075 \u0075
// v    \\u0076 \u0076
// w    \\u0077 \u0077
// x    \\u0078 \u0078
// y    \\u0079 \u0079
// z    \\u007a \u007a
// {    \\u007b \u007b
// |    \\u007c \u007c
// }    \\u007d \u007d
// ~    \\u007e \u007e