#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
// #include <openssl/md2.h>
#include "admutils.h"

#include  "packit.h"
static int fastdupnum = 10;
static double fastdupthresh = 0.75;
static double fastdupkill = 0.75;
static int snptab = NO;


int hashit (char *str);

int
countcol (char *fname)
{
  FILE *fp;
  int t;

  openit (fname, &fp, "r");
  t = countcolumns (fp);
  fclose (fp);
  return t;
}


int
countcolumns (FILE * fp)
{                               /* count number of text columns separated by whitespace */
  int i = 0, c;
  fpos_t ptr;

  if (fgetpos (fp, &ptr)) {
    printf ("error counting columns\n");
    return 0;
  }

  while ((c = getc (fp)) != '\n') {
    if (isgraph (c)) {
      i++;
      while (isgraph (c = getc (fp))) {
      }
      ungetc (c, fp);
    }
  }
  fsetpos (fp, &ptr);
  return i;
}

void
sett1 (double *tt, double theta, int numstates)
{
  if (numstates == 2) {
    tt[0] = 1.0 - theta;
    tt[1] = theta;
    tt[2] = 0.0;
  }
  if (numstates == 3) {
    tt[0] = (1.0 - theta) * (1.0 - theta);
    tt[1] = 2.0 * theta * (1.0 - theta);
    tt[2] = theta * theta;
  }
}

void
sett1r (double *tt, double theta, int numstates, double risk)
{
  double y;
  sett1 (tt, theta, numstates);
  tt[1] *= risk;
  tt[2] *= risk * risk;
  y = asum (tt, numstates);
  vst (tt, tt, 1.0 / y, numstates);
}

void
gettln (SNP * cupt, Indiv * indx,
        double *ptheta, double *plambda, int *pnumstates, int *pignore)

/* set theta, lambda numstates */
{
  double theta, lambda;
  int numstates, chrom, ignore;

  theta = indx->theta_mode;
  lambda = indx->lambda_mode;
  ignore = indx->ignore;
  numstates = 3;

  chrom = cupt->chrom;

  if (chrom == 23) {
    theta = indx->Xtheta_mode;
    lambda = indx->Xlambda_mode;
    if (indx->gender == 'M')
      numstates = 2;
    if (indx->gender == 'U')
      ignore = YES;
  }
  if (ptheta != NULL)
    *ptheta = theta;
  if (plambda != NULL)
    *plambda = lambda;
  if (pnumstates != NULL)
    *pnumstates = numstates;
  if (pignore != NULL)
    *pignore = ignore;
}


void
puttln (SNP * cupt, Indiv * indx, double ptheta, double plambda)

/* put theta, lambda */
{

  int chrom;


  chrom = cupt->chrom;

  if (chrom == 23) {
    indx->Xtheta_mode = ptheta;
    indx->Xlambda_mode = plambda;
    return;
  }
  indx->theta_mode = ptheta;
  indx->lambda_mode = plambda;
  return;
}


double
hwcheck (SNP * cupt, double *cc)
{

  int i, n, g;


  vzero (cc, 3);

  n = cupt->ngtypes;
  for (i = 0; i < n; i++) {
    g = getgtypes (cupt, i);
    if (g < 0)
      continue;
    ++cc[g];
  }
  return (hwstat (cc));

}

double
hwcheckx (SNP * cupt, Indiv ** indm, double *cc)
// deals with X  
{

  int i, n, g, ignore, numstates;
  Indiv *indx;
  double t, l;


  vzero (cc, 3);

  n = cupt->ngtypes;
  for (i = 0; i < n; i++) {
    indx = indm[i];
    gettln (cupt, indx, &t, &l, &numstates, &ignore);
    if (ignore)
      continue;
    if (numstates != 3)
      continue;
    g = getgtypes (cupt, i);
    if (g < 0)
      continue;
    ++cc[g];
  }
  return (hwstat (cc));

}

void
hap2dip (SNP * cupt)
// duplicate chromosomes           
{
  int i, n, g;

  n = cupt->ngtypes;
  for (i = 0; i < n; i++) {
    g = getgtypes (cupt, i);
    if (g < 0)
      continue;
    if (g == 2)
      g = -1;
    if (g == 1)
      g = 2;
    putgtypes (cupt, i, g);
  }
}

