/*
 * Copyright (c) 2020-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.
 */

#ifndef MLXLINK_AMBER_COLLECTOR_H
#define MLXLINK_AMBER_COLLECTOR_H

#include <array>

#include "mlxlink_reg_parser.h"
#include "amber_field.h"

// Un-comment to see access register failures
// #define VALIDATE_REG_REQUEST

using namespace std;

struct FIELDS_COUNT
{
    u_int32_t numOfIbFields;
    u_int32_t numOfEthFields;
    u_int32_t numOfPcieFields;
};

class MlxlinkAmBerCollector : public MlxlinkRegParser
{
public:
    MlxlinkAmBerCollector(Json::Value& jsonRoot);
    virtual ~MlxlinkAmBerCollector();

    virtual void init();
    // Main functions
    vector<AmberField> getIndexesInfo();
    vector<AmberField> getGeneralInfo();
    virtual vector<AmberField> getSystemInfo();
    virtual vector<AmberField> getLinkStatus();
    virtual vector<AmberField> getSerdesHDR();
    virtual vector<AmberField> getSerdesNDR();
    virtual vector<AmberField> getSerdes5nmGen7();
    virtual vector<AmberField> getModuleStatus();
    virtual vector<AmberField> getPortCounters();
    virtual vector<AmberField> getTroubleshootingInfo();
    virtual vector<AmberField> getPhyOperationInfo();
    virtual vector<AmberField> getLinkUpInfo();
    virtual vector<AmberField> getLinkDownInfo();
    virtual vector<AmberField> getTestModeInfo();
    virtual vector<AmberField> getTestModeModuleInfo();
    virtual vector<AmberField> getPhyDebugInfo();
    virtual vector<AmberField> getExtModuleStatus();
    virtual vector<AmberField> getRecoveryCounters();
    virtual vector<AmberField> getSerdesGen8NVLink();

    virtual void get5nmGen7SlsirFields(vector<AmberField>& fields);
    virtual void get5nmGen7SltpFields(vector<AmberField>& fields);

    // Auxiliary functions
    virtual void getPemiLaserMonitors(vector<AmberField>& fields, bool isGroupSupported);
    void getPemiModuleStatus(vector<AmberField>& fields, bool isGroupSupported);
    void getPemiPreFecBer(vector<AmberField>& fields, bool isGroupSupported);
    void getMTMGFields(vector<AmberField>& fields);
    void getMTMRFields(vector<AmberField>& fields);

    void getPpcntBer(u_int32_t portType, vector<AmberField>& fields);
    bool isGBValid();
    bool isMCMValid();

    string getClRawBer();
    void startCollector();

