<commit_before>/* Copyright (c) 2014 Jason Paulos
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

#include <QMessageBox>
#include <QFileDialog>
#include <QFileInfo>
#include <QSqlError>
#include <QPainter>
#include "MainWindow.h"
#include "ui_MainWindow.h"
#include "DatabaseDialog.h"

MainWindow::MainWindow(QWidget *parent):
    QMainWindow(parent),
    ui(new Ui::MainWindow()),
    partialStop(false),
    isMaleDone(false),
    isFemaleDone(false),
    maleEngine(nullptr),
    femaleEngine(nullptr),
    printEngine(nullptr),
    maleThread(new QThread()),
    femaleThread(new QThread()),
    dialog(nullptr),
    pdfDialog(nullptr)
{
    ui->setupUi(this);
    ui->pdfInfo->setText(QDir::homePath() + "/matches.pdf");

    connect(this, SIGNAL(signalShowError(QString)), this, SLOT(slotShowError(QString)));
    connect(this, SIGNAL(signalUsersLoaded()), this, SLOT(slotUsersLoaded()));

    MatchMaker::instance = &matchMaker;

    maleThread->start();
    femaleThread->start();
}

MainWindow::~MainWindow(){
    maleThread->quit();
    femaleThread->quit();

    maleThread->deleteLater();
    femaleThread->deleteLater();

    if(maleEngine){
        maleEngine->deleteLater();
    }

    if(femaleEngine){
        femaleEngine->deleteLater();
    }

    if(printEngine){
        printEngine->deleteLater();
    }

    delete dialog;
    delete pdfDialog;
}

QString MainWindow::getPdfSavePath(){
    return ui->pdfInfo->text();
}

QString MainWindow::getPdfPageTitle(){
    return ui->titleEdit->text();
}

void MainWindow::printToPdf(){
    printEngine = new PrintEngine(this);

    //We'll reuse femaleThead to host printEngine
    printEngine->moveToThread(femaleThread);

    connect(printEngine, SIGNAL(progress(int)), this, SLOT(printingProgress(int)));
    connect(printEngine, SIGNAL(done()), this, SLOT(printingDone()));

    emit printEngine->pleaseSetup();
    emit printEngine->pleaseStartPrinting();
}

void MainWindow::userQuery(QSqlQuery *query, Gender gen, std::vector<User> &users){
    if(query->exec()){
        unsigned int dimensions = matchMaker.dbSetup.getQuestions().size() + matchMaker.dbSetup.hasGrade();
        bool hasFirst = matchMaker.dbSetup.hasFirstName(), hasMiddle = matchMaker.dbSetup.hasMiddleName(), hasLast = matchMaker.dbSetup.hasLastName();

        while(query->next()){
            int i = 0;
            QString first(hasFirst ? query->value(i++).toString() : ""), middle(hasMiddle ? query->value(i++).toString(): ""), last(hasLast ? query->value(i++).toString() : "");

            User user(
                        first + (middle.isEmpty() ? "" : " ") +
                        middle + (last.isEmpty() ? "" : " ") +
                        last,
                        gen,
                        dimensions
            );

            for(unsigned int a = 0; a < dimensions; ++a){
                user.answers.elements[a] = query->value(i++).toInt();//TODO: check for error?
            }

            users.push_back(user);
        }

    }else{
        emit signalShowError(query->lastError().text());
    }
}

void MainWindow::on_selectDatabase_clicked(){
    if(!dialog && !pdfDialog){
        dialog = new DatabaseDialog(this);

        connect(dialog, SIGNAL(finished(bool, QScopedPointer<Database>&, DatabaseSetup&)), this, SLOT(databaseDialogFinished(bool, QScopedPointer<Database>&, DatabaseSetup&)));

        dialog->show();
    }
}

void MainWindow::on_start_clicked(){
    ui->start->setEnabled(false);
    ui->stop->setEnabled(false);
    ui->clear->setEnabled(false);

    //TODO: check that the pdf file is a valid file name

    if(partialStop){
        if(!isMaleDone){
            emit maleEngine->pleaseStartMatching();
        }

        if(!isFemaleDone){
            emit femaleEngine->pleaseStartMatching();
        }

        if(isMaleDone && isFemaleDone){
            emit printEngine->pleaseStartPrinting();
        }
    }else{
        isMaleDone = isFemaleDone = false;

        ui->inputGroup->setEnabled(false);
        ui->outputGroup->setEnabled(false);

        ui->usersProgress->setMaximum(0);
        ui->usersProgress->setValue(-1);
        ui->usersInfo->setText("Loading...");

        QString query("SELECT " +
                      (matchMaker.dbSetup.hasFirstName() ? matchMaker.dbSetup.getFirstName() + ", " : "") +
                      (matchMaker.dbSetup.hasMiddleName() ? matchMaker.dbSetup.getMiddleName() + ", " : "") +
                      (matchMaker.dbSetup.hasLastName() ? matchMaker.dbSetup.getLastName() + ", " : "") +
                      (matchMaker.dbSetup.hasGrade() ? matchMaker.dbSetup.getGrade() + ", " : "")
        );

        const QStringList &questions(matchMaker.dbSetup.getQuestions());

        for(auto i = questions.begin(); i != questions.end(); ++i){
            query += *i + (questions.endsWith(*i) ? " ": ", ");
        }

        query += "FROM " + matchMaker.dbSetup.getTable() + " WHERE ";

        matchMaker.dbManager->queryConnection(CONNECTION, query + matchMaker.dbSetup.getGender() + " = " + QString::number(Gender::MALE),
        [this, query](QSqlQuery *maleQuery){
            userQuery(maleQuery, Gender::MALE, matchMaker.male);

            matchMaker.dbManager->queryConnection(CONNECTION, query + matchMaker.dbSetup.getGender() + " = " + QString::number(Gender::FEMALE),
            [this](QSqlQuery *femaleQuery){
                userQuery(femaleQuery, Gender::FEMALE, matchMaker.female);

                emit signalUsersLoaded();
            });
        });
    }
}

void MainWindow::on_stop_clicked(){
    partialStop = true;

    ui->start->setEnabled(true);
    ui->stop->setEnabled(false);
    ui->clear->setEnabled(true);

    if(!isMaleDone){
        emit maleEngine->pleaseStopMatching();
    }

    if(!isFemaleDone){
        emit femaleEngine->pleaseStopMatching();
    }

    if(isMaleDone && isFemaleDone){
        emit printEngine->pleaseStartPrinting();
    }
}

void MainWindow::on_clear_clicked(){
    partialStop = false;

    ui->start->setEnabled(true);
    ui->clear->setEnabled(false);

    ui->inputGroup->setEnabled(true);
    ui->outputGroup->setEnabled(true);

    ui->usersProgress->setMaximum(1);
    ui->usersProgress->setValue(0);
    ui->usersInfo->setText("");

    ui->maleProgress->setMaximum(1);
    ui->maleProgress->setValue(0);
    ui->maleInfo->setText("0/0");

    ui->femaleProgress->setMaximum(1);
    ui->femaleProgress->setValue(0);
    ui->femaleInfo->setText("0/0");

    ui->totalProgress->setMaximum(1);
    ui->totalProgress->setValue(0);
    ui->totalInfo->setText("0/0");

    ui->printingProgress->setMaximum(1);
    ui->printingProgress->setValue(0);
    ui->printingInfo->setText("0/0");

    matchMaker.male.clear();
    matchMaker.female.clear();

    if(maleEngine){
        maleEngine->deleteLater();
        maleEngine = nullptr;
    }

    if(femaleEngine){
        femaleEngine->deleteLater();
        femaleEngine = nullptr;
    }

    if(printEngine){
        printEngine->deleteLater();
        printEngine = nullptr;
    }
}

void MainWindow::on_selectPdf_clicked(){
    if(!pdfDialog && !dialog){

        //Qt::Sheet will make the dialog appear as a sheet in Mac OSX
        pdfDialog = new QFileDialog(this, Qt::Sheet);

        pdfDialog->setAcceptMode(QFileDialog::AcceptSave);
        //pdfDialog->setWindowModality(Qt::WindowModal);

        pdfDialog->setWindowTitle(tr("Save matches"));
        pdfDialog->setDirectory(QDir::homePath());
        pdfDialog->setNameFilter(tr("PDF (*.pdf);; All Files (*)"));

        pdfDialog->open(this, SLOT(pdfFileSelected(QString)));
        connect(pdfDialog, SIGNAL(rejected()), this, SLOT(pdfFileCancelled()));

        pdfDialog->show();
    }
}

void MainWindow::databaseDialogFinished(bool success, QScopedPointer<Database> &db, DatabaseSetup &dbSetup){
    if(success){
        QString info;

        switch(db->getType()){
        case DB_MYSQL:
            info = "MySQL: ";
            break;
        case DB_SQLITE:
            info = "SQLite: ";
            break;
        default:
            info = "Database type was not recognized";
        }

        info += db->getDatabaseName();

        ui->databaseInfo->setText(info);

        int questions = dbSetup.getQuestions().size();

        ui->databaseQuestions->setText(questions == 1 ? "1 question" : QString::number(questions) + " questions");

        ui->start->setEnabled(true);

        matchMaker.dbSetup = dbSetup;
        matchMaker.db.swap(db);
    }

    disconnect(dialog, SIGNAL(finished(bool, QScopedPointer<Database>&, DatabaseSetup&)), this, SLOT(databaseDialogFinished(bool, QScopedPointer<Database>&, DatabaseSetup&)));

    dialog = nullptr;
}

void MainWindow::pdfFileSelected(const QString &file){
    if(!file.isNull()){
        ui->pdfInfo->setText(file);
    }

    disconnect(pdfDialog, SIGNAL(rejected()), this, SLOT(pdfFileCancelled()));

    pdfDialog = nullptr;
}

void MainWindow::pdfFileCancelled(){
    disconnect(pdfDialog, SIGNAL(rejected()), this, SLOT(pdfFileCancelled()));

    pdfDialog = nullptr;
}

void MainWindow::slotShowError(QString error){
    ui->usersProgress->setMaximum(1);
    ui->usersProgress->setValue(0);
    ui->usersInfo->setText("Failed");

    QMessageBox::warning(
                this,
                tr("Failed to Load Users"),
                tr("An error occured when trying to load users from the database:\n\n") + error,
                QMessageBox::Ok
    );
}

void MainWindow::slotUsersLoaded(){
    ui->stop->setEnabled(true);

    ui->usersProgress->setMaximum(1);
    ui->usersProgress->setValue(1);
    ui->usersInfo->setText("Done");

    ui->maleProgress->setMaximum(static_cast<int>(matchMaker.male.size()));
    ui->femaleProgress->setMaximum(static_cast<int>(matchMaker.female.size()));
    ui->totalProgress->setMaximum(ui->maleProgress->maximum() + ui->femaleProgress->maximum());
    ui->printingProgress->setMaximum(ui->totalProgress->maximum());

    ui->maleInfo->setText("0/" + QString::number(ui->maleProgress->maximum()));
    ui->femaleInfo->setText("0/" + QString::number(ui->femaleProgress->maximum()));
    ui->totalInfo->setText("0/" + QString::number(ui->totalProgress->maximum()));
    ui->printingInfo->setText(ui->totalInfo->text());

    MathVec max(std::vector<float>(matchMaker.dbSetup.getQuestions().size(), static_cast<float>(ui->rangeSpinBox->value())));
    float mag = max.getMagnitude() + 3; // + 3 because grades are considered questions too

    maleEngine = new MatchEngine(&matchMaker.male, &matchMaker.female, ui->matchAmountSpinner->value(), mag);
    maleEngine->moveToThread(maleThread);

    femaleEngine = new MatchEngine(&matchMaker.female, &matchMaker.male, ui->matchAmountSpinner->value(), mag);
    femaleEngine->moveToThread(femaleThread);

    connect(maleEngine, SIGNAL(progress(int)), this, SLOT(maleProgress(int)));
    connect(maleEngine, SIGNAL(done()), this, SLOT(maleDone()));
    connect(femaleEngine, SIGNAL(progress(int)), this, SLOT(femaleProgress(int)));
    connect(femaleEngine, SIGNAL(done()), this, SLOT(femaleDone()));

    emit maleEngine->pleaseSetup();
    emit femaleEngine->pleaseSetup();

    emit maleEngine->pleaseStartMatching();
    emit femaleEngine->pleaseStartMatching();
}

void MainWindow::maleProgress(int complete){
    ui->maleProgress->setValue(complete);
    ui->maleInfo->setText(QString::number(complete) + "/" + QString::number(ui->maleProgress->maximum()));

    complete += ui->femaleProgress->value();
    ui->totalProgress->setValue(complete);
    ui->totalInfo->setText(QString::number(complete) + "/" + QString::number(ui->totalProgress->maximum()));
}

void MainWindow::femaleProgress(int complete){
    ui->femaleProgress->setValue(complete);
    ui->femaleInfo->setText(QString::number(complete) + "/" + QString::number(ui->femaleProgress->maximum()));

    complete += ui->maleProgress->value();
    ui->totalProgress->setValue(complete);
    ui->totalInfo->setText(QString::number(complete) + "/" + QString::number(ui->totalProgress->maximum()));
}

void MainWindow::printingProgress(int complete){
    ui->printingProgress->setValue(complete);
    ui->printingInfo->setText(QString::number(complete) + "/" + QString::number(ui->printingProgress->maximum()));
}

void MainWindow::maleDone(){
    isMaleDone = true;

    if(isFemaleDone){
        printToPdf();
    }
}

void MainWindow::femaleDone(){
    isFemaleDone = true;

    if(isMaleDone){
        printToPdf();
    }
}

void MainWindow::printingDone(){
    ui->stop->setEnabled(false);
    ui->clear->setEnabled(true);
}
<commit_msg>Fixed incorrect magnitude calculation<commit_after>/* Copyright (c) 2014 Jason Paulos
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

#include <QMessageBox>
#include <QFileDialog>
#include <QFileInfo>
#include <QSqlError>
#include <QPainter>
#include "MainWindow.h"
#include "ui_MainWindow.h"
#include "DatabaseDialog.h"

MainWindow::MainWindow(QWidget *parent):
    QMainWindow(parent),
    ui(new Ui::MainWindow()),
    partialStop(false),
    isMaleDone(false),
    isFemaleDone(false),
    maleEngine(nullptr),
    femaleEngine(nullptr),
    printEngine(nullptr),
    maleThread(new QThread()),
    femaleThread(new QThread()),
    dialog(nullptr),
    pdfDialog(nullptr)
{
    ui->setupUi(this);
    ui->pdfInfo->setText(QDir::homePath() + "/matches.pdf");

    connect(this, SIGNAL(signalShowError(QString)), this, SLOT(slotShowError(QString)));
    connect(this, SIGNAL(signalUsersLoaded()), this, SLOT(slotUsersLoaded()));

    MatchMaker::instance = &matchMaker;

    maleThread->start();
    femaleThread->start();
}

MainWindow::~MainWindow(){
    maleThread->quit();
    femaleThread->quit();

    maleThread->deleteLater();
    femaleThread->deleteLater();

    if(maleEngine){
        maleEngine->deleteLater();
    }

    if(femaleEngine){
        femaleEngine->deleteLater();
    }

    if(printEngine){
        printEngine->deleteLater();
    }

    delete dialog;
    delete pdfDialog;
}

QString MainWindow::getPdfSavePath(){
    return ui->pdfInfo->text();
}

QString MainWindow::getPdfPageTitle(){
    return ui->titleEdit->text();
}

void MainWindow::printToPdf(){
    printEngine = new PrintEngine(this);

    //We'll reuse femaleThead to host printEngine
    printEngine->moveToThread(femaleThread);

    connect(printEngine, SIGNAL(progress(int)), this, SLOT(printingProgress(int)));
    connect(printEngine, SIGNAL(done()), this, SLOT(printingDone()));

    emit printEngine->pleaseSetup();
    emit printEngine->pleaseStartPrinting();
}

void MainWindow::userQuery(QSqlQuery *query, Gender gen, std::vector<User> &users){
    if(query->exec()){
        unsigned int dimensions = matchMaker.dbSetup.getQuestions().size() + matchMaker.dbSetup.hasGrade();
        bool hasFirst = matchMaker.dbSetup.hasFirstName(), hasMiddle = matchMaker.dbSetup.hasMiddleName(), hasLast = matchMaker.dbSetup.hasLastName();

        while(query->next()){
            int i = 0;
            QString first(hasFirst ? query->value(i++).toString() : ""), middle(hasMiddle ? query->value(i++).toString(): ""), last(hasLast ? query->value(i++).toString() : "");

            User user(
                        first + (middle.isEmpty() ? "" : " ") +
                        middle + (last.isEmpty() ? "" : " ") +
                        last,
                        gen,
                        dimensions
            );

            for(unsigned int a = 0; a < dimensions; ++a){
                user.answers.elements[a] = query->value(i++).toInt();//TODO: check for error?
            }

            users.push_back(user);
        }

    }else{
        emit signalShowError(query->lastError().text());
    }
}

void MainWindow::on_selectDatabase_clicked(){
    if(!dialog && !pdfDialog){
        dialog = new DatabaseDialog(this);

        connect(dialog, SIGNAL(finished(bool, QScopedPointer<Database>&, DatabaseSetup&)), this, SLOT(databaseDialogFinished(bool, QScopedPointer<Database>&, DatabaseSetup&)));

        dialog->show();
    }
}

void MainWindow::on_start_clicked(){
    ui->start->setEnabled(false);
    ui->stop->setEnabled(false);
    ui->clear->setEnabled(false);

    //TODO: check that the pdf file is a valid file name

    if(partialStop){
        if(!isMaleDone){
            emit maleEngine->pleaseStartMatching();
        }

        if(!isFemaleDone){
            emit femaleEngine->pleaseStartMatching();
        }

        if(isMaleDone && isFemaleDone){
            emit printEngine->pleaseStartPrinting();
        }
    }else{
        isMaleDone = isFemaleDone = false;

        ui->inputGroup->setEnabled(false);
        ui->outputGroup->setEnabled(false);

        ui->usersProgress->setMaximum(0);
        ui->usersProgress->setValue(-1);
        ui->usersInfo->setText("Loading...");

        QString query("SELECT " +
                      (matchMaker.dbSetup.hasFirstName() ? matchMaker.dbSetup.getFirstName() + ", " : "") +
                      (matchMaker.dbSetup.hasMiddleName() ? matchMaker.dbSetup.getMiddleName() + ", " : "") +
                      (matchMaker.dbSetup.hasLastName() ? matchMaker.dbSetup.getLastName() + ", " : "") +
                      (matchMaker.dbSetup.hasGrade() ? matchMaker.dbSetup.getGrade() + ", " : "")
        );

        const QStringList &questions(matchMaker.dbSetup.getQuestions());

        for(auto i = questions.begin(); i != questions.end(); ++i){
            query += *i + (questions.endsWith(*i) ? " ": ", ");
        }

        query += "FROM " + matchMaker.dbSetup.getTable() + " WHERE ";

        matchMaker.dbManager->queryConnection(CONNECTION, query + matchMaker.dbSetup.getGender() + " = " + QString::number(Gender::MALE),
        [this, query](QSqlQuery *maleQuery){
            userQuery(maleQuery, Gender::MALE, matchMaker.male);

            matchMaker.dbManager->queryConnection(CONNECTION, query + matchMaker.dbSetup.getGender() + " = " + QString::number(Gender::FEMALE),
            [this](QSqlQuery *femaleQuery){
                userQuery(femaleQuery, Gender::FEMALE, matchMaker.female);

                emit signalUsersLoaded();
            });
        });
    }
}

void MainWindow::on_stop_clicked(){
    partialStop = true;

    ui->start->setEnabled(true);
    ui->stop->setEnabled(false);
    ui->clear->setEnabled(true);

    if(!isMaleDone){
        emit maleEngine->pleaseStopMatching();
    }

    if(!isFemaleDone){
        emit femaleEngine->pleaseStopMatching();
    }

    if(isMaleDone && isFemaleDone){
        emit printEngine->pleaseStartPrinting();
    }
}

void MainWindow::on_clear_clicked(){
    partialStop = false;

    ui->start->setEnabled(true);
    ui->clear->setEnabled(false);

    ui->inputGroup->setEnabled(true);
    ui->outputGroup->setEnabled(true);

    ui->usersProgress->setMaximum(1);
    ui->usersProgress->setValue(0);
    ui->usersInfo->setText("");

    ui->maleProgress->setMaximum(1);
    ui->maleProgress->setValue(0);
    ui->maleInfo->setText("0/0");

    ui->femaleProgress->setMaximum(1);
    ui->femaleProgress->setValue(0);
    ui->femaleInfo->setText("0/0");

    ui->totalProgress->setMaximum(1);
    ui->totalProgress->setValue(0);
    ui->totalInfo->setText("0/0");

    ui->printingProgress->setMaximum(1);
    ui->printingProgress->setValue(0);
    ui->printingInfo->setText("0/0");

    matchMaker.male.clear();
    matchMaker.female.clear();

    if(maleEngine){
        maleEngine->deleteLater();
        maleEngine = nullptr;
    }

    if(femaleEngine){
        femaleEngine->deleteLater();
        femaleEngine = nullptr;
    }

    if(printEngine){
        printEngine->deleteLater();
        printEngine = nullptr;
    }
}

void MainWindow::on_selectPdf_clicked(){
    if(!pdfDialog && !dialog){

        //Qt::Sheet will make the dialog appear as a sheet in Mac OSX
        pdfDialog = new QFileDialog(this, Qt::Sheet);

        pdfDialog->setAcceptMode(QFileDialog::AcceptSave);
        //pdfDialog->setWindowModality(Qt::WindowModal);

        pdfDialog->setWindowTitle(tr("Save matches"));
        pdfDialog->setDirectory(QDir::homePath());
        pdfDialog->setNameFilter(tr("PDF (*.pdf);; All Files (*)"));

        pdfDialog->open(this, SLOT(pdfFileSelected(QString)));
        connect(pdfDialog, SIGNAL(rejected()), this, SLOT(pdfFileCancelled()));

        pdfDialog->show();
    }
}

void MainWindow::databaseDialogFinished(bool success, QScopedPointer<Database> &db, DatabaseSetup &dbSetup){
    if(success){
        QString info;

        switch(db->getType()){
        case DB_MYSQL:
            info = "MySQL: ";
            break;
        case DB_SQLITE:
            info = "SQLite: ";
            break;
        default:
            info = "Database type was not recognized";
        }

        info += db->getDatabaseName();

        ui->databaseInfo->setText(info);

        int questions = dbSetup.getQuestions().size();

        ui->databaseQuestions->setText(questions == 1 ? "1 question" : QString::number(questions) + " questions");

        ui->start->setEnabled(true);

        matchMaker.dbSetup = dbSetup;
        matchMaker.db.swap(db);
    }

    disconnect(dialog, SIGNAL(finished(bool, QScopedPointer<Database>&, DatabaseSetup&)), this, SLOT(databaseDialogFinished(bool, QScopedPointer<Database>&, DatabaseSetup&)));

    dialog = nullptr;
}

void MainWindow::pdfFileSelected(const QString &file){
    if(!file.isNull()){
        ui->pdfInfo->setText(file);
    }

    disconnect(pdfDialog, SIGNAL(rejected()), this, SLOT(pdfFileCancelled()));

    pdfDialog = nullptr;
}

void MainWindow::pdfFileCancelled(){
    disconnect(pdfDialog, SIGNAL(rejected()), this, SLOT(pdfFileCancelled()));

    pdfDialog = nullptr;
}

void MainWindow::slotShowError(QString error){
    ui->usersProgress->setMaximum(1);
    ui->usersProgress->setValue(0);
    ui->usersInfo->setText("Failed");

    QMessageBox::warning(
                this,
                tr("Failed to Load Users"),
                tr("An error occured when trying to load users from the database:\n\n") + error,
                QMessageBox::Ok
    );
}

void MainWindow::slotUsersLoaded(){
    ui->stop->setEnabled(true);

    ui->usersProgress->setMaximum(1);
    ui->usersProgress->setValue(1);
    ui->usersInfo->setText("Done");

    ui->maleProgress->setMaximum(static_cast<int>(matchMaker.male.size()));
    ui->femaleProgress->setMaximum(static_cast<int>(matchMaker.female.size()));
    ui->totalProgress->setMaximum(ui->maleProgress->maximum() + ui->femaleProgress->maximum());
    ui->printingProgress->setMaximum(ui->totalProgress->maximum());

    ui->maleInfo->setText("0/" + QString::number(ui->maleProgress->maximum()));
    ui->femaleInfo->setText("0/" + QString::number(ui->femaleProgress->maximum()));
    ui->totalInfo->setText("0/" + QString::number(ui->totalProgress->maximum()));
    ui->printingInfo->setText(ui->totalInfo->text());

    MathVec max(std::vector<float>(matchMaker.dbSetup.getQuestions().size() + 1, static_cast<float>(ui->rangeSpinBox->value())));
    max.elements.back() = 3.0F; //3 because one "question" is grade level
    float mag = max.getMagnitude();

    maleEngine = new MatchEngine(&matchMaker.male, &matchMaker.female, ui->matchAmountSpinner->value(), mag);
    maleEngine->moveToThread(maleThread);

    femaleEngine = new MatchEngine(&matchMaker.female, &matchMaker.male, ui->matchAmountSpinner->value(), mag);
    femaleEngine->moveToThread(femaleThread);

    connect(maleEngine, SIGNAL(progress(int)), this, SLOT(maleProgress(int)));
    connect(maleEngine, SIGNAL(done()), this, SLOT(maleDone()));
    connect(femaleEngine, SIGNAL(progress(int)), this, SLOT(femaleProgress(int)));
    connect(femaleEngine, SIGNAL(done()), this, SLOT(femaleDone()));

    emit maleEngine->pleaseSetup();
    emit femaleEngine->pleaseSetup();

    emit maleEngine->pleaseStartMatching();
    emit femaleEngine->pleaseStartMatching();
}

void MainWindow::maleProgress(int complete){
    ui->maleProgress->setValue(complete);
    ui->maleInfo->setText(QString::number(complete) + "/" + QString::number(ui->maleProgress->maximum()));

    complete += ui->femaleProgress->value();
    ui->totalProgress->setValue(complete);
    ui->totalInfo->setText(QString::number(complete) + "/" + QString::number(ui->totalProgress->maximum()));
}

void MainWindow::femaleProgress(int complete){
    ui->femaleProgress->setValue(complete);
    ui->femaleInfo->setText(QString::number(complete) + "/" + QString::number(ui->femaleProgress->maximum()));

    complete += ui->maleProgress->value();
    ui->totalProgress->setValue(complete);
    ui->totalInfo->setText(QString::number(complete) + "/" + QString::number(ui->totalProgress->maximum()));
}

void MainWindow::printingProgress(int complete){
    ui->printingProgress->setValue(complete);
    ui->printingInfo->setText(QString::number(complete) + "/" + QString::number(ui->printingProgress->maximum()));
}

void MainWindow::maleDone(){
    isMaleDone = true;

    if(isFemaleDone){
        printToPdf();
    }
}

void MainWindow::femaleDone(){
    isFemaleDone = true;

    if(isMaleDone){
        printToPdf();
    }
}

void MainWindow::printingDone(){
    ui->stop->setEnabled(false);
    ui->clear->setEnabled(true);
}
<|endoftext|>


<commit_before>// Time:  O(m * n)
// Space: O(m)

class Solution {
public:
    /**
     * @param m: An integer m denotes the size of a backpack
     * @param A: Given n items with size A[i]
     * @return: The maximum size
     */
    int backPack(int m, vector<int> A) {
        // table[i][j] denotes whether using the first elements
        // could fulfill size j.
        vector<vector<bool>> table(2, vector<bool>(m + 1, false));
        int max_size = 0;
        table[0][0] = true;

        for (int i = 1; i <= A.size(); ++i) {
            table[i % 2][0] = true;
            for (int j = 1; j <= m; ++j) {
                // If first i - 1 elements could fulfill the backpack, then
                // first i elements would also do.
                table[i % 2][j] = table[(i - 1) % 2][j];

                // Using the ith element to fulfill the backpack.
                if (j >= A[i - 1]) {
                    table[i % 2][j] = table[i % 2][j]
                    || table[(i - 1) % 2][j - A[i - 1]];
                }

                // If it fulfulls size j, update max size.
                if (table[i % 2][j]) {
                    max_size = max(max_size, j);
                }
            }
        }

        return max_size;
    }
};
<commit_msg>Update backpack.cpp<commit_after>// Time:  O(m * n)
// Space: O(m)

