package terrasaur.fits;

import java.util.EnumSet;
import java.util.Map;

public enum AltPipelnEnum {

  // settings enums. Used to determine type of product to create.
  ANCIGLOBAL,

  // optional: tells code to skip generation of products for highest res shape model
  SKIPORIGINALSHP,

  // controls whether or not certain global products get created.
  // REQUIRED TO BE IN CONFIGFILE:
  DOGLOBALSHAPE, OBJTOFITS, ADDOBJCOMMENTS, GLOBALRES0, DUMBERVALUES, DOGRAVGLOBAL, DOGLOBALGRAV_ANCI, DOGLOBALTILT_ANCI, DOGLOBALMISC_ANCI, DOGLOBALTILT,

  // controls number of slots per job to use when running global distributed gravity
  // in grid engine mode. Does not apply if running in local parallel mode
  GLOBALGRAVSLOTS,

  // controls number of slots per job to use when running local distributed gravity
  // in grid engine mode. Does not apply if running in local parallel mode
  LOCALGRAVSLOTS,

  // full path to SPICE metakernel to use when generating DSK products
  DSKERNEL,

  // enable/disable the creation of global and local DSK files
  DOGLOBALDSK, DOLOCALDSK,

  // global tilt semi-major axis in km. Now a required variable
  GTILTMAJAXIS,

  // settings for every local product generated by the pipeline
  USEOLDMAPLETS, DODTMFITSOBJ, DOGRAVLOCAL, GENLOCALGRAV, DOLOCALTILT, DOLOCAL_GRAVANCI, DOLOCAL_TILTANCI, DOLOCAL_MISCANCI,

  // controls whether to use average gravitational potential for global and local gravity
  // calculations. =0 use minimum reference potential, =1 use average reference potential
  AVGGRAVPOTGLOBAL, AVGGRAVPOTLOCAL,

  // controls RunBigMap.
  // integrate slope to height required. Defaults to "n" if this enum does not exist in config file.
  // otherwise will evaluate value. 0="n", 1="y"
  INTSLOPE,

  // use grotesque model in RunBigMap. Defaults to not using it if this enum does not exist in
  // config file
  // otherwise will evaluate value. 0="do not use grotesque model", 1="do use grotesque model"
  USEGROTESQUE,

  // controls the source data, product destination, naming convention,
  // and process flow.
  DATASOURCE, REPORTTYPE, INDATADIR, OUTPUTDIR, PDSNAMING, RENAMEGLOBALOBJ, USEBIGMAPS, DOREPORT,

  // shape model density and rotation rate are now required variables. This way we can easily spot
  // what we are using
  // as defaults.
  SMDENSITY, SMRRATE,

  // stores type of naming convention. Ex. AltProduct, AltNFTMLN, DartProduct.
  NAMINGCONVENTION,

  // set values that cannot be derived from data.
  REPORTBASENAME, VERSION,

  // everything after this is not a required keyword

  // (Optional) controls whether there is an external body that needs to be accounted for when
  // running gravity code
  // the values should be a csv string with no spaces. THe values are: mass(kg),x,y,z where x,y,z
  // are the body
  // fixed coordinates in km.
  // e.g. 521951167,1.19,0,0
  EXTERNALBODY,

  // (Optional). If the keyword exists and value is 1 then no GLOBAL DTMs are assumed to be created.
  // for example, in the DART Derived Product set we are not creating g_*dtm*.fits files
  NOGLOBALDTM,
  
  // (Optional). If the keyword exists then evaluate the shapes to process by parsing the 
  // comma-separated values. Ex.values are 0,1,2 then pipeline will assume it has to 
  // process shape0, shape1, shape2. The pipeline will also disregard the values in 
  // DUMBERVALUES that otherwise determine how many shape files to process.
  SHAPE2PROC,
  
  // (optional) controls whether or not STL files get generated. If these do not exist in the
  // pipeConfig file then they will NOT
  // get generated!
  GLOBALSTL, LOCALSTL,

  // keywords for local products
  //
  // MAPSmallerSZ: resize local DTMs to a different half size. For pipeline we may want to generate
  // DTMs at halfsize + tilt radius then resize the DTMs to halfsize in order to have tilts
  // evaluated with the full range of points at the edges.
  //
  // MAPFILE: contains pointer to map centers file (optional). Used by TileShapeModelWithBigmaps.
  // defaults to auto-generated tiles if this is not specified.
  // allow for pointers to different files for 30cm and 10cm map products.
  DOLOCALMAP, MAPDIR, MAPSCALE, MAPHALFSZ, REPORT, MAPSmallerSZ, MAPFILE, ISTAGSITE, LTILTMAJAXIS, LTILTMINAXIS, LTILTPA, MAXSCALE,

  // settings for local tag sites. Note TAGSFILE is not optional.
  // it contains the tagsite name and lat,lon of tag site tile center
  TAGDIR, TAGSCALE, TAGHALFSZ, TAGSFILE, REPORTTAG,

  // pointer to OLA database. only required if DATASOURCE is OLA
  OLADBPATH,

  // force sigma files to all be NaN
  FORCESIGMA_NAN,

  // global sigma scale factor
  SIGMA_SCALEFACTOR,

  // local sigma scale factor
  LOCAL_SIGMA_SCALEFACTOR,

  // SIGMA file type. No longer tied to DataSource!
  SIGMAFILE_TYPE,

  // force the Report page to be HTML. Default is created at PHP
  REPORTASHTML,

