/*
 * Copyright (C) 2015 by Multi-Tech Systems
 *
 * This file is part of libmts-io.
 *
 * libmts-io is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 2 of the License, or
 * (at your option) any later version.
 *
 * libmts-io is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with libmts-io.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

/*!
 \file MTS_IO_CellularRadio.h
 \brief A brief description
 \date Nov 5, 2014
 \author sgodinez

 A more elaborate description
*/
#ifndef MTS_IO_CELLULARRADIO_H_
#define MTS_IO_CELLULARRADIO_H_

#include <string>
#include <vector>

#include <json/json.h>

#include <mts/MTS_IO_ICellularRadio.h>
#include <mts/MTS_IO_SerialConnection.h>
#include <mts/MTS_NonCopyable.h>
#include <mts/MTS_AutoPtr.h>
#include <mts/MTS_Stdint.h>

namespace MTS {
    namespace IO {
        class CellularRadio : public ICellularRadio {

            public:
                const std::string& getName() const override;

                ~CellularRadio() override;

                bool initialize(uint32_t iTimeoutMillis = 5000) override;
                bool resetConnection(uint32_t iTimeoutMillis = 5000) override;
                void shutdown() override;

                CODE getFirmware(std::string& sFirmware) override;
                CODE getFirmwareBuild(std::string& sFirmwareBuild) override;
                CODE getHardware(std::string& sHardware) override;
                CODE getManufacturer(std::string& sManufacturer) override;
                CODE getImei(std::string& sImei) override;
                CODE getMeid(std::string& sMeid) override;
                CODE getImsi(std::string& sImsi) override;
                CODE getSimStatus(std::string& sSimStatus) override;
                CODE getSimStatusSummary(Json::Value& jData) override;
                CODE getLac(std::string& sLac) override;
                CODE getMdn(std::string& sMdn) override;
                CODE getMsid(std::string& sMsid) override;
                CODE getType(std::string& sType) override;
                CODE getCarrier(std::string& sCarrier) override;
                CODE getTower(std::string& sTower) override;
                CODE getTime(std::string& sDate, std::string& sTime, std::string& sTimeZone) override;
                CODE getRoaming(bool& bRoaming) override;
                CODE getCellularMode(CELLULAR_MODES &networks) override;

                CODE getSignalStrength(int32_t& iRssi) override;
                CODE getModemLocation(std::string& sLocation) override;

                CODE getRegistration(REGISTRATION& eRegistration) override;
                CODE convertRegistrationToString(REGISTRATION eRegistration, std::string& sRegistration) override;

                CODE unlockSimCard(const Json::Value& jArgs) override;

                CODE getMipProfile(Json::Value& jMipProfile) override;
                CODE validateMsl(const Json::Value& jArgs) override;
                CODE setMsid(const Json::Value& jArgs) override;
                CODE setMipActiveProfile(const Json::Value& jArgs) override;
                CODE setMipNai(const Json::Value& jArgs) override;
                CODE setMipHomeIp(const Json::Value& jArgs) override;
                CODE setMipPrimaryHa(const Json::Value& jArgs) override;
                CODE setMipSecondaryHa(const Json::Value& jArgs) override;
                CODE setMipMnAaaSpi(const Json::Value& jArgs) override;
                CODE setMipMnHaSpi(const Json::Value& jArgs) override;
                CODE setMipRevTun(const Json::Value& jArgs) override;
                CODE setMipMnAaaSs(const Json::Value& jArgs) override;
                CODE setMipMnHaSs(const Json::Value& jArgs) override;
                CODE updateDc(const Json::Value& jArgs, UpdateCb& stepCb) override;
                CODE updatePrl(const Json::Value& jArgs, UpdateCb& stepCb) override;
                CODE updateFumo(const Json::Value& jArgs, UpdateCb& stepCb) override;
                CODE resetHfa(const Json::Value& jArgs, UpdateCb& stepCb) override;
                CODE activate(const Json::Value& jArgs, UpdateCb& stepCb) override;
                CODE setActiveFirmware(const Json::Value& jArgs) override;
                CODE getActiveFirmware(std::string& sFwId) override;
                CODE getEcho(bool& bEnabled) override;
                CODE setEcho(bool bEnabled = true) override;
                CODE getStaticInformation(Json::Value& jData) override;
                CODE sendBasicCommand(const std::string& sCmd, int32_t timeoutMillis = 100, const char& ESC = ICellularRadio::CR) override;

