AppDisplay::AppDisplay() : QWidget() {
  this->successful = false;
  this->resize(WIDTH, HEIGHT);
  this->setWindowTitle("Illini Motorsports CAN Translator - 2015-2016");
  this->setLayout(&layout);

  connect(&data, SIGNAL(error(QString)), this, SLOT(handleError(QString)));
  connect(&data, SIGNAL(progress(int)), this, SLOT(updateProgress(int)));
  connect(&config, SIGNAL(error(QString)), this, SLOT(handleError(QString)));

  computeThread.data = &data;
  coalesceComputeThread.data = &data;

  layout.addLayout(&layout_headers);

  QFont font_header("Helvetica", 20, QFont::Bold);
  QFont font_subheader("Helvetica", 15);
  QFont font_message("Helvetica", 15, QFont::Black);
  QFont font_signal("Helvetica", 9);

  lbl_header.setText("Illini Motorsports CAN Translator - 2015-2016");
  lbl_header.setFont(font_header);
  lbl_header.setStyleSheet("QLabel { color: black; }");
  lbl_header.setAlignment(Qt::AlignCenter);
  layout_headers.addWidget(&lbl_header, 1);

  lbl_subheader.setText("Created By: Andrew Mass");
  lbl_subheader.setFont(font_subheader);
  lbl_subheader.setAlignment(Qt::AlignCenter);
  layout_headers.addWidget(&lbl_subheader, 1);

  lbl_keymaps.setText("[c] Convert Custom File     [v] Convert Vector File     [s] Coalesce Converted Logfiles     [q] Quit");
  lbl_keymaps.setFont(font_subheader);
  lbl_keymaps.setAlignment(Qt::AlignCenter);
  layout_headers.addWidget(&lbl_keymaps, 1);

  btn_read_custom.setText("Select Custom File to Convert");
  layout_reads.addWidget(&btn_read_custom, 1);

  btn_read_vector.setText("Select Vector File to Convert");
  layout_reads.addWidget(&btn_read_vector, 1);

  btn_coalesce.setText("Coalesce Converted Logfiles");
  layout_reads.addWidget(&btn_coalesce, 1);

  layout.addLayout(&layout_reads);

  // Configure config area (left side)
  area_config_helper.setLayout(&layout_config);
  area_config.setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
  area_config.setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
  area_config.setWidgetResizable(true);
  area_config.setWidget(&area_config_helper);

  // Configure progress area (right side)
  layout_progress.addWidget(&bar_convert, 1);

  // Add config and progress areas to main layout
  layout_main.addWidget(&area_config);
  layout_main.addLayout(&layout_progress);
  layout.addLayout(&layout_main);

  // Parse CAN spec from config file
  map<uint16_t, Message> messages = config.getMessages();
  if (messages.size() > 0) {
    this->successful = true;
  }

  // Add message defintions to config area
  typedef map<uint16_t, Message>::iterator it_msg;
  for(it_msg msgIt = messages.begin(); msgIt != messages.end(); msgIt++) {
    Message msg = msgIt->second;

    QGroupBox* messageGroup = new QGroupBox(msg.toString());
    QVBoxLayout* signalsLayout = new QVBoxLayout();
    messageGroup->setLayout(signalsLayout);

    for (Signal sig: msg.sigs) {
      signalsLayout->addWidget(new QLabel(sig.toString()));
    }

    layout_config.addWidget(messageGroup);
  }

  connect(&computeThread, SIGNAL(finish(bool)), this, SLOT(convertFinish(bool)));
  connect(&computeThread, SIGNAL(addFileProgress(QString)), this, SLOT(addFileProgress(QString)));
  connect(&coalesceComputeThread, SIGNAL(finish(bool)), this, SLOT(coalesceFinish(bool)));

  connect(&btn_read_custom, SIGNAL(clicked()), this, SLOT(readDataCustom()));
  connect(&btn_read_vector, SIGNAL(clicked()), this, SLOT(readDataVector()));
  connect(&btn_coalesce, SIGNAL(clicked()), this, SLOT(coalesceLogfiles()));
}
void resultCombiner(const char * name_dv1, const char * name_cm1, const int length1, const char * name_dv2, const char * name_cm2, const int length2, int ftr = 1, const char * outputNameStub = "output")
{
    TVectorD dv1(length1), dv2(length2);
    TMatrixT<double> cm1(length1, length1), cm2(length2, length2);
    double binLimits1[length1][2], binLimits2[length2][2], ccCov1[length1], ccCov2[length1];

    readDataVector(name_dv1, dv1, binLimits1, ftr, ccCov1);
    printf("Read data vector 1 (%d)\n",length1);

    readDataVector(name_dv2, dv2, binLimits2, ftr, ccCov2);
    printf("Read data vector 2 (%d)\n",length2);

    readCovMatrix(name_cm1, cm1);
    printf("Read covariance matrix 1\n");

    readCovMatrix(name_cm2, cm2);
    printf("Read covariance matrix 2\n");

    std::vector<double*> binLimits;
    std::vector<std::vector<int > > preU;
    int i1 = 0, i2 = 0;
    while(i1 < length1 || i2 < length2)
    {
        if(i1 < length1 && i2 < length2)
        {
            if((binLimits1[i1][1] + binLimits1[i1][0])/2 > binLimits2[i2][0] && (binLimits1[i1][1] + binLimits1[i1][0])/2 < binLimits2[i2][1])
            {
                binLimits.push_back(binLimits1[i1]);
                std::vector<int> tmp;
                tmp.push_back(i1);
                tmp.push_back(i2);
                preU.push_back(tmp);
                i1++;
                i2++;
            }
            else if((binLimits1[i1][1] + binLimits1[i1][0])/2 <= binLimits2[i2][0])
            {
                binLimits.push_back(binLimits1[i1]);
                std::vector<int> tmp;
                tmp.push_back(i1);
                tmp.push_back(-1);
                preU.push_back(tmp);
                i1++;
            }
            else
            {
                binLimits.push_back(binLimits2[i2]);
                std::vector<int> tmp;
                tmp.push_back(-1);
                tmp.push_back(i2);
                preU.push_back(tmp);
                i2++;
            }
        }
        else if(i1 < length1 && i2 >= length2)
        {
            binLimits.push_back(binLimits1[i1]);
            std::vector<int> tmp;
            tmp.push_back(i1);
            tmp.push_back(-1);
            preU.push_back(tmp);
            i1++;
        }
        else
        {
            binLimits.push_back(binLimits2[i2]);
            std::vector<int> tmp;
            tmp.push_back(-1);
            tmp.push_back(i2);
            preU.push_back(tmp);
            i2++;
        }
    }

    TVectorD dv(length1 + length2);
    for(int i = 0; i < length1 + length2; i++)
    {
        dv[i] = (i < length1) ? dv1[i] : dv2[i - length1];
    }

    TMatrixT<double> cm(length1 + length2, length1 + length2), U(length1 + length2, preU.size());
    for(int i = 0; i < length1; i++)
    {
        for(int j = 0; j < length1; j++)
        {
            cm[i][j] = cm1[i][j];
        }
    }
    for(int i = length1; i < length1 + length2; i++)
    {
        for(int j = length1; j < length1 + length2; j++)
        {
            cm[i][j] = cm2[i - length1][j - length1];
        }
    }

    for(unsigned int i = 0; i < preU.size(); i++)
    {
        if(preU[i][0] >= 0) U[preU[i][0]][i] = 1;
        if(preU[i][1] >= 0) U[preU[i][1] + length1][i] = 1;
        if(ftr > 1 && preU[i][0] >= 0 && preU[i][1] >= 0)  cm[preU[i][0]][preU[i][1] + length1] = cm[preU[i][1] + length1][preU[i][0]] = ccCov1[preU[i][0]]*ccCov2[preU[i][1]];
    }
    
    //    cm.Print();

    TMatrixT<double> Ut(U);
    Ut.T();

    TMatrixT<double> cmInv(cm);
    cmInv.Invert();
    TMatrixT<double> step1 = Ut * cmInv * U;
    TMatrixT<double> step2 = Ut * cmInv;
    TMatrixT<double> lambda = step1.Invert() * step2;
    TVectorD bV = lambda*dv;
    TMatrixT<double> bcm = (Ut * cmInv * U).Invert();

    printf("Done with combination.\n");

    //write output
    FILE *file;
    char bVoutName[128], CMoutName[128];
    sprintf(bVoutName, "%s_data.txt", outputNameStub);

    file = fopen(bVoutName, "w");
    if(file)
    {
        fprintf(file, "#\n#%9s %9s %9s %15s %15s\n", "Bin", "Y_min", "Y_max", "Value", "Uncertainty");
        for(int i = 0; i < bV.GetNoElements(); i++)
        {
            fprintf(file, " %9i %9.2f %9.2f %15e %15e\n", i + 1, binLimits[i][0], binLimits[i][1], bV[i], sqrt(bcm[i][i]));
        }
        fclose(file);
    }

    sprintf(CMoutName, "%s_covMat.txt", outputNameStub);

    file = fopen(CMoutName, "w");
    if(file)
    {
        fprintf(file, "#\n#%9s %9s %15s\n", "Bin i", "Bin j", "Value");
        for(int i = 0; i < bcm.GetNrows(); i++)
        {
            for(int j = 0; j < bcm.GetNcols(); j++)
            {
                fprintf(file, " %9i %9i %15e\n", i + 1, j + 1, bcm[i][j]);
            }
        }
        fclose(file);
    }
    printf("Output complete.\n");
}