class Solution {
public:
    /**
     * @param m: An integer m denotes the size of a backpack
     * @param A: Given n items with size A[i]
     * @return: The maximum size
     */
    int backPack(int m, vector<int> A) {
        // table[i][j] denotes whether using the first elements
        // could fulfill size j.
        vector<vector<bool>> table(2, vector<bool>(m + 1, false));
        int max_size = 0;
        table[0][0] = true;

        for (int i = 1; i <= A.size(); ++i) {
            table[i % 2][0] = true;
            for (int j = 1; j <= m; ++j) {
                // If first i - 1 elements could fulfill the backpack, then
                // first i elements would also do.
                table[i % 2][j] = table[(i - 1) % 2][j];

                // Using the ith element to fulfill the backpack.
                if (j >= A[i - 1]) {
                    table[i % 2][j] = table[i % 2][j]
                    || table[(i - 1) % 2][j - A[i - 1]];
                }

                // If it fullfills size j, update max size.
                if (table[i % 2][j]) {
                    max_size = max(max_size, j);
                }
            }
        }

        return max_size;
    }
};
<|endoftext|>


<commit_before>/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * This file incorporates work covered by the following license notice:
 *
 *   Licensed to the Apache Software Foundation (ASF) under one or more
 *   contributor license agreements. See the NOTICE file distributed
 *   with this work for additional information regarding copyright
 *   ownership. The ASF licenses this file to you under the Apache
 *   License, Version 2.0 (the "License"); you may not use this file
 *   except in compliance with the License. You may obtain a copy of
 *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
 */

