/****************************************************************************
**
** Copyright (C) 2020 Minnesota Department of Transportation
** Office of Materials & Road Research
** 1400 Gervais Avenue
** Saint Paul, Minnesota 55109-2044
** USA
** http://www.dot.state.mn.us/app/pavecool
**
**
** $QT_BEGIN_LICENSE:GPL$
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
** GNU General Public License for more details.
**
** If you did not receive a copy of the GNU General Public License
** see http://www.gnu.org/licenses
**
** $QT_END_LICENSE$
**
****************************************************************************/

#include "pavecool.h"
#include "ui_pavecool.h"
#include "globals.h"
#include "helpdlg.h"
#include "tdlg.h"
#include "about.h"

PaveCool::PaveCool(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::PaveCool)
{
    ui->setupUi(this);

    calendar = ui->dateEdit->calendarWidget();
    calendar->setLocale(QLocale::system());

    // translatables
    tDisclaimer = tr("Some asphalt mixtures will require compaction times and temperatures different from those recommended by this program. Good judgement must be exercised in order to ensure a properly compacted surface. Special considerations should be made for polymer modified asphalt binders and warm-mix asphalt (WMA). In these cases, manufacturer guidelines should supersede recommendations made by this program. Consult the Help file for further details. In no event will the Minnesota Department of Transportation, the University of Minnesota or their suppliers be liable for damages or expenses arising out of the use of this program.");

    int i;

    // Initialize lists
    bList.reserve(5);         // number of items in the list
    bList.append(false);      // 0 default start & stop temperatures, true = user-defined
    bList.append(false);      // 1 Display English units, true = SI
    bList.append(false);      // 2 12 hour time format, true = 24 hour
    bList.append(false);      // 3 Calculate after opening file
    bList.append(false);      // 4 US date format, true = ISO
    iList.reserve(7);
    iList.append(1);          // 0 cloud cover
    iList.append(0);          // 1 fine/dense or SMA
    iList.append(0);          // 2 high PG temperature
    iList.append(0);          // 3 low PG temperature
    iList.append(0);          // 4 existing surface type
    iList.append(0);          // 5 wet or dry
    iList.append(0);          // 6 frozen or not
    dList.reserve(8);
    dList.append(0.0);        // 0 lift thickness (mm)
    dList.append(0.0);        // 1 latitude (°)
    dList.append(0.0);        // 2 air temperature (°C)
    dList.append(0.0);        // 3 mix delivery temperature
    dList.append(0.0);        // 4 existing surface temperature
    dList.append(0.0);        // 5 user start temperature
    dList.append(0.0);        // 6 user stop temperature
    dList.append(0.0);        // 7 wind velocity (km/h)
    sList.reserve(1);
    sList.append("");        // 0 project title
    vList.reserve(2);
    vList.append(QDate());    // 0 start date
    vList.append(QTime());    // 1 start time

    pAction[0] = ui->action1;
    pAction[1] = ui->action2;
    pAction[2] = ui->action3;
    pAction[3] = ui->action4;
    pAction[4] = ui->action5;
    pAction[5] = ui->action6;

    for(i = 0; i < MaxRecentFiles; ++i)
    {
        pAction[i]->setVisible(false);
    }

    // Initialize other variables
    bdefault = false;
    bopen = false;
    bspin = false;
    noreset = false;
    bunit = false;
    bcalc = false;
    bimport = true;
    bList[0] = false;    // default start & stop temperatures
// The following are set in windows registry
//    bList[1] = bsi = false;     // Display English units
//    bList[2] = false;           // 12 hour time format
//    bList[4] = false;           // US date format
    dList[5] = TSTART58;          // Start compacting
    dList[6] = TSTOP_DEF;         // Stop compacting

    sizemult = 1.;
    nVersion = QApplication::applicationVersion().toInt();
    tFile = "";

    // initialize variables for temporary user data
    for(i = 0; i < 8; ++i) bedit[i] = false;
    for(i = 0; i < 4; ++i) val[i] = 0.0;
    for(i = 0; i < 5; ++i) tval[i] = "";

    SetDefaults();
    pcSettings("", READBOOL);
    bmodified = false;
}

PaveCool::~PaveCool()
{
    delete ui;
}

void PaveCool::resizeEvent(QResizeEvent *e)
{
    int i = e->size().height();
    int j = e->size().width();
    double ht = double(i) / double(PaveCool::minimumHeight());
    double w = double(j) / double(PaveCool::minimumWidth());
    if(w < ht) sizemult = w;
    else sizemult = ht;
    ht *= 8;
    w *= 8;
    if(w < 8) w = 8;
    if(w < ht) i = nint(w);
    else i = nint(ht);
    QFont newFont = ui->projectLabel->font();
    if(i != newFont.pointSize())
    {
        newFont.setPointSize(i);
        QApplication::setFont(newFont);
    }
    QMainWindow::resizeEvent(e);
}

void PaveCool::closeEvent(QCloseEvent *event)
{
    if(bmodified)
    {
        if(askSave())
        {
            pcSettings("", SETBOOL);
            event->accept();
        }
        else event->ignore();
    }
    else
    {
        pcSettings("", SETBOOL);
        event->accept();
    }
}

void PaveCool::pcSettings(const QString &fileName, const int &nmode)
{
    int i;
    QSettings settings;
    QStringList files = settings.value(RECENT_FILES_KEY).toStringList();

    switch (nmode)
    {
        case READREG:
        {
            tPath = settings.value(DEFAULT_DIR_KEY).toString();
        }
        break;
        case SETREG:
        {
            settings.setValue(DEFAULT_DIR_KEY, QFileInfo(fileName).absolutePath());
            files.removeAll(fileName);
            files.prepend(fileName);
            while (files.size() > MaxRecentFiles)
                files.removeLast();
            settings.setValue(RECENT_FILES_KEY, files);
        }
        break;
        case NOFILE:
        {
            files.removeAll(fileName);
            settings.setValue(RECENT_FILES_KEY, files);
        }
        break;
        case SETBOOL:
        {
            settings.setValue(UNITS_SI_KEY, bList[1] ? "1" : "0");
            settings.setValue(TIME_24H_KEY, bList[2] ? "1" : "0");
            settings.setValue(DATE_ISO_KEY, bList[4] ? "1" : "0");
        }
        break;
        case READBOOL:
        {
            bList[1] = bsi = settings.value(UNITS_SI_KEY).toInt();
            bList[2] = settings.value(TIME_24H_KEY).toInt();
            bList[4] = settings.value(DATE_ISO_KEY).toInt();
            updateView();
        }
        break;
    }
    // populate recent files in ui
    int nRecentFiles = qMin(files.size(), int(MaxRecentFiles));

    for(i = 0; i < nRecentFiles; ++i)
    {
        QString text = tr("&%1 %2").arg(i + 1).arg(QFileInfo(files[i]).fileName());
        pAction[i]->setText(text);
        pAction[i]->setData(files[i]);
        pAction[i]->setVisible(true);
    }
    for (i = nRecentFiles; i < MaxRecentFiles; ++i)
        pAction[i]->setVisible(false);
}

void PaveCool::on_actionNew_triggered()
{
// Create a new window
    pcSettings("", SETBOOL); // make same settings as open document
    PaveCool *other = new PaveCool;
    other->resize(this->size());
    other->move(this->pos() + QPoint(40,40));
    other->show();
}

void PaveCool::on_actionOpen_triggered()
{
    pcSettings("", READREG);
// File opens in a new window unless the old window is unmodified
    if(!tName.isEmpty())
    {
        PaveCool *other = new PaveCool;
        other->pcSettings("", READREG);
        if(other->Open())
        {
            other->resize(this->size());
            other->move(this->pos() + QPoint(40,40));
            other->show();
        }
        else other->destroy();
    }
    else Open();
}

void PaveCool::on_actionSave_triggered()
{
    if(Save(tFile))
        PaveCool::setWindowTitle(newWinTitle(tName));
}

void PaveCool::on_actionSave_As_triggered()
{
    if(SaveAs(tFile))
        PaveCool::setWindowTitle(newWinTitle(tName));
}

