# include "addstar.h"

Stars *LoadStars (char *filename, int *Nstars, Image **images, int *Nimages, int photcode) {

  int i, Nfile, Nheaders, NheaderSets, mode, *extsize;
  char **file;
  FILE *f;
  glob_t globList;
  Header **headers;
  Stars *stars;
  HeaderSet *headerSets;

  // parse the filename as a glob
  globList.gl_offs = 0;
  glob (filename, 0, NULL, &globList);

  // if the glob does not match, save the literal word:
  // otherwise save all glob matches
  if (globList.gl_pathc == 0) {
    Nfile = 1;
    ALLOCATE (file, char *, Nfile);
    file[0] = strcreate (filename);
  } else {
    Nfile = globList.gl_pathc;
    ALLOCATE (file, char *, Nfile);
    for (i = 0; i < Nfile; i++) {
      file[i] = strcreate (globList.gl_pathv[i]);
    }
  }

  *Nimages = 0;
  *Nstars = 0;
  *images = NULL;
  stars = NULL;

  for (i = 0; i < Nfile; i++) {
    f = fopen (file[i], "r");
    if (f == NULL) {
      fprintf (stderr, "can't read file %s, skipping\n", file[i]);
      continue;
    }

    headers = LoadHeaders (f, &mode, &Nheaders);
    headerSets = MatchHeaders (&extsize, &NheaderSets, mode, headers, Nheaders);
    if (headerSets == NULL) {
      fprintf (stderr, "ERROR: can't read headers for %s\n", file[i]);
      continue;
    }
    if (NheaderSets == 0) {
      fprintf (stderr, "no object data in file %s, skipping\n", file[i]);
      continue;
    }
    if (VERBOSE) fprintf (stderr, "file %s has %d headers, including %d images\n", file[i], Nheaders, NheaderSets);

    /* supplied photcode is incompatible with multi-chip images */
    if ((NheaderSets > 1) && photcode) {
      fprintf (stderr, "ERROR: photcode cannot be supplied to multi-chip images -- manually adjust the headers\n");
      exit (1);
    }

    LoadData (f, file[i], images, Nimages, &stars, Nstars, headers, extsize, headerSets, NheaderSets);
  }

  if (*Nimages == 0) {
    if (Nfile == 1) 
      fprintf (stderr, "no valid image data in any of these files, giving up\n");
    else 
      fprintf (stderr, "no valid image data in this file, giving up\n");
    exit (0);
  }

  return stars;
}

// load all of the headers, jump in file to skip data segments
Header **LoadHeaders (FILE *f, int *mode, int *Nheaders) {

  int i, status, Nskip, NHEADERS;
  Header **headers;

  /* we need to examine the extensions to determine the headers and the data */
  NHEADERS = 10;
  ALLOCATE (headers, Header *, NHEADERS);

  // load all headers into memory
  for (i = 0;; i++) {
    ALLOCATE (headers[i], Header, 1);
    status = gfits_fread_header (f, headers[i]);
    if (!status) { 
      *Nheaders = i;
      return (headers);
    }

    // check the mode for this file
    if (i == 0) {
      *mode = GetFileMode (headers[0]);
      if ((*mode == SIMPLE_CMP) || (*mode == MOSAIC_CMP)) {
	*Nheaders = i;
	return (headers);
      }
    }

    // advance to the next header
    Nskip = gfits_data_size (headers[i]);
    fseek (f, Nskip, SEEK_CUR); 
    if (i == NHEADERS - 1) {
      NHEADERS += 10;
      REALLOCATE (headers, Header *, NHEADERS);
    }
  }
}

