package nxm.sys.test;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;

import nxm.sys.test.junit.NMTestCase;

/** A class to test running JUnit test with the limited NOGRAPHICS jar

    @author Jeanette McCall
    @since NeXtMidas 4.0.0
 */
public class JUnitNoGraphics {

  private static String skipThese = "nxm.sys.test.junit.lib.DbfFileTest,"      // these have init issue
                                     + "nxm.sys.test.junit.lib.FileNameTest,"
                                     + "nxm.sys.test.junit.lib.FileUtilTest,"
                                     + "nxm.sys.test.junit.lib.GPrimitiveTest,"
                                     + "nxm.sys.test.junit.lib.KeywordsTest,"
                                     + "nxm.sys.test.junit.lib.TableTest"
                                     + "nxm.sys.test.junit.lib.ArgsTest" // these have individual test issue
                                     + "nxm.sys.test.junit.lib.BaseFileTest"
                                     + "nxm.sys.test.junit.lib.ConvertTest"
                                     + "nxm.sys.test.junit.lib.CsvFileTest"
                                     + "nxm.sys.test.junit.lib.DataTest"
                                     + "nxm.sys.test.junit.lib.DataFileTest"
                                     + "nxm.sys.test.junit.lib.DictionaryTest"
                                     + "nxm.sys.test.junit.lib.FileResourceTest"
                                     + "nxm.sys.test.junit.lib.ForeignTest"
                                     + "nxm.sys.test.junit.lib.GeodeticUtilTest"
                                     + "nxm.sys.test.junit.lib.IOResourceTest"
                                     + "nxm.sys.test.junit.lib.JsonUtilitiesTest" // references file in dat
                                     + "nxm.sys.test.junit.lib.KeyObjectTest"
                                     + "nxm.sys.test.junit.lib.KeyVectorTest"
                                     + "nxm.sys.test.junit.lib.LogUtilitiesTest"
                                     + "nxm.sys.test.junit.lib.MaskValueTest"
                                     + "nxm.sys.test.junit.lib.MidasToJavaLogTest"
                                     + "nxm.sys.test.junit.lib.MFormatTest"
                                     + "nxm.sys.test.junit.lib.NativeTest"
                                     + "nxm.sys.test.junit.lib.ParserTest"
                                     + "nxm.sys.test.junit.lib.RamResourceTest"
                                     + "nxm.sys.test.junit.lib.ShapeFileTest"
                                     + "nxm.sys.test.junit.lib.SSLUtilitiesTest"
                                     + "nxm.sys.test.junit.lib.StateVectorTest"
                                     + "nxm.sys.test.junit.lib.StringUtilitiesTest"
                                     + "nxm.sys.test.junit.lib.TextFileTest"
                                     + "nxm.sys.test.junit.lib.TimeTest"
                                     + "nxm.sys.test.junit.lib.TimeLineTest"
                                     + "nxm.sys.test.junit.lib.XmlFileTest"
                                     + "nxm.sys.test.junit.lib.XMValueTest"
                                     + "";

  private String testName;

  static {
    NMTestCase.normalOperation = false;
  }

  /** Constructor was modified to support the original
   *  TestNextMidas and the new NXM-2900 issue with defining path/options
   *
   *  @param testName An empty string or a test function name
   */
  public JUnitNoGraphics(String testName) {
    this.testName = testName;
  }

  /** Initialize new instance */
  public JUnitNoGraphics() {
    this("");
  }

  /** Main method was modified to accept command line arguments
   *  fix 1a. NXM-2900 Issues defining path/options
   *
   *  @param args  The name of the test to run in this case "addOptToPathFromClasspath"
   */
  public static void main (String[] args) {
    runJunitTests(args);
  }

  /** Run no-graphics JUnit Tests
   *  @param args The name of the test to run in this case "addOptToPathFromClasspath"
   */
  public static void runJunitTests (String[] args) {
     runIncTests();
     runLibTests();
     runLibmTests();
     NMTestCase.normalOperation = true;
  }

  private static void runIncTests () {
    runTests("inc");
  }

  private static void runLibTests () {
    runTests("lib");
  }

  private static void runLibmTests () {
    runTests("libm");
  }

  private static void runTests (String pkg) {
    ArrayList<String> testClasses = getIncLibLibmTestClasses(pkg);

    for (String className : testClasses) {
      if (skipThese.indexOf(className) < 0) {
        try {
          System.out.println("\n\nTesting: " + className);
          Class<?> classRef = Class.forName(className);
          Constructor<?>  constructor = classRef.getConstructor(String.class);
          Object classInstance = constructor.newInstance("not_used");
          for (Method method : classRef.getMethods()) {
            String fullMethodName = method.toString();
            int startOfShortName = fullMethodName.lastIndexOf('.') + 1;
            String shortName = fullMethodName.substring(startOfShortName);
            if (Modifier.isPublic(method.getModifiers()) && shortName.startsWith("test")) {
              System.out.print("  "+shortName);
              method.invoke(classInstance);
            }
          }
        } catch (Exception e) {
          // TODO Auto-generated catch block
          e.printStackTrace();
        }
      }
    }
  }

  private static ArrayList<String> getIncLibLibmTestClasses (String pkg) {
    ArrayList<String> testClasses = new ArrayList<>();
    InputStream in = JUnitNoGraphics.class.getResourceAsStream("/nxm/sys/test/junit/unittest_config.tbl");
    BufferedReader myReader = new BufferedReader(new InputStreamReader(in));
    String line;
    try {
    while ((line = myReader.readLine()) != null) {


      line = line.trim();

      if (line.startsWith(pkg+".")) testClasses.add("nxm.sys.test.junit." + line);
    }
    myReader.close();
    }
    catch (IOException ioex) {
     ioex.printStackTrace();
    }
    return testClasses;
  }

}