void
flipalleles (SNP * cupt)
// flip reference, variant counts
{
  int i, n, g;
  n = cupt->ngtypes;
  for (i = 0; i < n; i++) {
    g = getgtypes (cupt, i);
    if (g < 0)
      continue;
    putgtypes (cupt, i, 2 - g);
  }
}

void
flipalleles_phased (SNP * cupt)
// flip reference, variant counts
{
  int i, n, g;
  n = cupt->ngtypes;
  for (i = 0; i < n; i++) {
    g = getgtypes (cupt, i);
    if (g < 0)
      continue;
    if (g > 1)
      fatalx ("genotype > 1 in phased file\n");
    putgtypes (cupt, i, 1 - g);
  }
}


void
cntit (double *xc, SNP * c1, SNP * c2)
{
  int n, i, e, f;

  n = MIN (c1->ngtypes, c2->ngtypes);
  vzero (xc, 9);
  for (i = 0; i < n; i++) {
    e = getgtypes (c1, i);
    f = getgtypes (c2, i);
    if (e < 0)
      continue;
    if (f < 0)
      continue;
    ++xc[3 * e + f];
  }
}

/******** UTILITY FUNCTIONS **********/
void
fataly (const char *name)
{
  printf ("%s", name);
  exit (1);
}

int
compare_doubles (const void *a, const void *b)
{
  const double *da = (const double *) a;
  const double *db = (const double *) b;

  return (*da > *db) - (*da < *db);
}

void
pcheck (char *name, char x)
{

  if (name != NULL)
    return;
  if (x != CNULL)
    fatalx ("parameter %c compulsory\n", x);
  else
    fatalx ("missing argument\n");
}

void
printm (double **M, int numstates)
{
  int i, j;
  printf ("M:\n");
  for (i = 0; i < numstates; i++) {
    for (j = 0; j < numstates; j++) {
      printf ("%9.3f ", M[j][i]);
    }
    printf ("\n");
  }
}


int
numvalidgtypes (SNP * cupt)
{
  int nvalid, n, i, k;
  if (cupt->isfake)
    return 0;
  n = cupt->ngtypes;
  nvalid = 0;
  for (i = 0; i < n; i++) {
    k = getgtypes (cupt, i);
    if (k >= 0)
      ++nvalid;
  }
  return nvalid;
}

int
numvalids (Indiv * indx, SNP ** snpmarkers, int fc, int lc)
{
  SNP *cupt;
  int idnum, numstates, ignore;
  int k, nval = 0;

  if (fc > lc)
    return 0;
  if (lc < 0)
    return 0;
  idnum = indx->idnum;
  for (k = fc; k <= lc; ++k) {
    cupt = snpmarkers[k];
    if (cupt->isfake)
      continue;
    if (cupt->ignore)
      continue;

/**
    gettln(cupt, indx, NULL, NULL, &numstates, &ignore) ; 
    if (ignore) continue ; 
*/
    if (cupt->ngtypes == 0)
      continue;
    if (getgtypes (cupt, idnum) >= 0)
      ++nval;
  }
  return nval;
}

double
malefreq (Indiv ** indmarkers, int numindivs)

/* pop freq of males in sample */
{
  int i;
  Indiv *indx;
  double cmale, cfemale;

  cmale = 0;
  for (i = 0; i < numindivs; ++i) {
    indx = indmarkers[i];
    if (indx->gender == 'M')
      ++cmale;
  }

  cmale /= (double) numindivs;

  return cmale;
}

int
isimatch (int a, int b)
{
  if (a < 0)
    return YES;
  if (b < 0)
    return YES;
  if (a == b)
    return YES;
  return NO;
}

void
gethpos (int *fc, int *lc, SNP ** snpm, int numsnps,
         int xchrom, int lo, int hi)
{
  int k, xfc, xlc, pos;
  SNP *cupt;

  xfc = 9999999;
  xlc = -9999999;
  for (k = 0; k < numsnps; k++) {
    cupt = snpm[k];
    if (cupt->chrom != xchrom)
      continue;
    pos = cupt->physpos;
    if (pos < lo)
      continue;
    if (pos > hi)
      continue;
    xfc = MIN (xfc, k);
    xlc = MAX (xlc, k);
  }
  *fc = xfc;
  *lc = xlc;
}

