
/*
 * Copyright (C) Jan 2013 Mellanox Technologies Ltd. All rights reserved.
 * Copyright (c) 2021 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
 *
 * This software is available to you under a choice of one of two
 * licenses.  You may choose to be licensed under the terms of the GNU
 * General Public License (GPL) Version 2, available from the file
 * COPYING in the main directory of this source tree, or the
 * OpenIB.org BSD license below:
 *
 *     Redistribution and use in source and binary forms, with or
 *     without modification, are permitted provided that the following
 *     conditions are met:
 *
 *      - Redistributions of source code must retain the above
 *        copyright notice, this list of conditions and the following
 *        disclaimer.
 *
 *      - Redistributions in binary form must reproduce the above
 *        copyright notice, this list of conditions and the following
 *        disclaimer in the documentation and/or other materials
 *        provided with the distribution.
 *
 * 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.
 */

/*
 *  mlxarchive_mfa2_builder.cpp
 *
 *  Created on: March 26, 2017
 *      Author: Ahmad Soboh
 */

#include <json/writer.h>
#include <json/reader.h>

#include "mlxfwops/lib/mlxfwops_com.h"
#include "mlxfwops/lib/fw_ops.h"
#include "mlxarchive_mfa2_builder.h"

using namespace mfa2;

#define VERSION_STR "Version"
#define CREATION_TIME_STR "Creation Time"
#define COMMENT_STR "Comment"
#define DEVICEDESCRIPTORS_STR "Device Descriptors"
#define COMPONENTS_STR "Components"
#define PSID_STR "PSID"
#define SOURCE_STR "Source"

/* Class FWDirectoryBuilder */

FWDirectoryBuilder::FWDirectoryBuilder(const string& version, string directory) :
    _version(VersionExtension(version)), _directory(directory)
{
    string fileExtension = ".bin";
    vector<string> files;
    int index = 0;
    try
    {
        listDir(directory.c_str(), files);
    }
    catch (std::exception& e)
    {
        std::string err_str = "locale::facet::_S_create_c_locale name not valid";
        if (!err_str.compare(e.what()))
        {
            fprintf(
              stderr,
              "Exception: '%s' was catched.\nPlease try to add the following line into your /etc/profile file and "
              "retry:\nexport LC_ALL=C; unset LANGUAGE\n"
              "Please note, you need to reload the .profile file, after editing. \nsource /etc/profile might help.\n",
              e.what());
            exit(1);
        }
        throw e;
    }
    VECTOR_ITERATOR(string, files, file)
    {
        if ((*file).rfind(fileExtension) == ((*file).size() - fileExtension.size()))
        {
            string fullPath = directory + "/" + (*file);
            //_files.push_back(fullPath);

            // Query FW Image retrieve version, date, psid info
            char errBuff[1024];
            FwOperations* ops =
              FwOperations::FwOperationsCreate((void*)fullPath.c_str(), NULL, NULL, FHT_FW_FILE, errBuff, 1024);
            if (!ops)
            {
                printf("Can't handle the FW image file %s\n", fullPath.c_str());
                exit(1);
            }
            fw_info_t fwQueryResult;
            if (!ops->FwQuery(&fwQueryResult, true, false))
            {
                // throw exception
                printf("Can't query FW image file %s:%s\n", fullPath.c_str(), ops->err());
                exit(1);
            }
            /*FWInfo fwInfo;
            memcpy(fwInfo.version, fwQueryResult.fw_info.fw_ver, sizeof(fwInfo.version));
            memcpy(fwInfo.date, fwQueryResult.fw_info.fw_rel_date, sizeof(fwInfo.date));
            fwInfo.psid = fwQueryResult.fw_info.psid;
            _fwInfo[fullPath] = fwInfo;*/
            //_imgsFwOps[fullPath] = ops;
            vector<ComponentPointerExtension> componentPointers;
            PSIDExtension PSID(fwQueryResult.fw_info.psid);
            ComponentPointerExtension componentPointer(index++);
            componentPointers.push_back(componentPointer);
            DeviceDescriptor deviceDescriptor(componentPointers, PSID);
            _deviceDescriptors.push_back(deviceDescriptor);
            VersionExtension version(fwQueryResult.fw_info.fw_ver, fwQueryResult.fw_info.fw_rel_date);
            vector<u_int8_t> data;
            if (!ops->FwExtract4MBImage(data, true))
            {
                printf("Can't Extract FW data from the image file %s:%s\n", fullPath.c_str(), ops->err());
                exit(1);
            }
            ComponentDescriptor componentDescriptor(version, data);
            Component component(componentDescriptor);
            _components.push_back(component);
        }
    }
};

PackageDescriptor FWDirectoryBuilder::getPackageDescriptor() const
{
    PackageDescriptor packageDescriptor(_deviceDescriptors.size(), _components.size(), _version);
    return packageDescriptor;
}

vector<DeviceDescriptor> FWDirectoryBuilder::getDeviceDescriptors() const
{
    return _deviceDescriptors;
    /*vector<DeviceDescriptor> deviceDescriptors;

    CONST_VECTOR_ITERATOR(string, _files, file) {
        PSIDExtension PSID("MT_0000000");
        vector<ComponentPointerExtension> componentPointers;

        ComponentPointerExtension componentPointer(
                distance(_files.begin(), file));
        componentPointers.push_back(componentPointer);
        DeviceDescriptor deviceDescriptor(componentPointers, PSID);
        deviceDescriptors.push_back(deviceDescriptor);
    }

    return deviceDescriptors;*/
}

vector<Component> FWDirectoryBuilder::getComponents() const
{
    return _components;
    /*vector<Component> components;

    CONST_VECTOR_ITERATOR(string, _files, file) {
        VersionExtension version("4.5.666", "20.9.1992");
        vector<u_int8_t> data;
        _imgsFwOps[(*file)]->FwExtract4MBImage(data, false);
        ComponentDescriptor componentDescriptor(version, data);

        Component component(componentDescriptor);
        components.push_back(component);
    }

    return components;*/
}

/*FWDirectoryBuilder::~FWDirectoryBuilder()
{
    VECTOR_ITERATOR(FwOperations*, _imgsFwOps, imgFwOps) {
        if ((*imgFwOps)) {
            (*imgFwOps)->FwCleanUp();
            delete (*imgFwOps);
        }
    }
}*/
