package futils;

import javax.swing.*;
import java.awt.*;
import java.io.*;
import java.util.StringTokenizer;

/** The Futil class contains a number of methods for manipulating
 * files.
 *
 * @author Douglas Lyon
 * @version 2.0
 */
public final class Futil {
  /**
   * Don't let anyone instantiate this class.
   */
  private Futil() {
  }

  public static boolean isSwing = false;

  public static String getFile(File file) {
    try {
      char[] chars = new char[(int) file.length()];
      BufferedReader in = new BufferedReader(new FileReader(file));
      in.read(chars);
      in.close();
      return new String(chars);
    } catch (IOException e) {
      System.out.println("failed reading " + file.getName() + ": " + e);
      return null;
    }
  }
  public static void testGetFile() {
      String s = Futil.getFile(Futil.getReadFile("select a file"));
      System.out.println(s);
  }
  public static void main(String args[]) {
      testGetFile();
  }

  public static void saveFile(File file, String newText) {
    try {
      char[] chars = newText.toCharArray();
      BufferedWriter out = new BufferedWriter(
          new FileWriter(file));
      out.write(chars);
      out.close();
    } catch (IOException e) {
      System.out.println(
          "failed reading "
          + file.getName()
          + ": " + e);
    }
  }

  public static void binaryCopyFile() {
    byte b[] = readBytes(getReadFile("select a file"));
    writeBytes(getWriteFile("select a file to copy to"), b);
    System.out.println("copy done!");
  }

  /**
   *  copy the file input stream into the file output
   * stream.
   */
  public static void binaryCopyFile(FileInputStream fis,
                                    FileOutputStream fos)
      throws IOException {
    byte buffer[] = new byte[512];
    int count;
    while ((count = fis.read(buffer)) > 0)
      fos.write(buffer, 0, count);


  }

  public static void print(byte b[]) {
    for (int i = 0; i < b.length; i++) {
      if ((i % 10) == 0)
        System.out.println();
      System.out.print(b[i] + " ");
    }
  }

  /**
   * Futil.writeBytes inputs a File, f and byte array.
   *
   * Any failures cause readBytes to return false and
   * a message is printed to the console.
   * Otherwise, writeBytes returns true.
   */
  public static boolean writeBytes(File f, byte b[]) {
    FileOutputStream fos = null;
    try {
      fos = new FileOutputStream(f);
      fos.write(b);
      fos.close();
      return true;
    } catch (IOException e) {
      System.out.println("Futil.writeBytes,Could not open" + f);
      return false;
    }
  }

  /**
   * Futil.readBytes inputs a File, f and
   * returns an array of bytes read from the file.
   * Any failures cause readBytes to return null.
   * A message is printed to the console.
   */
  public static byte[] readBytes(File f) {
    FileInputStream fis = null;
    int sizeInBytes = -1;
    byte buffer[] = null;
    try {
      fis = new FileInputStream(f);
      sizeInBytes = fis.available();
      buffer = new byte[sizeInBytes];
      fis.read(buffer);
      fis.close();
    } catch (IOException e) {
      System.out.println("Futil:readBytes, Could not open file");
    }
    return buffer;
  }


  /** copy and input file to an output file.
   */
  public static void copyFile(BufferedReader br,
                              BufferedWriter bw)
      throws IOException {
    String line = null;
    while ((line =
        br.readLine()) != null)
      bw.write(line + "\n");
    br.close();
    bw.close();
  }


  public static FileOutputStream getFileOutputStream(String prompt) {
    return getFileOutputStream(
        getWriteFile(prompt));
  }

  public static FileOutputStream getFileOutputStream(File f) {
    try {
      return new FileOutputStream(f);
    } catch (Exception e) {
      System.out.println("Er: FileOutputStream in Futil.java");
    }
    return null;
  }

  public static FileInputStream getFileInputStream(String prompt) {
    try {
      return new FileInputStream(
          Futil.getReadFile(prompt));
    } catch (Exception e) {
      System.out.println("Er: FileOutputStream in Futil.java");
    }
    return null;
  }

  public static boolean isSwing() {
    return isSwing;
  }
  public static void setSwing(boolean b) {
    isSwing = b;
  }




// Some versions of windows will
// create a .* suffix on a file name
// The following code will strip it:
  public static String FilterFileNameBug(String fname) {
    if (fname.endsWith(".*.*")) {
      fname = fname.substring(0, fname.length() - 4);
    }
    return fname;
  }



// Open the file, return -1 if file cannot be opened
// otherwise return the size in bytes
  public static int available(File file) {
    FileInputStream fis = null;
    int sizeInBytes = -1;
    try {
      fis = new FileInputStream(file);
      sizeInBytes = fis.available();
      fis.close();
    } catch (IOException e) {
      System.out.println("Futil:Could not open file");
    }
    return sizeInBytes;
  }