void
makedir (char *dirname)
// AT wrote original 
// sets up directory.  Will fail hard if directory does not 
// exist and can't be made 
{
  int fdir;
  fdir = open (dirname, O_RDONLY, 0);
  if (fdir >= 0) {
    close (fdir);
    return;
  }
  fdir = mkdir (dirname, 0775);
  if (fdir < 0) {
    perror ("makedir");
    fatalx ("(makedir) directory %s not created\n");
  }
  printf ("Created a new directory %s\n", dirname);
}


int
indxindex (char **namelist, int len, char *strid)
// look for string in list
{
  int k;
  for (k = 0; k < len; k++) {
    if (strcmp (namelist[k], strid) == 0)
      return k;
  }
  return -1;
}

int
indindex (Indiv ** indivmarkers, int numindivs, char *indid)

/* hash table would be good here */
{
  int k;
  for (k = 0; k < numindivs; k++) {
    if (strcmp (indivmarkers[k]->ID, indid) == 0)
      return k;
  }
  return -1;
}

void
inddupcheck (Indiv ** indivmarkers, int numindivs)
{
  // fail hard if duplicate
  int t, k, n;
  char **ss;

  freesnpindex ();
  n = numindivs;
  ZALLOC (ss, n, char *);
  for (k = 0; k < n; k++) {
    ss[k] = strdup (indivmarkers[k]->ID);
  }
  t = finddup (ss, n);
  if (t >= 0)
    fatalx ("duplicate sample: %s\n", ss[t]);
  freeup (ss, n);
  free (ss);
}

int
snpindex (SNP ** snpmarkers, int numsnps, char *snpid)
{
  int k;
  char **ss;

  if (snptab == NO) {
// set up hash table
    snptab = YES;
    ZALLOC (ss, numsnps, char *);
    for (k = 0; k < numsnps; k++) {
      ss[k] = strdup (snpmarkers[k]->ID);
    }
    xloadsearch (ss, numsnps);
    freeup (ss, numsnps);
    free (ss);
  }

  k = xfindit (snpid);
  return k;
}

void
freesnpindex ()
{
  if (snptab == NO)
    return;
  snptab = NO;
  xdestroy ();
}

int
ignoresnp (SNP * cupt)
{
  if (cupt->ignore)
    return YES;
  if (cupt->isfake)
    return YES;
  if (cupt->ngtypes == 0)
    return YES;
  if (cupt->isrfake)
    return NO;
  return NO;
}

double
entrop (double *a, int n)
{
  int i;
  double ysum, t, ans;

  ans = 0.0;
  ysum = asum (a, n);
  for (i = 0; i < n; i++) {
    t = a[i] / ysum;
    ans += xxlog2 (t);
  }
  return -ans;
}

double
xxlog2 (double t)
{
  if (t <= 0.0)
    return t;
  return t * log (t) / log (2.0);
}

void
testnan (double *a, int n)
{
  int i;

  for (i = 0; i < n; i++) {
    if (!finite (a[i]))
      fatalx ("(testnan) fails:  index %d\n", i);
  }
}

void
getgall (SNP * cupt, int *x, int n)
{
  int k, t, a;
  unsigned char b, w;

  if (cupt->gtypes == NULL) {
    ivclear (x, -1, n);
    return;
  }

  if (!packmode) {
    copyiarr (cupt->gtypes, x, n);
    return;
  }

  k = 0;
  for (a = 0; 4 * a < n; ++a) {
    w = cupt->pbuff[a];
    for (t = 0; t < 4; t++) {
      b = w >> 2 * (3 - t);
      x[k] = b & 3;
      ++k;
      if (k >= n)
        break;
    }
  }
}

int
getgtypes (SNP * cupt, int k)
{
  char *buff;
  int g;

  if (cupt->gtypes == NULL)
    return -1;

  if (packmode) {
    buff = cupt->pbuff;
    g = rbuff ((unsigned char *) buff, k);
    if (g == 3)
      g = -1;
    return g;
  }

  return cupt->gtypes[k];
}

