package nxm.ucl.intr;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.PrintStream;
import java.util.ArrayList;

import nxm.sys.lib.Intrinsic;
import nxm.sys.lib.MidasException;
import nxm.sys.lib.StringUtil;

/** Removes the tabs from a file.

    @author  J. Czechowski IV
    @since   NeXtMidas 2.1.0
 */
public class Removetabs extends Intrinsic {
  /** A tab character. */
  private static final char TAB   = '\t';
  /** A space Character. */
  private static final char SPACE = ' ';

  /** default constructor */
  public Removetabs () {}

  public int process () {
    int tabSize  = MA.getL("/TABSIZE", 8);

    for (int i = 1; i <= MA.getNArgs(); i++) {
      String fileName = MA.getFileName(i).toString();

      if (fileName.length() == 0) {
        throw new MidasException("Removetabs: No input file specified.");
      }
      else if (fileName.indexOf(':') > 2) {
        throw new MidasException("Removetabs: Only accepts local files at this time, given '"+ fileName + "'.");
      }
      else {
        File file = new File(fileName);

        if (!file.exists()) {
          throw new MidasException("Removetabs: File not found, given '" + fileName + "'.");
        }
        else {
          try {
            BufferedReader in  = new BufferedReader(new FileReader(file));

            String lines[] = readFile(in);

            in.close();

            if (lines == null) {
              M.info("Removetabs: No tabs found in "+file);
            }
            else {
              PrintStream out = new PrintStream(new FileOutputStream(file));
              int tabCount = writeFile(tabSize, lines, out);

              out.close();
              M.info("Removetabs: Replaced " + tabCount + " tabs in "+file);
            }
          } catch(IOException e) {
            throw new MidasException("Removetabs: Error accessing file.", e);
          }
        }
      }
    }

    return FINISH;
  }

  /** Checks the line lengths of all the lines in a file.
      @param in      The input stream from the input file.
      @return The lines in the file or null if no tabs are found.
      @throws IOException If there is an error reading from the file.
   */
  private static String[] readFile (BufferedReader in) throws IOException {
    ArrayList<String> lines = new ArrayList<>();
    String   line     = null;
    String[] retVal   = null;
    int      tabCount = 0;

    while ((line = in.readLine()) != null) {
      if (line.indexOf('\t') >=0 ) {
        tabCount++;
      }

      lines.add(line);
    }

    if (tabCount > 0) {
      retVal = lines.toArray(StringUtil.EMPTY_STRING_ARRAY);
    }

    return retVal;
  }

  /** Outputs the lines of the file replacing tabs with spaces.
      @param tabSize The size of a tab.
      @param lines   The lines in the input file.
      @param out     The output stream to write output to.
      @return The number of tabs replaced.
      @throws IOException If there is an error reading from the file.
   */
  private static int writeFile (int tabSize, String[] lines, PrintStream out) throws IOException {
    int tabCount = 0;

    for (String line : lines) {
      if (line.indexOf('\t') < 0) {
        out.println(line);
      }
      else {
        int index = 0; // output index

        for (int j = 0; j < line.length(); j++) {
          char inChar = line.charAt(j);

          if (inChar != TAB) {
            out.print(inChar); index++;
          }
          else {
            tabCount++;
            out.print(SPACE); index++;

            while ((index%tabSize)!=0) {
              out.print(SPACE); index++;
            }
          }
        } // end inner for loop (chars in line)
        out.println();
      }
    } // end outer for loop (lines)

    return tabCount;
  }
}
