package nxm.xbc.prim;

import java.io.File;
import java.util.ArrayList;
import java.util.List;

import nxm.sys.lib.Build;
import nxm.sys.lib.Convert;
import nxm.sys.lib.OptionTree;
import nxm.sys.lib.Primitive;
import nxm.sys.lib.StringUtil;
import nxm.sys.lib.Table;
import nxm.sys.lib.TextFile;


/** Checks to see if the M$ calls in a host primitive are implemented in XBC.

    @author  J. Czechowski IV / L. Nguyen
 */
public class checkxbc extends Primitive {
  /** The list of prefixes used in X-Midas (M$ is the most common). */
  private static final String[] PREFIX_LIST = { "M$", "MD$", "MX$", "MXF$", "XTX$" };

  private Table     supportTable    = new Table();  // The table of supported commands.
  private Table     unsupportPrefix = new Table();  // The table of unsupported prefixes.
  private TextFile  hostPrim;                       // The host primitive.

  /** The option tree. */
  private String          opt;
  /** Holds a list of host primitives. */
  private List<TextFile>  hostPrims = new ArrayList<>();
  /** Used to determine if warning should be displayed. */
  private boolean         warnings;
  /** Used to determine if a summary of the warnings should be displayed. */
  private boolean         summary;

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

  public int open() {
    hostPrim    = MA.getTextFile("FILE");
    verbose     = MA.getState("/VERBOSE");
    summary     = MA.getState("/SUMMARIZE");
    warnings    = MA.getState("/WARN", !summary);
    opt         = MA.getS("OPT").toLowerCase();
    String path = OptionTree.getOptPath(opt, "host");

    if (hostPrim.filename.length() > 0) {
      hostPrims.add(hostPrim);
      hostPrim.open(TextFile.INPUT|TextFile.FORCEABORT);
    }
    else {
      File directory = new File(path);
      if (directory.isDirectory()) {
        File [] files = directory.listFiles();
        for (File f : files) {
          if (f.isFile() && Build.FOR_SOURCE_FILTER.accept(f)) {
            TextFile temp = new TextFile(M, f.getAbsolutePath());
            // Only pass in the Fortran files
            hostPrims.add(temp);
            temp.open(TextFile.INPUT|TextFile.FORCEABORT);
          }
        }
      }
      else {
        M.warning("The option tree [OPT=] was not found.");
      }
    }

    Table tbl = MA.getTable("/TAB");
    if (tbl == null) {
      tbl = Convert.o2t("nxm.xbc.docs.supported_calls.tbl",this);
    }

    String[] keys = tbl.getKeys();
    for (String key : keys) {
      Table subTbl = tbl.getTable(key);

      if (key.equals("_UNSUPPORTED_PREFIXES_")) {
        unsupportPrefix = subTbl;
      } else {
        String[] subKeys = subTbl.getKeys();
        for (String subKey : subKeys) {
          supportTable.put(subKey, subTbl.get(subKey));
        }
      }
    }
    return NORMAL;
  }


  public int process() {
    int summaryCount = 0; // Used to provide a summary of total warnings
    for (TextFile hp : hostPrims) {
      String line    = hp.read();
      int    lineNum = 1;

      while (line != null) {
        line = line.trim().toUpperCase();

        if (line.length() == 0) {
          line = null;
        }
        else {
          int start = -1;
          int end   = -1;
          String call = null;
          for (int i = 0; i < PREFIX_LIST.length; i++) {
            int index = line.indexOf(PREFIX_LIST[i]);
            if (start <  0) { start = index; }
            else if (index >= 0) { start = Math.min(start, index); }
          }

          if (start >= 0) {
            for (end = start+1; end < line.length(); end++) {
              if (!Character.isJavaIdentifierPart(line.charAt(end))) {
                break;
              }
            }
            call = line.substring(start,end);
            line = line.substring(end);

            Table  tbl     = supportTable.getTable(call);
            String lineStr = StringUtil.padLeft(Integer.toString(lineNum), 4);
            String callStr = StringUtil.padRight(call, 16);


            if (tbl != null) {
              String support = tbl.getS("SUPPORT", "").toUpperCase();
              String comment = tbl.getS("COMMENT", "").trim();

              if (comment.length() > 0) { comment = " (" + comment + ")"; }

              if (support.equals("FULL")) {
                if (verbose) {
                  M.info("Line "+lineStr+": "+callStr+" is supported"+comment);
                }
              } else if (support.equals("PARTIAL")) {
                if (warnings) {
                  M.warning("Line "+lineStr+": "+callStr+" is only partially supported"+comment);
                }
                summaryCount ++;
              } else if (support.equals("DEPRECATED")) {
                if (warnings) {
                  M.warning("Line "+lineStr+": "+callStr+" is deprecated in X-Midas"+comment);
                }
                summaryCount ++;
              } else if (support.equals("NONE")) {
                if (warnings) {
                  M.warning("Line "+lineStr+": "+callStr+" is not supported at this time"+comment);
                }
                summaryCount ++;
              } else if (support.equals("NOSUPPORT")) {
                if (warnings) {
                  M.warning("Line "+lineStr+": "+callStr+" is not supported"+comment);
                }
                summaryCount ++;
              } else {
                if (warnings) {
                  M.warning("CHECKXBC: Unknown support "+support+" for "+call);
                }
                summaryCount ++;
              }
            } else {
              String[] prefixes  = unsupportPrefix.getKeys();
              String   badPrefix = null;

              for (int i = 0; (badPrefix == null) && (i < prefixes.length); i++) {
                if (call.startsWith(prefixes[i])) {
                  badPrefix = prefixes[i];
                }
              }

              if (badPrefix != null) {
                String comment = unsupportPrefix.getTable(badPrefix).getS("COMMENT", "");

                if (warnings) {
                  M.warning("Line "+lineStr+": "+callStr+" no "+comment+" calls starting with "
                      +badPrefix+" are supported");
                }
                summaryCount ++;
              } else {
                if (warnings) {
                  M.warning("Line "+lineStr+": Command support not found for " + callStr);
                }
                summaryCount ++;
              }
            }
          } else {
            line = null;
          }
        }

        if (line == null) {
          line = hp.read();
          lineNum++;
        }
      }
    }

    if (summary && summaryCount >= 1) {
      M.warning("There were " + summaryCount + " warnings for calling X-Midas M$ functions.");
      M.warning("To view the warnings run with the /WARN switch.");
    }
    return FINISH;
  }

  public int close() {
    for (TextFile hp : hostPrims) {
      hp.close();
    }
    return NORMAL;
  }
}