void PaveCool::on_actionSave_PDF_triggered()
{   // font: 72 pts/in; pdf: 1200 pixels/in
    pcSettings("", READREG);
    on_calcButton_clicked();
    QString ttmp = tName;
    QString newName = ttmp.replace(".pc3", ".pdf");
    if(newName.isEmpty()) newName = sList[0].isEmpty() ? QApplication::applicationName() + "1" : sList[0];
    newName = QFileDialog::getSaveFileName(this, tr("Save") + " PDF " + tr("Report"),
                           tPath + "/" + newName, "PDF " + tr("Files") + " (*.pdf)");
    if(!newName.isEmpty())
    {
        QPdfWriter ppdf(newName);
        ppdf.setPageSize(QPagedPaintDevice::Letter);
        ppdf.setPageMargins(QMarginsF(72,54,54,54)); // L 1", R,T,B 0.75"
        ppdf.setTitle(newWinTitle("") + " " + tr("Report"));
        ppdf.newPage();

        QPainter painter(&ppdf);

        QFont arial10("Arial");
        arial10.setPointSize(10);
        QFont arial12("Arial");
        arial12.setPointSize(14);
        QFont arial12b("Arial");
        arial12b.setPointSize(14);
        arial12b.setWeight(QFont::Bold);
        QFont arial14("Arial");
        arial14.setPointSize(14);
        arial14.setWeight(QFont::Bold);
        QFont arial18("Arial");
        arial18.setPointSize(18);
        arial18.setWeight(QFont::Bold);

        QTextOption tleft, tcenter, tright, tfile;
        tleft.setAlignment(Qt::AlignLeft);
        tcenter.setAlignment(Qt::AlignCenter);
        tright.setAlignment(Qt::AlignRight);
        tfile.setAlignment(Qt::AlignLeft);
        tfile.setAlignment(Qt::AlignBottom);
        tfile.setWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere);

        QPen pen;
        pen.setBrush(Qt::black);
        pen.setWidth(8);
        painter.setPen(pen);
        QRectF txrect;
        double top, bot, wid, ht;
        top = 0;
        wid = 8100; // 6.75"

        ht = 450;
        painter.setFont(arial18);
        top = pdfRect(&txrect,wid,top,ht,1,0);
        painter.drawText(txrect,ppdf.title(),tcenter);

        ht = 525;
        ttmp = "";
        if(sList[0] != "") ttmp = tr("Project") + ": " + sList[0];
        painter.setFont(arial12);
        top = pdfRect(&txrect,wid,top,ht,1,0);
        painter.drawText(txrect,ttmp,tleft);

        ht = 400;
        painter.setFont(arial14);
        bot = pdfRect(&txrect,wid,top,ht,3,0);
        painter.drawRect(txrect);
        painter.drawText(txrect,tr("Date") + " & " + tr("Time"),tcenter);
        bot = pdfRect(&txrect,wid,top,ht,3,1);
        painter.drawRect(txrect);
        painter.drawText(txrect,tr("Start Rolling") + "*",tcenter);
        top = pdfRect(&txrect,wid,top,ht,3,2);
        painter.drawRect(txrect);
        painter.drawText(txrect,tr("Stop Rolling") + "*",tcenter);

        bot = pdfRect(&txrect,wid,top,ht,3,0);
        painter.drawRect(txrect);
        painter.drawText(txrect,ui->dateEdit->text()
                + "    " + ui->timeEdit->text(),tcenter);
        bot = pdfRect(&txrect,wid,top,ht,3,1);
        painter.drawRect(txrect);
        painter.drawText(txrect,ui->startEdit->text() + " " + tr("minutes") + " ("
                + txtdbl(convt(true,tstart,bsi),DEC_T)
                + " " + txtt(bsi) + ")",tcenter);
        top = pdfRect(&txrect,wid,top,ht,3,2);
        painter.drawRect(txrect);
        painter.drawText(txrect,ui->stopEdit->text() + " " + tr("minutes") + " ("
                + txtdbl(convt(true,tstop,bsi),DEC_T)
                + " " + txtt(bsi) + ")",tcenter);

        top += 100;
        ht = 400;
        painter.setFont(arial12b);
        bot = pdfRect(&txrect,wid,top,ht,4,0);
        painter.drawRect(txrect);
        painter.drawText(txrect,tr("Mix Type"),tcenter);
        bot = pdfRect(&txrect,wid,top,ht,4,1);
        painter.drawRect(txrect);
        painter.drawText(txrect,tr("Binder Grade"),tcenter);
        bot = pdfRect(&txrect,wid,top,ht,4,2);
        painter.drawRect(txrect);
        painter.drawText(txrect,tr("Thickness"),tcenter);
        top = pdfRect(&txrect,wid,top,ht,4,3);
        painter.drawRect(txrect);
        painter.drawText(txrect,tr("Delivery Temp."),tcenter);

        ht = 600;
        painter.setFont(arial12);
        bot = pdfRect(&txrect,wid,top,ht,4,0);
        painter.drawRect(txrect);
        painter.drawText(txrect,ui->gradCombo->currentText(),tcenter);
        bot = pdfRect(&txrect,wid,top,ht,4,1);
        painter.drawRect(txrect);
        painter.drawText(txrect,"PG " + ui->hiCombo->currentText()
                + ui->loCombo->currentText(),tcenter);
        bot = pdfRect(&txrect,wid,top,ht,4,2);
        painter.drawRect(txrect);
        painter.drawText(txrect,ui->hDSpin->text() + " " + txtl(bsi),tcenter);
        top = pdfRect(&txrect,wid,top,ht,4,3);
        painter.drawRect(txrect);
        painter.drawText(txrect,ui->tmSpin->text() + " " + txtt(bsi),tcenter);

        top += 100;
        ht = 400;
        painter.setFont(arial12b);
        bot = pdfRect(&txrect,wid,top,ht,4,0);
        painter.drawRect(txrect);
        painter.drawText(txrect,tr("Air Temp."),tcenter);
        bot = pdfRect(&txrect,wid,top,ht,4,1);
        painter.drawRect(txrect);
        painter.drawText(txrect,tr("Wind Speed"),tcenter);
        bot = pdfRect(&txrect,wid,top,ht,4,2);
        painter.drawRect(txrect);
        painter.drawText(txrect,tr("Sky"),tcenter);
        top = pdfRect(&txrect,wid,top,ht,4,3);
        painter.drawRect(txrect);
        painter.drawText(txrect,tr("Latitude"),tcenter);

        painter.setFont(arial12);
        bot = pdfRect(&txrect,wid,top,ht,4,0);
        painter.drawRect(txrect);
        painter.drawText(txrect,ui->taEdit->text() + " " + txtt(bsi),tcenter);
        bot = pdfRect(&txrect,wid,top,ht,4,1);
        painter.drawRect(txrect);
        painter.drawText(txrect,ui->swEdit->text() + " " + txtv(bsi),tcenter);
        bot = pdfRect(&txrect,wid,top,ht,4,2);
        painter.drawRect(txrect);
        painter.drawText(txrect,ui->skyCombo->currentText(),tcenter);
        top = pdfRect(&txrect,wid,top,ht,4,3);
        painter.drawRect(txrect);
        QString tdir = " °";
        if(dList[1] > 0) tdir = " ° " + tr("North");
        else if(dList[1] < 0) tdir = " ° " + tr("South");
        painter.drawText(txrect,QString::number(qFabs(dList[1])) + tdir,tcenter);

        top += 100;
        painter.setFont(arial12b);
        bot = pdfRect(&txrect,wid,top,ht,4,0);
        painter.drawRect(txrect);
        painter.drawText(txrect,tr("Existing Surface"),tcenter);
        bot = pdfRect(&txrect,wid,top,ht,4,1);
        painter.drawRect(txrect);
        painter.drawText(txrect,tr("Moisture"),tcenter);
        bot = pdfRect(&txrect,wid,top,ht,4,2);
        painter.drawRect(txrect);
        painter.drawText(txrect,tr("State"),tcenter);
        top = pdfRect(&txrect,wid,top,ht,4,3);
        painter.drawRect(txrect);
        painter.drawText(txrect,tr("Surface Temp."),tcenter);

        painter.setFont(arial12);
        bot = pdfRect(&txrect,wid,top,ht,4,0);
        painter.drawRect(txrect);
        painter.drawText(txrect,ui->matCombo->currentText(),tcenter);
        bot = pdfRect(&txrect,wid,top,ht,4,1);
        painter.drawRect(txrect);
        painter.drawText(txrect,ui->wCombo->currentText(),tcenter);
        bot = pdfRect(&txrect,wid,top,ht,4,2);
        painter.drawRect(txrect);
        painter.drawText(txrect,ui->stateCombo->currentText(),tcenter);
        top = pdfRect(&txrect,wid,top,ht,4,3);
        painter.drawRect(txrect);
        painter.drawText(txrect,ui->tsEdit->text() + " " + txtt(bsi),tcenter);

        top += 20;
        drawGraph(&painter, 200, int(top), 5400, 5200, true);

        painter.setFont(arial10);
        ttmp = "";
        if(tName != "") ttmp = tr("%1 File:").arg(APP) + "\n" + tName;
        ht = 1400;
        top += 3600;
        top = pdfRect(&txrect,wid,top,ht,4,3);
        painter.drawText(txrect,ttmp,tfile);

        top += 210;
        top = pdfRect(&txrect,wid,top,1400,1,0);
        painter.drawText(txrect,"*" + tDisclaimer,tleft);

        ht = 200;
        top += 100;
        top = pdfRect(&txrect,wid,top,ht,2,1);
        painter.drawText(txrect,tr("Report Created") + " " + QDateTime::currentDateTime().toString("yyyy-MM-dd  hh:mm:ss"),tright);

        painter.end();

        //Open file with default PDF application
        QDesktopServices::openUrl((QUrl("file:/" + newName)));
    }
}

void PaveCool::on_action1_triggered()
{
    openRecent();
}

void PaveCool::on_action2_triggered()
{
    openRecent();
}

void PaveCool::on_action3_triggered()
{
    openRecent();
}

void PaveCool::on_action4_triggered()
{
    openRecent();
}

void PaveCool::on_action5_triggered()
{
    openRecent();
}

void PaveCool::on_action6_triggered()
{
    openRecent();
}

void PaveCool::on_actionExit_triggered()
{
    if(bmodified)
    {
        if(askSave()) qApp->exit();
    }
    else qApp->exit();
}

