void
affx::TsvFileDiff::p_diff_1line(affx::TsvFile& tsv1, affx::TsvFile& tsv2)
{
  std::string val1,val2;
  int tsv1_clvl=tsv1.lineLevel();
  int tsv1_cidx_max=tsv1.getColumnCount(tsv1_clvl);

  //
  p_linenums(tsv1,tsv2);
  printf("!");
  //
  for (int cidx=0;cidx<tsv1_cidx_max;cidx++) {
    if (cidx!=0) {
      printf("\t");
    }
    printf("\t");
    tsv1.get(tsv1_clvl,cidx,val1);
    tsv2.get(tsv1_clvl,cidx,val2);
    if (val1==val2) {
      printf("%s",val1.c_str());
    }
    else {
      printf("'%s'/'%s'",val1.c_str(),val2.c_str());
    }
  }
  printf("\n");
}
void affx::TsvFileDiff::p_line(affx::TsvFile& tsv) {
  int clvl=tsv.lineLevel();
  int cidx_max=tsv.getColumnCount(clvl);
  std::string val;
  //
  for (int i=0;i<clvl;i++) {
    printf("\t");
  }
  //
  for (int cidx=0;cidx<cidx_max;cidx++) {
    if (cidx!=0) {
      printf("\t");
    }
    printf("\t");
    tsv.get(clvl,cidx,val);
    printf("%s",val.c_str());
  }
  printf("\n");
}
int
affx::TsvFileDiff::diffData(affx::TsvFile& tsv1, affx::TsvFile& tsv2)
{
  int start_diff_cnt=m_diff_cnt;
  std::string val1,val2;
    
  //
  open_residuals(m_residuals_filename,tsv1,tsv2);

  //
  tsv1.rewind();
  tsv2.rewind();

  //
  tsv1.nextLine();
  tsv2.nextLine();

  //
  while ((!tsv1.eof())||(!tsv2.eof())) {
    //
    int tsv1_clvl=tsv1.lineLevel();
    int tsv2_clvl=tsv2.lineLevel();
    //
    while (((tsv1_clvl>tsv2_clvl)||tsv2.eof())&&(!tsv1.eof())) {
      if (p_inc()) {
        p_linenums(tsv1,tsv2);
        printf("-");
        p_line(tsv1);
      }
      m_diff_cnt+=tsv1.getColumnCount(tsv1_clvl);
      tsv1.nextLine();
      tsv1_clvl=tsv1.lineLevel();
    }
    //
    while (((tsv2_clvl>tsv1_clvl)||tsv1.eof())&&(!tsv2.eof())) {
      if (p_inc()) {
        p_linenums(tsv1,tsv2);
        printf("+");
        p_line(tsv2);
      }
      m_diff_cnt+=tsv2.getColumnCount(tsv2_clvl);
      tsv2.nextLine();
      tsv2_clvl=tsv2.lineLevel();
    }
    //
    if ((tsv1_clvl>=0)&&(tsv2_clvl>=0)) {
      int tsv1_cidx_max=tsv1.getColumnCount(tsv1_clvl);
      int tsv2_cidx_max=tsv2.getColumnCount(tsv2_clvl);
      //
      int cidx_max;
      if (tsv1_cidx_max<tsv2_cidx_max) {
        cidx_max=tsv2_cidx_max;
      } else {
        cidx_max=tsv1_cidx_max;
      }
      
      // count diffs on the line
      int line_diff_cnt=0;
      double d1,d2;
      for (int cidx=0;cidx<cidx_max;cidx++) {
        tsv1.get(tsv1_clvl,cidx,val1);
        tsv2.get(tsv2_clvl,cidx,val2);
        // the same?
        if (val1==val2) {
          // record the base value
          if (m_residuals_tsv!=NULL) {
            // numeric?
            if (tsv1.get(tsv1_clvl,cidx,d1)==affx::TSV_OK) {
              // put a zero
              m_residuals_tsv->set(tsv1_clvl,cidx,"0");
            } else {
              // put the value
              m_residuals_tsv->set(tsv1_clvl,cidx,val1);
            }
          }
        }
        // Not string equal -- check for numeric diff
        else if ((tsv1.get(tsv1_clvl,cidx,d1)==affx::TSV_OK) &&
                 (tsv2.get(tsv2_clvl,cidx,d2)==affx::TSV_OK)) {
          double d_diff=d1-d2;
          // output the result...
          if (m_residuals_tsv!=NULL) {
            m_residuals_tsv->set(tsv1_clvl,cidx,d_diff);
          }
          // if small, it isnt a diff
          if (!((m_opt_max_diff>0.0) && (fabs(d_diff)<=m_opt_max_diff))) {
            // too big -- mark it down as a diff.
            m_diff_cnt++;
            line_diff_cnt++;
            //
          }
        }
        // normal text diff
        else {
          if (m_residuals_tsv!=NULL) {
            m_residuals_tsv->set(tsv1_clvl,cidx,"'"+val1+"'/'"+val2+"'");
          }
        }
      }
      
      // output the result line
      if (m_residuals_tsv!=NULL) {
        m_residuals_tsv->writeLevel(tsv1_clvl);
      }

      // print unchanged lines?
      if ((m_opt_print_same || (line_diff_cnt!=0)) &&
          (p_inc())) {
        //
        if (line_diff_cnt==0) {
          p_linenums(tsv1,tsv2);
          printf(" ");
          p_line(tsv1);
        }
        else if (m_opt_print_format==TsvFileDiff::FMT_1) {
          p_diff_1line(tsv1,tsv2);
        } 
        else if (m_opt_print_format==TsvFileDiff::FMT_2) {
          p_diff_2line(tsv1,tsv2);
        }
        else {
          Err::errAbort("Bad format");
        }
      }
    }
    
    //
    tsv1.nextLine();
    tsv2.nextLine();
  }
  
  close_residuals();
  
  return m_diff_cnt-start_diff_cnt;
}