    u_int32_t _pnat;
    u_int32_t _localPort;
    u_int32_t _depth;
    u_int32_t _pcieIndex;
    u_int32_t _node;
    u_int32_t _devID;
    u_int32_t _productTechnology;
    string _csvFileName;
    string _mstDevName;
    u_int32_t _iteration;
    string _testMode;
    MlxlinkMaps* _mlxlinkMaps;
    u_int32_t _numOfLanes;
    bool _isModeAsActive;
    bool _isNvlinkModeA;
    bool _isNvlinkModeB;
    bool _isNvlinkTestModeBOper;
    vector<PortGroup> _localPorts; // will be valid for switches
    bool _isHca;
    vector<AMBER_SHEET> _sheetsToDump;

private:
    string getRawFieldValue(const string fieldName);
    string getNodeGUID();
    string getMACAddress();
    string getCurrentTimeStamp();
    void getEthComplianceCodes(u_int32_t cableTechnology,
                               string& ethComplianceStr,
                               string& extComplianceStr,
                               u_int32_t cableMediaType);
    void getIbComplianceCodes(string& ibComplianceCodeStr);
    string getCableTechnologyStr(u_int32_t cableTechnology);
    string getCableBreakoutStr(u_int32_t cableBreakout, u_int32_t cableIdentifier);
    void getModuleInfoPage(vector<AmberField>& fields);
    string getSmfLength(const u_int32_t smfLength, const u_int32_t cableTechnology, const bool optical);
    string getDateCode(u_int64_t dateCode);
    void getTxBiasLane(vector<AmberField>& fields);
    string getByMap(u_int32_t flags, std::map<u_int32_t, std::string> map);
    void getCmisComplianceCode(u_int32_t ethComplianceCode,
                               u_int32_t extEthComplianceCode,
                               string& ethComplianceStr,
                               string& extComplianceStr,
                               u_int32_t cableMediaType,
                               u_int32_t cableTechnology);
    void initCableIdentifier(u_int32_t cableIdentifier);
    void getModuleLatchedFlagInfoPage(vector<AmberField>& fields);
    string getPrbsModeCap(u_int32_t modeSelector, u_int32_t capsMask);
    string getPrpsRateCap(u_int32_t capsMask);
    void groupValidIf(bool condition);
    void getTestModeModulePMPT(vector<AmberField>& fields, string moduleSide, ModuleAccess_t mode);
    void getTestModeModulePMPD(vector<AmberField>& fields, string moduleSide);
    u_int32_t getSheetIndex(AMBER_SHEET sheet);
    void getPemiSnr(vector<AmberField>& fields, bool isGroupSupported);

    void collect();
    vector<AmberField> collectSheet(AMBER_SHEET sheet);
    void initAmberSheetsToDump();
    u_int32_t fixFieldsData();
    void exportToCSV();
    void exportToConsole();

    bool _isQsfpCable;
    bool _isSfpCable;
    bool _cablePlugged;
    u_int32_t _labelPort;
    u_int32_t _splitPort;
    u_int32_t _secondSplit;
    bool _isFnmPort;
    map<AMBER_SHEET, vector<AmberField>> _amberCollection;
    map<AMBER_SHEET, FIELDS_COUNT> _baseSheetsList;

protected:
    void resetLocalParser(const string& regName);
    string getLocalFieldStr(const string& fieldName);
    u_int32_t getLocalFieldValue(const string& fieldName);
    void sendRegister(const string& regName, maccess_reg_method_t method);
    void sendLocalPrmReg(const string& regName, maccess_reg_method_t method, const char* fields, ...);

    string getBitmaskPerLaneStr(u_int32_t bitmask);
    void fillParamsToFields(const string& title, const vector<string>& values, vector<AmberField>& fields);
    void pushModulePerLaneField(vector<AmberField>& fields,
                                string fieldName,
                                float valueCorrection = 1.0,
                                string laneSep = "_",
                                string suffix = "",
                                float multiplier = 1.0,
                                string displayName = "");
    void pushModuleDpPerLane(vector<AmberField>& fields, const string str, string suffix = "");

    // Helper functions
    virtual string getBerAndErrorTitle(u_int32_t portType);
    bool isTestModeNvlinkModeB();
    virtual void getTestModePrpsInfo(const string& prbsReg, vector<vector<string>>& params, bool isNvlinkTestModeB);
    virtual void getModuleLinkUpInfoPage(vector<AmberField>& fields);
    virtual void updateModeAsActive();
    void updateNumOfLanesForTestModeNVL6();

    virtual void getSlsirGen8Fields(vector<AmberField>& fields);
    void getSltpGen8Fields(vector<AmberField>& fields);
    void getSltrGen8Fields(vector<AmberField>& fields, u_int32_t testType);

    // Callers

    bool _isCmisCable;
    bool _isPortIB;
    bool _isPortETH;
    bool _isPortNVLINK;
    bool _isPortPCIE;
    bool _isMCMSysValid;
    bool _isGBSysValid;
    bool _isValidSensorMvcap;
    bool _isValidSensorMtcap;
    bool _inPRBSMode;
    u_int32_t _pllGroup;
    u_int32_t _moduleHostSt;
    u_int32_t _moduleMediaSt;