  /*
   * The following are used to change default values used by the pipeline these are the shape model
   * density, rotation rate, gravitational algorithm, gravitational constant, global average
   * reference potential, local average reference potential. Added values defining the tilt ellipse
   * to use when evaluating tilts. Note the different enums for global versus local tilt ellipse
   * parameters. The pipeline will use default values for these enums if they are not defined in the
   * pipeline configuration file.
   */
  GALGORITHM, GRAVCONST, GTILTMINAXIS, GTILTPA, MASSUNCERT, VSEARCHRAD_PCTGSD, FSEARCHRAD_PCTGSD, PXPERDEG,

  // The following are options to subvert normal pipeline operations or to configure pipeline for
  // other missions


  // global objs are supplied at all resolutions as the starting point.
  // This means we can skip ICQ2PLT, ICQDUMBER, and PLT2OBJ calls
  OBJASINPUT,

  // gzip the obj files to save space
  DOGZIP,

  // specify the queue to use in the GRID ENGINE
  GRIDQUEUE,

  // default mode for local product creation is to parallelize DistributedGravity
  // for each tile. Then processing for each job is done in local mode.
  // set this flag to 1 to submit DistributedGravity for each tile sequentially,
  // and have each job spawn to the grid engine
  DISTGRAVITY_USEGRID,

  // override grid engine mode and use local parallel mode with the specified number of cores
  LOCALPARALLEL,

  // when creating local gravity products skip creation of gravity files that already exist
  USEOLDGRAV,

  // override ancillary fits table default setting (binary). Set to ASCII instead
  ANCITXTTABLE,

  // contains pointer to fits header config file (optional)
  FITSCONFIGFILE,

  // contains pointer to OBJ comments header file (optional). Will only
  // add commentes if ADDOBJCOMMENTS flag is set.
  OBJCOMHEADER,

  // identifies whether there are poisson reconstruct data products to include in the webpage report
  LOCALPOISSON, GLOBALPOISSON;

  /*
   * The following enumerations are required to exist in the altwg pipeline config file.
   */
  public static final EnumSet<AltPipelnEnum> reqTags = EnumSet.range(DOGLOBALSHAPE, VERSION);

  /*
   * The following enumerations do not have to be present in the config file. But, if they are not
   * then the pipeline should use the default values associated with the enums.
   */
  public static final EnumSet<AltPipelnEnum> overrideTags = EnumSet.range(SMDENSITY, GTILTPA);

  public static String mapToString(Map<AltPipelnEnum, String> pipeConfig) {
    StringBuilder sb = new StringBuilder();
    for (Map.Entry<AltPipelnEnum, String> entry : pipeConfig.entrySet()) {
      sb.append(String.format("%s:%s\n", entry.getKey().toString(), entry.getValue()));
    }

    return sb.toString();
  }

  public static AltPipelnEnum fromString(String textString) {
    for (AltPipelnEnum anciType : AltPipelnEnum.values()) {
      if (anciType.toString().equals(textString))
        return anciType;
    }
    return null;
  }

  /**
   * Convenience method for evaluating configuration parameter where the value indicates whether or
   * not the parameter is true or false via an integer value. Assumes 0 or less = false, 1 or more =
   * true. If the key does not exist then return false.
   * 
   * @param pipeConfig
   * @param key
   * @return
   */
  public static boolean isTrue(Map<AltPipelnEnum, String> pipeConfig, AltPipelnEnum key) {
    boolean returnFlag = false;
    int parsedVal = 0;
    if (pipeConfig.containsKey(key)) {
      try {
        parsedVal = Integer.valueOf(pipeConfig.get(key));
      } catch (NumberFormatException e) {
        System.err.println("ERROR! Could not parse integer value for pipeConfig line:");
        System.err.println(key.toString() + "," + pipeConfig.get(key));
        System.err.println("Stopping with error!");
        System.exit(1);
      }

      if (parsedVal > 0) {
        returnFlag = true;
      }

    }
    return returnFlag;
  }

  /**
   * Checks to see whether key exists. If so then return value mapped to key. Otherwise return empty
   * string.
   * 
   * @param pipeConfig
   * @param key
   * @return
   */
  public static String checkAndGet(Map<AltPipelnEnum, String> pipeConfig, AltPipelnEnum key) {
    String value = "";
    if (pipeConfig.containsKey(key)) {
      value = pipeConfig.get(key);
    }
    return value;
  }

  /*
   * Some enums will have a default value, e.g. the ones in the overrideTags EnumSet. It is easier
   * to keep them as string values then convert them to other primitives as needed. Sometimes other
   * executables will be called w/ the default values, so it is better to keep them as strings to
   * avoid double conversion.
   */
  public static String getDefault(AltPipelnEnum thisEnum) {

    if (overrideTags.contains(thisEnum)) {

      switch (thisEnum) {

        // shape model density and rotation rate must now be explicitly defined in the configuration
        // file!
        // case SMDENSITY:
        // return "1.186";
        //
        // case SMRRATE:
        // return "0.00040626";

        case GALGORITHM:
          return "werner";

        case GRAVCONST:
          return "6.67408e-11";

        case LTILTMAJAXIS:
          return "0.0125";

        case GTILTMINAXIS:
          return "0.0125";

        case GTILTPA:
        case LTILTPA:
          return "0.0";

        case MASSUNCERT:
          return "0.01";

        case VSEARCHRAD_PCTGSD:
          return "0.25";

        case FSEARCHRAD_PCTGSD:
          return "0.5";

        default:
          return "NA";

      }
    }
    return "NA";

  };

}