  public static void close(OutputStream os) {
    try {
      os.close();
    } catch (IOException exe) {
      System.out.println(
          "futil: could not close output stream");
    }
  }


  static public void filterHtmls() {
    File files[] = Ls.getWildFiles(".gui.html");
    File input_dir = Futil.getReadFile("select an gui.html file");
    System.out.println(files.length + " file(s) to process");

    File output_dir = new File(input_dir.getParent(), "out");
    if (output_dir.exists())
      System.out.println("Output dir exists:" + output_dir);
    else
      output_dir.mkdir();

    //for (int i=0; i < files.length; i++)
    //          writeFilteredHrefFile(
    //              input_dir+files[i],
    //              output_dir+
    //              "/"+
    //              files[i]);

  }

  public static void writeFilteredHrefFile() throws IOException {
    FileReader fr = ReaderUtil.getFileReader("select an gui.html file");
    StreamTokenizer st =
        new StreamTokenizer(fr);


    FileWriter fw = WriterUtil.getFileWriter("select an HTML file for output");
    PrintWriter pw = new PrintWriter(fw);
    int i;
    int next = 0;
    st.resetSyntax();
    st.wordChars(0, 255);
    st.quoteChar('"');
    while ((next = st.nextToken()) != st.TT_EOF) {
      switch (next) {
        case '"':
          pw.print('"');
          for (i = 0; i < st.sval.length(); i++)
            if (st.sval.charAt(i) == ' ')
              pw.print("%20");
            else
              pw.print(st.sval.charAt(i));
          pw.print('"');
          break;
        case StreamTokenizer.TT_WORD:
          pw.print(st.sval + " ");
          break;
        case StreamTokenizer.TT_NUMBER:
          pw.print(st.nval + " ");
          break;
        case StreamTokenizer.TT_EOL:
          pw.println();
          break;
      } // end switch
    } // end while
    WriterUtil.close(fw);
    ReaderUtil.close(fr);
  }


  public static void writeFilteredJavaFile() {
    try {
      FileReader is = ReaderUtil.getFileReader("select a java file");
      StreamTokenizer tokens = new StreamTokenizer(is);

      PrintStream output = System.out;
      int i;
      int next = 0;
      tokens.resetSyntax();
      tokens.wordChars(0, 255);
      tokens.quoteChar(';');
      while ((next = tokens.nextToken()) != tokens.TT_EOF) {
        switch (next) {
          case ';':

            output.print("got a line:" + tokens.lineno());
            break;
          case StreamTokenizer.TT_WORD:
            output.print(tokens.sval + " ");
            break;
          case StreamTokenizer.TT_NUMBER:
            output.print(tokens.nval + " ");
            break;
          case StreamTokenizer.TT_EOL:
            output.println();
            break;
        } // end switch
      } // end while
      is.close();
    } // end try
    catch (Exception exe) {
      System.out.println("writeFilteredHrefFile:er!");
    }
  }

  /**
   * Inputs an gui.html file and uses
   * %20 where spaces are seen in the hrefs.
   */
  public static void filterFileHrefs() throws IOException {
    FileReader fis = ReaderUtil.getFileReader("select an gui.html file");
    StreamTokenizer tokens = new StreamTokenizer(fis);
    int next = 0;
    tokens.resetSyntax();
    tokens.wordChars(0, 255);
    tokens.quoteChar('"');

    while ((next = tokens.nextToken())
        != tokens.TT_EOF) {
      switch (next) {
        case '"':
          System.out.print('"');
          StringTokenizer st =
              new StringTokenizer(tokens.sval, " ");
          while (st.hasMoreTokens()) {
            System.out.print(st.nextToken());
            if (st.countTokens() > 1) {
              System.out.print("%20");
            }
          }
          System.out.print('"');
          break;
        case StreamTokenizer.TT_WORD:
          System.out.print(tokens.sval + " ");
          break;
        case StreamTokenizer.TT_NUMBER:
          System.out.print(tokens.nval + " ");
          break;
        case StreamTokenizer.TT_EOL:
          System.out.println();
          break;
      } // switch
    }
    System.out.println();
    ReaderUtil.close(fis);
  }