HeaderSet *MatchHeaders (int **extsize, int *nimage, int mode, Header **headers, int Nheaders) {

  int i, j, Nimage, NIMAGE;
  char extname[80], exttype[80], exthead[80];
  HeaderSet *headerSets;

  ALLOCATE (extsize[0], int, Nheaders);

  Nimage = 0;
  NIMAGE = 10;
  ALLOCATE (headerSets, HeaderSet, NIMAGE);

  // what is the mode of the first header (ie, do we have a PHU DIS image?)
  mode = GetFileMode (headers[0]);

  if (mode == MOSAIC_MEF) {
    headerSets[Nimage].exthead     = strcreate ("PHU");
    headerSets[Nimage].extdata     = strcreate ("NONE");
    headerSets[Nimage].extnum_data = -1;
    headerSets[Nimage].extnum_head =  0;
    Nimage ++;
  }

  // now examine the headers, count the table entries, find corresponding headers
  for (i = 0; i < Nheaders; i++) {
    if (mode == SIMPLE_CMP) {
      extsize[0][i] = headers[i][0].size;
    } else {
      extsize[0][i] = headers[i][0].size + gfits_data_size (headers[i]);
    }
    gfits_scan (headers[i], "EXTTYPE", "%s", 1, exttype);

    if (!strcmp (exttype, "SMPDATA")) goto keep;
    if (!strcmp (exttype, "PS1_DEV_0")) goto keep;
    if (!strcmp (exttype, "PS1_DEV_1")) goto keep;
    continue;

  keep:
    headerSets[Nimage].exttype = strcreate (exttype);

    gfits_scan (headers[i], ExtnameKeyword, "%s", 1, extname);
    gfits_scan (headers[i], "EXTHEAD", "%s", 1, exthead);

    headerSets[Nimage].extdata     = strcreate (extname);
    headerSets[Nimage].exthead     = strcreate (exthead);
    headerSets[Nimage].extnum_data = i;
    headerSets[Nimage].extnum_head = -1;

    // find the matching exthead entry
    for (j = 0; j < Nheaders; j++) {
      if (!gfits_scan (headers[j], ExtnameKeyword, "%s", 1, extname)) continue;
      if (strcmp (extname, headerSets[Nimage].exthead)) continue;
      headerSets[Nimage].extnum_head = j;
      break;
    }

    // skip or crash on table with missing matching header?
    if (headerSets[Nimage].extnum_head == -1) {
      return NULL;
    }
    Nimage ++;
    if (Nimage == NIMAGE) {
      NIMAGE += 10;
      REALLOCATE (headerSets, HeaderSet, NIMAGE);
    }
  }

  // some old format files did not write EXTTYPE.  they have a single table in the first
  // extension matched to the header in the PHU
  if (Nimage == 0) {
    extsize[0][0] = headers[0][0].size + gfits_data_size (headers[0]);
    extsize[0][1] = headers[1][0].size + gfits_data_size (headers[1]);
    gfits_scan (headers[1], ExtnameKeyword, "%s", 1, extname);
    if (!strcmp (extname, "SMPFILE")) {
      headerSets[Nimage].extdata     = strcreate (extname);
      headerSets[Nimage].exttype     = strcreate ("SMPDATA");
      headerSets[Nimage].exthead     = strcreate ("PHU");
      headerSets[Nimage].extnum_head = 0;
      headerSets[Nimage].extnum_data = 1;
      Nimage = 1;
    }
  }
  
  *nimage = Nimage;
  return (headerSets);
}

// examine the header sets and set the Image entries for the the valid images
int LoadData (FILE *f, char *file, Image **images, int *nvalid, Stars **stars, int *Nstars, Header **headers, int *extsize, HeaderSet *headerSets, int Nimages) {

  char *name;
  int i, j, Nvalid, Nhead, Ndata, Nskip;
  Stars *inStars;

  if (images[0] == NULL) {
    Nvalid = 0;
    NVALID = 10;
    ALLOCATE (images[0], Image, NVALID);
  } else {
    Nvalid = *nvalid;
    NVALID = Nvalid + 10;
    REALLOCATE (images[0], Image, NVALID);
  }    

  // find image rootname
  name = filebasename (file);

  // now run through the images, interpret the headers and read the stars
  for (i = 0; i < Nimages; i++) {
    Nhead = headerSets[i].extnum_head;

    if (VERBOSE) fprintf (stderr, "reading header for %s (%s)\n", headerSets[i].exthead, headerSets[i].extdata);
    if (!ReadImageHeader (headers[Nhead], &images[0][Nvalid], 0)) {
      fprintf (stderr, "skipping %s\n", headerSets[i].exthead);
      continue;
    }

    // XXX use something to set the chip name? EXTNAME?
    if (!strcmp(headerSets[i].exthead, "PHU") && (Nimages == 1)) {
      snprintf (images[0][Nvalid].name, 64, "%s", name);
    } else {
      snprintf (images[0][Nvalid].name, 64, "%s[%s]", name, headerSets[i].exthead);
    }

    // skip the table if there is no data segment (eg, mosaic WRP image)
    if (!strcmp(headerSets[i].extdata, "NONE")) {
      Nvalid++;
      if (Nvalid == NVALID) {
	NVALID += 10;
	REALLOCATE (images[0], Image, NVALID);
      }
      continue;
    }

    // advance the pointer to the start of the corresponding table block
    Ndata = headerSets[i].extnum_data;
    Nskip = 0;
    for (j = 0; j < Ndata; j++) {
      Nskip += extsize[j];
    }
    fseek (f, Nskip, SEEK_SET); 
	 
    inStars = ReadStarsFITS (f, headers[Nhead], headers[Ndata], &images[0][Nvalid].nstar);
    inStars = FilterStars (inStars, &images[0][Nvalid]);
    *stars = MergeStars (*stars, Nstars, inStars, images[0][Nvalid].nstar);
    Nvalid++;
  }
  free (name);
  *nvalid = Nvalid;
  return (TRUE);
}