#include "WrappedResultSet.hxx"
#include "core_resource.hxx"
#include "core_resource.hrc"
#include <com/sun/star/sdbc/XResultSetUpdate.hpp>
#include <connectivity/dbexception.hxx>

#include <limits>

using namespace dbaccess;
using namespace ::connectivity;
using namespace ::dbtools;
using namespace ::com::sun::star::uno;
using namespace ::com::sun::star::beans;
using namespace ::com::sun::star::sdbc;
using namespace ::com::sun::star::sdbcx;
using namespace ::com::sun::star::container;
using namespace ::com::sun::star::lang;
using namespace ::osl;

void WrappedResultSet::construct(const Reference< XResultSet>& _xDriverSet,const OUString& i_sRowSetFilter)
{
    SAL_INFO("dbaccess", "WrappedResultSet::construct" );
    OCacheSet::construct(_xDriverSet,i_sRowSetFilter);
    m_xUpd.set(_xDriverSet,UNO_QUERY_THROW);
    m_xRowLocate.set(_xDriverSet,UNO_QUERY_THROW);
    m_xUpdRow.set(_xDriverSet,UNO_QUERY_THROW);
}

Any SAL_CALL WrappedResultSet::getBookmark() throw(SQLException, RuntimeException)
{
    SAL_INFO("dbaccess", "WrappedResultSet::getBookmark" );
    if ( m_xRowLocate.is() )
    {
        return m_xRowLocate->getBookmark( );
    }
    return makeAny(m_xDriverSet->getRow());
}

sal_Bool SAL_CALL WrappedResultSet::moveToBookmark( const Any& bookmark ) throw(SQLException, RuntimeException)
{
    SAL_INFO("dbaccess", "WrappedResultSet::moveToBookmark" );
    return m_xRowLocate->moveToBookmark( bookmark );
}

sal_Bool SAL_CALL WrappedResultSet::moveRelativeToBookmark( const Any& bookmark, sal_Int32 rows ) throw(SQLException, RuntimeException)
{
    SAL_INFO("dbaccess", "WrappedResultSet::moveRelativeToBookmark" );
    return m_xRowLocate->moveRelativeToBookmark( bookmark,rows );
}

sal_Int32 SAL_CALL WrappedResultSet::compareBookmarks( const Any& _first, const Any& _second ) throw(SQLException, RuntimeException)
{
    SAL_INFO("dbaccess", "WrappedResultSet::compareBookmarks" );
    return m_xRowLocate->compareBookmarks( _first,_second );
}

sal_Bool SAL_CALL WrappedResultSet::hasOrderedBookmarks(  ) throw(SQLException, RuntimeException)
{
    SAL_INFO("dbaccess", "WrappedResultSet::hasOrderedBookmarks" );
    return m_xRowLocate->hasOrderedBookmarks();
}

sal_Int32 SAL_CALL WrappedResultSet::hashBookmark( const Any& bookmark ) throw(SQLException, RuntimeException)
{
    SAL_INFO("dbaccess", "WrappedResultSet::hashBookmark" );
    return m_xRowLocate->hashBookmark(bookmark);
}

// ::com::sun::star::sdbcx::XDeleteRows
Sequence< sal_Int32 > SAL_CALL WrappedResultSet::deleteRows( const Sequence< Any >& rows ,const connectivity::OSQLTable& /*_xTable*/) throw(SQLException, RuntimeException)
{
    SAL_INFO("dbaccess", "WrappedResultSet::deleteRows" );
    Reference< ::com::sun::star::sdbcx::XDeleteRows> xDeleteRow(m_xRowLocate,UNO_QUERY);
    if(xDeleteRow.is())
    {
        return xDeleteRow->deleteRows(rows);
    }
    return Sequence< sal_Int32 >();
}

void SAL_CALL WrappedResultSet::insertRow( const ORowSetRow& _rInsertRow,const connectivity::OSQLTable& /*_xTable*/ ) throw(SQLException, RuntimeException)
{
    SAL_INFO("dbaccess", "WrappedResultSet::insertRow" );

    m_xUpd->moveToInsertRow();
    sal_Int32 i = 1;
    connectivity::ORowVector< ORowSetValue > ::Vector::iterator aEnd = _rInsertRow->get().end();
    for(connectivity::ORowVector< ORowSetValue > ::Vector::iterator aIter = _rInsertRow->get().begin()+1;aIter != aEnd;++aIter,++i)
    {
        aIter->setSigned(m_aSignedFlags[i-1]);
        updateColumn(i,m_xUpdRow,*aIter);
    }
    m_xUpd->insertRow();
    (*_rInsertRow->get().begin()) = getBookmark();
}

void SAL_CALL WrappedResultSet::updateRow(const ORowSetRow& _rInsertRow ,const ORowSetRow& _rOrginalRow,const connectivity::OSQLTable& /*_xTable*/  ) throw(SQLException, RuntimeException)
{
    SAL_INFO("dbaccess", "WrappedResultSet::updateRow" );
    sal_Int32 i = 1;
    connectivity::ORowVector< ORowSetValue > ::Vector::const_iterator aOrgIter = _rOrginalRow->get().begin()+1;
    connectivity::ORowVector< ORowSetValue > ::Vector::iterator aEnd = _rInsertRow->get().end();
    for(connectivity::ORowVector< ORowSetValue > ::Vector::iterator aIter = _rInsertRow->get().begin()+1;aIter != aEnd;++aIter,++i,++aOrgIter)
    {
        aIter->setSigned(aOrgIter->isSigned());
        updateColumn(i,m_xUpdRow,*aIter);
    }
    m_xUpd->updateRow();
}

void SAL_CALL WrappedResultSet::deleteRow(const ORowSetRow& /*_rDeleteRow*/ ,const connectivity::OSQLTable& /*_xTable*/  ) throw(SQLException, RuntimeException)
{
    SAL_INFO("dbaccess", "WrappedResultSet::deleteRow" );
    m_xUpd->deleteRow();
}

void SAL_CALL WrappedResultSet::cancelRowUpdates(  ) throw(SQLException, RuntimeException)
{
    SAL_INFO("dbaccess", "WrappedResultSet::cancelRowUpdates" );
    m_xUpd->cancelRowUpdates();
}

void SAL_CALL WrappedResultSet::moveToInsertRow(  ) throw(SQLException, RuntimeException)
{
    SAL_INFO("dbaccess", "WrappedResultSet::moveToInsertRow" );
    m_xUpd->moveToInsertRow();
}

void SAL_CALL WrappedResultSet::moveToCurrentRow(  ) throw(SQLException, RuntimeException)
{
    SAL_INFO("dbaccess", "WrappedResultSet::moveToCurrentRow" );
    m_xUpd->moveToCurrentRow();
}

void WrappedResultSet::fillValueRow(ORowSetRow& _rRow,sal_Int32 _nPosition)
{
    SAL_INFO("dbaccess", "WrappedResultSet::fillValueRow" );
    OCacheSet::fillValueRow(_rRow,_nPosition);
}

void WrappedResultSet::updateColumn(sal_Int32 nPos,Reference< XRowUpdate > _xParameter,const ORowSetValue& _rValue)
{
    SAL_INFO("dbaccess", "WrappedResultSet::updateColumn" );
    if(_rValue.isBound() && _rValue.isModified())
    {
        if(_rValue.isNull())
            _xParameter->updateNull(nPos);
        else
        {

            switch(_rValue.getTypeKind())
            {
                case DataType::DECIMAL:
                case DataType::NUMERIC:
                    _xParameter->updateNumericObject(nPos,_rValue.makeAny(),m_xSetMetaData->getScale(nPos));
                    break;
                case DataType::CHAR:
                case DataType::VARCHAR:
                    _xParameter->updateString(nPos,_rValue);
                    break;
                case DataType::BIGINT:
                    if ( _rValue.isSigned() )
                        _xParameter->updateLong(nPos,_rValue);
                    else
                        _xParameter->updateString(nPos,_rValue);
                    break;
                case DataType::BIT:
                case DataType::BOOLEAN:
                    _xParameter->updateBoolean(nPos,_rValue);
                    break;
                case DataType::TINYINT:
                    if ( _rValue.isSigned() )
                        _xParameter->updateByte(nPos,_rValue);
                    else
                        _xParameter->updateShort(nPos,_rValue);
                    break;
                case DataType::SMALLINT:
                    if ( _rValue.isSigned() )
                        _xParameter->updateShort(nPos,_rValue);
                    else
                        _xParameter->updateInt(nPos,_rValue);
                    break;
                case DataType::INTEGER:
                    if ( _rValue.isSigned() )
                        _xParameter->updateInt(nPos,_rValue);
                    else
                        _xParameter->updateLong(nPos,_rValue);
                    break;
                case DataType::FLOAT:
                    _xParameter->updateFloat(nPos,_rValue);
                    break;
                case DataType::DOUBLE:
                case DataType::REAL:
                    _xParameter->updateDouble(nPos,_rValue);
                    break;
                case DataType::DATE:
                    _xParameter->updateDate(nPos,_rValue);
                    break;
                case DataType::TIME:
                    _xParameter->updateTime(nPos,_rValue);
                    break;
                case DataType::TIMESTAMP:
                    _xParameter->updateTimestamp(nPos,_rValue);
                    break;
                case DataType::BINARY:
                case DataType::VARBINARY:
                case DataType::LONGVARBINARY:
                    _xParameter->updateBytes(nPos,_rValue);
                    break;
                case DataType::BLOB:
                case DataType::CLOB:
                    _xParameter->updateObject(nPos,_rValue.getAny());
                    break;
            }
        }
    }
}

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
<commit_msg>make sure value passed to updateBoolean is treated as a boolean<commit_after>/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * This file incorporates work covered by the following license notice:
 *
 *   Licensed to the Apache Software Foundation (ASF) under one or more
 *   contributor license agreements. See the NOTICE file distributed
 *   with this work for additional information regarding copyright
 *   ownership. The ASF licenses this file to you under the Apache
 *   License, Version 2.0 (the "License"); you may not use this file
 *   except in compliance with the License. You may obtain a copy of
 *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
 */

#include "WrappedResultSet.hxx"
#include "core_resource.hxx"
#include "core_resource.hrc"
#include <com/sun/star/sdbc/XResultSetUpdate.hpp>
#include <connectivity/dbexception.hxx>

#include <limits>

using namespace dbaccess;
using namespace ::connectivity;
using namespace ::dbtools;
using namespace ::com::sun::star::uno;
using namespace ::com::sun::star::beans;
using namespace ::com::sun::star::sdbc;
using namespace ::com::sun::star::sdbcx;
using namespace ::com::sun::star::container;
using namespace ::com::sun::star::lang;
using namespace ::osl;