void
putgtypes (SNP * cupt, int k, int val)
{
  char *buff;
  int g;

  if (k >= cupt->ngtypes)
    fatalx ("(putgtypes)\n");
  if (packmode) {
    buff = cupt->pbuff;
    g = val;
    if (g < 0)
      g = 3;
    wbuff ((unsigned char *) buff, k, g);
    return;
  }
  cupt->gtypes[k] = val;
}

int
getep (SNP * cupt, int k)
{
  char *buff;
  int g;

  if (cupt->gtypes == NULL)
    return -1;
  if (k >= cupt->ngtypes)
    return -1;
  buff = cupt->ebuff;
  g = rbuff ((unsigned char *) buff, k);
  if (g == 3)
    g = -1;
  return g;

}

void
putep (SNP * cupt, int k, int val)
{
  char *buff;
  int g;

  buff = cupt->ebuff;
  if (buff == NULL)
    fatalx ("(putep) no buffer\n");
  if (k >= cupt->ngtypes)
    fatalx ("(putep)\n");
  g = val;
  if (g < 0)
    g = 3;
  wbuff ((unsigned char *) buff, k, g);
  return;

}

int
hasharr (char **xarr, int nxarr)
// in application ordering  matters so we hash order dependent 
{

  int hash, thash, i, n;

  hash = 0;

  for (i = 0; i < nxarr; i++) {
    thash = hashit (xarr[i]);
    hash *= 17;
    hash ^= thash;
  }
  return hash;
}

int
hashit (char *str)
{

/* simple and unimpressive hash function NJP */
  int j, len, hash;

  hash = 0;
  len = strlen (str);

  for (j = 0; j < len; j++) {
    hash *= 23;
    hash += (int) str[j];
  }
  return hash;
}

void
wbuff (unsigned char *buff, int num, int g)
// low level routine writes 2 bits to buffer 
// g should be 0 1 2 or 3   (3 = missing) 
{

  int wnum, wplace;
  unsigned char mm, msk, ones;
  static int ncall = 0;

  if ((g < 0) || (g > 3))
    fatalx ("(wbuff) invalid g value\n", g);

  ++ncall;

  msk = 3 << 6;
  mm = g << 6;
  ones = 0XFF;

  wnum = num / 4;
  wplace = num % 4;

  mm = mm >> (wplace * 2);
  msk = (msk >> (wplace * 2)) ^ ones;
  buff[wnum] &= msk;
  buff[wnum] |= mm;

/**
     printf("zz %d  %d %d %d %02x\n", num, wnum, wplace, g, buff[wnum]) ;
     printf("yyy %d %d\n", g, rbuff(buff,num)) ;
*/
}

int
rbuff (unsigned char *buff, int num)
{
  int wnum, wplace, rshft;
  unsigned char b;
  static int ncall = 0;

// ++ncall ;


  wnum = num >> 2;
  wplace = num & 3;

  rshft = (3 - wplace) << 1;
  b = buff[wnum] >> rshft;

  b = b & 3;
  return b;
}

// fast dup code
void
setfastdupnum (int num)
{
  fastdupnum = num;
}

void
setfastdupthresh (double thresh, double kill)
{
  fastdupthresh = thresh;
  fastdupkill = kill;
}

void
killxhets (SNP ** snpmarkers, Indiv ** indivmarkers, int numsnps,
           int numindivs)
{
  SNP *cupt;
  Indiv *indx;
  int i, k, g;

  for (i = 0; i < numsnps; i++) {
    cupt = snpmarkers[i];
    if (cupt->ignore)
      continue;
    if (cupt->isfake)
      continue;
    if (cupt->chrom != 23)
      continue;
    for (k = 0; k < numindivs; k++) {
      indx = indivmarkers[k];
      if (indx->gender != 'M')
        continue;
      g = getgtypes (cupt, k);
      if (g != 1)
        continue;
      putgtypes (cupt, k, -1);
    }
  }
}