                std::string sendCommand(const std::string& sCmd,
                                                const std::vector<std::string>& vBail = DEFAULT_BAIL_STRINGS,
                                                int32_t timeoutMillis = 100,
                                                const char& ESC = ICellularRadio::CR) override;



                std::string sendCommand(const std::string& sCmd,
                                                IsNeedMoreData& isNeedMoreData,
                                                int32_t timeoutMillis = 100,
                                                const char& ESC = ICellularRadio::CR) override;


            protected:

                CellularRadio(const std::string& sName, const std::string& sRadioPort);

                virtual bool getCarrierFromFirmware(const std::string& sFirmware, std::string& sCarrier);
                virtual bool getHardwareVersionFromFirmware(const std::string& sFirmware, std::string& sHardware);

                virtual void getCommonNetworkStats(Json::Value& jData);

                /**
                 * @brief getIsSimInserted - returns if the SIM card is inserted / installed or not.
                 *
                 * @param bData - an object to be filled with the SIM card insertion status.
                 *        `true` when SIM card is inserted / installed / present,
                 *        `false` otherwise.
                 * @return CODE::SUCCESS when SIM insertion status is fetched successfully,
                 *         CODE::NOT_APPLICABLE when the modem doesn't support this feature,
                 *         CODE::ERROR otherwise (when modem is inaccessible or in other cases).
                 */
                virtual CODE getIsSimInserted(bool& bData) = 0;

                /**
                 * @brief getSimLockStatus - return the SIM lock status as defined by AT+CPIN? command.
                 *        Returns "READY", "SIM PIN", "SIM PUK" or other SIM status.
                 *
                 * @param sData - an object to be filled with the SIM lock status
                 * @return CODE::SUCCESS when SIM status is fetched successfully,
                 *         CODE::NOT_APPLICABLE when the modem doesn't support this feature,
                 *         CODE::ERROR otherwise (SIM card removed, modem is inaccessible, etc).
                 */
                virtual CODE getSimLockStatus(std::string& sData);

                /**
                 * @brief getSimLockAttempts - get the number of SIM unlock attempts left.
                 *
                 * @param iAttemptsPin - the number of attempts left to enter a PIN code.
                 * @param iAttemptsPuk - the number of attempts left to enter a PUK code.
                 * @return CODE::SUCCESS when both numbers are fetched successfully,
                 *         CODE::NOT_APPLICABLE when the modem doesn't support this feature,
                 *         CODE::ERROR otherwise (SIM card removed, modem is inaccessible, etc).
                 */
                virtual CODE getSimLockAttempts(int& iAttemptsPin, int& iAttemptsPuk) = 0;

                void initMipProfile(Json::Value& jData);
                bool splitAndAssign(const std::string& sLine, const std::string& sKey, Json::Value& jParent, const std::string& sJsonKey, Json::ValueType eType = Json::ValueType::stringValue);

                virtual std::string queryLteLac();
                virtual std::string queryCGREGstring();
                virtual void setCGREG(std::string value);

                const std::vector<std::string> getRegistrationCommands();
                REGISTRATION parseRegResponse(std::string sResult);
                CODE getRegistration(REGISTRATION& eRegistration, const std::string& sType);

                class RadioBandMap : public MTS::NonCopyable {
                    public:
                        RadioBandMap()
                        {
                            m_sChannel = ICellularRadio::VALUE_UNKNOWN;
                            m_iChannel = 0;
                            m_sRadioType = ICellularRadio::VALUE_UNKNOWN;
                        }

                        RadioBandMap(const std::string &channel, const std::string &radioType) :
                            m_sChannel(channel),
                            m_sRadioType(radioType)
                        {
                            m_iChannel = strtol(m_sChannel.c_str(), NULL, 10);
                        }

                        virtual ~RadioBandMap() {}

                        const char *getRadioBandName();
                        const char *getRadioBandName(const std::string &channel, const std::string &radioType);

                    private:

                        const char *getLTEBand(const int channel);
                        const char *getCDMABand(const int channel);
                        const char *getGSMBand(const int channel);

                        std::string    m_sChannel;
                        int            m_iChannel;
                        std::string    m_sRadioType;
                };

            private:
                std::string m_sName;
                std::string m_sRadioPort;
                std::string m_sFirmware;
                std::string m_sCarrier;
                MTS::AutoPtr<MTS::IO::Connection> m_apIo;

                bool m_bEchoEnabled;
                bool m_bEnableEchoOnClose;
        };
    }
}

#endif /* MTS_IO_CELLULARRADIO_H_ */