void WrappedResultSet::construct(const Reference< XResultSet>& _xDriverSet,const OUString& i_sRowSetFilter)
{
    SAL_INFO("dbaccess", "WrappedResultSet::construct" );
    OCacheSet::construct(_xDriverSet,i_sRowSetFilter);
    m_xUpd.set(_xDriverSet,UNO_QUERY_THROW);
    m_xRowLocate.set(_xDriverSet,UNO_QUERY_THROW);
    m_xUpdRow.set(_xDriverSet,UNO_QUERY_THROW);
}

Any SAL_CALL WrappedResultSet::getBookmark() throw(SQLException, RuntimeException)
{
    SAL_INFO("dbaccess", "WrappedResultSet::getBookmark" );
    if ( m_xRowLocate.is() )
    {
        return m_xRowLocate->getBookmark( );
    }
    return makeAny(m_xDriverSet->getRow());
}

sal_Bool SAL_CALL WrappedResultSet::moveToBookmark( const Any& bookmark ) throw(SQLException, RuntimeException)
{
    SAL_INFO("dbaccess", "WrappedResultSet::moveToBookmark" );
    return m_xRowLocate->moveToBookmark( bookmark );
}

sal_Bool SAL_CALL WrappedResultSet::moveRelativeToBookmark( const Any& bookmark, sal_Int32 rows ) throw(SQLException, RuntimeException)
{
    SAL_INFO("dbaccess", "WrappedResultSet::moveRelativeToBookmark" );
    return m_xRowLocate->moveRelativeToBookmark( bookmark,rows );
}

sal_Int32 SAL_CALL WrappedResultSet::compareBookmarks( const Any& _first, const Any& _second ) throw(SQLException, RuntimeException)
{
    SAL_INFO("dbaccess", "WrappedResultSet::compareBookmarks" );
    return m_xRowLocate->compareBookmarks( _first,_second );
}

sal_Bool SAL_CALL WrappedResultSet::hasOrderedBookmarks(  ) throw(SQLException, RuntimeException)
{
    SAL_INFO("dbaccess", "WrappedResultSet::hasOrderedBookmarks" );
    return m_xRowLocate->hasOrderedBookmarks();
}

sal_Int32 SAL_CALL WrappedResultSet::hashBookmark( const Any& bookmark ) throw(SQLException, RuntimeException)
{
    SAL_INFO("dbaccess", "WrappedResultSet::hashBookmark" );
    return m_xRowLocate->hashBookmark(bookmark);
}

// ::com::sun::star::sdbcx::XDeleteRows
Sequence< sal_Int32 > SAL_CALL WrappedResultSet::deleteRows( const Sequence< Any >& rows ,const connectivity::OSQLTable& /*_xTable*/) throw(SQLException, RuntimeException)
{
    SAL_INFO("dbaccess", "WrappedResultSet::deleteRows" );
    Reference< ::com::sun::star::sdbcx::XDeleteRows> xDeleteRow(m_xRowLocate,UNO_QUERY);
    if(xDeleteRow.is())
    {
        return xDeleteRow->deleteRows(rows);
    }
    return Sequence< sal_Int32 >();
}

void SAL_CALL WrappedResultSet::insertRow( const ORowSetRow& _rInsertRow,const connectivity::OSQLTable& /*_xTable*/ ) throw(SQLException, RuntimeException)
{
    SAL_INFO("dbaccess", "WrappedResultSet::insertRow" );

    m_xUpd->moveToInsertRow();
    sal_Int32 i = 1;
    connectivity::ORowVector< ORowSetValue > ::Vector::iterator aEnd = _rInsertRow->get().end();
    for(connectivity::ORowVector< ORowSetValue > ::Vector::iterator aIter = _rInsertRow->get().begin()+1;aIter != aEnd;++aIter,++i)
    {
        aIter->setSigned(m_aSignedFlags[i-1]);
        updateColumn(i,m_xUpdRow,*aIter);
    }
    m_xUpd->insertRow();
    (*_rInsertRow->get().begin()) = getBookmark();
}

void SAL_CALL WrappedResultSet::updateRow(const ORowSetRow& _rInsertRow ,const ORowSetRow& _rOrginalRow,const connectivity::OSQLTable& /*_xTable*/  ) throw(SQLException, RuntimeException)
{
    SAL_INFO("dbaccess", "WrappedResultSet::updateRow" );
    sal_Int32 i = 1;
    connectivity::ORowVector< ORowSetValue > ::Vector::const_iterator aOrgIter = _rOrginalRow->get().begin()+1;
    connectivity::ORowVector< ORowSetValue > ::Vector::iterator aEnd = _rInsertRow->get().end();
    for(connectivity::ORowVector< ORowSetValue > ::Vector::iterator aIter = _rInsertRow->get().begin()+1;aIter != aEnd;++aIter,++i,++aOrgIter)
    {
        aIter->setSigned(aOrgIter->isSigned());
        updateColumn(i,m_xUpdRow,*aIter);
    }
    m_xUpd->updateRow();
}

void SAL_CALL WrappedResultSet::deleteRow(const ORowSetRow& /*_rDeleteRow*/ ,const connectivity::OSQLTable& /*_xTable*/  ) throw(SQLException, RuntimeException)
{
    SAL_INFO("dbaccess", "WrappedResultSet::deleteRow" );
    m_xUpd->deleteRow();
}

void SAL_CALL WrappedResultSet::cancelRowUpdates(  ) throw(SQLException, RuntimeException)
{
    SAL_INFO("dbaccess", "WrappedResultSet::cancelRowUpdates" );
    m_xUpd->cancelRowUpdates();
}

void SAL_CALL WrappedResultSet::moveToInsertRow(  ) throw(SQLException, RuntimeException)
{
    SAL_INFO("dbaccess", "WrappedResultSet::moveToInsertRow" );
    m_xUpd->moveToInsertRow();
}

void SAL_CALL WrappedResultSet::moveToCurrentRow(  ) throw(SQLException, RuntimeException)
{
    SAL_INFO("dbaccess", "WrappedResultSet::moveToCurrentRow" );
    m_xUpd->moveToCurrentRow();
}

void WrappedResultSet::fillValueRow(ORowSetRow& _rRow,sal_Int32 _nPosition)
{
    SAL_INFO("dbaccess", "WrappedResultSet::fillValueRow" );
    OCacheSet::fillValueRow(_rRow,_nPosition);
}

void WrappedResultSet::updateColumn(sal_Int32 nPos,Reference< XRowUpdate > _xParameter,const ORowSetValue& _rValue)
{
    SAL_INFO("dbaccess", "WrappedResultSet::updateColumn" );
    if(_rValue.isBound() && _rValue.isModified())
    {
        if(_rValue.isNull())
            _xParameter->updateNull(nPos);
        else
        {

            switch(_rValue.getTypeKind())
            {
                case DataType::DECIMAL:
                case DataType::NUMERIC:
                    _xParameter->updateNumericObject(nPos,_rValue.makeAny(),m_xSetMetaData->getScale(nPos));
                    break;
                case DataType::CHAR:
                case DataType::VARCHAR:
                    _xParameter->updateString(nPos,_rValue);
                    break;
                case DataType::BIGINT:
                    if ( _rValue.isSigned() )
                        _xParameter->updateLong(nPos,_rValue);
                    else
                        _xParameter->updateString(nPos,_rValue);
                    break;
                case DataType::BIT:
                case DataType::BOOLEAN:
                    _xParameter->updateBoolean(nPos,static_cast<bool>(_rValue));
                    break;
                case DataType::TINYINT:
                    if ( _rValue.isSigned() )
                        _xParameter->updateByte(nPos,_rValue);
                    else
                        _xParameter->updateShort(nPos,_rValue);
                    break;
                case DataType::SMALLINT:
                    if ( _rValue.isSigned() )
                        _xParameter->updateShort(nPos,_rValue);
                    else
                        _xParameter->updateInt(nPos,_rValue);
                    break;
                case DataType::INTEGER:
                    if ( _rValue.isSigned() )
                        _xParameter->updateInt(nPos,_rValue);
                    else
                        _xParameter->updateLong(nPos,_rValue);
                    break;
                case DataType::FLOAT:
                    _xParameter->updateFloat(nPos,_rValue);
                    break;
                case DataType::DOUBLE:
                case DataType::REAL:
                    _xParameter->updateDouble(nPos,_rValue);
                    break;
                case DataType::DATE:
                    _xParameter->updateDate(nPos,_rValue);
                    break;
                case DataType::TIME:
                    _xParameter->updateTime(nPos,_rValue);
                    break;
                case DataType::TIMESTAMP:
                    _xParameter->updateTimestamp(nPos,_rValue);
                    break;
                case DataType::BINARY:
                case DataType::VARBINARY:
                case DataType::LONGVARBINARY:
                    _xParameter->updateBytes(nPos,_rValue);
                    break;
                case DataType::BLOB:
                case DataType::CLOB:
                    _xParameter->updateObject(nPos,_rValue.getAny());
                    break;
            }
        }
    }
}

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
<|endoftext|>


<commit_before>#include "Runtime/Weapon/CFlameThrower.hpp"

#include "Runtime/CSimplePool.hpp"
#include "Runtime/CStateManager.hpp"
#include "Runtime/GameGlobalObjects.hpp"
#include "Runtime/Collision/CInternalRayCastStructure.hpp"
#include "Runtime/Graphics/CBooRenderer.hpp"
#include "Runtime/Particle/CElementGen.hpp"
#include "Runtime/Weapon/CFlameInfo.hpp"
#include "Runtime/Weapon/CFlameThrower.hpp"
#include "Runtime/World/CGameLight.hpp"
#include "Runtime/World/CPlayer.hpp"

#include "TCastTo.hpp" // Generated file, do not modify include path

namespace urde {
const zeus::CVector3f CFlameThrower::kLightOffset(0, 3.f, 2.f);

CFlameThrower::CFlameThrower(const TToken<CWeaponDescription>& wDesc, std::string_view name, EWeaponType wType,
                             const CFlameInfo& flameInfo, const zeus::CTransform& xf, EMaterialTypes matType,
                             const CDamageInfo& dInfo, TUniqueId uid, TAreaId aId, TUniqueId owner,
                             EProjectileAttrib attribs, CAssetId playerSteamTxtr, s16 playerHitSfx,
                             CAssetId playerIceTxtr)
: CGameProjectile(false, wDesc, name, wType, xf, matType, dInfo, uid, aId, owner, kInvalidUniqueId, attribs, false,
                  zeus::CVector3f(1.f), {}, -1, false)
, x2e8_flameXf(xf)
, x338_(flameInfo.x10_)
, x33c_flameDesc(g_SimplePool->GetObj({FOURCC('PART'), flameInfo.GetFlameFxId()}))
, x348_flameGen(std::make_unique<CElementGen>(x33c_flameDesc))
, x34c_flameWarp(176.f - float(flameInfo.GetLength()), xf.origin, bool(flameInfo.GetAttributes() & 0x4))
, x3f4_playerSteamTxtr(playerSteamTxtr)
, x3f8_playerHitSfx(playerHitSfx)
, x3fc_playerIceTxtr(playerIceTxtr)
, x400_24_active(false)
, x400_25_particlesActive(false)
, x400_26_(!(flameInfo.GetAttributes() & 1))
, x400_27_coneCollision((flameInfo.GetAttributes() & 0x2) != 0) {

}

void CFlameThrower::Accept(IVisitor& visitor) { visitor.Visit(this); }

void CFlameThrower::AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId uid, CStateManager& mgr) {
  if (msg == EScriptObjectMessage::Registered) {
    xe6_27_thermalVisorFlags |= 2;
    mgr.AddWeaponId(xec_ownerId, xf0_weaponType);
  } else if (msg == EScriptObjectMessage::Deleted) {
    mgr.RemoveWeaponId(xec_ownerId, xf0_weaponType);
    DeleteProjectileLight(mgr);
  }

  CGameProjectile::AcceptScriptMsg(msg, uid, mgr);
}

void CFlameThrower::SetTransform(const zeus::CTransform& xf, float) { x2e8_flameXf = xf; }

void CFlameThrower::Reset(CStateManager& mgr, bool resetWarp) {
  SetFlameLightActive(mgr, false);
  if (resetWarp) {
    SetActive(false);
    x400_25_particlesActive = false;
    x3f0_flameState = EFlameState::Default;
    x330_particleWaitDelayTimer = 0.f;
    x334_fireStopTimer = 0.f;
    x318_flameBounds = zeus::skNullBox;
    x348_flameGen->SetParticleEmission(false);
    x34c_flameWarp.ResetPosition(x2e8_flameXf.origin);
  } else {
    x348_flameGen->SetParticleEmission(false);
    x400_25_particlesActive = false;
    x3f0_flameState = EFlameState::FireStopTimer;
  }
}

void CFlameThrower::Fire(const zeus::CTransform&, CStateManager& mgr, bool) {
  SetActive(true);
  x400_25_particlesActive = true;
  x400_24_active = true;
  x3f0_flameState = EFlameState::FireStart;
  CreateFlameParticles(mgr);
}

void CFlameThrower::CreateFlameParticles(CStateManager& mgr) {
  DeleteProjectileLight(mgr);
  x348_flameGen = std::make_unique<CElementGen>(x33c_flameDesc);
  x348_flameGen->SetParticleEmission(true);
  x348_flameGen->SetZTest(x400_27_coneCollision);
  x348_flameGen->AddModifier(&x34c_flameWarp);
  if (x348_flameGen->SystemHasLight() && x2c8_projectileLight == kInvalidUniqueId)
    CreateProjectileLight("FlameThrower_Light"sv, x348_flameGen->GetLight(), mgr);
}

void CFlameThrower::AddToRenderer(const zeus::CFrustum&, const CStateManager& mgr) const {
  g_Renderer->AddParticleGen(*x348_flameGen);
  EnsureRendered(mgr, x2e8_flameXf.origin, GetRenderBounds());
}

