@Override
  public void run() {
    boolean poison = false;
    while (!poison) {
      try {
        WorkPackage pack = m_workpackage_queue.take();
        if (!pack.getPoison()) {
          analyze(pack);
        } else {
          poison = pack.getPoison();
        }

      } catch (InterruptedException ex) {
        ex.printStackTrace();
      }
    }

    //        if (rConnection != null) {
    //            rConnection.close();
    //        }
  }
  private static void determineFoldchange(
      double[] genotypes, double[] expression, Result r, int d, int p, WorkPackage wp) {
    int numAA = 0;
    int numBB = 0;

    double sumAA = 0;
    double sumBB = 0;

    for (int i = 0; i < genotypes.length; i++) {
      //	    if (indWGA[i] != -1) {
      if (genotypes[i] == 0) {
        sumAA += (expression[i] * 2);
        numAA += 2;
      }
      if (genotypes[i] == 1) {
        sumAA += (expression[i]);
        sumBB += (expression[i]);
        numAA++;
        numBB++;
      }
      if (genotypes[i] == 2) {
        sumBB += (expression[i] * 2);
        numBB += 2;
      }
      //	    }

    }

    sumAA /= (double) numAA;
    sumBB /= (double) numBB;

    double min = sumAA;
    if (sumBB < min) {
      min = sumBB;
    }

    // normalize to mean of 1
    if (min < 0) {
      sumAA += Math.abs(min) + 1;
      sumBB += Math.abs(min) + 1;
    }
    if (wp.getFlipSNPAlleles()[d]) {

      r.fc[d][p] = sumAA / sumBB;
    } else {
      r.fc[d][p] = sumBB / sumAA;
    }
  }
  private void convertResultsToPValues(WorkPackage wp, Result dsResults) {
    // per probe, convert to p-value
    int numProbes = dsResults.zscores[0].length;

    boolean hasResults = false;

    for (int p = 0; p < numProbes; p++) {
      int nrDatasetsPassingQC = 0;
      int nrTotalSamples = 0;
      double zSum = 0;
      double betasum = 0;

      for (int d = 0; d < m_numDatasets; d++) {
        // TODO: check whether this actually returns the correct Z-scores: should the stored values
        // be flipped?
        double zscore = dsResults.zscores[d][p];
        double correlation = dsResults.correlations[d][p];

        Integer numSamples = dsResults.numSamples[d];
        if (!Double.isNaN(correlation)) {
          boolean flipalleles = wp.getFlipSNPAlleles()[d];
          if (m_useAbsoluteZScores) {
            zscore = Math.abs(zscore);
            dsResults.zscores[d][p] = Math.abs(zscore);
            dsResults.correlations[d][p] = Math.abs(correlation);
            if (!Double.isNaN(dsResults.beta[d][p])) {
              dsResults.beta[d][p] = Math.abs(dsResults.beta[d][p]);
            }
            wp.getFlipSNPAlleles()[d] = false;
          } else if (flipalleles) {
            zscore = -zscore;
            //                        dsResults.zscores[d][p] = zscore;
            //                        correlation = -correlation;
            //                        dsResults.correlations[d][p] = correlation;
          }
          nrDatasetsPassingQC++;

          double weight = Descriptives.getSqrt(numSamples);

          zSum += (zscore * weight);
          nrTotalSamples += numSamples;

          if (determinebeta) {
            if (flipalleles) {
              betasum += (-dsResults.beta[d][p] * numSamples);
              dsResults.beta[d][p] = -dsResults.beta[d][p];
            } else {
              betasum += (dsResults.beta[d][p] * numSamples);
            }
          }
        }
      }

      if (nrTotalSamples > 0
              && (testSNPsPresentInBothDatasets && nrDatasetsPassingQC == m_numDatasets)
          || (!testSNPsPresentInBothDatasets && nrDatasetsPassingQC > 0)) {
        testsPerformed++;
        hasResults = true;
        double sqrtSample = Descriptives.getSqrt(nrTotalSamples);
        double zScore = zSum / sqrtSample;
        double pValueOverall = Descriptives.convertZscoreToPvalue(zScore);
        dsResults.pvalues[p] = pValueOverall;
        dsResults.finalZScore[p] = zScore;

        // determine assessed allele....
        if (determinebeta) {
          betasum /= nrTotalSamples;
          double metase = 1 / Math.sqrt(nrTotalSamples);
          dsResults.finalBeta[p] = betasum;
          dsResults.finalBetaSe[p] = metase;
        }
      } else {
        dsResults.pvalues[p] = Double.NaN;
        dsResults.finalZScore[p] = Double.NaN;
      }
    }

    wp.setHasResults(hasResults);

    wp.setResult(dsResults);
  }
  private void analyze(WorkPackage wp) {
    testsPerformed = 0;
    currentWP = wp;
    wp.setNumTested(0);
    //        RunTimer t1 = new RunTimer();
    // load SNP genotypes
    SNP[] snps = wp.getSnps();
    int[] probes = wp.getProbes();
    Result dsResults = null;

    double[] snpvariances = new double[m_numDatasets];
    double[][] snpmeancorrectedgenotypes = new double[m_numDatasets][0];
    double[][] originalgenotypes = new double[m_numDatasets][0];
    boolean[][] includeExpressionSample = new boolean[m_numDatasets][0];

    for (int d = 0; d < m_numDatasets; d++) {
      SNP dSNP = snps[d];

      if (dSNP != null) {

        double[] x = dSNP.selectGenotypes(m_expressionToGenotypeIds[d], false, true);
        originalgenotypes[d] = dSNP.selectGenotypes(m_expressionToGenotypeIds[d], false, false);

        int xLen = x.length;
        double meanX = JSci.maths.ArrayMath.mean(x);

        snpmeancorrectedgenotypes[d] = new double[xLen];

        for (int i = 0; i < xLen; i++) {
          snpmeancorrectedgenotypes[d][i] = x[i] - meanX;
        }

        double varianceX = JSci.maths.ArrayMath.variance(x);
        if (varianceX != 0) {
          snpvariances[d] = varianceX;

          int inds[] = m_expressionToGenotypeIds[d];
          int sampleCount = m_expressionToGenotypeIds[d].length;
          includeExpressionSample[d] = new boolean[sampleCount];
          byte[] genotypes = dSNP.getGenotypes();
          for (int s = 0; s < sampleCount; s++) {
            int ind = inds[s];
            double valX = genotypes[ind]; // loadedSNPGenotype[ind];
            if (valX != -1) {
              includeExpressionSample[d][s] = true;
            } else {
              includeExpressionSample[d][s] = false;
            }
          }
        } else {
          dSNP.clearGenotypes();
          dSNP = null;
          wp.getFlipSNPAlleles()[d] = null;
          snps[d] = null;
        }
      }
    }

    if (cisOnly) {
      dsResults = new Result(m_numDatasets, wp.getProbes().length, wp.getId());
      for (int d = 0; d < m_numDatasets; d++) {
        SNP dSNP = snps[d];

        if (dSNP != null) {
          dsResults.numSamples[d] = snpmeancorrectedgenotypes[d].length;
          double[][] rawData = m_expressiondata[d].getMatrix();
          double[] varY = m_expressiondata[d].getProbeVariance();
          double[] meanY = m_expressiondata[d].getProbeMean();
          int samplecount = m_expressiondata[d].getIndividuals().length;

          double[][] covariates = null;
          if (m_covariates != null) {
            DoubleMatrixDataset<String, String> covariateData = m_covariates[d];
            covariates = covariateData.rawData;
          }

          for (int p = 0; p < probes.length; p++) {
            int pid = probes[p];
            Integer probeId = m_probeTranslation.get(d, pid);
            if (probeId != -9) {
              test(
                  d,
                  p,
                  probeId,
                  snpmeancorrectedgenotypes[d],
                  originalgenotypes[d],
                  snpvariances[d],
                  varY[probeId],
                  meanY[probeId],
                  includeExpressionSample[d],
                  samplecount,
                  rawData,
                  covariates,
                  dsResults,
                  this.currentWP,
                  this.metaAnalyseModelCorrelationYHat,
                  this.metaAnalyseInteractionTerms,
                  this.determinefoldchange);
            } else {
              dsResults.correlations[d][p] = Double.NaN;
              dsResults.zscores[d][p] = Double.NaN;
            }
          }

        } else {
          for (int p = 0; p < probes.length; p++) {
            dsResults.correlations[d][p] = Double.NaN;
            dsResults.zscores[d][p] = Double.NaN;
          }
        }
      }
    } else if (transOnly) {

      HashSet<Integer> probestoExclude = null;
      if (probes != null) {
        probestoExclude = new HashSet<Integer>();
        for (int p = 0; p < probes.length; p++) {
          probestoExclude.add(probes[p]);
        }
      }
      dsResults = new Result(m_numDatasets, m_numProbes, wp.getId());
      for (int d = 0; d < m_numDatasets; d++) {
        SNP dSNP = snps[d];
        dsResults.numSamples[d] = snpmeancorrectedgenotypes[d].length;
        double[][] rawData = m_expressiondata[d].getMatrix();
        double[] varY = m_expressiondata[d].getProbeVariance();
        double[] meanY = m_expressiondata[d].getProbeMean();
        int samplecount = m_expressiondata[d].getIndividuals().length;
        if (dSNP != null) {
          dsResults.numSamples[d] = snpmeancorrectedgenotypes[d].length;
          for (int pid = 0; pid < m_numProbes; pid++) {
            if (probestoExclude == null || !probestoExclude.contains(pid)) {
              Integer probeId = m_probeTranslation.get(d, pid);
              if (probeId != -9) {
                test(
                    d,
                    pid,
                    probeId,
                    snpmeancorrectedgenotypes[d],
                    originalgenotypes[d],
                    snpvariances[d],
                    varY[probeId],
                    meanY[probeId],
                    includeExpressionSample[d],
                    samplecount,
                    rawData,
                    null,
                    dsResults,
                    this.currentWP,
                    this.metaAnalyseModelCorrelationYHat,
                    this.metaAnalyseInteractionTerms,
                    this.determinefoldchange);
              } else {
                dsResults.correlations[d][pid] = Double.NaN;
                dsResults.zscores[d][pid] = Double.NaN;
              }
            } else {
              dsResults.correlations[d][pid] = Double.NaN;
              dsResults.zscores[d][pid] = Double.NaN;
            }
          }
        } else {
          for (int p = 0; p < m_numProbes; p++) {
            dsResults.correlations[d][p] = Double.NaN;
            dsResults.zscores[d][p] = Double.NaN;
          }
        }
      }
    } else {
      dsResults = new Result(m_numDatasets, m_numProbes, wp.getId());
      for (int d = 0; d < m_numDatasets; d++) {
        SNP dSNP = snps[d];
        dsResults.numSamples[d] = snpmeancorrectedgenotypes[d].length;
        double[][] rawData = m_expressiondata[d].getMatrix();
        double[] varY = m_expressiondata[d].getProbeVariance();
        double[] meanY = m_expressiondata[d].getProbeMean();
        int samplecount = m_expressiondata[d].getIndividuals().length;
        if (dSNP != null) {
          dsResults.numSamples[d] = snpmeancorrectedgenotypes[d].length;
          //                    RunTimer t2 = new RunTimer();
          for (int pid = 0; pid < m_numProbes; pid++) {
            Integer probeId = m_probeTranslation.get(d, pid);
            if (probeId != -9) {
              test(
                  d,
                  pid,
                  probeId,
                  snpmeancorrectedgenotypes[d],
                  originalgenotypes[d],
                  snpvariances[d],
                  varY[probeId],
                  meanY[probeId],
                  includeExpressionSample[d],
                  samplecount,
                  rawData,
                  null,
                  dsResults,
                  this.currentWP,
                  this.metaAnalyseModelCorrelationYHat,
                  this.metaAnalyseInteractionTerms,
                  this.determinefoldchange);
            } else {
              dsResults.correlations[d][pid] = Double.NaN;
              dsResults.zscores[d][pid] = Double.NaN;
            }
          }
          //                    System.out.println("Test: "+t2.getTimeDesc());
        } else {
          for (int p = 0; p < m_numProbes; p++) {
            dsResults.correlations[d][p] = Double.NaN;
            dsResults.zscores[d][p] = Double.NaN;
          }
        }
      }
    }

    convertResultsToPValues(wp, dsResults);

    if (m_eQTLPlotter != null) {
      for (int p = 0; p < dsResults.pvalues.length; p++) {
        double pval = dsResults.pvalues[p];
        if (!Double.isNaN(pval)) {
          if (pval < m_pvaluePlotThreshold) {
            ploteQTL(wp, p);
          }
        }
      }
    }

    snps = wp.getSnps();
    if (snps != null) {
      for (SNP snp : snps) {
        if (snp != null) {
          snp.clearGenotypes();
        }
      }
    }

    // if result output is binary, convert to bytes and deflate the set of bytes.
    //        if (m_binaryoutput) {
    //            deflateResults(wp);
    //        }
    // now push the results in the queue..
    try {
      wp.setNumTested(testsPerformed);
      m_result_queue.put(wp);
    } catch (InterruptedException e) {
      e.printStackTrace();
    }

    //        System.out.println("Analyze: "+t1.getTimeDesc());
  }