void
fastdupcheck (SNP ** snpmarkers, Indiv ** indivmarkers, int numsnps,
              int numindivs)
{
  SNP *cupt;
  Indiv *indx;
  int *gtypes;
  int i, j, k, n;
  int *snphets, *indsnp, tab[15], ww[15], **codeit, *cc, g, *cbuff;
  int *buff, val, vv, lbuff, itry, ilo, ihi;

  ZALLOC (gtypes, numindivs, int);
  ZALLOC (cbuff, 2 * numindivs, int);
  ZALLOC (codeit, numindivs, int *);
  ZALLOC (snphets, numsnps, int);
  ZALLOC (indsnp, numsnps, int);
  for (i = 0; i < numsnps; i++) {
    cupt = snpmarkers[i];
    if (cupt->ignore)
      continue;
    if (cupt->isfake)
      continue;
    if (cupt->chrom > 22)
      continue;
    grabgtypes (gtypes, cupt, numindivs);
    for (k = 0; k < numindivs; k++) {
      if (gtypes[k] == 1)
        ++snphets[i];
    }
  }
  ivst (snphets, snphets, -1, numsnps);
  isortit (snphets, indsnp, numsnps);
// make fastdupnum shots at exact match on 15 snps */
  for (itry = 1; itry < fastdupnum; itry++) {
    ilo = 15 * itry;
    if ((ilo + 15) >= numsnps)
      break;
    for (i = 0; i < 15; i++) {
      j = indsnp[i + ilo];
      tab[i] = j;
    }
    n = 0;
    for (k = 0; k < numindivs; ++k) {
      indx = indivmarkers[k];
      if (indx->ignore)
        continue;
      for (i = 0; i < 15; i++) {
        j = tab[i];
        g = getgtypes (snpmarkers[j], k);
        if (g < 0)
          break;
        ww[i] = g;
      }
      if (g < 0)
        continue;
      cc = codeit[n] = cbuff + 2 * n;
      cc[0] = kcode (ww, 15, 4);
      cc[1] = k;
      ++n;
    }


    if (n == 0)
      continue;
    ipsortit (codeit, NULL, n, 2);

    buff = gtypes;
    lbuff = 0;
    val = -1;

    for (i = 0; i < n; i++) {
      cc = codeit[i];
      vv = cc[0];
      if (vv != val) {
        cdup (snpmarkers, indivmarkers, numsnps, buff, lbuff);
        lbuff = 0;
        val = vv;
      }
      buff[lbuff] = cc[1];
      ++lbuff;
    }
    cdup (snpmarkers, indivmarkers, numsnps, buff, lbuff);
  }                             // itry

  free (snphets);
  free (indsnp);
  free (gtypes);
  free (codeit);
  free (cbuff);
}

void
cdup (SNP ** snpm, Indiv ** indm, int nsnp, int *buff, int lbuff)
{
  static int ncall = 0;
  SNP *cupt;
  Indiv *inda, *indb;
  double ytot, yhit;
  int g1, g2, k1, k2, match, nomatch;
  int i1, i2, j;
#define MINMARK 200


  if (lbuff <= 1)
    return;
  ++ncall;

  if (ncall <= 1) {
//printf ("cdup: %d\n", ncall) ;
    printf ("fastdupthresh, kill: %9.3f %9.3f\n", fastdupthresh, fastdupkill);
//printimat(buff, lbuff, 1) ;
  }
// if (ncall==1) printf(" cdup %9.3f %9.3f\n", fastdupthresh, fastdupkill) ;
  for (i1 = 0; i1 < lbuff; ++i1) {
    for (i2 = i1 + 1; i2 < lbuff; ++i2) {
      k1 = buff[i1];
      k2 = buff[i2];
      match = nomatch = 0;
      for (j = 0; j < nsnp; ++j) {
        cupt = snpm[j];
        if (cupt->ignore)
          continue;
        if (cupt->isfake)
          continue;
        g1 = getgtypes (cupt, k1);
        g2 = getgtypes (cupt, k2);
        if ((g1 < 0) || (g2 < 0))
          continue;
        if (g1 == g2)
          ++match;
        if (g1 != g2)
          ++nomatch;
      }

      inda = indm[k1];
      indb = indm[k2];
      ytot = (double) (match + nomatch);
      if (ytot < MINMARK)
        continue;
      yhit = ((double) match) / ytot;

      if (yhit > fastdupthresh) {
        printdup (snpm, nsnp, inda, indb, match, nomatch);
        if (yhit > fastdupkill)
          killdup (inda, indb, snpm, nsnp);
      }
    }
  }
}

