/*
** Sat Jan 29 16:44:50 EST 2005: this used to "open the seperate
** datafile, and set the FILE* in nio->dataFile, which otherwise will
** stay NULL", but now we support multiple detached data files.  So.
**
** The job of this function is to map the "data file" specification to
** one or more filenames that can be passed direction to fopen for 
** reading in the data.  This involves parsing the various formats for
** identifying multiple data files, and possibly prefixing them with
** nio->path.
*/
int
_nrrdReadNrrdParse_data_file (FILE *ffile, Nrrd *nrrd, 
                              NrrdIoState *nio, int useBiff) {
  char me[]="_nrrdReadNrrdParse_data_file", err[BIFF_STRLEN];
  char *info, *nums;
  unsigned int linelen;
  int tmp;
  airArray *mop;

  mop = airMopNew();
  info = airStrdup(nio->line + nio->pos);
  if (!info) {
    sprintf(err, "%s: couldn't copy line!", me);
    biffMaybeAdd(NRRD, err, useBiff); return 1;
  }
  airMopAdd(mop, info, airFree, airMopAlways);

  if (_nrrdContainsPercentDAndMore(info)) {
    /* ---------------------------------------------------------- */
    /* --------- format.%d <min> <max> <step> [<dim>] ----------- */
    /* ---------------------------------------------------------- */
    nums = info + strcspn(info, _nrrdFieldSep);
    tmp = strspn(nums, _nrrdFieldSep);
    nums[0] = 0;   /* terminate so that format is now in info */
    nums += tmp;
    if (!( 3 == sscanf(nums, "%d %d %d",&(nio->dataFNMin), 
                       &(nio->dataFNMax), &(nio->dataFNStep)) )) {
      sprintf(err, "%s: couldn't parse three ints (min, max, step) after "
              "data filename template", me);
      biffMaybeAdd(NRRD, err, useBiff); airMopError(mop); return 1;
    }
    if ( 4 == sscanf(nums, "%d %d %d %u", &(nio->dataFNMin), 
                     &(nio->dataFNMax), &(nio->dataFNStep), 
                     &(nio->dataFileDim)) ) {
      if (!( nio->dataFileDim >= 1 && nio->dataFileDim <= nrrd->dim )) {
        sprintf(err, "%s: datafile dimension %d outside valid range [1,%d]", 
                me, nio->dataFileDim, nrrd->dim);
        biffMaybeAdd(NRRD, err, useBiff); airMopError(mop); return 1;
      }
    } else {
      nio->dataFileDim = nrrd->dim-1;
    }
    if (0 == nio->dataFNStep) {
      sprintf(err, "%s: file number step must be non-zero", me);
      biffMaybeAdd(NRRD, err, useBiff); airMopError(mop); return 1;
    }
    if ((nio->dataFNMax - nio->dataFNMin)*(nio->dataFNStep) < 0) {
      sprintf(err, "%s: file number max %d not approached from min %d "
              "by step %d", me, 
              nio->dataFNMax, nio->dataFNMin, nio->dataFNStep);
      biffMaybeAdd(NRRD, err, useBiff); airMopError(mop); return 1;
    }
    if (!( nio->dataFNFormat = airStrdup(info) )) {
      sprintf(err, "%s: couldn't copy data filename format", me);
      biffMaybeAdd(NRRD, err, useBiff); airMopError(mop); return 1;
    }
  } else if (!strncmp(info, NRRD_LIST_FLAG, strlen(NRRD_LIST_FLAG))) {
    /* ---------------------------------------------------------- */
    /* ------------------------- LIST --------------------------- */
    /* ---------------------------------------------------------- */
    if (_nrrdHeaderCheck(nrrd, nio, AIR_TRUE)) {
      sprintf(err, "%s: NRRD header is incomplete. \"" NRRD_LIST_FLAG 
              "\" data file specification must be contiguous with "
              "end of header!", me);
      biffMaybeAdd(NRRD, err, useBiff); airMopError(mop); return 1;
    }
    info += strlen(NRRD_LIST_FLAG);
    if (info[0]) {
      if (1 == sscanf(info, "%u", &(nio->dataFileDim))) {
        if (!( nio->dataFileDim >= 1 && nio->dataFileDim <= nrrd->dim )) {
          sprintf(err, "%s: datafile dimension %d outside valid range [1,%d]",
                  me, nio->dataFileDim, nrrd->dim);
          biffMaybeAdd(NRRD, err, useBiff); airMopError(mop); return 1;
        }
      } else {
        sprintf(err, "%s: couldn't parse info after \"" 
                NRRD_LIST_FLAG "\" as an int", me);
        biffMaybeAdd(NRRD, err, useBiff); airMopError(mop); return 1;
      }
    } else {
      /* nothing after NRRD_LIST_FLAG, so dataFileDim is implicit */
      nio->dataFileDim = nrrd->dim-1;
    }
    /* read in all the datafile names */
    do {
      /* yes, nio->line is re-used/over-written here, but I don't
         think that's a problem */
      if (_nrrdOneLine(&linelen, nio, ffile)) {
        sprintf(err, "%s: trouble getting file name line", me);
        biffMaybeAdd(NRRD, err, useBiff); airMopError(mop); return 1;
      }
      if (linelen > 0) {
        tmp = airArrayLenIncr(nio->dataFNArr, 1);
        nio->dataFN[tmp] = airStrdup(nio->line);
      }
    } while (linelen > 0);

  } else {
    /* ---------------------------------------------------------- */
    /* -------------------- (single filename) ------------------- */
    /* ---------------------------------------------------------- */
    /* there is apparently only a single detached data file */
    tmp = airArrayLenIncr(nio->dataFNArr, 1);
    nio->dataFN[tmp] = airStrdup(info);
    nio->dataFileDim = nrrd->dim;
  }
  if (_nrrdDataFNCheck(nio, nrrd, useBiff)) {
    sprintf(err, "%s: trouble with number of datafiles", me);
    biffMaybeAdd(NRRD, err, useBiff); airMopError(mop); return 1;
  }
  airMopOkay(mop);   
  return 0;
}
int
unrrdu_diceMain(int argc, char **argv, char *me, hestParm *hparm) {
  hestOpt *opt = NULL;
  char *base, *err, fnout[AIR_STRLEN_MED], /* file name out */
    fffname[AIR_STRLEN_MED],  /* format for filename */
    *ftmpl;                   /* format template */
  Nrrd *nin, *nout;
  int top, pret, start, fit;
  unsigned int axis;
  size_t pos;
  airArray *mop;

  OPT_ADD_AXIS(axis, "axis to slice along");
  OPT_ADD_NIN(nin, "input nrrd");
  hestOptAdd(&opt, "s,start", "start", airTypeInt, 1, 1, &start, "0",
             "integer value to start numbering with");
  hestOptAdd(&opt, "ff,format", "form", airTypeString, 1, 1, &ftmpl, "",
             "a printf-style format to use for generating all "
             "filenames.  Use this to override the number of characters "
             "used to represent the slice position, or the file format "
             "of the output, e.g. \"-ff %03.ppm\" for 000.ppm, "
             "001.ppm, etc. By default (not using this option), slices "
             "are saved in NRRD format (or PNM or PNG where possible) "
             "with shortest possible filenames.");
  hestOptAdd(&opt, "o,output", "prefix", airTypeString, 1, 1, &base, NULL,
             "output filename prefix (excluding info set via \"-ff\"), "
             "basically to set path of output files (so be sure to end "
             "with \"/\".");

  mop = airMopNew();
  airMopAdd(mop, opt, (airMopper)hestOptFree, airMopAlways);

  USAGE(_unrrdu_diceInfoL);
  PARSE();
  airMopAdd(mop, opt, (airMopper)hestParseFree, airMopAlways);

  if (start < 0) {
    fprintf(stderr, "%s: given start index (%d) less than zero\n", me, start);
    airMopError(mop);
    return 1;
  }
  if (!( axis < nin->dim )) {
    fprintf(stderr, "%s: given axis (%u) outside range [0,%u]\n",
            me, axis, nin->dim-1);
    airMopError(mop);
    return 1;
  }

  if (airStrlen(ftmpl)) {
    if (!_nrrdContainsPercentDAndMore(ftmpl)) {
      fprintf(stderr, "%s: given filename format \"%s\" doesn't seem to "
              "have the format sequence to print an integer\n", me, ftmpl);
      airMopError(mop);
      return 1;
    }
    sprintf(fffname, "%%s%s", ftmpl);
  } else {
    top = start + nin->axis[axis].size-1;
    if (top > 9999999) {
      sprintf(fffname, "%%s%%08d.nrrd");
    } else if (top > 999999) {
      sprintf(fffname, "%%s%%07d.nrrd");
    } else if (top > 99999) {
      sprintf(fffname, "%%s%%06d.nrrd");
    } else if (top > 9999) {
      sprintf(fffname, "%%s%%05d.nrrd");
    } else if (top > 999) {
      sprintf(fffname, "%%s%%04d.nrrd");
    } else if (top > 99) {
      sprintf(fffname, "%%s%%03d.nrrd");
    } else if (top > 9) {
      sprintf(fffname, "%%s%%02d.nrrd");
    } else {
      sprintf(fffname, "%%s%%01d.nrrd");
    }
  }
  nout = nrrdNew();
  airMopAdd(mop, nout, (airMopper)nrrdNuke, airMopAlways);

  for (pos=0; pos<nin->axis[axis].size; pos++) {
    if (nrrdSlice(nout, nin, axis, pos)) {
      airMopAdd(mop, err = biffGetDone(NRRD), airFree, airMopAlways);
      fprintf(stderr, "%s: error slicing nrrd:%s\n", me, err);
      airMopError(mop);
      return 1;
    }
    if (0 == pos && !airStrlen(ftmpl)) {
      /* See if these slices would be better saved as PNG or PNM images.
         Altering the file name will tell nrrdSave() to use a different
         file format. */
      if (nrrdFormatPNG->fitsInto(nout, nrrdEncodingRaw, AIR_FALSE)) {
        strcpy(fffname + strlen(fffname) - 4, "png");
      } else {
        fit = nrrdFormatPNM->fitsInto(nout, nrrdEncodingRaw, AIR_FALSE);
        if (2 == fit) {
          strcpy(fffname + strlen(fffname) - 4, "pgm");
        } else if (3 == fit) {
          strcpy(fffname + strlen(fffname) - 4, "ppm");
        }
      }
    }
    sprintf(fnout, fffname, base, pos+start);
    fprintf(stderr, "%s: %s ...\n", me, fnout);
    if (nrrdSave(fnout, nout, NULL)) {
      airMopAdd(mop, err = biffGetDone(NRRD), airFree, airMopAlways);
      fprintf(stderr, "%s: error writing nrrd to \"%s\":%s\n",
              me, fnout, err);
      airMopError(mop);
      return 1;
    }
  }

  airMopOkay(mop);
  return 0;
}