void CFlameThrower::Render(const CStateManager&) const {}

std::optional<zeus::CAABox> CFlameThrower::GetTouchBounds() const { return std::nullopt; }

void CFlameThrower::Touch(CActor&, CStateManager&) {}

void CFlameThrower::SetFlameLightActive(CStateManager& mgr, bool active) {
  if (x2c8_projectileLight == kInvalidUniqueId)
    return;

  if (TCastToPtr<CGameLight> light = mgr.ObjectById(x2c8_projectileLight))
    light->SetActive(active);
}

void CFlameThrower::UpdateFlameState(float dt, CStateManager& mgr) {
  switch(x3f0_flameState) {
  case EFlameState::FireStart:
    x3f0_flameState = EFlameState::FireActive;
    break;
  case EFlameState::FireStopTimer:
    x334_fireStopTimer += 4.f * dt;
    if (x334_fireStopTimer > 1.f) {
      x334_fireStopTimer = 1.f;
      x3f0_flameState = EFlameState::FireWaitForParticlesDone;
      x400_24_active = false;
    }
    break;
  case EFlameState::FireWaitForParticlesDone:
    x330_particleWaitDelayTimer += dt;
    if (x330_particleWaitDelayTimer > 0.1f && x348_flameGen && x348_flameGen->GetParticleCountAll() == 0) {
      x3f0_flameState = EFlameState::Default;
      Reset(mgr, true);
    }
    break;
  default:
    break;
  }
}

CRayCastResult CFlameThrower::DoCollisionCheck(TUniqueId& idOut, const zeus::CAABox& aabb, CStateManager& mgr) {
  CRayCastResult ret;
  rstl::reserved_vector<TUniqueId, 1024> nearList;
  mgr.BuildNearList(nearList, aabb, CMaterialFilter::skPassEverything, this);
  const auto& colPoints = x34c_flameWarp.GetCollisionPoints();
  if (x400_27_coneCollision && colPoints.size() > 0) {
    float radiusPitch = (x34c_flameWarp.GetMaxSize() - x34c_flameWarp.GetMinSize()) /
        float(colPoints.size()) * 0.5f;
    float curRadius = radiusPitch;
    for (int i = 1; i < colPoints.size(); ++i) {
      zeus::CVector3f delta = colPoints[i] - colPoints[i - 1];
      zeus::CTransform lookXf = zeus::lookAt(colPoints[i - 1], colPoints[i]);
      lookXf.origin = delta * 0.5f + colPoints[i - 1];
      zeus::COBBox obb(lookXf, {curRadius, delta.magnitude() * 0.5f, curRadius});
      for (TUniqueId id : nearList) {
        if (CActor* act = static_cast<CActor*>(mgr.ObjectById(id))) {
          CProjectileTouchResult tres = CanCollideWith(*act, mgr);
          if (tres.GetActorId() == kInvalidUniqueId)
            continue;
          auto tb = act->GetTouchBounds();
          if (!tb)
            continue;
          if (obb.AABoxIntersectsBox(*tb)) {
            CCollidableAABox caabb(*tb, act->GetMaterialList());
            zeus::CVector3f flameToAct = act->GetAimPosition(mgr, 0.f) - x2e8_flameXf.origin;
            float flameToActDist = flameToAct.magnitude();
            CInternalRayCastStructure rc(x2e8_flameXf.origin, flameToAct.normalized(), flameToActDist,
                                         {}, CMaterialFilter::skPassEverything);
            CRayCastResult cres = caabb.CastRayInternal(rc);
            if (cres.IsInvalid())
              continue;
            return cres;
          }
        }
      }
      curRadius += radiusPitch;
    }
  } else {
    for (int i = 0; i < colPoints.size() - 1; ++i) {
      zeus::CVector3f delta = colPoints[i + 1] - colPoints[i];
      float deltaMag = delta.magnitude();
      if (deltaMag <= 0.f)
        break;
      CRayCastResult cres = RayCollisionCheckWithWorld(idOut, colPoints[i], colPoints[i + 1], deltaMag, nearList, mgr);
      if (cres.IsValid())
        return cres;
    }
  }
  return ret;
}

void CFlameThrower::ApplyDamageToActor(CStateManager& mgr, TUniqueId id, float dt) {
  if (mgr.GetPlayer().GetUniqueId() == id && x3f4_playerSteamTxtr.IsValid() && x3fc_playerIceTxtr.IsValid())
    mgr.GetPlayer().Freeze(mgr, x3f4_playerSteamTxtr, x3f8_playerHitSfx, x3fc_playerIceTxtr);
  CDamageInfo useDInfo = CDamageInfo(x12c_curDamageInfo, dt);
  ApplyDamageToActors(mgr, useDInfo);
}

void CFlameThrower::Think(float dt, CStateManager& mgr) {
  CWeapon::Think(dt, mgr);
  if (!GetActive())
    return;

  UpdateFlameState(dt, mgr);

  zeus::CVector3f flamePoint = x2e8_flameXf.origin;
  bool r28 = x3f0_flameState == EFlameState::FireActive || x3f0_flameState == EFlameState::FireStopTimer;
  if (r28) {
    x34c_flameWarp.Activate(true);
    x34c_flameWarp.SetWarpPoint(flamePoint);
    x34c_flameWarp.SetStateManager(mgr);
    x348_flameGen->SetTranslation(flamePoint);
    x348_flameGen->SetOrientation(x2e8_flameXf.getRotation());
  } else {
    x34c_flameWarp.Activate(false);
  }

  x348_flameGen->Update(dt);
  x34c_flameWarp.SetMaxDistSq(0.f);
  x34c_flameWarp.SetFloatingPoint(flamePoint);

  if (r28 && x34c_flameWarp.IsProcessed()) {
    x318_flameBounds = x34c_flameWarp.CalculateBounds();
    TUniqueId id = kInvalidUniqueId;
    CRayCastResult res = DoCollisionCheck(id, x318_flameBounds, mgr);
    if (TCastToPtr<CActor> act = mgr.ObjectById(id)) {
      ApplyDamageToActor(mgr, id, dt);
    } else if (res.IsValid()) {
      CMaterialFilter useFilter = xf8_filter;
      CDamageInfo useDInfo = CDamageInfo(x12c_curDamageInfo, dt);
      mgr.ApplyDamageToWorld(xec_ownerId, *this, res.GetPoint(), useDInfo, useFilter);
    }
  }

  CActor::SetTransform(x2e8_flameXf.getRotation());
  CActor::SetTranslation(x2e8_flameXf.origin);

  if (x2c8_projectileLight != kInvalidUniqueId) {
    if (TCastToPtr<CGameLight> light = mgr.ObjectById(x2c8_projectileLight)) {
      light->SetTransform(GetTransform());
      light->SetTranslation(x34c_flameWarp.GetFloatingPoint());
      if (x348_flameGen && x348_flameGen->SystemHasLight())
        light->SetLight(x348_flameGen->GetLight());
    }
  }
}
} // namespace urde
<commit_msg>CFlameThrower: Resolve sign-conversion warnings in DoCollisionCheck()<commit_after>#include "Runtime/Weapon/CFlameThrower.hpp"

#include "Runtime/CSimplePool.hpp"
#include "Runtime/CStateManager.hpp"
#include "Runtime/GameGlobalObjects.hpp"
#include "Runtime/Collision/CInternalRayCastStructure.hpp"
#include "Runtime/Graphics/CBooRenderer.hpp"
#include "Runtime/Particle/CElementGen.hpp"
#include "Runtime/Weapon/CFlameInfo.hpp"
#include "Runtime/Weapon/CFlameThrower.hpp"
#include "Runtime/World/CGameLight.hpp"
#include "Runtime/World/CPlayer.hpp"

#include "TCastTo.hpp" // Generated file, do not modify include path

namespace urde {
const zeus::CVector3f CFlameThrower::kLightOffset(0, 3.f, 2.f);

CFlameThrower::CFlameThrower(const TToken<CWeaponDescription>& wDesc, std::string_view name, EWeaponType wType,
                             const CFlameInfo& flameInfo, const zeus::CTransform& xf, EMaterialTypes matType,
                             const CDamageInfo& dInfo, TUniqueId uid, TAreaId aId, TUniqueId owner,
                             EProjectileAttrib attribs, CAssetId playerSteamTxtr, s16 playerHitSfx,
                             CAssetId playerIceTxtr)
: CGameProjectile(false, wDesc, name, wType, xf, matType, dInfo, uid, aId, owner, kInvalidUniqueId, attribs, false,
                  zeus::CVector3f(1.f), {}, -1, false)
, x2e8_flameXf(xf)
, x338_(flameInfo.x10_)
, x33c_flameDesc(g_SimplePool->GetObj({FOURCC('PART'), flameInfo.GetFlameFxId()}))
, x348_flameGen(std::make_unique<CElementGen>(x33c_flameDesc))
, x34c_flameWarp(176.f - float(flameInfo.GetLength()), xf.origin, bool(flameInfo.GetAttributes() & 0x4))
, x3f4_playerSteamTxtr(playerSteamTxtr)
, x3f8_playerHitSfx(playerHitSfx)
, x3fc_playerIceTxtr(playerIceTxtr)
, x400_24_active(false)
, x400_25_particlesActive(false)
, x400_26_(!(flameInfo.GetAttributes() & 1))
, x400_27_coneCollision((flameInfo.GetAttributes() & 0x2) != 0) {

}

void CFlameThrower::Accept(IVisitor& visitor) { visitor.Visit(this); }

void CFlameThrower::AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId uid, CStateManager& mgr) {
  if (msg == EScriptObjectMessage::Registered) {
    xe6_27_thermalVisorFlags |= 2;
    mgr.AddWeaponId(xec_ownerId, xf0_weaponType);
  } else if (msg == EScriptObjectMessage::Deleted) {
    mgr.RemoveWeaponId(xec_ownerId, xf0_weaponType);
    DeleteProjectileLight(mgr);
  }

  CGameProjectile::AcceptScriptMsg(msg, uid, mgr);
}

void CFlameThrower::SetTransform(const zeus::CTransform& xf, float) { x2e8_flameXf = xf; }

void CFlameThrower::Reset(CStateManager& mgr, bool resetWarp) {
  SetFlameLightActive(mgr, false);
  if (resetWarp) {
    SetActive(false);
    x400_25_particlesActive = false;
    x3f0_flameState = EFlameState::Default;
    x330_particleWaitDelayTimer = 0.f;
    x334_fireStopTimer = 0.f;
    x318_flameBounds = zeus::skNullBox;
    x348_flameGen->SetParticleEmission(false);
    x34c_flameWarp.ResetPosition(x2e8_flameXf.origin);
  } else {
    x348_flameGen->SetParticleEmission(false);
    x400_25_particlesActive = false;
    x3f0_flameState = EFlameState::FireStopTimer;
  }
}

void CFlameThrower::Fire(const zeus::CTransform&, CStateManager& mgr, bool) {
  SetActive(true);
  x400_25_particlesActive = true;
  x400_24_active = true;
  x3f0_flameState = EFlameState::FireStart;
  CreateFlameParticles(mgr);
}

void CFlameThrower::CreateFlameParticles(CStateManager& mgr) {
  DeleteProjectileLight(mgr);
  x348_flameGen = std::make_unique<CElementGen>(x33c_flameDesc);
  x348_flameGen->SetParticleEmission(true);
  x348_flameGen->SetZTest(x400_27_coneCollision);
  x348_flameGen->AddModifier(&x34c_flameWarp);
  if (x348_flameGen->SystemHasLight() && x2c8_projectileLight == kInvalidUniqueId)
    CreateProjectileLight("FlameThrower_Light"sv, x348_flameGen->GetLight(), mgr);
}

void CFlameThrower::AddToRenderer(const zeus::CFrustum&, const CStateManager& mgr) const {
  g_Renderer->AddParticleGen(*x348_flameGen);
  EnsureRendered(mgr, x2e8_flameXf.origin, GetRenderBounds());
}

void CFlameThrower::Render(const CStateManager&) const {}

std::optional<zeus::CAABox> CFlameThrower::GetTouchBounds() const { return std::nullopt; }

void CFlameThrower::Touch(CActor&, CStateManager&) {}

void CFlameThrower::SetFlameLightActive(CStateManager& mgr, bool active) {
  if (x2c8_projectileLight == kInvalidUniqueId)
    return;

  if (TCastToPtr<CGameLight> light = mgr.ObjectById(x2c8_projectileLight))
    light->SetActive(active);
}

void CFlameThrower::UpdateFlameState(float dt, CStateManager& mgr) {
  switch(x3f0_flameState) {
  case EFlameState::FireStart:
    x3f0_flameState = EFlameState::FireActive;
    break;
  case EFlameState::FireStopTimer:
    x334_fireStopTimer += 4.f * dt;
    if (x334_fireStopTimer > 1.f) {
      x334_fireStopTimer = 1.f;
      x3f0_flameState = EFlameState::FireWaitForParticlesDone;
      x400_24_active = false;
    }
    break;
  case EFlameState::FireWaitForParticlesDone:
    x330_particleWaitDelayTimer += dt;
    if (x330_particleWaitDelayTimer > 0.1f && x348_flameGen && x348_flameGen->GetParticleCountAll() == 0) {
      x3f0_flameState = EFlameState::Default;
      Reset(mgr, true);
    }
    break;
  default:
    break;
  }
}

