#include "GlibcHeapInfoDialog.h"

#include <utility>
#include "ui_GlibcHeapInfoDialog.h"

GlibcHeapInfoDialog::GlibcHeapInfoDialog(RVA offset, QString status, QWidget *parent)
    : QDialog(parent), ui(new Ui::GlibcHeapInfoDialog), offset(offset), status(std::move(status))
{
    ui->setupUi(this);

    // set window title
    QString windowTitle = tr("Chunk @ ") + RzAddressString(offset);
    if (!this->status.isEmpty()) {
        windowTitle += QString("(" + this->status + ")");
    }
    this->setWindowTitle(windowTitle);

    connect(ui->saveButton, &QPushButton::clicked, this, &GlibcHeapInfoDialog::saveChunkInfo);

    updateFields();
}

GlibcHeapInfoDialog::~GlibcHeapInfoDialog()
{
    delete ui;
}

void GlibcHeapInfoDialog::updateFields()
{
    // get data about the heap chunk from the API
    RzHeapChunkSimple *chunk = Core()->getHeapChunk(offset);
    if (!chunk) {
        return;
    }

    // Update the information in the widget
    this->ui->baseEdit->setText(RzAddressString(offset));
    this->ui->sizeEdit->setText(RzHexString(chunk->size));
    this->ui->bkEdit->setText(RzAddressString(chunk->bk));
    this->ui->fdEdit->setText(RzAddressString(chunk->fd));
    this->ui->bknsEdit->setText(RzAddressString(chunk->bk_nextsize));
    this->ui->fdnsEdit->setText(RzAddressString(chunk->fd_nextsize));
    this->ui->prevSizeEdit->setText(RzHexString(chunk->prev_size));
    if (chunk->is_mmapped) {
        this->ui->rbIM->setChecked(true);
    } else {
        this->ui->rbIM->setChecked(false);
    }
    if (chunk->prev_inuse) {
        this->ui->rbPI->setChecked(true);
    } else {
        this->ui->rbPI->setChecked(false);
    }
    if (chunk->non_main_arena) {
        this->ui->rbNMA->setChecked(true);
    } else {
        this->ui->rbNMA->setChecked(false);
    }

    free(chunk);
}

void GlibcHeapInfoDialog::saveChunkInfo()
{
    QMessageBox msgBox(this);
    msgBox.setText("Do you want to overwrite chunk metadata?");
    msgBox.setInformativeText(
            "Any field which cannot be converted to a valid integer will be saved as zero");
    msgBox.setStandardButtons(QMessageBox::Save | QMessageBox::Cancel);
    msgBox.setDefaultButton(QMessageBox::Save);

    int ret = msgBox.exec();
    switch (ret) {
    case QMessageBox::Save:
        // Save was clicked
        RzHeapChunkSimple chunkSimple;
        chunkSimple.size = Core()->math(ui->sizeEdit->text());
        chunkSimple.fd = Core()->math(ui->fdEdit->text());
        chunkSimple.bk = Core()->math(ui->bkEdit->text());
        chunkSimple.fd_nextsize = Core()->math(ui->fdnsEdit->text());
        chunkSimple.bk_nextsize = Core()->math(ui->bknsEdit->text());
        chunkSimple.addr = offset;
        if (ui->rbIM->isChecked()) {
            chunkSimple.is_mmapped = true;
        } else {
            chunkSimple.is_mmapped = false;
        }
        if (ui->rbNMA->isChecked()) {
            chunkSimple.non_main_arena = true;
        } else {
            chunkSimple.non_main_arena = false;
        }
        if (ui->rbPI->isChecked()) {
            chunkSimple.prev_inuse = true;
        } else {
            chunkSimple.prev_inuse = false;
        }
        if (Core()->writeHeapChunk(&chunkSimple)) {
            updateFields();
            QMessageBox::information(this, tr("Chunk saved"),
                                     tr("Chunk header successfully overwritten"));
        } else {
            QMessageBox::information(this, tr("Chunk not saved"),
                                     tr("Chunk header not successfully overwritten"));
        }
        break;
    case QMessageBox::Cancel:
        // Cancel was clicked
        break;
    }
}