    Json::Value& _jsonRoot;
    vector<MlxlinkCmdPrint> _amBerCollectorOutput;
    vector<pair<AMBER_SHEET, FIELDS_COUNT>> _sheetsList;

    u_int32_t _activeSpeed;
    u_int32_t _protoActive;
    u_int32_t _moduleIndex;
    u_int32_t _slotIndex;
    u_int32_t _maxLanes;

    // ---------- SLTR functions ----------
    string getSltrFieldPrmName(const string& baseName, u_int32_t groupIndex, bool isArray = false);
    string getSltrFieldDisplayName(const string& baseName, u_int32_t lane, u_int32_t groupIndex);
    virtual void handleSltrGroup(vector<AmberField>& fields,
                                 u_int32_t lane,
                                 const string& groupName,
                                 const std::array<uint8_t, 2>& limits,
                                 bool isArray = false);
    virtual void handleSltrVGroup(vector<AmberField>& fields, u_int32_t lane);
    virtual void handleSltrXGroup(vector<AmberField>& fields, u_int32_t lane);
    virtual void handleSltrBsGroup(vector<AmberField>& fields, u_int32_t lane);
    virtual void handleSltrJbGroup(vector<AmberField>& fields, u_int32_t lane);
    virtual void handleSltrQbcGroup(vector<AmberField>& fields, u_int32_t lane);
    virtual void handleSltrBcGroup(vector<AmberField>& fields, u_int32_t lane);
    virtual void handleSltrCGroup(vector<AmberField>& fields, u_int32_t lane);
    virtual void handleSltrDGroup(vector<AmberField>& fields, u_int32_t lane);
    virtual void handleSltrIGroup(vector<AmberField>& fields, u_int32_t lane);
    virtual void handleSltrMGroup(vector<AmberField>& fields, u_int32_t lane);
    virtual void handleSltrOGroup(vector<AmberField>& fields, u_int32_t lane);
    virtual void handleSltrQaGroup(vector<AmberField>& fields, u_int32_t lane);
    virtual void handleSltrPGroup(vector<AmberField>& fields, u_int32_t lane);
    virtual void handleSltrTGroup(vector<AmberField>& fields, u_int32_t lane);
    virtual void handleSltrAfGroup(vector<AmberField>& fields, u_int32_t lane);
    virtual void handleSltrZGroup(vector<AmberField>& fields, u_int32_t lane);
    virtual void handleSltrUGroup(vector<AmberField>& fields, u_int32_t lane);
    virtual void handleSltrHGroup(vector<AmberField>& fields, u_int32_t lane);
    virtual void handleSltrSGroup(vector<AmberField>& fields, u_int32_t lane);
    virtual void handleSltrGGroup(vector<AmberField>& fields, u_int32_t lane);
    virtual void handleSltrJaGroup(vector<AmberField>& fields, u_int32_t lane);
    virtual void handleSltrJcGroup(vector<AmberField>& fields, u_int32_t lane);
    virtual void handleSltrAaGroup(vector<AmberField>& fields, u_int32_t lane);
    virtual void handleSltrAcGroup(vector<AmberField>& fields, u_int32_t lane);
    virtual void handleSltrEGroup(vector<AmberField>& fields, u_int32_t lane);
    virtual void handleSltrWGroup(vector<AmberField>& fields, u_int32_t lane);
    virtual void handleSltrAfmGroup(vector<AmberField>& fields, u_int32_t lane);
    virtual void handleSltrFGroup(vector<AmberField>& fields, u_int32_t lane);
    virtual void handleSltrQGroup(vector<AmberField>& fields, u_int32_t lane);
    virtual void handleSltrAbGroup(vector<AmberField>& fields, u_int32_t lane);
    virtual void handleSltrYGroup(vector<AmberField>& fields, u_int32_t lane);
    // ---------- end SLTR functions ----------
};

#endif /* MLXLINK_AMBER_COLLECTOR_H */