CRayCastResult CFlameThrower::DoCollisionCheck(TUniqueId& idOut, const zeus::CAABox& aabb, CStateManager& mgr) {
  CRayCastResult ret;
  rstl::reserved_vector<TUniqueId, 1024> nearList;
  mgr.BuildNearList(nearList, aabb, CMaterialFilter::skPassEverything, this);
  const auto& colPoints = x34c_flameWarp.GetCollisionPoints();

  if (x400_27_coneCollision && !colPoints.empty()) {
    const float radiusPitch =
        (x34c_flameWarp.GetMaxSize() - x34c_flameWarp.GetMinSize()) / float(colPoints.size()) * 0.5f;
    float curRadius = radiusPitch;

    for (size_t i = 1; i < colPoints.size(); ++i) {
      const zeus::CVector3f delta = colPoints[i] - colPoints[i - 1];
      zeus::CTransform lookXf = zeus::lookAt(colPoints[i - 1], colPoints[i]);
      lookXf.origin = delta * 0.5f + colPoints[i - 1];
      const zeus::COBBox obb(lookXf, {curRadius, delta.magnitude() * 0.5f, curRadius});

      for (const TUniqueId id : nearList) {
        if (auto* act = static_cast<CActor*>(mgr.ObjectById(id))) {
          const CProjectileTouchResult tres = CanCollideWith(*act, mgr);
          if (tres.GetActorId() == kInvalidUniqueId) {
            continue;
          }

          const auto tb = act->GetTouchBounds();
          if (!tb) {
            continue;
          }

          if (obb.AABoxIntersectsBox(*tb)) {
            const CCollidableAABox caabb(*tb, act->GetMaterialList());
            const zeus::CVector3f flameToAct = act->GetAimPosition(mgr, 0.f) - x2e8_flameXf.origin;
            const float flameToActDist = flameToAct.magnitude();
            const CInternalRayCastStructure rc(x2e8_flameXf.origin, flameToAct.normalized(), flameToActDist, {},
                                               CMaterialFilter::skPassEverything);
            const CRayCastResult cres = caabb.CastRayInternal(rc);
            if (cres.IsInvalid()) {
              continue;
            }
            return cres;
          }
        }
      }

      curRadius += radiusPitch;
    }
  } else {
    for (size_t i = 0; i < colPoints.size() - 1; ++i) {
      const zeus::CVector3f delta = colPoints[i + 1] - colPoints[i];
      const float deltaMag = delta.magnitude();
      if (deltaMag <= 0.f) {
        break;
      }

      const CRayCastResult cres = RayCollisionCheckWithWorld(idOut, colPoints[i], colPoints[i + 1], deltaMag, nearList, mgr);
      if (cres.IsValid()) {
        return cres;
      }
    }
  }

  return ret;
}

void CFlameThrower::ApplyDamageToActor(CStateManager& mgr, TUniqueId id, float dt) {
  if (mgr.GetPlayer().GetUniqueId() == id && x3f4_playerSteamTxtr.IsValid() && x3fc_playerIceTxtr.IsValid())
    mgr.GetPlayer().Freeze(mgr, x3f4_playerSteamTxtr, x3f8_playerHitSfx, x3fc_playerIceTxtr);
  CDamageInfo useDInfo = CDamageInfo(x12c_curDamageInfo, dt);
  ApplyDamageToActors(mgr, useDInfo);
}

void CFlameThrower::Think(float dt, CStateManager& mgr) {
  CWeapon::Think(dt, mgr);
  if (!GetActive())
    return;

  UpdateFlameState(dt, mgr);

  zeus::CVector3f flamePoint = x2e8_flameXf.origin;
  bool r28 = x3f0_flameState == EFlameState::FireActive || x3f0_flameState == EFlameState::FireStopTimer;
  if (r28) {
    x34c_flameWarp.Activate(true);
    x34c_flameWarp.SetWarpPoint(flamePoint);
    x34c_flameWarp.SetStateManager(mgr);
    x348_flameGen->SetTranslation(flamePoint);
    x348_flameGen->SetOrientation(x2e8_flameXf.getRotation());
  } else {
    x34c_flameWarp.Activate(false);
  }

  x348_flameGen->Update(dt);
  x34c_flameWarp.SetMaxDistSq(0.f);
  x34c_flameWarp.SetFloatingPoint(flamePoint);

  if (r28 && x34c_flameWarp.IsProcessed()) {
    x318_flameBounds = x34c_flameWarp.CalculateBounds();
    TUniqueId id = kInvalidUniqueId;
    CRayCastResult res = DoCollisionCheck(id, x318_flameBounds, mgr);
    if (TCastToPtr<CActor> act = mgr.ObjectById(id)) {
      ApplyDamageToActor(mgr, id, dt);
    } else if (res.IsValid()) {
      CMaterialFilter useFilter = xf8_filter;
      CDamageInfo useDInfo = CDamageInfo(x12c_curDamageInfo, dt);
      mgr.ApplyDamageToWorld(xec_ownerId, *this, res.GetPoint(), useDInfo, useFilter);
    }
  }

  CActor::SetTransform(x2e8_flameXf.getRotation());
  CActor::SetTranslation(x2e8_flameXf.origin);

  if (x2c8_projectileLight != kInvalidUniqueId) {
    if (TCastToPtr<CGameLight> light = mgr.ObjectById(x2c8_projectileLight)) {
      light->SetTransform(GetTransform());
      light->SetTranslation(x34c_flameWarp.GetFloatingPoint());
      if (x348_flameGen && x348_flameGen->SystemHasLight())
        light->SetLight(x348_flameGen->GetLight());
    }
  }
}
} // namespace urde
<|endoftext|>


<commit_before>/*=========================================================================

  Program:   Insight Segmentation & Registration Toolkit
  Module:    itkSliceIteratorTest.cxx
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

  Copyright (c) 2000 National Library of Medicine
  All rights reserved.

  See COPYRIGHT.txt for copyright details.

=========================================================================*/
#include "itkImage.h"
#include "itkNeighborhood.h"
#include "itkSliceIterator.h"
#include "itkImageRegionIterator.h"
#include "itkSmartRegionNeighborhoodIterator.h"
#include <iostream>

template< class T, unsigned int N >
void FillRegionSequential(itk::SmartPointer< itk::Image<T, N> > I)
{
  unsigned int iTemp, ArrayLength, iDim,i;
  itk::Size<N> Index;
  unsigned long int Location[N];
  unsigned int mult;
  T value;

  itk::ImageRegionIterator<T, N> data(I, I->GetRequestedRegion());

  Index = (I->GetRequestedRegion()).GetSize();
  data.Begin();

  for (ArrayLength=1, iTemp = 0; iTemp<N; iTemp++)
	{
	  Location[iTemp] =0;
	  ArrayLength*=Index[iTemp];
	}

  for (i=0; i<ArrayLength; i++, ++data)
	{
	  for (iDim=0, mult=1, value=0; iDim<N; iDim++, mult*=10)
		{
		  value += mult *  Location[N-iDim-1];
		}
	  *data = value;

	  for (iDim=N-1; iDim>=0; iDim--)
		{
		  Location[iDim]++;
		  if (Location[iDim]==Index[(N-1)-iDim]) Location[iDim]=0;
		  else break;
		}

	}
}

template< class T, unsigned int TDimension >
void PrintRegion(itk::SmartPointer< itk::Image<T, TDimension> > I)
{
  int iDim, i, ArrayLength;
  int nnf[TDimension];
  unsigned long rsz[TDimension];
  unsigned long Location[TDimension];

  memcpy(rsz, I->GetRequestedRegion().GetSize().m_Size,
         sizeof(unsigned long) * TDimension);
  memset(Location, 0, sizeof(unsigned long) * TDimension);
  for (iDim = 0; iDim < TDimension; ++iDim)
    {
      std::cout << "iDim = " << iDim << std::endl;
      std::cout << "\tRegionSize = "
           << I->GetRequestedRegion().GetSize().m_Size[iDim]
           << std::endl;
      std::cout << "\tRegionStartIndex = "
           << I->GetRequestedRegion().GetIndex()[iDim] << std::endl;
    }

  itk::ImageRegionIterator<T, TDimension> iter( I, I->GetRequestedRegion());

  for (iter.Begin(); ! iter.IsAtEnd(); ++iter)
    {
      std::cout << *iter << " ";

      for (iDim=TDimension-1; iDim>=0; iDim--)
		{
		  Location[iDim]++;
		  if (Location[iDim]==rsz[TDimension-1 -iDim])
            {
              std::cout << std::endl;
              Location[iDim]=0;
            }
		  else break;
		}
    }
}

template <class TContainer>
void PrintSlice(TContainer s)
{
  std::cout << "[" ;
  for (s=s.Begin(); s < s.End(); s++)
    {
      std::cout << *s << " ";
    }
  std::cout << "]" << std::endl;

}

main()
{

  try {

      itk::ImageRegion<2> reg;
      itk::Size<2> hoodRadius;
      itk::Size<2> imgSize;
      itk::Index<2> zeroIndex;
      zeroIndex[0]=zeroIndex[1]=0;
      imgSize[0]=imgSize[1]=20;
      hoodRadius[0]=hoodRadius[1]=2;
      reg.SetIndex(zeroIndex);
      reg.SetSize(imgSize);

      std::slice hslice(10, 5, 1); // slice through the horizontal center
      std::slice vslice(2, 5, 5);  // slice through the vertical center
      itk::Neighborhood<int, 2> temp;
      itk::SliceIterator<int, itk::Neighborhood<int,2> > hnsi(&temp, hslice);
      itk::SliceIterator<int, itk::Neighborhood<int,2> > vnsi(&temp, vslice);
      itk::Neighborhood<int, 2> op;
      op.SetRadius(hoodRadius);
      op = 2;
      op.PrintSelf();

      itk::Index<2> idx;
      idx[0]=idx[1]=0;

      itk::Image<int, 2>::Pointer ip = itk::Image<int,2>::New();
      ip->SetRequestedRegion(reg);
      ip->SetBufferedRegion(reg);
      ip->SetLargestPossibleRegion(reg);
      ip->Allocate();

      FillRegionSequential<int, 2>(ip);
      PrintRegion<int,2>(ip);

      itk::SmartRegionNeighborhoodIterator<int,2> it(hoodRadius, ip, reg);
      const itk::SmartRegionNeighborhoodIterator<int,2> itEnd = it.End();

      for (it = it.Begin(); it < itEnd; ++it)
        {
          temp = it.GetNeighborhood();
          temp.PrintSelf();
          PrintSlice(hnsi);
          PrintSlice(vnsi);
        }
  }
  catch (itk::ExceptionObject &err)
    {
      (&err)->Print(std::cerr);
      return 2;
    }
  return EXIT_SUCCESS;
}
<commit_msg>ERR: main must return an int.<commit_after>/*=========================================================================

  Program:   Insight Segmentation & Registration Toolkit
  Module:    itkSliceIteratorTest.cxx
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

  Copyright (c) 2000 National Library of Medicine
  All rights reserved.

  See COPYRIGHT.txt for copyright details.

=========================================================================*/
#include "itkImage.h"
#include "itkNeighborhood.h"
#include "itkSliceIterator.h"
#include "itkImageRegionIterator.h"
#include "itkSmartRegionNeighborhoodIterator.h"
#include <iostream>

template< class T, unsigned int N >
void FillRegionSequential(itk::SmartPointer< itk::Image<T, N> > I)
{
  unsigned int iTemp, ArrayLength, iDim,i;
  itk::Size<N> Index;
  unsigned long int Location[N];
  unsigned int mult;
  T value;

  itk::ImageRegionIterator<T, N> data(I, I->GetRequestedRegion());

  Index = (I->GetRequestedRegion()).GetSize();
  data.Begin();

  for (ArrayLength=1, iTemp = 0; iTemp<N; iTemp++)
	{
	  Location[iTemp] =0;
	  ArrayLength*=Index[iTemp];
	}

  for (i=0; i<ArrayLength; i++, ++data)
	{
	  for (iDim=0, mult=1, value=0; iDim<N; iDim++, mult*=10)
		{
		  value += mult *  Location[N-iDim-1];
		}
	  *data = value;

	  for (iDim=N-1; iDim>=0; iDim--)
		{
		  Location[iDim]++;
		  if (Location[iDim]==Index[(N-1)-iDim]) Location[iDim]=0;
		  else break;
		}

	}
}

template< class T, unsigned int TDimension >
void PrintRegion(itk::SmartPointer< itk::Image<T, TDimension> > I)
{
  int iDim, i, ArrayLength;
  int nnf[TDimension];
  unsigned long rsz[TDimension];
  unsigned long Location[TDimension];

  memcpy(rsz, I->GetRequestedRegion().GetSize().m_Size,
         sizeof(unsigned long) * TDimension);
  memset(Location, 0, sizeof(unsigned long) * TDimension);
  for (iDim = 0; iDim < TDimension; ++iDim)
    {
      std::cout << "iDim = " << iDim << std::endl;
      std::cout << "\tRegionSize = "
           << I->GetRequestedRegion().GetSize().m_Size[iDim]
           << std::endl;
      std::cout << "\tRegionStartIndex = "
           << I->GetRequestedRegion().GetIndex()[iDim] << std::endl;
    }

  itk::ImageRegionIterator<T, TDimension> iter( I, I->GetRequestedRegion());

  for (iter.Begin(); ! iter.IsAtEnd(); ++iter)
    {
      std::cout << *iter << " ";

      for (iDim=TDimension-1; iDim>=0; iDim--)
		{
		  Location[iDim]++;
		  if (Location[iDim]==rsz[TDimension-1 -iDim])
            {
              std::cout << std::endl;
              Location[iDim]=0;
            }
		  else break;
		}
    }
}

template <class TContainer>
void PrintSlice(TContainer s)
{
  std::cout << "[" ;
  for (s=s.Begin(); s < s.End(); s++)
    {
      std::cout << *s << " ";
    }
  std::cout << "]" << std::endl;

}

