/* fssops.cpp

Copyright (c) 2015, Nikolaj Schlej. All rights reserved.
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution.  The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php

THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.

*/

#include "ffsops.h"

FfsOperations::FfsOperations(TreeModel* treeModel)
    : model(treeModel)
{
}

FfsOperations::~FfsOperations()
{
}

void FfsOperations::msg(const QString & message, const QModelIndex & index)
{
    messagesVector.push_back(std::pair<QString, QModelIndex>(message, index));
}

std::vector<std::pair<QString, QModelIndex> > FfsOperations::getMessages() const
{
    return messagesVector;
}

void FfsOperations::clearMessages()
{
    messagesVector.clear();
}

STATUS FfsOperations::extract(const QModelIndex & index, QString & name, QByteArray & extracted, const UINT8 mode)
{
    // Sanity check
    if (!index.isValid())
        return ERR_INVALID_PARAMETER;

    // Get data from parsing data
    PARSING_DATA pdata = parsingDataFromQModelIndex(index);

    // Construct a name for extracted data
    QString itemName = model->name(index);
    QString itemText = model->text(index);
    switch (model->type(index)) {
    case Types::Volume: {
        if (pdata.volume.hasExtendedHeader)
            name = guidToQString(pdata.volume.extendedHeaderGuid);
        else
            name = itemName;
    } break;
    case Types::NvramVariableNvar:
    case Types::File: {
        name = itemText.isEmpty() ? itemName : itemText.replace(' ', '_');
    } break;
    case Types::Section: {
        // Get parent file name
        QModelIndex fileIndex = model->findParentOfType(index, Types::File);
        QString fileText = model->text(fileIndex);
        name = fileText.isEmpty() ? model->name(fileIndex) : fileText.replace(' ', '_');
        // Append section subtype name
        name += QChar('_') + itemName.replace(' ', '_');
    } break;
    case Types::Capsule:
    case Types::Image:
    case Types::Region:
    case Types::Padding:
    default:
        name = itemName.replace(' ', '_').replace('/', '_');
    }

    // Get extracted data
    if (mode == EXTRACT_MODE_AS_IS) {
        // Extract as is, with header body and tail
        extracted.clear();
        extracted.append(model->header(index));
        extracted.append(model->body(index));
        // Handle file tail
        if (model->type(index) == Types::File) {
            if (pdata.file.hasTail)
                extracted.append(pdata.file.tailArray[0]).append(pdata.file.tailArray[1]);
        }
    }
    else if (mode == EXTRACT_MODE_BODY) {
        name += QObject::tr("_body");
        // Extract without header and tail
        extracted.clear();
        extracted.append(model->body(index));
    }
    else if (mode == EXTRACT_MODE_BODY_UNCOMPRESSED) {
        name += QObject::tr("_body_unc");
        // Extract without header and tail, uncompressed
        extracted.clear();
        // There is no need to redo decompression, we can use child items
        for (int i = 0; i < model->rowCount(index); i++) {
             QModelIndex childIndex = index.child(i, 0);
             extracted.append(model->header(childIndex));
             extracted.append(model->body(childIndex));
        }
    }
    else
        return ERR_UNKNOWN_EXTRACT_MODE;

    return ERR_SUCCESS;
}

STATUS  FfsOperations::replace(const QModelIndex & index, const QString & data, const UINT8 mode)
{
    // Sanity check
    if (!index.isValid())
        return ERR_INVALID_PARAMETER;

    // Get data from parsing data
    //PARSING_DATA pdata = parsingDataFromQModelIndex(index);

    if (mode == REPLACE_MODE_AS_IS) {
        return ERR_NOT_IMPLEMENTED;
    }
    else if (mode == REPLACE_MODE_BODY) {
        return ERR_NOT_IMPLEMENTED;
    }
    else 
        return ERR_UNKNOWN_REPLACE_MODE;
    
    return ERR_NOT_IMPLEMENTED;
}

STATUS FfsOperations::remove(const QModelIndex & index)
{
    // Sanity check
    if (!index.isValid())
        return ERR_INVALID_PARAMETER;

    // Set remove action
    model->setAction(index, Actions::Remove);

    return ERR_SUCCESS;
}

STATUS FfsOperations::rebuild(const QModelIndex & index)
{
    // Sanity check
    if (!index.isValid())
        return ERR_INVALID_PARAMETER;

    // On insert action, set insert action for children
    //if (action == Actions::Insert)
    //    for (int i = 0; i < item->childCount(); i++)
    //        setAction(index.child(i, 0), Actions::Insert);

    // Set rebuild action
    model->setAction(index, Actions::Rebuild);

    // Rebuild parent, if it has no action now
    QModelIndex parent = index.parent();
    if (parent.isValid() && model->type(parent) != Types::Root
        && model->action(parent) == Actions::NoAction)
       rebuild(parent);
    
    return ERR_SUCCESS;
}