  public static void processJava() {
    FileReader fis = ReaderUtil.getFileReader("select a java file");
    String line;
    BufferedReader dis = new BufferedReader(fis);
    System.out.println("<HTML><BODY><PRE>");
    try {
      while ((line = dis.readLine()) != null)
        System.out.println(line);
    } catch (IOException e) {
      System.out.println("Futil: ER! in processJava");
    }
    System.out.println("</PRE></BODY></HTML>");
    ReaderUtil.close(fis);
  }

  /** Inputs a path to a file, lists all the files in
   * the directory and renames them so that they are lower case.
   *
   * @param thePath the path to file used for processing.
   */
  public static void lowerFileNames(File thePath) {
    String[] fileNames = thePath.list();
    String pathstr = thePath.getPath();
    for (int i = 0;
         fileNames != null &&
        i < fileNames.length; i++) {
      String aFileName = fileNames[i];
      String newFileName = aFileName.toLowerCase();
      File theFile = new File(pathstr, aFileName);
      if (theFile.isFile()) {
        //rename theFile to lower case
        System.out.print(i + ":" + aFileName);
        theFile.renameTo(new File(pathstr, newFileName));
        System.out.println("\t==>\t" + newFileName);
      } else {
        //case theFile is Dir, in the Dir, repeat same procedure
        System.out.println("Dir:" + aFileName);
        lowerFileNames(new File(pathstr + aFileName));
      }
    }
    return;
  }//lowerFileNames

  /**
   * inputs all the files in a directory and
   * outputs a series of HREFS in gui.html as a table
   * of contents.
   */
  public static void makeTocHtml() {
    File[] files = WriterUtil.getFiles("select an gui.html file");
    System.out.println(files.length +
                       " file(s):");
    FileWriter fw = WriterUtil.getFileWriter("Select select List.gui.html");
    PrintWriter pw = new PrintWriter(fw);
    writeTocInHtml(pw, files);
    WriterUtil.close(fw);
  }

  public static File getReadFile(String prompt) {
    if (isSwing) return JGetReadFile(prompt);
    return getReadFileAWT(prompt);
  }

  // File f = getReadFile("select a file");
  public static File getReadFileAWT(String prompt) {
    FileDialog fd = new FileDialog(
        new Frame(),
        prompt);
    fd.setVisible(true);
    return new File(fd.getDirectory() + fd.getFile());
  }

  public static File JGetReadFile(String prompt) {
    JFileChooser jfc = new JFileChooser();
    jfc.showOpenDialog(new JFrame());
    return jfc.getSelectedFile();
  }

  public static File getReadDirFile(String prompt) {
    File f = Futil.getReadFile(prompt);
    return f.getParentFile();
  }


  private static void writeTocInHtml(PrintWriter pw,
                                     File files[]) {
    pw.println("<HTML>");
    pw.println("<BODY>");
    pw.println("<ul>");
    for (int i = 0; i < files.length; i++) {
      pw.println(
          "<LI><a href = \"" +
          files[i] +
          "\">" +
          files[i] +
          "</a><P>");
      System.out.println(files[i]);
    }
    pw.println("</ul>");
    pw.println("</BODY>");
    pw.println("</HTML>");
  }


  void writeObject(ObjectOutputStream oos)
      throws IOException {
    oos.defaultWriteObject();
  }

  void readObject(ObjectInputStream ois) throws ClassNotFoundException, IOException {
    ois.defaultReadObject();
  }

  public static void testCopyFile() {
    Examples.testCopyFile();
  }

  public static File getWriteFile(
      String prompt) {
    if (isSwing())
      return getWriteFileSwing(prompt);
    return getWriteFileAWT(prompt);
  }

  private static File getWriteFileAWT(
      String prompt) {
    FileDialog fd =
        new FileDialog(
            new Frame(),
            prompt,
            FileDialog.SAVE);
    fd.setVisible(true);

    return new File(
        fd.getDirectory()
        + fd.getFile());
  }

  public static File getWriteFileSwing(
      String prompt) {
    JFileChooser fd =
        new JFileChooser(

            prompt);
    fd.showSaveDialog(new JFrame());

    return
        fd.getSelectedFile();
  }


  public static void readDataFile(String fn, double data[]) {
    System.out.println("processing:\t" + fn);
    FileInputStream is =
        getFileInputStream(fn);
    InputStreamReader isr = new InputStreamReader(is);
    BufferedReader br = new BufferedReader(isr);
    StreamTokenizer tokens = new StreamTokenizer(br);
    int next = 0;
    int num = 0;
    try {
      while ((next = tokens.nextToken()) != tokens.TT_EOF) {
        switch (next) {
          case StreamTokenizer.TT_WORD:
            break;
          case StreamTokenizer.TT_NUMBER:
            data[num] = (double) tokens.nval;
            System.out.println(num + ": " + data[num]);
            num = num + 1;
            break;
          case StreamTokenizer.TT_EOL:
            break;
        }
      }

    } catch (Exception exe) {
      System.out.println("listFilteredHrefFile:er!");
    }
    closeInputStream(is);
  }