int main()
{

  try {

      itk::ImageRegion<2> reg;
      itk::Size<2> hoodRadius;
      itk::Size<2> imgSize;
      itk::Index<2> zeroIndex;
      zeroIndex[0]=zeroIndex[1]=0;
      imgSize[0]=imgSize[1]=20;
      hoodRadius[0]=hoodRadius[1]=2;
      reg.SetIndex(zeroIndex);
      reg.SetSize(imgSize);

      std::slice hslice(10, 5, 1); // slice through the horizontal center
      std::slice vslice(2, 5, 5);  // slice through the vertical center
      itk::Neighborhood<int, 2> temp;
      itk::SliceIterator<int, itk::Neighborhood<int,2> > hnsi(&temp, hslice);
      itk::SliceIterator<int, itk::Neighborhood<int,2> > vnsi(&temp, vslice);
      itk::Neighborhood<int, 2> op;
      op.SetRadius(hoodRadius);
      op = 2;
      op.PrintSelf();

      itk::Index<2> idx;
      idx[0]=idx[1]=0;

      itk::Image<int, 2>::Pointer ip = itk::Image<int,2>::New();
      ip->SetRequestedRegion(reg);
      ip->SetBufferedRegion(reg);
      ip->SetLargestPossibleRegion(reg);
      ip->Allocate();

      FillRegionSequential<int, 2>(ip);
      PrintRegion<int,2>(ip);

      itk::SmartRegionNeighborhoodIterator<int,2> it(hoodRadius, ip, reg);
      const itk::SmartRegionNeighborhoodIterator<int,2> itEnd = it.End();

      for (it = it.Begin(); it < itEnd; ++it)
        {
          temp = it.GetNeighborhood();
          temp.PrintSelf();
          PrintSlice(hnsi);
          PrintSlice(vnsi);
        }
  }
  catch (itk::ExceptionObject &err)
    {
      (&err)->Print(std::cerr);
      return 2;
    }
  return EXIT_SUCCESS;
}
<|endoftext|>


<commit_before>// Disk class utilities

#include "SAMdisk.h"
#include "DiskUtil.h"

static void item_separator (int items)
{
	if (!items)
		util::cout << colour::grey << '[' << colour::none;
	else
		util::cout << ',';
}

void DumpTrack (const CylHead &cylhead, const Track &track, const ScanContext &context, int flags)
{
	if (opt.hex != 1)
		util::cout << util::fmt(" %2u.%u  ", cylhead.cyl, cylhead.head);
	else
		util::cout << util::fmt(" %s.%u  ", CylStr(cylhead.cyl), cylhead.head);

	if (track.empty())
		util::cout << colour::grey << "<blank>" << colour::none;
	else
	{
		for (auto &sector : track.sectors())
		{
			util::cout << RecordStr(sector.header.sector);

			// Use 'd' suffix for deleted sectors, or 'a' for alt-DAM
			if (sector.is_deleted())
				util::cout << colour::green << "d" << colour::none;
			else if (sector.is_altdam())
				util::cout << colour::YELLOW << "a" << colour::none;
			else if (sector.is_rx02dam())
				util::cout << colour::YELLOW << "x" << colour::none;

			auto items = 0;

			if (sector.header.cyl != context.sector.header.cyl)
			{
				item_separator(items++);
				util::cout << colour::yellow << "c" << std::string(CylStr(sector.header.cyl)) << colour::none;
			}

			if (sector.header.head != context.sector.header.head)
			{
				item_separator(items++);
				util::cout << colour::yellow << "h" << std::string(HeadStr(sector.header.head)) << colour::none;
			}

			if (sector.header.size != context.sector.header.size)
			{
				item_separator(items++);
				util::cout << colour::yellow << "n" << std::string(SizeStr(sector.header.size)) << colour::none;
			}

			if (sector.copies() > 1)
			{
				item_separator(items++);
				util::cout << "m" << sector.copies();
			}

			if (sector.has_badidcrc())
			{
				item_separator(items++);
				util::cout << colour::RED << "ic" << colour::none;	// ID header CRC error
			}

			if (!sector.has_badidcrc() && !sector.has_data())		// No data field
			{
				item_separator(items++);
				util::cout << colour::YELLOW << "nd" << colour::none;
			}

			if (sector.has_baddatacrc())
			{
				item_separator(items++);
				util::cout << colour::RED << "dc" << colour::none;	// Data field CRC error
			}

			if (track.is_repeated(sector))
			{
				item_separator(items++);
				util::cout << colour::YELLOW << "r" << colour::none;	// Repeated sector
			}

			if (sector.has_data() && sector.data_size() == 0)
			{

				item_separator(items++);
				util::cout << colour::YELLOW << "z" << colour::none;	// Zero data stored
			}
#if 0
			// ToDo: take extent into account?
			else if (sector.has_data() && sector.has_shortdata())
			{
				item_separator(items++);
				util::cout << colour::yellow << "-" << (sector.size() - sector.data_size()) << colour::none;	// Less data than sector size
			}
#endif
			if (sector.encoding == Encoding::FM && context.sector.encoding == Encoding::MFM)
			{
				item_separator(items++);
				util::cout << colour::CYAN << "fm" << colour::none;	// FM sector on MFM track
			}

			if (sector.has_gapdata())
			{
				item_separator(items++);
				util::cout << colour::CYAN << "+" << (sector.data_size() - sector.size()) << colour::none;	// More data than sector size (crc, gaps, ...)
			}

			if (items)
				util::cout << colour::grey << ']' << colour::none;

			util::cout << ' ';
		}
		//		p--;

		// If we've got a track length and sector data, show the sector offsets too
		if ((flags & DUMP_OFFSETS) && !track.empty() && track.tracklen)
		{
			auto prevoffset = 0;
			auto shift = (context.sector.encoding == Encoding::FM) ? 5 : 4;

			util::cout << util::fmt("\n         %s: ", WordStr(track.tracklen >> shift));

			for (const auto &sector : track.sectors())
			{
				auto offset = sector.offset;

				// Invalid or missing offset?
				if (offset < prevoffset)
				{
					// Show a red question mark instead of the offset
					util::cout << colour::RED << '?' << colour::none;
				}
				else
				{
					// Show offset from previous sector
					if (offset > prevoffset)
						util::cout << util::fmt("%s ", WordStr((offset - prevoffset) >> shift));
					else
						util::cout << util::fmt("-%s ", WordStr((prevoffset - offset) >> shift));

					if (!opt.absoffsets)
						prevoffset = offset;
				}
			}

			// Show the gap until end of track
			auto last_offset = track.sectors()[track.size() - 1].offset;
			if (track.tracklen > last_offset)
				util::cout << util::fmt("[%s]", WordStr((track.tracklen - last_offset) >> shift));
			else
				util::cout << util::fmt("[-%s]", WordStr((last_offset - track.tracklen) >> shift));
		}
	}

	util::cout << "\n";

	if (flags & DUMP_DIFF)
	{
		for (const auto &sector : track.sectors())
		{
			// If we have more than 1 copy, compare them
			if (sector.copies() > 1)
			{
				util::cout << "        diff (" << RecordStr(sector.header.sector) << "): ";

				auto i = 0;
				for (auto &diff : DiffSectorCopies(sector))
				{
					util::cout << diff.first << diff.second << ' ';
					if (++i > 12)
					{
						util::cout << "...";
						break;
					}
				}
				util::cout << '\n';
			}
		}
	}
}

void OverrideFormat (Format &fmt, bool full_control/*=false*/)
{
	static const DataRate rates[] = { DataRate::_500K, DataRate::_300K, DataRate::_250K, DataRate::_1M };

	if (full_control)
	{
		if (opt.sectors != -1) fmt.sectors = opt.sectors;
		if (opt.size >= 0 && opt.size <= 7) fmt.size = opt.size;
	}

	// Merge any overrides from the command-line
	if (opt.fm == 1) fmt.encoding = Encoding::FM;
	if (opt.fill >= 0) fmt.fill = static_cast<uint8_t>(opt.fill);
	if (opt.gap3 >= 0) fmt.gap3 = opt.gap3;
	if (opt.base != -1) fmt.base = opt.base;
	if (opt.interleave >= 0) fmt.interleave = opt.interleave;
	if (opt.skew >= 0) fmt.skew = opt.skew;
	if (opt.head0 != -1) fmt.head0 = opt.head0;
	if (opt.head1 != -1) fmt.head1 = opt.head1;
	if (opt.rate != -1) fmt.datarate = rates[opt.rate & 3];	// ToDo: remove this?

/*
	// ToDo: auto-adjust density to match sector content?
	// Check the gap size required for the current settings
	uint8_t gap3 = GetFormatGap(RPM_TIME_300, fmt.datarate, fmt.encoding, fmt.sectors, fmt.size);

	// Does it fit?
	if (!gap3)
	{
	// If not, try again with high density
	pf_->encrate = (pf_->encrate & ~FD_RATE_MASK) | FD_RATE_500K;
	gap3 = GetFormatGap(RPM_TIME_300, pf_->encrate, pf_->sectors, pf_->size);

	// If that still doesn't fit, assume extra density (we'll check properly later)
	if (!gap3)
	pf_->encrate = (pf_->encrate & ~FD_RATE_MASK) | FD_RATE_1M;
	}
*/
}

std::vector<std::pair<char, size_t>> DiffSectorCopies (const Sector &sector)
{
	assert(sector.copies() > 0);
	std::vector<std::pair<char, size_t>> diffs;

	auto &smallest = sector.data_copy(sector.copies() - 1);
	auto it = smallest.begin();
	auto itEnd = smallest.end();

	//	int extent = pt_->GetDataExtent(nSector_);	// ToDo
	auto change_count = 0;

	auto diff = 0;
	while (it < itEnd)
	{
		auto offset = std::distance(smallest.begin(), it);
		auto same = std::distance(it, itEnd);

		for (const auto &data : sector.datas())
		{
			if (same)
			{
				// Find the prefix length where all data copies match
				auto pair = std::mismatch(it, it + same, data.begin() + offset);
				auto offset2 = std::distance(it, pair.first);
				same = std::min(same, offset2);
			}
		}
		it = it + same;

		if (same >= MIN_DIFF_BLOCK)
		{
			if (diff)
			{
				++change_count;
				diffs.push_back(std::make_pair('-', diff));
				diff = 0;
			}

			++change_count;
			diffs.push_back(std::make_pair('=', same));
			same = 0;
		}

		offset = std::distance(smallest.begin(), it);
		auto match = std::distance(it, itEnd);

		for (const auto &data : sector.datas())
		{
			if (match)
			{
				// Find the prefix length where each copy has matching filler
				auto pair = std::mismatch(data.begin() + offset, data.begin() + offset + match - 1, data.begin() + offset + 1);
				auto offset2 = 1 + std::distance(data.begin() + offset, pair.first);
				match = std::min(match, offset2);
			}
		}
		it = it + match;

		if (match >= MIN_DIFF_BLOCK)
		{
			if (diff)
			{
				++change_count;
				diffs.push_back(std::make_pair('-', diff));
				diff = 0;
			}

			++change_count;
			diffs.push_back(std::make_pair('+', match));
			match = 0;
		}

		diff += static_cast<int>(same + match);
	}

	if (diff)
	{
		++change_count;
		diffs.push_back(std::make_pair('-', diff));
	}

	return diffs;
}

// Determine the common properties of sectors on a track.
// This is mostly used by scan track headers, to reduce the detail shown for each sector.
Sector GetTypicalSector (const CylHead &cylhead, const Track &track, Sector last_sector)
{
	std::map<DataRate, int> datarates;
	std::map<Encoding, int> encodings;
	std::map<int, int> cyls, heads, sizes, gap3s;

	Sector typical = last_sector;

	// Find the most common values
	for (const auto &sector : track.sectors())
	{
		if (++datarates[sector.datarate] > datarates[typical.datarate])
			typical.datarate = sector.datarate;

		if (++encodings[sector.encoding] > encodings[typical.encoding])
			typical.encoding = sector.encoding;

		if (++cyls[sector.header.cyl] > cyls[typical.header.cyl])
			typical.header.cyl = sector.header.cyl;

		if (++heads[sector.header.head] > heads[typical.header.head])
			typical.header.head = sector.header.head;

		if (++sizes[sector.header.size] > sizes[typical.header.size])
			typical.header.size = sector.header.size;

		if (++gap3s[sector.gap3] > gap3s[typical.gap3])
			typical.gap3 = sector.gap3;
	}

	// If they are no better than the last typical sector, use with the previous values.

	if (datarates[typical.datarate] == datarates[last_sector.datarate])
		typical.datarate = last_sector.datarate;

	if (encodings[typical.encoding] == encodings[last_sector.encoding])
		typical.encoding = last_sector.encoding;

	if (cyls[typical.header.cyl] == cyls[last_sector.header.cyl])
		typical.header.cyl = last_sector.header.cyl;
	else if (cyls[typical.header.cyl] == 1)		// changed cyl from previous, but only 1 sector?
		typical.header.cyl = cylhead.cyl;		// use physical cyl instead

	if (heads[typical.header.head] == heads[last_sector.header.head])
		typical.header.head = last_sector.header.head;
	else if (heads[typical.header.head] == 1)	// changed head from previous, but only 1 sector?
		typical.header.head = cylhead.head;		// use physical head instead

	if (sizes[typical.header.size] == sizes[last_sector.header.size])
		typical.header.size = last_sector.header.size;

	// Clear the gap3 value unless all gaps are the same size or undefined
	if ((gap3s[typical.gap3] + gap3s[0]) != track.size())
		typical.gap3 = 0;

	return typical;
}