void PaveCool::on_actionStart_Stop_Temperatures_triggered()
{
    bool btmp = bList[0];
    tdlg dlg;
    dlg.setWindowTitle(tr("Start") + " & " + tr("Stop") + " " + tr("Temperatures"));
    int w = nint(dlg.minimumWidth()*sizemult);
    int h = nint(dlg.minimumHeight()*sizemult);
    dlg.resize(w,h);
    QFont dlgfont = PaveCool::font();
    dlg.setFont(dlgfont);
    double Ttmp = iList[2] > PG_CUTOFF ? TSTART52 : TSTART58;
    dlg.buser = bList[0];
    dlg.Tdef[0] = nint(rnd2dec(convt(true, Ttmp, bsi), 0));
    dlg.Tdef[1] = nint(rnd2dec(convt(true, TSTOP_DEF, bsi), 0));
    dlg.Tusr[0] = nint(rnd2dec(convt(true, dList[5], bsi), 0));
    dlg.Tusr[1] = nint(rnd2dec(convt(true, dList[6], bsi), 0));
    dlg.Tmin[0] = nint(rnd2dec(convt(true, TM_MIN, bsi), 0));
    dlg.Tmin[1] = nint(rnd2dec(convt(true, TSTOP_MIN, bsi), 0));
    dlg.Tmax[0] = nint(rnd2dec(convt(true, TM_MAX, bsi), 0));
    dlg.Tmax[1] = nint(rnd2dec(convt(true, TSTOP_MAX, bsi), 0));
    dlg.tunit = txtt(bsi);
    dlg.updateView();

    int nret = dlg.exec();
    if(nret == 1)
    {
        bList[0] = dlg.buser;
        double tmp1 = convt(bsi, double(dlg.Tusr[0]));
        double tmp2 = convt(bsi, double(dlg.Tusr[1]));
          if(qFabs(bList[0] - btmp) > EN12
          || qFabs(convt(bsi, dList[5]) - tmp1) > EN12
          || qFabs(convt(bsi, dList[6]) - tmp2) > EN12)
        {
            dList[5] = tmp1;
            dList[6] = tmp2;
            //pcSettings("", SETBOOL);
            bmodified = true;
            resetOutput();
        }
    }
    updateView();
}

void PaveCool::on_actionEnglish_triggered()
{
    bList[1] = bsi = false;
    noreset = true;
    bunit = true;
    updateView();
}

void PaveCool::on_actionSI_triggered()
{
    bList[1] = bsi = true;
    noreset = true;
    bunit = true;
    updateView();
}

void PaveCool::on_action12_Hour_triggered()
{
    bList[2] = false;
    noreset = true;
    updateView();
}

void PaveCool::on_action24_Hour_triggered()
{
    bList[2] = true;
    noreset = true;
    updateView();
}

void PaveCool::on_actionUS_triggered()
{
    bList[4] = false;
    noreset = true;
    updateView();
}

void PaveCool::on_actionISO_triggered()
{
    bList[4] = true;
    noreset = true;
    updateView();
}


void PaveCool::on_actionReset_Defaults_triggered()
{
    if(bmodified)
    {
        if(askSave())
        {
            bList[0] = false;             // true = user-defined temperatures
            bList[1] = bsi = false;       // true = display SI units, false = English units
            bList[2] = false;             // true = 24 hour time format
            bList[4] = false;             // true = ISO date format
            SetDefaults(true);
            pcSettings("", SETBOOL);
        }
    }
    else
    {
        bList[0] = false;             // true = user-defined temperatures
        bList[1] = bsi = false;       // true = display SI units, false = English units
        bList[2] = false;             // true = 24 hour time format
        bList[4] = false;             // true = ISO date format
        SetDefaults(true);
        pcSettings("", SETBOOL);
        bmodified = true;
    }
    resetOutput();
}

void PaveCool::on_actionHelp_Topics_triggered()
{// create a modeless help window
    QString hloc = DEFHELP;
    hloc.replace("en", QLocale::system().name().left(2)); // use only the language code
    QFile hfile(DEFHELP);
    QFile hfile2(hloc);


    if(!hfile.exists() && !hfile2.exists()) QDesktopServices::openUrl(WEBHELP);
    else
    {
        QFont hfont = PaveCool::font();
        double hpt = hfont.pointSizeF() * 1.2;
        HelpDlg *hlp = new HelpDlg(this);
        hlp->setWindowTitle(APP + " " + tr("Help"));
        hlp->resize(PaveCool::size());
        hfont.setPointSize(int(hpt));
        hlp->setFont(hfont);
        hlp->tPath = tPath;
        hlp->show();
    }
}

void PaveCool::on_actionAbout_PaveCool_triggered()
{//659
    about dlg;
    dlg.setWindowTitle(tr("About") + " " + APP);
    int w = nint(dlg.minimumWidth()*sizemult);
    int h = nint(dlg.minimumHeight()*sizemult);
    dlg.resize(w,h);
    QFont dlgfont = PaveCool::font();
    dlg.setFont(dlgfont);
    dlg.exec();
}

void PaveCool::on_projectEdit_textEdited(const QString &arg1)
{
    sList[0] = arg1;
    bmodified = true;
}

void PaveCool::on_dateEdit_dateChanged(const QDate &date)
{
    vList[0] = date;
    bedit[7] = true;
}

void PaveCool::on_dateEdit_editingFinished()
{
    if(bedit[7])
    {
        resetOutput();
        bedit[7] = false;
    }
}

void PaveCool::on_timeEdit_textEdited(const QString &arg1)
{
    tval[0] = arg1;
    bedit[0] = true;
}

void PaveCool::on_timeEdit_editingFinished()
{
    if(bedit[0])
    {
        vList[1] = TimeText(&tval[0], bList[2]);
        ui->timeEdit->setText(tval[0]);
        bedit[0] = false;
        resetOutput();
    }
}

void PaveCool::on_timeButton_clicked()
{
    if(vList[0] != QDate::currentDate() ||
            vList[1] != QTime::currentTime())
    {
        vList[0] = QDate::currentDate();
        vList[1] = QTime::currentTime();
        resetOutput();
    }
    updateView();
}

void PaveCool::on_taEdit_textEdited(const QString &arg1)
{
    tval[1] = arg1;
    bedit[1] = true;
}

void PaveCool::on_taEdit_editingFinished()
{
    if(bedit[1])
    {
        bedit[1] = false;
        double dTa = rnd2dec(tval[1].toDouble(), DEC_T);
        if(qFabs(convt(bsi, dTa) - dList[2]) > EN12)
        {
            checkval(&dTa, TA_MIN, TA_MAX, TEMP);
            dList[2] = convt(bsi, dTa); // stored as °C
            ui->taEdit->setText(txtdbl(dTa, DEC_T));
            resetOutput();
        }
    }
}

void PaveCool::on_swEdit_textEdited(const QString &arg1)
{
    tval[2] = arg1;
    bedit[2] = true;
}

void PaveCool::on_swEdit_editingFinished()
{
    if(bedit[2])
    {
        bedit[2] = false;
        double dSw = rnd2dec(tval[2].toDouble(), DEC_V);
        if(qFabs(convlll(bsi, dSw) - dList[7]) > EN12)
        {
            checkval(&dSw, V_MIN, V_MAX, VEL);
            dList[7] = convlll(bsi, dSw); // stored as km/h
            ui->swEdit->setText(txtdbl(dSw, DEC_V));
            resetOutput();
        }
    }
}

void PaveCool::on_skyCombo_currentIndexChanged(int index)
{
    iList[0] = index;
    resetOutput();
}

void PaveCool::on_latEdit_textEdited(const QString &arg1)
{
    bedit[3] = true;
    tval[3] = arg1;
}

void PaveCool::on_latEdit_editingFinished()
{
    if(bedit[3])
    {
        bedit[3] = false;
        double dL = rnd2dec(tval[3].toDouble(), LAT_DEC);
        if(qFabs(dL - dList[1]) > EN12)
        {
            checkval(&dL, LAT_MIN, LAT_MAX, LAT);
            dList[1] = dL;
            ui->latEdit->setText(txtdbl(dL, LAT_DEC, false, true, false));
            resetOutput();
        }
    }
}

void PaveCool::on_gradCombo_currentIndexChanged(int index)
{
    iList[1] = index;
    resetOutput();
}

void PaveCool::on_hiCombo_currentIndexChanged(int index)
{
    iList[2] = index;
    if(!bopen && bList[0]) on_actionStart_Stop_Temperatures_triggered();
    resetOutput();
}

void PaveCool::on_loCombo_currentIndexChanged(int index)
{
    iList[3] = index;
    if(!bopen && bList[0]) on_actionStart_Stop_Temperatures_triggered();
    resetOutput();
}

void PaveCool::on_hDSpin_valueChanged(double arg1)
{
    val[0] = arg1;
    bedit[4] = true;
    if(bunit)
    {
        resetOutput();
        bunit = false;
    }
    if(setSpin(rnd2dec(convl(true, dList[0], bsi), decl(bsi)), &val[0], incl(bsi)))
    {// check to see if spinner was used and reset the value if necessary
        bspin = true;
        ui->hDSpin->clearFocus();
    }
}

void PaveCool::on_hDSpin_editingFinished()
{
    if(bedit[4])
    {
        bedit[4] = false;
        val[0] = rnd2dec(val[0], decl(bsi));
        if(qFabs(convl(bsi, val[0]) - dList[0]) > EN12)
        {
            checkval(&val[0], H_MIN, H_MAX, HT);
            dList[0] = convl(bsi, val[0]);
            ui->hDSpin->setValue(val[0]);
            if(bspin)
            {
                ui->hDSpin->setFocus();
                bspin = false;
            }
            resetOutput();
        }
    }
}

void PaveCool::on_tmSpin_valueChanged(int arg1)
{
    val[1] = double(arg1);
    bedit[5] = true;
    if(bunit)
    {
        resetOutput();
        bunit = false;
    }
}

void PaveCool::on_tmSpin_editingFinished()
{
    if(bedit[5])
    {
        bedit[5] = false;
        if(qFabs(convt(bsi, val[1]) - dList[3]) > EN12)
        {
            checkval(&val[1], TM_MIN, TM_MAX, TEMP);
            dList[3] = convt(bsi, val[1]); // stored as °C
            ui->tmSpin->setValue(nint(val[1]));
            resetOutput();
        }
    }
}

void PaveCool::on_matCombo_currentIndexChanged(int index)
{
    if(!bopen)
    {
        iList[4] = index;
        updateView();
        resetOutput();
    }
}

