# include <dvo.h>

/* load the text photcode table */
int LoadPhotcodesText (char *filename) {
  
  /* XXX fix these */
  PhotCodeData *table = NULL;
  PhotCode *photcode;

  FILE *f;
  int i, Nsecfilt, Nsec, Ncode, NPHOTCODE, Nfield;
  int code;
  char *c;
  char line[256];
  char name[32], type[32], Zero[32], Airmass[32], Offset[32],
    C1[32], C2[32], Slope[32], Color[32], Primary[32];
  int c1, c2;

  table = GetPhotcodeTable ();
  if (table[0].code != NULL) free (table[0].code);
  /* we are using a 16-bit int for the photcodes, so these indexes can be fixed-length */
  /* XXX if we need to go with a larger photcode, we'll need to use a sequenced index and a
     binary search to get to a given value (0x100000000 ints would take quite a few
     bytes...) */
  for (i = 0; i < 0x10000; i++) {
    table[0].hashcode[i] = -1;
    table[0].hashNsec[i] = -1;
    table[0].codeNsec[i] = -1;
  }

  f = fopen (filename, "r");
  if (f == (FILE *) NULL) {
    table[0].Ncode    = 0;
    table[0].Nsecfilt = 0;
    table[0].code     = (PhotCode *) NULL;
    return (FALSE);
  }

  Ncode = 0;
  NPHOTCODE = 10;
  ALLOCATE (photcode, PhotCode, NPHOTCODE);

  while (scan_line (f, line) != EOF) {
    for (c = line; isspace (*c); c++);
    if (*c == '#') continue;
    Nfield = sscanf (c, "%d %s %s %s %s %s %s %s %s %s %s", 
		     &code, name, type, Zero, Airmass, Offset, C1, C2, Slope, Color, Primary);
    if (Nfield != 11) { continue; }
    
    c1 = atof (C1);
    c2 = atof (C2);
    if (!strcmp (C1, "-")) { c1 = 0; }
    if (!strcmp (C2, "-")) { c2 = 0; }

    if (!code) {
	fprintf (stderr, "photcode values may not be 0: fix %s\n", name);
	return (FALSE);
    }

    photcode[Ncode].type = 0;
    photcode[Ncode].code = code;
    memset (photcode[Ncode].name, 0, 32);
    strcpy (photcode[Ncode].name, name);
    if (!strncasecmp (type, "pri", 3)) {
      photcode[Ncode].type  = PHOT_SEC;
      photcode[Ncode].C     = 1000*atof (Zero);
      photcode[Ncode].K     = atof (Airmass);
      photcode[Ncode].dC    = 1000*atof (Offset);
      photcode[Ncode].dX    = 1000*atof (Color);
      photcode[Ncode].c1    = c1;
      photcode[Ncode].c2    = c2;
      photcode[Ncode].equiv = atoi (Primary);
      ParseColorTerms (Slope, photcode[Ncode].X, &photcode[Ncode].Nc);
    }      
    if (!strncasecmp (type, "sec", 3)) {
      photcode[Ncode].type  = PHOT_SEC;
      photcode[Ncode].C     = 1000*atof (Zero);
      photcode[Ncode].K     = atof (Airmass);
      photcode[Ncode].dC    = 1000*atof (Offset);
      photcode[Ncode].dX    = 1000*atof (Color);
      photcode[Ncode].c1    = c1;
      photcode[Ncode].c2    = c2;
      photcode[Ncode].equiv = atoi (Primary);
      ParseColorTerms (Slope, photcode[Ncode].X, &photcode[Ncode].Nc);
    }      
    if (!strncasecmp (type, "dep", 3)) {
      photcode[Ncode].type  = PHOT_DEP;
      photcode[Ncode].C     = 1000*atof (Zero);    /* zero point in millimags */
      photcode[Ncode].K     = atof (Airmass);      /* airmass coeff (millimag / millimag) */
      photcode[Ncode].dC    = 1000*atof (Offset);  /* color ref z.p. (millimag) */
      photcode[Ncode].dX    = 1000*atof (Color);   /* average color (millimag) */
      photcode[Ncode].c1    = c1;
      photcode[Ncode].c2    = c2;
      photcode[Ncode].equiv = atoi (Primary);
      ParseColorTerms (Slope, photcode[Ncode].X, &photcode[Ncode].Nc);
    }      
    if (!strncasecmp (type, "ref", 3)) {
      photcode[Ncode].type  = PHOT_REF;
      photcode[Ncode].C     = 0;
      photcode[Ncode].K     = 0;
      photcode[Ncode].dC    = 0;
      photcode[Ncode].dX    = 0;
      photcode[Ncode].c1    = 0;
      photcode[Ncode].c2    = 0;
      photcode[Ncode].equiv = atoi (Primary);
      photcode[Ncode].X[0]  = 0;
      photcode[Ncode].Nc    = 0;
    }

    /* alt photcodes are a little different: they have the SAME photcode as an existing
       pri/sec photcode, but define an alternate transformation for that code */
    if (!strncasecmp (type, "alt", 3)) {
      photcode[Ncode].type  = PHOT_ALT;
      photcode[Ncode].C     = 1000*atof (Zero);    /* zero point in millimags */
      photcode[Ncode].K     = atof (Airmass);      /* airmass coeff (millimag / millimag) */
      photcode[Ncode].dC    = 1000*atof (Offset);  /* color ref z.p. (millimag) */
      photcode[Ncode].dX    = 1000*atof (Color);   /* average color (millimag) */
      photcode[Ncode].c1    = c1;
      photcode[Ncode].c2    = c2;
      photcode[Ncode].equiv = atoi (Primary);
      ParseColorTerms (Slope, photcode[Ncode].X, &photcode[Ncode].Nc);
    }
    if (!photcode[Ncode].type) {
      fprintf (stderr, "error in Photfile: unknown type %s\n", type);
    }

    Ncode++;
    if (Ncode == NPHOTCODE) {
      NPHOTCODE += 10;
      REALLOCATE (photcode, PhotCode, NPHOTCODE);
    }
  }
  fclose (f);
  
  /* set up photcode indexes (see dvo_photcode_ops.c) */
  Nsecfilt = 0;
  for (i = 0; i < Ncode; i++) {
    if (photcode[i].type == PHOT_ALT) continue; /* no hashcode for ALT codes */
    if (table[0].hashcode[photcode[i].code] != -1) {
      fprintf (stderr, "duplicate photcodes in file\n");
      code = table[0].hashcode[photcode[i].code];
      fprintf (stderr, "conflict between %s (%d) and %s (%d)\n",
	       photcode[i].name, photcode[i].code, photcode[code].name, photcode[code].code);
      free (photcode);
      return (FALSE);
    }
    table[0].hashcode[photcode[i].code] = i;
    if (photcode[i].type == PHOT_SEC) {
      table[0].hashNsec[photcode[i].code] = Nsecfilt;
      table[0].codeNsec[Nsecfilt] = photcode[i].code;
      Nsecfilt ++;
    }
  }

  // validity check for references
  // photcode.equiv of 0 means "undefined"
  for (i = 0; i < Ncode; i++) {
    if (photcode[i].type == PHOT_DEP) {
      if (photcode[i].equiv == 0) continue;
      Nsec = table[0].hashcode[photcode[i].equiv];
      if ((Nsec >= Ncode) || (Nsec < 0)) {
	fprintf (stderr, "reference for dependent photcode is not a valid photcode\n");
	free (photcode);
	return (FALSE);
      }
      if (photcode[Nsec].type != PHOT_SEC) {
	fprintf (stderr, "reference for dependent photcode is not an average photcode\n");
	free (photcode);
	return (FALSE);
      }
    }
    if (photcode[i].type == PHOT_ALT) {
      Nsec = table[0].hashcode[photcode[i].code];
      if ((Nsec >= Ncode) || (Nsec < 0)) {
	fprintf (stderr, "reference for alternate photcode is not in photcodes\n");
	free (photcode);
	return (FALSE);
      }
      if (photcode[Nsec].type != PHOT_SEC) {
	fprintf (stderr, "reference for alternate photcode is not an average photcode\n");
	free (photcode);
	return (FALSE);
      }
    }
  }
  table[0].code     = photcode;
  table[0].Ncode    = Ncode;
  table[0].Nsecfilt = Nsecfilt;

  return (TRUE);
}

# define NCTERMS 4
void ParseColorTerms (char *terms, float *X, int *N) {

  int i;
  char *p;

  p = terms;

  for (i = 0; (p != NULL) && (i < NCTERMS); i++) {
    X[i] = atof (p);
    p = strchr (p, ',');
    if (p == (char *) NULL) continue;
    p ++;
  }
  *N = i;
}