void
killdup (Indiv * inda, Indiv * indb, SNP ** snpm, int nsnp)
{
  int t1, t2;
  Indiv *indx;

  t1 = numvalids (inda, snpm, 0, nsnp - 1);
  t2 = numvalids (indb, snpm, 0, nsnp - 1);
  indx = inda;
  if (t1 > t2)
    indx = indb;
  indx->ignore = YES;
  printf ("dup.  %s ignored\n", indx->ID);
}

void
printdup (SNP ** snpm, int numsnp, Indiv * inda, Indiv * indb, int nmatch,
          int nnomatch)
{
  int t1, t2;
  double y;

  if (nmatch <= 0)
    return;
  if (inda->ignore)
    return;
  if (indb->ignore)
    return;

  t1 = numvalids (inda, snpm, 0, numsnp - 1);
  t2 = numvalids (indb, snpm, 0, numsnp - 1);
  printf ("dup? %s %s  match: %d mismatch: %d   %d %d ",
          inda->ID, indb->ID, nmatch, nnomatch, t1, t2);
  printf ("%20s ", inda->egroup);
  printf ("%20s", indb->egroup);
  y = nnomatch / (double) (nnomatch + nmatch);
  printf (" %9.3f", y);
  printnl ();
}

int
kcode (int *w, int len, int base)
{
  int i, t;
  t = 0;
  for (i = 0; i < len; i++) {
    t *= base;
    t += w[i];
  }
  return t;
}

int
grabgtypes (int *gtypes, SNP * cupt, int numindivs)
{

  int k;

  for (k = 0; k < numindivs; k++) {
    gtypes[k] = getgtypes (cupt, k);
  }

}

double
kurtosis (double *a, int n)
{

  double y1, y2, y4;
  double *w;

  ZALLOC (w, n, double);

  y1 = asum (a, n) / (double) n;
  vsp (w, a, -y1, n);

  y2 = asum2 (w, n) / (double) n;
  vst (w, w, 1.0 / sqrt (y2), n);

  vvt (w, w, w, n);

  y4 = asum2 (w, n) / (double) n;


  free (w);
  return y4;

}

int
getlist (char *name, char **list)
{
#define MAXSTR 128
#define MAXFF 5
  FILE *fff;
  char line[MAXSTR];
  char *spt[MAXFF];
  char *sx;
  int nsplit, num = 0;

  num = 0;
  if (name == NULL)
    fatalx ("(numlines)  no name");
  openit (name, &fff, "r");
  while (fgets (line, MAXSTR, fff) != NULL) {
    nsplit = splitup (line, spt, MAXFF);
    if (nsplit == 0)
      continue;
    sx = spt[0];
    if (sx[0] == '#') {
      freeup (spt, nsplit);
      continue;
    }
    list[num] = strdup (sx);
    ++num;
    freeup (spt, nsplit);
  }
  fclose (fff);
  return num;
}

void
printvers (char *progname, char *vers)
{
  printf ("## %s  version: %s", progname, vers);
  printnl ();
}

int
numvalidind (Indiv ** indivmarkers, int numind)
{
  int i;
  int nvalids = 0;
  Indiv *indx;

  for (i = 0; i < numind; i++) {
    indx = indivmarkers[i];
    if (indx->ignore)
      continue;
    ++nvalids;
  }
  return nvalids;
}

void
numvalidgtallind (int *x, SNP ** snpm, int numsnps, int numind)
{
// count valids for all 
  int n = 0;
  int k, t, j;
  SNP *cupt;
  int *z;

  ZALLOC (z, numind, int);
  ivzero (x, numind);
  for (k = 0; k < numsnps; ++k) {
    cupt = snpm[k];
    if (cupt->ignore)
      continue;
    getgall (cupt, z, numind);
    for (j = 0; j < numind; ++j) {
      if (z[j] >= 0)
        ++x[j];
    }
  }
  free (z);
}