void PaveCool::on_wCombo_currentIndexChanged(int index)
{
    if(index >= 0)
    {
        iList[5] = index;
        resetOutput();
    }
}

void PaveCool::on_stateCombo_currentIndexChanged(int index)
{
    if(index >= 0)
    {
        iList[6] = index;
        resetOutput();
    }
}

void PaveCool::on_tsEdit_textEdited(const QString &arg1)
{
    tval[4] = arg1;
    bedit[6] = true;
}

void PaveCool::on_tsEdit_editingFinished()
{
    if(bedit[6])
    {
        bedit[6] = false;
        double dTs = rnd2dec(tval[4].toDouble(), DEC_T);
        if(qFabs(convt(bsi, dTs) - dList[4]) > EN12)
        {
            checkval(&dTs, TS_MIN, TS_MAX, TEMP);
            dList[4] = convt(bsi, dTs); // stored as °C
            ui->tsEdit->setText(txtdbl(dTs, DEC_T));
            resetOutput();
        }
    }
}

void PaveCool::on_calcButton_clicked()
{
    calculate();
    ui->startEdit->setText(txtdbl(timeStart, 0));
    ui->stopEdit->setText(tStop);
}

void PaveCool::on_discButton_clicked()
{
    QMessageBox msg;
    msg.setFont(PaveCool::font());
    msg.setWindowTitle(APP + " " + tr("Disclaimer"));
    msg.setText(tDisclaimer);
    msg.exec();
}

void PaveCool::on_exportButton_clicked()
{
    int i;
    pcSettings("", READREG);
    QString ttmp = tName;
    QString tfilter = "";
    QString newName = ttmp.replace(".pc3", "");
    if(newName.isEmpty()) newName = sList[0].isEmpty() ? QApplication::applicationName() + "1" : sList[0];
    newName = QFileDialog::getSaveFileName(this, tr("Export %1 Data").arg(APP), tPath + "/" + newName,
                                           "Excel (*.xls);;" + tr("Comma-Delimited Text") + " (*.csv);;"
                                           + tr("Tab-Delimited Text") + " (*.txt)", &tfilter);
    tfilter = tfilter.left(1); // E, C or T

    if(!newName.isEmpty())
    {
        QSaveFile txtFile(newName);
        if(!txtFile.open(QIODevice::WriteOnly))
        {
            QMessageBox msg;
            msg.setText(tr("Export file could not be opened."));
            msg.exec();
            return;
        }
        QTextStream out(&txtFile);

        QChar d = tfilter == "E" ? '\t' : ' ';	// delimiter for input summary
        QChar ds = tfilter == "C" ? ',' : '\t'; // delimiter for temperature data

        out << PaveCool::windowTitle() << " " << tr("Simulation Output") << "\n";
        out << sList[0] << "\n";
        out << tr("Report Created") << " " << QDateTime::currentDateTime().toString("yyyy-MM-dd  hh:mm:ss") << "\n\n";
        out << tr("Paving Start Time") << "\n";
        out << ui->dateEdit->text() << d << ui->timeEdit->text() << "\n\n";
        out << tr("Mix Properties") << "\n";
        out << tr("Mix") << ":" << d << ui->gradCombo->currentText() << "\n";
        out << tr("Binder") << ":" << d << "PG " << ui->hiCombo->currentText();
        out << ui->loCombo->currentText() << "\n";
        out << tr("Lift") << ":" << d << txtdbl(convl(true, dList[0], bsi), decl(bsi)) << d << txtl(bsi) << "\n";
        out << tr("Deliv.") << ":" << d << txtdbl(convt(true, dList[3], bsi),DEC_T) << d << txtt(bsi) << "\n\n";
        out << tr("Environmental Conditions") << "\n";
        out << tr("The following data represent average conditions during compaction.") << "\n";
        out << tr("Air") << ":" << d << ui->taEdit->text() << d << txtt(bsi) << "\n";
        out << tr("Wind") << ":" << d << ui->swEdit->text() << d << txtv(bsi) << "\n";
        out << tr("Sky") << ":" << d << ui->skyCombo->currentText() << "\n";
        ttmp = "°";
        if(dList[1] > 0) ttmp = "° " + tr("North");
        else if(dList[1] < 0) ttmp = "° " + tr("South");
        out << tr("Latitude") << ":" << d << QString::number(qFabs(dList[1])) << d << ttmp << "\n\n";
        out << tr("Existing Surface") << "\n";
        out << tr("Material") << ":" << d << ui->matCombo->currentText();
        ttmp = iList[4] > 1 ? " " + ui->wCombo->currentText() : "";
        out << ttmp;
        ttmp = iList[4] > 1 ? " " + ui->stateCombo->currentText() : "";
        out << ttmp << "\n";
        out << tr("Temp.") << ":" << d << ui->tsEdit->text() << d << txtt(bsi) << "\n\n";
        out << tr("Compaction Recommendations") << "\n";
        out << tr("Start") << ":" << d << ui->startEdit->text() << d << tr("min.") << d;
        out << txtdbl(convt(true, tstart, bsi), DEC_T) << d << txtt(bsi) << "\n";
        out << tr("Stop") << ":" << d << ui->stopEdit->text() << d << tr("min.") << d;
        out << txtdbl(convt(true, tstop, bsi), DEC_T) << d << txtt(bsi) << "\n\n";
        if(tfilter == "T") out << tDisclaimer << "\n\n";
        else
        {// parse disclaimer for spreadsheet view

            QString tdisc = tDisclaimer;
            int indx = -1;
            while(tdisc.length() > 0)
            {
                indx = tdisc.indexOf(' ', 68); // max line width = 68
                if(indx > 0)
                {
                    ttmp = tdisc.left(indx);
                    tdisc.remove(0, ttmp.length()+1);
                }
                else
                {
                    ttmp = tdisc;
                    tdisc = "";
                }
                out << ttmp << "\n";
            }
        }
        out << "\n" << tr("Cooling Curve") << "\n";
        out << tr("Time") << ds << tr("Temp.") << "\n";
        out << tr("min.") << ds << txtt(bsi) << "\n";
        //Print data for t=0
        out << "0" << ds << txtdbl(convt(true, THMA[0], bsi), 1) << "\n";
        //now do rest of data file
        for(i = 1; i < THMA.size(); i++) //was i = 0
        {
            if(fmod(i,3)==0)
            {
                out << QString::number(i/3) << ds;
                out << txtdbl(convt(true, THMA[i], bsi), 1) << "\n";
            }
        }
        bool bcom = txtFile.commit();
        if(!bcom)
        {
            QMessageBox msg;
            msg.setText("Export failed.");
            msg.exec();
        }
        else QDesktopServices::openUrl((QUrl("file:/" + newName)));
    }
}

void PaveCool::openRecent()
{
    QAction *action = qobject_cast<QAction *>(sender());
    if(action)
    {
        if(!tName.isEmpty())
        {
            PaveCool *other = new PaveCool;
            if(other->Read(action->data().toString()))
            {
                other->resize(this->size());
                other->move(this->pos() + QPoint(40,40));
                other->show();
            }
            else
            {
                other->destroy();
                pcSettings(action->data().toString(), NOFILE);
            }
        }
        else
            if(!Read(action->data().toString()))
                pcSettings(action->data().toString(), NOFILE);
    }
}

void PaveCool::checkval(double *CheckValue, double Min, double Max, const int &ntype)
{
    bool btrim = false;
    int dec = 0;
    QString twarn = "";
    QString tunit = "";
    QString tmsg = "";

    switch (ntype)
    {
        case TEMP:
        {
            dec = DEC_T;
            twarn = tr("Temperature");
            tunit = txtt(bsi);
            Min = rnd2dec(convt(true, Min, bsi), DEC_T);
            Max = rnd2dec(convt(true, Max, bsi), DEC_T);
        }
        break;
        case HT:
        {
            dec = decl(bsi);
            twarn = tr("Lift Thickness");
            tunit = txtl(bsi);
            Min = rnd2dec(convl(true, Min, bsi), decl(bsi));
            Max = rnd2dec(convl(true, Max, bsi), decl(bsi));
        }
        break;
        case VEL:
        {
            twarn = tr("Wind speed");
            dec = DEC_V;
            tunit = txtv(bsi);
            Min = rnd2dec(convlll(true, Min, bsi), DEC_V);
            Max = rnd2dec(convlll(true, Max, bsi), DEC_V);
        }
        break;
        case LAT:
        {
            btrim = true;
            twarn = tr("Latitude");
            dec = DEC_LAT;
            tunit = "°N";
        }
        break;
    }
    if(*CheckValue < Min)
    {
        tmsg = tr("%1 must be at least %2 %3")
                .arg(twarn).arg(txtdbl(Min, dec, false, btrim, false)).arg(tunit);
        *CheckValue = Min;
    }
    else if(*CheckValue > Max)
    {
        tmsg = tr("%1 must not exceed %2 %3")
                .arg(twarn).arg(txtdbl(Max, dec, false, btrim, false)).arg(tunit);
        *CheckValue = Max;
    }
    if(tmsg != "")
    {
        QMessageBox msgBox;
        msgBox.setText(tmsg);
        msgBox.exec();
    }
}