  public static FileInputStream getFileInputStream(File file) {
    FileInputStream fis = null;
    try {
      fis = new FileInputStream(file);
    } catch (IOException e) {
      System.out.println("futil:Could not open file");
    }
    return fis;
  }

  public static FileWriter getFileWriter() {
    FileWriter fw = null;
    try {
      fw =
          new FileWriter(
              getWriteFile("select out file"));
    } catch (IOException e) {
      System.out.println("futil:Could not create file");
    }
    return fw;
  }

  public static void closeInputStream(InputStream is) {
    try {
      is.close();
    } // end try
    catch (IOException exe) {
      System.out.println("futil: could not close input stream");
    }
  }

  public static void lsWordPrintMerge() {
    String wild = "pict";

    File files[] = Ls.getWildFiles(wild);

    System.out.println(files.length + " file(s):");

    for (int i = 0; i < files.length; i++)
      System.out.println("\t" + files[i]);

  }

  public static void writeFilteredHrefFile(File inputFile, String outputName) {
    System.out.println("Filtering:\t" + inputFile + "\t>\t" + outputName);
    try {
      FileInputStream is = new FileInputStream(inputFile);
      InputStreamReader isr = new InputStreamReader(is);
      BufferedReader br = new BufferedReader(isr);
      StreamTokenizer tokens = new StreamTokenizer(br);
      FileWriter os = new FileWriter(outputName);
      PrintWriter output = new PrintWriter(os);
      int i;
      int next = 0;
      tokens.resetSyntax();
      tokens.wordChars(0, 255);
      tokens.quoteChar('"');
      while ((next = tokens.nextToken()) != tokens.TT_EOF) {
        switch (next) {
          case '"':
            output.print('"');
            for (i = 0; i < tokens.sval.length(); i++)
              if (tokens.sval.charAt(i) == ' ')
                output.print("%20");
              else
                output.print(tokens.sval.charAt(i));
            output.print('"');
            break;
          case StreamTokenizer.TT_WORD:
            output.print(tokens.sval + " ");
            break;
          case StreamTokenizer.TT_NUMBER:
            output.print(tokens.nval + " ");
            break;
          case StreamTokenizer.TT_EOL:
            output.println();
            break;
        } // end switch
      } // end while
      is.close();
      os.close();
    } // end try
    catch (Exception exe) {
      System.out.println("writeFilteredHrefFile:er!");
    }
  }

  public static void list_filtered_href_file(String file) {
    System.out.println("processing:\t" + file);
    try {
      FileInputStream is = new
          FileInputStream(file);
      InputStreamReader isr = new InputStreamReader(is);
      BufferedReader br = new BufferedReader(isr);
      StreamTokenizer tokens = new StreamTokenizer(br);
      int next = 0;
      tokens.resetSyntax();
      tokens.wordChars(0, 255);
      tokens.quoteChar('"');
      while ((next = tokens.nextToken()) != tokens.TT_EOF) {
        switch (next) {
          case '"':
            System.out.print('"');
            StringTokenizer st =
                new StringTokenizer(tokens.sval, " ");
            while (st.hasMoreTokens()) {
              System.out.print(st.nextToken());
              if (st.countTokens() > 1) {
                System.out.print("%20");
              }
            }
            System.out.print('"');
            break;
          case StreamTokenizer.TT_WORD:
            System.out.print(tokens.sval + " ");
            break;
          case StreamTokenizer.TT_NUMBER:
            System.out.print(tokens.nval + " ");
            break;
          case StreamTokenizer.TT_EOL:
            System.out.println();
            break;
        }
      }
      System.out.println();
      closeInputStream(is);
    } catch (Exception exe) {
      System.out.println("listFilteredHrefFile:er!");
    }
  }

    public static String getReadFileName(String prompt) {
        FileDialog fd = new
                FileDialog(new Frame(), prompt);
        fd.show();
        String file_name = fd.getFile();
        if (fd.getFile() == null) return null;
        String path_name = fd.getDirectory();
        String file_string = path_name + file_name;
        //println("Opening file: "+file_string);
        fd.dispose();
        return file_string;
    }

    public static String getReadFileName() {
        return
                getReadFileName("select a file");
    }

}