int
numvalidgtind (SNP ** snpm, int numsnps, int ind)
{
  int n = 0;
  int k, t;
  SNP *cupt;

  for (k = 0; k < numsnps; ++k) {
    cupt = snpm[k];
    if (cupt->ignore)
      continue;
    t = getgtypes (cupt, ind);
    if (t >= 0)
      ++n;
  }
  return n;
}

int
numvalidgt (Indiv ** indivmarkers, SNP * cupt)
     // like numvalidgtypes but tests ignore   
{
  int n, k, nvalids;
  if (cupt->gtypes == NULL)
    return 0;
  nvalids = 0;
  n = cupt->ngtypes;
  for (k = 0; k < n; k++) {
    if (indivmarkers[k]->ignore)
      continue;
    if (getgtypes (cupt, k) >= 0)
      ++nvalids;
  }
  return nvalids;
}

int
numvalidgtx (Indiv ** indivmarkers, SNP * cupt, int affst)
// like numvalidgtypes but tests ignore   counts only when status=affst
{
  int n, k, nvalids;
  if (cupt->gtypes == NULL)
    return 0;
  nvalids = 0;
  n = cupt->ngtypes;
  for (k = 0; k < n; k++) {
    if (indivmarkers[k]->ignore)
      continue;
    if (indivmarkers[k]->affstatus != affst)
      continue;
    if (getgtypes (cupt, k) >= 0)
      ++nvalids;
  }
  return nvalids;
}

int
isxmale (SNP * cupt, Indiv * indx)
{
  if (cupt->chrom != 23)
    return NO;
  if (indx->gender != 'M')
    return NO;
  return YES;
}

void
printmatz (double *ww, char **eglist, int n)
{
  int i, j, x;
  printf (" %4s", "   ");
  for (i = 0; i < n; i++) {
    printf (" %4s", get3 (eglist[i]));
  }
  printnl ();
  for (i = 0; i < n; i++) {
    printf ("%4s", get3 (eglist[i]));
    for (j = 0; j < n; j++) {
      x = nnint (1000 * ww[i * n + j]);
      printf (" %4d", x);
    }
    printnl ();
  }
}

void
printmatz5 (double *ww, char **eglist, int n)
{
  int i, j, x;
  printf (" %5s", "   ");
  for (i = 0; i < n; i++) {
    printf (" %5s", get3 (eglist[i]));
  }
  printnl ();
  for (i = 0; i < n; i++) {
    printf ("%5s", get3 (eglist[i]));
    for (j = 0; j < n; j++) {
      x = nnint (1000 * ww[i * n + j]);
      printf (" %5d", x);
    }
    printnl ();
  }
}

void
printmatz10 (double *ww, char **eglist, int n)
{
  int i, j, x;
  printf (" %5s", "   ");
  for (i = 0; i < n; i++) {
    printf (" %10s", get3 (eglist[i]));
  }
  printnl ();
  for (i = 0; i < n; i++) {
    printf ("%5s", get3 (eglist[i]));
    for (j = 0; j < n; j++) {
      x = nnint (1000000 * ww[i * n + j]);
      printf (" %10d", x);
    }
    printnl ();
  }
}



char *
get3 (char *ss)
{
  return getshort (ss, 3);
}

char *
getshort (char *ss, int n)
{
  static char xxx[MAXSTR];
  strcpy (xxx, ss);
  xxx[n - 2] = ' ';
  xxx[n - 1] = CNULL;
  return xxx;
}


int
setid2pops (char *idpopstring, Indiv ** indmarkers, int numindivs)
// replace pop by ID for certain samples
{
#define MAXS 1000
  char *spt[MAXS];
  char *sx;
  int nsplit, k, t;
  Indiv *indx;

  nsplit = splitupx (idpopstring, spt, MAXS, ':');
  for (k = 0; k < nsplit; ++k) {
    sx = spt[k];
    t = indindex (indmarkers, numindivs, sx);
    if (t < 0) {
      printf ("(setid2pops): %s not found\n");
      continue;
    }
    indx = indmarkers[t];
    freestring (&indx->egroup);
    indx->egroup = strdup (indx->ID);
  }
  freeup (spt, nsplit);
  return nsplit;
}