void PaveCool::SetDefaults(bool bkeepname)
{
    // Reset all values
    if(!bkeepname)
    {
        tName = "";
        tFile = "";
    }
// Serialized variables
    bList[0] = false;             // true = user-defined temperatures
    iList[0] = SKY_DEF;           // combo indexes
    iList[1] = GRAD_DEF;          // fine/dense or SMA
    iList[2] = PGHI_DEF;          // High PG temperature
    iList[3] = PGLO_DEF;          // Low PG temperature
    iList[4] = MAT_DEF;           // existing surface
    iList[5] = W_DEF;             // wet or dry
    iList[6] = STATE_DEF;         // frozen or not
    dList[0] = H_DEF;             // lift thickness
    dList[1] = LAT_DEF;           // Latitude
    dList[2] = TA_DEF;            // air temperature in °C
    dList[3] = TM_DEF;            // mix delivery temperature
    dList[4] = TS_DEF;            // existing surface temperature
    dList[7] = V_DEF;             // wind velocity in km/h
    sList[0] = "";
    vList[0] = QDate::currentDate();
    vList[1] = QTime::currentTime();
    updateView();
    bmodified = false;
}

void PaveCool::updateView()
{
    PaveCool::setWindowTitle(newWinTitle(tName));
    ui->actionEnglish->setChecked(!bsi);
    ui->actionSI->setChecked(bsi);
    ui->action12_Hour->setChecked(!bList[2]);
    ui->action24_Hour->setChecked(bList[2]);
    ui->actionUS->setChecked(!bList[4]);
    ui->actionISO->setChecked(bList[4]);
    QString dformat = bList[4] ? "yyyy-MM-dd" : "M/d/yyyy";
    ui->dateEdit->setDisplayFormat(dformat);
    ui->skyCombo->setCurrentIndex(iList[0]);
    ui->gradCombo->setCurrentIndex(iList[1]);
    ui->hiCombo->setCurrentIndex(iList[2]);
    ui->loCombo->setCurrentIndex(iList[3]);
    ui->matCombo->setCurrentIndex(iList[4]);
    if(iList[4] < 2)
    {// disable material condition buttons for asphalt and concrete
        ui->wCombo->setCurrentIndex(-1);
        ui->stateCombo->setCurrentIndex(-1);
        ui->wCombo->setDisabled(true);
        ui->stateCombo->setDisabled(true);
    }
    else
    {
        ui->wCombo->setDisabled(false);
        ui->stateCombo->setDisabled(false);
        ui->wCombo->setCurrentIndex(iList[5]);
        ui->stateCombo->setCurrentIndex(iList[6]);
    }
    ui->hDSpin->setDecimals(decl(bsi));
    ui->hDSpin->setSingleStep(incl(bsi));
    ui->hDSpin->setValue(rnd2dec(convl(true,dList[0], bsi), decl(bsi)));
    ui->latEdit->setText(txtdbl(dList[1], LAT_DEC, false, true, false));
    ui->taEdit->setText(txtdbl(convt(true, dList[2], bsi), DEC_T));
    ui->tmSpin->setValue(int(rnd2dec(convt(true, dList[3], bsi),0)));
    ui->tsEdit->setText(txtdbl(convt(true, dList[4], bsi), DEC_T));
    ui->swEdit->setText(txtdbl(convlll(true, dList[7], bsi), DEC_V));
    ui->projectEdit->setText(sList[0]);
    ui->dateEdit->setDate(vList[0].toDate());
    tval[0] = txthrmin(vList[1].toTime().hour(), vList[1].toTime().minute(), bList[2]);
    ui->timeEdit->setText(tval[0]);
    ui->huLabel->setText(txtl(bsi));
    ui->tauLabel->setText(txtt(bsi));
    ui->tmuLabel->setText(txtt(bsi));
    ui->tsuLabel->setText(txtt(bsi));
    ui->vuLabel->setText(txtv(bsi));
    if(bList[3]) on_calcButton_clicked();
    if(bcalc) ui->exportButton->setDisabled(false);
    else ui->exportButton->setDisabled(true);
    //tooltips
    if(bList[4]) ui->dateEdit->setAccessibleName("Start Date: year, month, day");
    else ui->dateEdit->setAccessibleName("Start Date: month, day, year");
    bopen = false;
    repaint();
    if(bimport)
    {
        bimport = false;
        Write(tFile);
    }
}

void PaveCool::resetOutput()
{
    if(!bopen)
    {
        bmodified = true;
        if(!noreset)
        {
            ui->startEdit->setText("");
            ui->stopEdit->setText("");
            ui->exportButton->setDisabled(true);
            bcalc = false;
            bList[3] = false;
            repaint();
        }
        noreset = false;
    }
}

bool PaveCool::Open()
{
    QString tOpenFile = QFileDialog::getOpenFileName(this, tr("Open %1 File").arg(APP),
                                          tPath, tr("%1 Files (*.%2)").arg(APP).arg(APPEXT));
    if(tOpenFile.isEmpty()) return false;
    else return Read(tOpenFile);
}

bool PaveCool::askSave()
{
    QMessageBox::StandardButton ret;
    ret = QMessageBox::warning(this, QApplication::applicationName(),
        tr("The document has been modified.") + "\n"
        + tr("Do you want to save your changes?"),
        QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel);
    if(ret == QMessageBox::Yes) return Save(tFile);
    else if(ret == QMessageBox::Cancel) return false;
    else return true;
}

bool PaveCool::Save(const QString &fileName)
{
    if(!fileName.isEmpty()) return Write(fileName);
    else return SaveAs(fileName);
}

bool PaveCool::SaveAs(const QString &fileName)
{
    pcSettings("", READREG);
    QString newName = fileName;
    if(newName.isEmpty()) newName = tName;
    if(newName.isEmpty()) newName = sList[0].isEmpty() ? QApplication::applicationName() + "1" : sList[0];
    newName = QFileDialog::getSaveFileName(this, tr("Save %1 File").arg(APP),
                                 tPath + "/" + newName, tr("%1 Files (*.%2)").arg(APP).arg(APPEXT));
    if(!newName.isEmpty()) return Write(newName);
    else return false;
}

bool PaveCool::Write(const QString &fileName)
{
    QSaveFile mFile(fileName);
    mFile.setFileName(fileName);
    mFile.setDirectWriteFallback(true);

    if(!mFile.open(QFile::WriteOnly))
    {
        QMessageBox msgBox;
        msgBox.setText(tr("File could not be saved."));
        msgBox.exec();
        return false;
    }
    QDataStream out(&mFile);

    // Save Qt version so data from old files can be updated if necessary
    out.setVersion(QDataStream::Qt_5_2);
    // Create header with verification number and version number
    out << qint32(0xC01DE57);
//    out << qint32(0xFADE2B); // verification test
    out << nVersion;

    out << bList; // QList of bool
    out << iList; // QList of int
    out << dList; // QList of double
    out << sList; // QList of QString
    out << vList; // QList of QVariant

    bool bcom = mFile.commit();
    if(bcom)
    {
        QFileInfo mInfo(fileName);
        tName = mInfo.fileName();
        tFile = fileName;
        updateView();
        bmodified = false;
        pcSettings(fileName, SETREG);
    }
    return bcom;
}

bool PaveCool::Read(const QString &fileName)
{
    int i;
    bopen = false;
    QFile mFile(fileName);
    if(!mFile.open(QFile::ReadOnly))
    {
        QMessageBox msgBox;
        msgBox.setText(tr("File not found."));
        msgBox.exec();
        return false;
    }
    QDataStream in(&mFile);

    // Verify header information
    qint32 verify, version;
    in >> verify;
    if(verify == 0xC01DE57)
    {
        // Get Qt version
//        int qver = in.version(); // for later use

        in >> version;
        if(version < nVersion)
        {// or if(version < 3000), if(version >= 3009)...
            // update values if necessary
        }

        in >> bList; // QList of bool
        in >> iList; // QList of int
        in >> dList; // QList of double
        in >> sList; // QList of QString
        in >> vList; // QList of QVariant

        bsi = bList[1];
        mFile.close();
    }
    else
    {
        mFile.close();
        QFile txtFile(fileName);
        txtFile.open(QIODevice::ReadOnly);
        QXmlStreamReader xml(&txtFile);
        xml.readNext();
        i = 0;
        while(xml.name() != "verify" && i < 10)
        {
            i += 1;
            xml.readNext();
        }
        verify = xml.readElementText().toInt();
        if(verify == 0xB01DE57)
        {// text file exported from PaveCool 2.5
            QList<int> nTime; // import time fragments from xml file
            nTime.reserve(5);
            for(i = 0; i < 5; ++i)
            {
                nTime.append(0);
            }
            while(xml.name() != "bList") xml.readNext();
            for(i = 0; i < 4; ++i)
            {
                xml.readNextStartElement();
                bList[i] = xml.readElementText().toInt();
            }
            while(xml.name() != "iList") xml.readNext();
            for(i = 0; i < 7; ++i)
            {
                xml.readNextStartElement();
                iList[i] = xml.readElementText().toInt();
            }
            while(xml.name() != "dList") xml.readNext();
            for(i = 0; i < 8; ++i)
            {
                xml.readNextStartElement();
                dList[i] = xml.readElementText().toDouble();
            }
            while(xml.name() != "nTime") xml.readNext();
            for(i = 0; i < nTime.size(); ++i)
            {
                xml.readNextStartElement();
                nTime[i] = xml.readElementText().toInt();
            }
            while(xml.name() != "projectTitle") xml.readNext();
            sList[0] = xml.readElementText();
            if(xml.hasError())
            {
                QMessageBox msgBox;
                msgBox.setText(tr("xml error"));
                msgBox.exec();
                return false;
            }
            bimport = true;
            bsi = bList[1];
            bList[3] = true; // calculate after opening
            vList[0] = QDate(nTime[0], nTime[1], nTime[2]);
            vList[1] = QTime(nTime[3], nTime[4]);
            tName = QFileInfo(fileName).fileName();
            QMessageBox msgBox;
            msgBox.setText(tr("File imported successfully."));
            msgBox.exec();
            txtFile.close();
        }
        else
        {
            QMessageBox msgBox;
            msgBox.setText(tr("Incorrect file format.%1Code %2").arg("\n").arg(QString::number(verify)));
            msgBox.exec();
            txtFile.close();
            return false;
        }
    }
    QFileInfo mInfo(fileName);
    tName = mInfo.fileName();
    tFile = fileName;
    bopen = true;
    updateView();
    bmodified = false;
    pcSettings(fileName, SETREG);
    return true;
}