bool WriteRegularDisk (FILE *f_, Disk &disk, const Format &fmt)
{
	auto missing = 0;

	fmt.range().each([&] (const CylHead &cylhead) {
		const auto &track = disk.read_track(cylhead);
		Header header(cylhead, 0, fmt.size);

		for (header.sector = fmt.base; header.sector < fmt.base + fmt.sectors; ++header.sector)
		{
			Data buf(fmt.sector_size(), fmt.fill);

			auto it = track.find(header);
			if (it != track.end() && (*it).has_data())
			{
				const auto &data = (*it).data_copy();
				std::copy(data.begin(), data.begin() + std::min(data.size(), buf.size()), buf.begin());
			}
			else
			{
				missing++;
			}

			if (!fwrite(buf.data(), buf.size(), 1, f_))
				throw util::exception("write error, disk full?");
		}
	}, fmt.cyls_first);

	if (missing && !opt.minimal)
		Message(msgWarning, "source missing %u sectors from %u/%u/%u/%u regular format", missing, fmt.cyls, fmt.heads, fmt.sectors, fmt.sector_size());

	return true;
}
<commit_msg>Added indicator for sectors with incomplete data<commit_after>// Disk class utilities

#include "SAMdisk.h"
#include "DiskUtil.h"

static void item_separator (int items)
{
	if (!items)
		util::cout << colour::grey << '[' << colour::none;
	else
		util::cout << ',';
}

void DumpTrack (const CylHead &cylhead, const Track &track, const ScanContext &context, int flags)
{
	if (opt.hex != 1)
		util::cout << util::fmt(" %2u.%u  ", cylhead.cyl, cylhead.head);
	else
		util::cout << util::fmt(" %s.%u  ", CylStr(cylhead.cyl), cylhead.head);

	if (track.empty())
		util::cout << colour::grey << "<blank>" << colour::none;
	else
	{
		for (auto &sector : track.sectors())
		{
			util::cout << RecordStr(sector.header.sector);

			// Use 'd' suffix for deleted sectors, or 'a' for alt-DAM
			if (sector.is_deleted())
				util::cout << colour::green << "d" << colour::none;
			else if (sector.is_altdam())
				util::cout << colour::YELLOW << "a" << colour::none;
			else if (sector.is_rx02dam())
				util::cout << colour::YELLOW << "x" << colour::none;

			auto items = 0;

			if (sector.header.cyl != context.sector.header.cyl)
			{
				item_separator(items++);
				util::cout << colour::yellow << "c" << std::string(CylStr(sector.header.cyl)) << colour::none;
			}

			if (sector.header.head != context.sector.header.head)
			{
				item_separator(items++);
				util::cout << colour::yellow << "h" << std::string(HeadStr(sector.header.head)) << colour::none;
			}

			if (sector.header.size != context.sector.header.size)
			{
				item_separator(items++);
				util::cout << colour::yellow << "n" << std::string(SizeStr(sector.header.size)) << colour::none;
			}

			if (sector.copies() > 1)
			{
				item_separator(items++);
				util::cout << "m" << sector.copies();
			}

			if (sector.has_badidcrc())
			{
				item_separator(items++);
				util::cout << colour::RED << "ic" << colour::none;	// ID header CRC error
			}

			if (!sector.has_badidcrc() && !sector.has_data())		// No data field
			{
				item_separator(items++);
				util::cout << colour::YELLOW << "nd" << colour::none;
			}

			if (sector.has_baddatacrc())
			{
				item_separator(items++);
				util::cout << colour::RED << "dc" << colour::none;	// Data field CRC error
			}

			if (track.is_repeated(sector))
			{
				item_separator(items++);
				util::cout << colour::YELLOW << "r" << colour::none;	// Repeated sector
			}

			if (sector.has_data() && sector.data_size() == 0)
			{

				item_separator(items++);
				util::cout << colour::YELLOW << "z" << colour::none;	// Zero data stored
			}
			else if (sector.has_data() && sector.has_shortdata() && !sector.has_baddatacrc())
			{
				item_separator(items++);
				util::cout << colour::RED << "-" << (sector.size() - sector.data_size()) << colour::none;	// Less data than sector size
			}

			if (sector.encoding == Encoding::FM && context.sector.encoding == Encoding::MFM)
			{
				item_separator(items++);
				util::cout << colour::CYAN << "fm" << colour::none;	// FM sector on MFM track
			}

			if (sector.has_gapdata())
			{
				item_separator(items++);
				util::cout << colour::CYAN << "+" << (sector.data_size() - sector.size()) << colour::none;	// More data than sector size (crc, gaps, ...)
			}

			if (items)
				util::cout << colour::grey << ']' << colour::none;

			util::cout << ' ';
		}
		//		p--;

		// If we've got a track length and sector data, show the sector offsets too
		if ((flags & DUMP_OFFSETS) && !track.empty() && track.tracklen)
		{
			auto prevoffset = 0;
			auto shift = (context.sector.encoding == Encoding::FM) ? 5 : 4;

			util::cout << util::fmt("\n         %s: ", WordStr(track.tracklen >> shift));

			for (const auto &sector : track.sectors())
			{
				auto offset = sector.offset;

				// Invalid or missing offset?
				if (offset < prevoffset)
				{
					// Show a red question mark instead of the offset
					util::cout << colour::RED << '?' << colour::none;
				}
				else
				{
					// Show offset from previous sector
					if (offset > prevoffset)
						util::cout << util::fmt("%s ", WordStr((offset - prevoffset) >> shift));
					else
						util::cout << util::fmt("-%s ", WordStr((prevoffset - offset) >> shift));

					if (!opt.absoffsets)
						prevoffset = offset;
				}
			}

			// Show the gap until end of track
			auto last_offset = track.sectors()[track.size() - 1].offset;
			if (track.tracklen > last_offset)
				util::cout << util::fmt("[%s]", WordStr((track.tracklen - last_offset) >> shift));
			else
				util::cout << util::fmt("[-%s]", WordStr((last_offset - track.tracklen) >> shift));
		}
	}

	util::cout << "\n";

	if (flags & DUMP_DIFF)
	{
		for (const auto &sector : track.sectors())
		{
			// If we have more than 1 copy, compare them
			if (sector.copies() > 1)
			{
				util::cout << "        diff (" << RecordStr(sector.header.sector) << "): ";

				auto i = 0;
				for (auto &diff : DiffSectorCopies(sector))
				{
					util::cout << diff.first << diff.second << ' ';
					if (++i > 12)
					{
						util::cout << "...";
						break;
					}
				}
				util::cout << '\n';
			}
		}
	}
}

void OverrideFormat (Format &fmt, bool full_control/*=false*/)
{
	static const DataRate rates[] = { DataRate::_500K, DataRate::_300K, DataRate::_250K, DataRate::_1M };

	if (full_control)
	{
		if (opt.sectors != -1) fmt.sectors = opt.sectors;
		if (opt.size >= 0 && opt.size <= 7) fmt.size = opt.size;
	}

	// Merge any overrides from the command-line
	if (opt.fm == 1) fmt.encoding = Encoding::FM;
	if (opt.fill >= 0) fmt.fill = static_cast<uint8_t>(opt.fill);
	if (opt.gap3 >= 0) fmt.gap3 = opt.gap3;
	if (opt.base != -1) fmt.base = opt.base;
	if (opt.interleave >= 0) fmt.interleave = opt.interleave;
	if (opt.skew >= 0) fmt.skew = opt.skew;
	if (opt.head0 != -1) fmt.head0 = opt.head0;
	if (opt.head1 != -1) fmt.head1 = opt.head1;
	if (opt.rate != -1) fmt.datarate = rates[opt.rate & 3];	// ToDo: remove this?

/*
	// ToDo: auto-adjust density to match sector content?
	// Check the gap size required for the current settings
	uint8_t gap3 = GetFormatGap(RPM_TIME_300, fmt.datarate, fmt.encoding, fmt.sectors, fmt.size);

	// Does it fit?
	if (!gap3)
	{
	// If not, try again with high density
	pf_->encrate = (pf_->encrate & ~FD_RATE_MASK) | FD_RATE_500K;
	gap3 = GetFormatGap(RPM_TIME_300, pf_->encrate, pf_->sectors, pf_->size);

	// If that still doesn't fit, assume extra density (we'll check properly later)
	if (!gap3)
	pf_->encrate = (pf_->encrate & ~FD_RATE_MASK) | FD_RATE_1M;
	}
*/
}

std::vector<std::pair<char, size_t>> DiffSectorCopies (const Sector &sector)
{
	assert(sector.copies() > 0);
	std::vector<std::pair<char, size_t>> diffs;

	auto &smallest = sector.data_copy(sector.copies() - 1);
	auto it = smallest.begin();
	auto itEnd = smallest.end();

	//	int extent = pt_->GetDataExtent(nSector_);	// ToDo
	auto change_count = 0;

	auto diff = 0;
	while (it < itEnd)
	{
		auto offset = std::distance(smallest.begin(), it);
		auto same = std::distance(it, itEnd);

		for (const auto &data : sector.datas())
		{
			if (same)
			{
				// Find the prefix length where all data copies match
				auto pair = std::mismatch(it, it + same, data.begin() + offset);
				auto offset2 = std::distance(it, pair.first);
				same = std::min(same, offset2);
			}
		}
		it = it + same;

		if (same >= MIN_DIFF_BLOCK)
		{
			if (diff)
			{
				++change_count;
				diffs.push_back(std::make_pair('-', diff));
				diff = 0;
			}

			++change_count;
			diffs.push_back(std::make_pair('=', same));
			same = 0;
		}

		offset = std::distance(smallest.begin(), it);
		auto match = std::distance(it, itEnd);

		for (const auto &data : sector.datas())
		{
			if (match)
			{
				// Find the prefix length where each copy has matching filler
				auto pair = std::mismatch(data.begin() + offset, data.begin() + offset + match - 1, data.begin() + offset + 1);
				auto offset2 = 1 + std::distance(data.begin() + offset, pair.first);
				match = std::min(match, offset2);
			}
		}
		it = it + match;

		if (match >= MIN_DIFF_BLOCK)
		{
			if (diff)
			{
				++change_count;
				diffs.push_back(std::make_pair('-', diff));
				diff = 0;
			}

			++change_count;
			diffs.push_back(std::make_pair('+', match));
			match = 0;
		}

		diff += static_cast<int>(same + match);
	}

	if (diff)
	{
		++change_count;
		diffs.push_back(std::make_pair('-', diff));
	}

	return diffs;
}

// Determine the common properties of sectors on a track.
// This is mostly used by scan track headers, to reduce the detail shown for each sector.
Sector GetTypicalSector (const CylHead &cylhead, const Track &track, Sector last_sector)
{
	std::map<DataRate, int> datarates;
	std::map<Encoding, int> encodings;
	std::map<int, int> cyls, heads, sizes, gap3s;

	Sector typical = last_sector;

	// Find the most common values
	for (const auto &sector : track.sectors())
	{
		if (++datarates[sector.datarate] > datarates[typical.datarate])
			typical.datarate = sector.datarate;

		if (++encodings[sector.encoding] > encodings[typical.encoding])
			typical.encoding = sector.encoding;

		if (++cyls[sector.header.cyl] > cyls[typical.header.cyl])
			typical.header.cyl = sector.header.cyl;

		if (++heads[sector.header.head] > heads[typical.header.head])
			typical.header.head = sector.header.head;

		if (++sizes[sector.header.size] > sizes[typical.header.size])
			typical.header.size = sector.header.size;

		if (++gap3s[sector.gap3] > gap3s[typical.gap3])
			typical.gap3 = sector.gap3;
	}

	// If they are no better than the last typical sector, use with the previous values.

	if (datarates[typical.datarate] == datarates[last_sector.datarate])
		typical.datarate = last_sector.datarate;

	if (encodings[typical.encoding] == encodings[last_sector.encoding])
		typical.encoding = last_sector.encoding;

	if (cyls[typical.header.cyl] == cyls[last_sector.header.cyl])
		typical.header.cyl = last_sector.header.cyl;
	else if (cyls[typical.header.cyl] == 1)		// changed cyl from previous, but only 1 sector?
		typical.header.cyl = cylhead.cyl;		// use physical cyl instead

	if (heads[typical.header.head] == heads[last_sector.header.head])
		typical.header.head = last_sector.header.head;
	else if (heads[typical.header.head] == 1)	// changed head from previous, but only 1 sector?
		typical.header.head = cylhead.head;		// use physical head instead

	if (sizes[typical.header.size] == sizes[last_sector.header.size])
		typical.header.size = last_sector.header.size;

	// Clear the gap3 value unless all gaps are the same size or undefined
	if ((gap3s[typical.gap3] + gap3s[0]) != track.size())
		typical.gap3 = 0;

	return typical;
}

bool WriteRegularDisk (FILE *f_, Disk &disk, const Format &fmt)
{
	auto missing = 0;

	fmt.range().each([&] (const CylHead &cylhead) {
		const auto &track = disk.read_track(cylhead);
		Header header(cylhead, 0, fmt.size);

		for (header.sector = fmt.base; header.sector < fmt.base + fmt.sectors; ++header.sector)
		{
			Data buf(fmt.sector_size(), fmt.fill);

			auto it = track.find(header);
			if (it != track.end() && (*it).has_data())
			{
				const auto &data = (*it).data_copy();
				std::copy(data.begin(), data.begin() + std::min(data.size(), buf.size()), buf.begin());
			}
			else
			{
				missing++;
			}

			if (!fwrite(buf.data(), buf.size(), 1, f_))
				throw util::exception("write error, disk full?");
		}
	}, fmt.cyls_first);

	if (missing && !opt.minimal)
		Message(msgWarning, "source missing %u sectors from %u/%u/%u/%u regular format", missing, fmt.cyls, fmt.heads, fmt.sectors, fmt.sector_size());

	return true;
}
<|endoftext|>