#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 ;
}