QString PaveCool::newWinTitle(const QString &tTitle)
{
    QString ttmp = QApplication::applicationName() + " "
            + txtdbl(double(nint(double(nVersion * 0.01))) * 0.1, 1);
    if(!tTitle.isEmpty())
    {
        ttmp = ttmp + " - " + tTitle;
    }
    return ttmp;
}

void PaveCool::paintEvent(QPaintEvent *)
{
    QPixmap pixmap(ui->curveLabel->size());
    QPainter painter(&pixmap);
    int gx = 0;
    int gy = 0;
    int gw = ui->curveLabel->width();
    int gh = ui->curveLabel->height();
    drawGraph(&painter, gx, gy, gw, gh);
    ui->curveLabel->setPixmap(pixmap);
}

void PaveCool::drawGraph(QPainter *gpaint, int gx, int gy, int gw, int gh, bool bpdf)
{
    int i;
    QPen pen;
    pen.setBrush(Qt::black);
    if(bpdf) pen.setWidth(12);
    else pen.setWidth(1);
    gpaint->setPen(pen);
    gpaint->setBrush(Qt::white);
    QRect grect(gx, gy, gw-1, gh-1);
    if(!bpdf) gpaint->drawRect(grect);
    int ox = gx+gw/8;
    int oy = gy+gh-gh/7;
    int endx = gx+gw-gw/12;
    int endy = gy+gh/8;
    int lx = endx-ox;
    int ly = oy-endy;
    int label;
    if(bpdf) label = 12;
    else
    {
        label = 10*gh/379;
        if(label > 10*gw/350) label = 10*gw/350;
    }
    gpaint->setFont(QFont("Arial", label));
    // x&y axis
    gpaint->setPen(pen);
    qreal ticx = qreal(gw) / 172.;
    qreal ticy = qreal(gh) / 175.;
    gpaint->drawLine(ox, oy, endx, oy);
    gpaint->drawLine(ox, oy, ox, endy);
    gpaint->drawText(ox+nint(qFloor(50*ticx)), oy+int(qFloor(20*ticy)), tr("Time, minutes"));
    // Tick marks
    int nticx = 6;
    int nticy;
    int nt = 20;
    int tgraph, tmin, tmax, ntemp;
    gpaint->drawText(ox-int(qFloor(15*ticx)), oy-ly-int(qFloor(10*ticy)), tr("Mix Temperature, %1").arg(txtt(bsi)));
    nticy = bsi ? 10 : 9;
    tgraph = int(convt(true,60.0,bsi));
    tmin = 60;
    tmax = 160;
    ntemp = bsi ? 10 : 20;
    double dx = double(lx)/double(nticx);
    double dy = double(ly)/double(nticy);
    int tick;
    QString sp = "  ";
    for(i = 0; i <= nticx; ++i)
    {
        tick = nint(rnd2dec(ox+i*dx,0));
        gpaint->drawLine(tick,oy,tick,oy+nint(qFloor(2*ticy)));
        gpaint->drawText(tick-int(qFloor(3*ticx)),oy+int(qFloor(10*ticy)),QString::number(i*nt));
    }
    for(i = 0; i <= nticy; ++i)
    {
        tick = nint(rnd2dec(oy-i*dy,0));
        gpaint->drawLine(ox,tick,ox-nint(qFloor(2*ticx)),tick);
        if(tgraph+i*ntemp >= 100) sp = "";
        gpaint->drawText(ox-int(qFloor(15*ticx)),tick+int(qFloor(2*ticy)),sp+QString::number(tgraph+i*ntemp));
    }
    //minor ticks
    for(i = 0; i <= nticx*2; ++i)
    {
        tick = nint(rnd2dec(ox+i*dx/2,0));
        gpaint->drawLine(tick,oy,tick,oy+int(qFloor(2*ticy)));
    }
    for(i = 0; i <= nticx*10; ++i)
    {
        tick = int(rnd2dec(ox+i*dx/10,0));
        gpaint->drawLine(tick,oy,tick,oy+int(qFloor(ticy)));
    }
    if(!bsi)
    {
        for(i = 0; i <= nticy*2; ++i)
        {
            tick = int(rnd2dec(oy-i*dy/2,0));
            gpaint->drawLine(ox,tick,ox-int(qFloor(2*ticx)),tick);
        }
    }
    for(i = 0; i <= nticy*10; ++i)
    {
        tick = int(rnd2dec(oy-i*dy/10,0));
        gpaint->drawLine(ox,tick,ox-int(qFloor(ticx)),tick);
    }
    double time = 0.;
    double ttotal = 120.;	// BT changed to static scales
    int oldx, oldy, newx, newy;
    oldx = int(ox);
    oldy = int(oy-(dList[3]-tmin)*ly/(tmax-tmin));

    if(bcalc || bpdf)
    {
        if(bpdf) pen.setWidth(24);
        else pen.setWidth(2);
        for(i = 0; i < THMA.size() && time <= ttotal*60; ++i)
        {
            time = double(i) * 20.;
            newx = int(qFloor(ox+lx*(time/60.0)/ttotal));
            if(THMA[i] <= tmax)
            {
                if(THMA[i] < tmin)
                {
                    THMA[i] = tmin; // complete curve without errors
                }
                pen.setBrush(QColor(nint(qFloor(105.+150.*(THMA[i]-tmin)/(tmax-tmin))),
                                    105,nint(qFloor(255-250.*(THMA[i]-tmin)/(tmax-tmin)))));
                gpaint->setPen(pen);
                newy = int(qFloor(oy-(THMA[i]-tmin)*ly/(tmax-tmin)));
                gpaint->drawLine(oldx,oldy,newx,newy);
                oldy = newy;
            }
            else oldy = int(oy-ly);
            oldx = newx;
        }
        // legend
        int length = 20;
        oldx = ox+int(qFloor(58*ticx));
        oldy = oy-ly+int(qFloor(3*ticy));
        for(int i = 1; i <= length; i++)
        {
            pen.setBrush(QColor(nint(qFloor(255.-150.*double(i)/double(length))),
                                105,nint(qFloor(5.+250.*double(i)/double(length)))));
            gpaint->setPen(pen);
            newx = ox+int(qFloor(58*ticx+i*ticx));
            newy = oy-ly+int(qFloor(3*ticy));
            gpaint->drawLine(oldx,oldy,newx,newy);
            oldx = newx;
            oldy = newy;
        }

        if(bList[0]) tstart = dList[5]; // User start temp
        else tstart = iList[2] > PG_CUTOFF ? TSTART52 : TSTART58;
        tstop = bList[0]? dList[6] : STOPTEMP; // m_StopTempSI;

        pen.setBrush(Qt::green);
        gpaint->setPen(pen);
        gpaint->drawLine(ox, int(qFloor(oy-(tstart-tmin)*ly/(tmax-tmin))),
                         int(qFloor(ox+lx*timeStart/ttotal)),
                         int(qFloor(oy-(tstart-tmin)*ly/(tmax-tmin))));
        gpaint->drawLine(int(qFloor(ox+lx*timeStart/ttotal)),
                         int(qFloor(oy-(tstart-tmin)*ly/(tmax-tmin))),
                         int(qFloor(ox+lx*timeStart/ttotal)), int(oy));
        // legend
        gpaint->drawLine(ox+int(qFloor(58*ticx)),oy-ly+int(qFloor(11*ticy)),
                       ox+int(qFloor(58*ticx+length*ticx)), oy-ly+int(qFloor(11*ticy)));

        pen.setBrush(Qt::red);
        gpaint->setPen(pen);
        gpaint->drawLine(ox, int(qFloor(oy-(tstop-tmin)*ly/(tmax-tmin))),
                         int(qFloor(ox+lx*timeStop/ttotal)),
                         int(qFloor(oy-(tstop-tmin)*ly/(tmax-tmin))));
        gpaint->drawLine(int(qFloor(ox+lx*timeStop/ttotal)),
                         int(qFloor(oy-(tstop-tmin)*ly/(tmax-tmin))),
                         int(qFloor(ox+lx*timeStop/ttotal)), int(oy));
        // legend
        gpaint->drawLine(ox+int(qFloor(58*ticx)),oy-ly+int(qFloor(19*ticy)),
                       ox+int(qFloor(58*ticx+length*ticx)), oy-ly+int(qFloor(19*ticy)));

        // legend text
        pen.setBrush(Qt::black);
        gpaint->setPen(pen);
        gpaint->drawText(ox+int(qFloor(80*ticx)),oy-ly+int(qFloor(5*ticy)), tr("Cooling Curve"));
        gpaint->drawText(ox+int(qFloor(80*ticx)),oy-ly+int(qFloor(13*ticy)), tr("Start Rolling"));
        gpaint->drawText(ox+int(qFloor(80*ticx)),oy-ly+int(21*ticy), tr("Stop Rolling"));
    }
}

void PaveCool::calculate()
{
    bcalc = false;
    THMA.clear();
    qToday = QDate::currentDate();
    qNow = QTime::currentTime();

    timeStart = 0.0; // not resetting caused an error when reducing Start Paving temperature
    timeStop = 0.0;

    double PctClouds = double(iList[0]) * 0.25;
    double LiftThick = dList[0];
    double Tair = dList[2];
    double BasT = dList[4];
    double tlift = dList[3];
    double Wind = dList[7];
    if(bList[0]) tstart = dList[5]; // User start temp
    else tstart = iList[2] > PG_CUTOFF ? TSTART52 : TSTART58;
    tstop = bList[0]? dList[6] : STOPTEMP; // m_StopTempSI;

    switch (iList[1]) // Mix Type
    {
    case 0:
        {
            AsphK	= DG_K;
            AsphCp	= DG_CP;
            AsphRho	= DG_RHO;
        }
        break;
    case 1:
        {
            AsphK	= SMA_K;
            AsphCp	= SMA_CP;
            AsphRho	= SMA_RHO;
        }
        break;
    default:
        break;
    }//end switch

    //FROM HERE TO THE END OF THE FUNCTION, EVERYTHING IS IN SI!!!

    //These arrays have been added so that the pavement system can be 'reverse numbered'
    int nn[MAXLAYER];			// Absolute number of last node in zone[LAYER]
    int zones;					// number of zones used, must be .LE. LAYER - 1
    double ap[SIZE],aw[SIZE];	// Coefficients
    double ae[SIZE],b[SIZE];	// Coefficients
    double T[SIZE];				// Temperature
    double Delx[SIZE];			// Node cell length
    double cp[SIZE];			// thermal properties vectors
    double rho[SIZE];
    double K[SIZE];

    int i,k;					// Counters
    int j;						// Counter for convergence check
    int Flag;					// Flag for checking if deform has been called
    int Nodes[MAXLAYER];		// number of nodes in each material adds up to nn[LAYER]

    double Told[SIZE];			// Old time step Temperature
    double Tconv[SIZE];         // used in residuals calculation

    double Delt;				// Time step
    double Tinit[MAXLAYER];		// Starting Temperaure of MAXLAYERs
    double cpinit[MAXLAYER];	// Specific heat of the material in each MAXLAYER
    double Lift[MAXLAYER];		// Starting thickness of the MAXLAYERs
    double Kinit[MAXLAYER];		// Inital thermal conductivity of MAXLAYERs
    double rhoinit[MAXLAYER];   // Initial density of LAYERs

    double delta;				// % compaction of lift - 0 to 100
    double h;                   // Atmoshperic properties
    double Sigma;				// Stephan-Boltzman Constant
    double Tsky;				// Sky temperature - 250K clouds - 100K clear night
    double Qsun;				// Heating performed by sun, 0 to as much as 388 W/m^2)
    int TotalDays;				// Number of days into year, used for Net Solar Flux

    double ptime;				// cooling time till compressed
    double stime;				// time to stop simulation, must be GE ptime
    double ttime;				// total time
    double Tsum;				// Total normailzed temp error, used for convergence
//    double omega;				// relaxation
    double epsilon = 0.95;		// emmisivity of asphalt
    double Depth;  				// depth into earth
    double Tave = 0.0;			// used to calculate total heat lost from lift
    int RtnTime = -1;           // Used when in fuction mode...When cooled to tstop
    double error;				// convergence check variable

    // set and convert the above variables into what we were reading in before Windows

    ptime = 20.0E5;             // not worried about compaction so never compact
    stime = 2.1 * 60 * 60;      // run the simulation out 2 hours, that should be enough
    delta = 0.0;                // if it does happen to compact, pass zero compaction

    Lift[1] = LiftThick/1000.0; //puts thickness into meters
    Tinit[1]	= tlift;

    Kinit[1] = AsphK;
    cpinit[1] = AsphCp;
    rhoinit[1] = AsphRho;

    switch (iList[4])           // existing surface
    {
    case 0:
        {//AC
            BasK	= AC_BASE_K;
            BasCp	= AC_BASE_CP;
            BasRho	= AC_BASE_RHO;
        }
        break;
    case 1:
        {//PCC
            BasK	= PCC_K;
            BasCp	= PCC_CP;
            BasRho	= PCC_RHO;
        }
        break;
    case 2:
        {//CA
            switch(iList[5]*2+iList[6])
            {
            case 0:
                {//dry unfrozen
                    BasK	= CDT_K;
                    BasCp	= CDT_CP;
                    BasRho	= CDT_RHO;
                }
                break;
            case 1:
                {//dry frozen
                    BasK	= CDF_K;
                    BasCp	= CDF_CP;
                    BasRho	= CDF_RHO;
                }
                break;
            case 2:
                {//wet unfrozen
                    BasK	= CWT_K;
                    BasCp	= CWT_CP;
                    BasRho	= CWT_RHO;
                }
                break;
            case 3:
                {//wet frozen
                    BasK	= CWF_K;
                    BasCp	= CWF_CP;
                    BasRho	= CWF_RHO;
                }
                break;
            }
        }
        break;
    case 3:
        {//FA
            switch(iList[5]*2+iList[6])
            {
            case 0:
                {//dry unfrozen
                    BasK	= FDT_K;
                    BasCp	= FDT_CP;
                    BasRho	= FDT_RHO;
                }
                break;
            case 1:
                {//dry frozen
                    BasK	= FDF_K;
                    BasCp	= FDF_CP;
                    BasRho	= FDF_RHO;
                }
                break;
            case 2:
                {//wet unfrozen
                    BasK	= FWT_K;
                    BasCp	= FWT_CP;
                    BasRho	= FWT_RHO;
                }
                break;
            case 3:
                {//wet frozen
                    BasK	= FWF_K;
                    BasCp	= FWF_CP;
                    BasRho	= FWF_RHO;
                }
                break;
            }
        }
        break;
    default:
        break;
    }

    Kinit[2]	= BasK;
    cpinit[2]	= BasCp;
    rhoinit[2]	= BasRho;
    Tinit[2]	= BasT;

    TotalDays = vList[0].toDate().dayOfYear();

    // calcualte net solar flux for clear sky
    // this function takes latitude,day of year, and hour of day and
    // calculated CLEAR sky solar flux, it returns zero if it is night

    double phi, t;
    int d;
    double theta,sigma,iflux,nsf;
    double psi,cZ,hp,beta,decl;
    double Pi,Ellip,Solar;
    Pi = 3.14159265359;

    phi = qFabs(dList[1]) * Pi / 180.0; // latitude
    d = TotalDays;
    t = double(vList[1].toTime().hour()) + double(vList[1].toTime().minute())/60.0;

    Ellip = 0.0167238;          // Ellipticity of Earth's orbit
    Solar = 1377.0;				// W/m^2

    theta = 2*Pi*(d-2)/365.242;
    if(d == 1) theta = 2*Pi*(d+363.0)/365.242;
    psi = 2*Pi*(d-1)/356.242;
    sigma = 279.9348+1.914827*qSin(psi)-0.079525*qCos(psi)
          +0.019938*qSin(2*psi)-0.001620*qCos(2*psi)+psi*180.0/Pi;
    decl=qAsin(qSin(0.409172)*qSin(sigma*Pi/180));

    if(dList[1] < 0) decl *= -1.; 	// added in 2014 for southern hemisphere locations

    beta=0.12357*qSin(psi)-0.004289*qCos(psi)+0.153809*qSin(2*psi)+0.060783*qCos(2*psi);
    hp=(t-beta-12.0)*Pi/12.0;
    cZ=qSin(phi)*qSin(decl)+qCos(phi)*qCos(decl)*qCos(hp);
    iflux=Solar*cZ*qPow(1+Ellip*qCos(theta),2)/(1-qPow(Ellip,2));
    nsf=(0.828*iflux-47.4);
    if(nsf<=0.0) nsf=0.0;
    Qsun = nsf;

// if nsf is zero its night, set Tsky accordingly work in Kelvins
// see example Krieth & Black pg 321
    if(qFabs(Qsun) < EN12) // avoid == 0.0 comparison
        Tsky = (Tair+48)*double(PctClouds)/100.0+225.0;
    else
        Tsky = Tair+273.0;

// finally set Qsun according to %Clouds & don't forget absorbance= 0.85
    Qsun = 0.85*Qsun*(1.0 - PctClouds); //PctClouds all ready in decimal

    // fix the rest of the variables that we did not read in....
    zones = 4;   // number of zones used, must be .LE. Layer - 1

    Nodes[1] = nint(100 * Lift[1]);   // seems to give good resolution for problem
    if(Nodes[1] <6) Nodes[1]=6;        // never run with less!
    if(Nodes[1] >50) Nodes[1]=50;      // defined SIZE controls maximum

    Nodes[2] = 6;
    Lift[2] = 0.06;

    Nodes[3] = 6;				// number of nodes in region 3
    Lift[3] = 0.1;              // Lower base material properties, meters
    Tinit[3] = Tinit[2];		// Deg C
    Kinit[3] = Kinit[2];		// W/m*K
    cpinit[3] = cpinit[2];		// J/kg*K
    rhoinit[3] = rhoinit[2];	// kg/m^3

    Nodes[4] = 8;				// number of nodes in region 4
    Lift[4] = 0.2;              // zone 4 material properties, meters
    Tinit[4] = Tinit[2];		// Deg C
    Kinit[4] = Kinit[2];		// W/m*K
    cpinit[4] = cpinit[2];		// J/kg*K
    rhoinit[4] = rhoinit[2];	// kg/m^3

    Delt = 20.0;                // time step seconds
    Wind /= 3.6;                // Convert km/h to m/s

    // h = 7.4+26.6*qPow(Wind/6.7,0.75);  Alford, et al - W/m^2*K
    // h = 4.89187*qPow(Wind,0.8);   Luoma's calcs
    // if(h < 1.0) h=1.0;
    // Convective Cooling Coeff (W/m^2*K)
    h = 3.152*(1.3 + 0.62*qPow(Wind*2.23,0.75));  // barber? from jordan thomas

    Sigma = 5.67e-08;			// Radiative cooling coefficient
    ttime = 0.0;				// initialize time
//    omega = 0.25;				// relaxation  not used
    error = 1.0e-5;             // allowed error
    Flag = 0;                   // set defomed flag to zero (has not been called)
    j = 0;                      // initialize counter
    nn[0] = 0;                  // initialized for loop, nn[0] not used otherwise
    for (i = 1; i <= zones; ++i)// calculate nn[i] - highest node number is a zone
    {
       nn[i] = nn[i-1] + Nodes[i];
    }
    /* Initialize T[i],cp[i],rho[i],K[i], and Delx[i], remember, node 0 is the
       special surface node and does not have a volume associated with it
       we set Delx[0] and cp[0] to zero to perform this w/o dividing by zero later on*/

    k = 1;
    for (i = 0; i<=nn[zones]; ++i)
    {
        if(i > nn[k]) ++k;      // if we are in the next zone, use those properties
        T[i] = Tinit[k];
        cp[i] = cpinit[k];
        rho[i] = rhoinit[k];
        K[i] = Kinit[k];
        Delx[i]=Lift[k]/(Nodes[k]);	// Initial thickness of CVFE cells
    }

    Delx[0] = 0.0;
    cp[0] = 0.0;

    for (i = 0; i<=nn[zones]; ++i)
    {
        Told[i] = T[i];			// map initial values into Told
    }

    Depth = 0.0;
    for (i = 0; i<=nn[zones]; ++i)     // print out initial node values
    {
        Depth = Depth + Delx[i]/2.0;
        if(i==0) Depth = 0.0;
        Depth = Depth + Delx[i]/2.0;
        if(i==0) Depth = 0.0;
    }

// Start of time step

     THMA.append(dList[3]); // m_DelivTempSI

ten: ttime += Delt;
// Map Temperature values for convergence check
twenty: for (i = 0; i<=nn[zones]; ++i)
    {
        Tconv[i] = T[i];		// map initial values into Tconv
    }

    // Start of iteration
    // Calculate Coefficients note - don't do end points
    for (i=1; i<=(nn[zones]-1); ++i)
    {  				// see Patanka pg46
        aw[i]=1.0/((Delx[i-1]/(2.0*K[i-1]))+(Delx[i]/(2.0*K[i])));
        ae[i]=1.0/((Delx[i+1]/(2.0*K[i+1]))+(Delx[i]/(2.0*K[i])));
        ap[i]=ae[i]+aw[i]+(rho[i]*cp[i]*Delx[i])/Delt;
         b[i]=(rho[i]*cp[i]*Delx[i])*Told[i]/Delt;
    }

    // Modify endpoints now...
    // Convective/radiative boundary condition on node 0 & 1 - see Patanka pg 27,80
    ae[0]=+(4.0/3.0)*K[1]*2.0/Delx[1];
    aw[0]=(1.0/3.0)/(Delx[1]/(2.0*K[1])+Delx[2]/(2.0*K[2]));
    ap[0]=ae[0]+h;
     b[0]=h*Tair+Qsun-epsilon*Sigma*(qPow((T[0]+273.0),4)-qPow(Tsky,4));

    // Modify node 1 coefficients for higher accuracy
    ae[1]=+(4.0/3.0)*ae[1];
    aw[1]=+(4.0/3.0)*K[1]*2.0/Delx[1];
    ap[1]=ae[1]+aw[1]+(rho[1]*cp[1]*Delx[1])/Delt;

    // insulated boundary condition
    ae[nn[zones]]=0.0;
    aw[nn[zones]]=1.0/((Delx[i-1]/2.0*K[i-1])+(Delx[i]/2.0*K[i]));
    ap[nn[zones]]=aw[nn[zones]]+(rho[i]*cp[i]*Delx[i])/(Delt);
     b[nn[zones]]=Told[nn[zones]]*(rho[i]*cp[i]*Delx[i])/(Delt);

    // Call Tri-Diagonal Matrix Solver
    // Note: all parameters used by solver
    // have been declared as global.

    /****
    * TDMA SOLVER - Tri diagonal matrix solver (Gauss elimination)
    *****/
    double p[SIZE],q[SIZE];
    double bot;

    p[0] = ae[0]/ap[0];
    q[0] = b[0]/ap[0];

    for (i=1; i<=(nn[zones]); ++i)
    {
        bot = ap[i] -aw[i] * p[i-1];
        p[i] = ae[i]/bot;
        q[i] = (b[i]+aw[i]*q[i-1])/bot;
    }
    T[nn[zones]]=q[nn[zones]];      // since p[nn[z]]=0 because ae[nn[z]]=0

    for (i=nn[zones]-1; i>= 0; --i)
    {
        T[i] = p[i]*T[i+1]+q[i];
    }
    //complete effort for second order accuracy, need to specially calculate
    // T[0] as documented on pg. 83 equation 5.44 of Patankar
    T[0] = (ae[0]*T[1] + aw[0]*(T[1]-T[2]) + b[0])/ap[0];

    // this check is needed to ensure convergence
    // because of non-linear source terms at boundary
    Tsum=0.0;
    ++j;                            // increment convergence counter
    for (i = 0; i <= ( nn[zones]); ++i)
    {//number of calls to TDMA
        Tsum=Tsum+(T[i]-Tconv[i])/(T[1]-Tair);
    }

    if(j>=100)                 // Check for infinite loop
    {//maximum number of iteration exceeded
        RtnTime = -2;
        goto end;
    }

    // Check for Convergence
    if(qFabs(Tsum) > error) goto twenty;
        j=0;                    // converged, reset counter

    // Swap Old for New for next time step
    for (i = 0; i <= (nn[zones]); ++i)
    {
        Told[i] = T[i];
    }

    // Check to see if it is time to deform grid and make sure you deform only once
    if((ttime >= ptime) && (Flag == 0))
    {
         /******
         * deformation subroutine
         *****/
        /* Currently we deform up to nn[1] nodes by a specified amount.  We hope
           to be able to define a constitutive model based on node temperature,
           local stress from rolling, and previous density for actual deformation */

        int i;

        // delta =36.0;		 percent deformation,max 36% from Nic-Daines

        for (i=1; i<=(nn[1]); ++i)
        {
             Delx[i] = Delx[i]*(1.0 - delta/100.0);
              rho[i] =  rho[i]/(1.0 - delta/100.0);
                K[i] =    K[i]/(1.0 - delta/100.0);
        }

        Flag=1;					// deform has been called

       Depth = 0.0;
       for (i = 0; i<=nn[zones]; ++i)
       {
           Depth = Depth + Delx[i]/2.0;
           if(i==0) Depth = 0.0;
           Depth = Depth + Delx[i]/2.0;    // prints for center of control volume
           if(i==0) Depth = 0.0;
       }
    }

    //if(ttime == Delt) THMA[0] = Tinit[1];
    //if((fmod(ttime,60) == 0) || (ttime == Delt))

    // calculate mean temperature in lift
    Tave = 0.0;
    for (i=1; i<= nn[1]; ++i)
    {
        Tave = Tave + T[i]/nn[1];
    }

    THMA.append(Tave);
    if(Tave >= tstart) timeStart = ttime/60.;
    else if(Tave >= tstop) timeStop = rnd2dec(ttime/60., 0);

    // don't want to run out to 12 hours, what we are really worried about
    // is if the lift has cooled below the cutoff required temperature, whatever
    // that is, for now we know that people care about magic numbers of 120 F
    // for the lowest temperature and 180 F for minimum rolling temp.

    if(Tave < tstop && RtnTime == -1) RtnTime = nint(ttime/60.0);
    if(Tave < 60.0 && qFabs(ttime - Delt) < EN12)      //cooled so fast we did not run!
    {
        RtnTime = -2;
        goto end;
    }
    if(Tave < 60. ) goto end;  //cooled to 122 Deg F so stop!

    if((ttime >= 5.0*60.0) && (ttime < 5.0*60.+Delt))
    {
        for (i = 0; i<=nn[zones]; ++i)     // print out initial node values
        {
            Depth = Depth + Delx[i]/2.0;
            if(i==0) Depth = 0.0;
            Depth = Depth + Delx[i]/2.0;
            if(i==0) Depth = 0.0;
        }
    }

    if((ttime >= 10.0*60.0) && (ttime < 10.0*60+Delt))
    {
        for (i = 0; i<=nn[zones]; ++i)     // print out initial node values
        {
            Depth = Depth + Delx[i]/2.0;
            if(i==0) Depth = 0.0;
            Depth = Depth + Delx[i]/2.0;
            if(i==0) Depth = 0.0;
        }
    }

    if((ttime >= 15.0*60.0) && (ttime < 15.0*60+Delt))
    {
        for (i = 0; i<=nn[zones]; ++i)     // print out initial node values
        {
            Depth = Depth + Delx[i]/2.0;
            if(i==0) Depth = 0.0;
            Depth = Depth + Delx[i]/2.0;
            if(i==0) Depth = 0.0;
        }
    }

    if((ttime >= 20.0*60.0) && (ttime < 20.0*60+Delt))
    {
        for (i = 0; i<=nn[zones]; ++i)     // print out initial node values
        {
            Depth = Depth + Delx[i]/2.0;
            if(i==0) Depth = 0.0;
            Depth = Depth + Delx[i]/2.0;
            if(i==0) Depth = 0.0;
        }
    }

    if(ttime < stime) goto ten;

end:
    timeStop = rnd2dec(timeStop, 0);
    if(timeStop > 120.)
    {
        timeStop = 120.;
        tStop = ">120";
    }
    else
    {
        tStop = txtdbl(timeStop, 0);
    }

    bcalc = true;
    bList[3] = true; // calculate if file is saved & opened
    ui->exportButton->setDisabled(false);

    PaveCool::update(); // repaints window
}
