/*
 * 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 .
 *
 */
/*!
 \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 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
typedef struct
{
	const char    *name;
	int32_t        low;
	int32_t        high;
} *pNameRangeMap, nameRangeMap;
static const unsigned int NUM_GSM_BANDS = 7;
static const unsigned int NUM_WCDMA_BANDS = 6;
static const unsigned int NUM_LTE_BANDS = 42;
// http://niviuk.free.fr/gsm_band.php
static const nameRangeMap GSMband[] =
{
            {"GSM 450", 259, 293}, {"GSM 480", 306, 340},
            {"GSM 750", 438, 511}, {"GSM 850", 128, 251},
            {"GSM 900 P", 1, 124}, {"GSM 900 E/R", 955, 1023},
            {"GSM DCS 1800/1900", 512, 885},
};
// http://niviuk.free.fr/umts_band.php
static const nameRangeMap WCDMAband[] =
{
            {"BAND I",   10592, 10838}, {"BAND II", 9662, 9938},
            {"BAND III",  1162,  1513}, {"BAND IV", 1537, 1738},
            {"BAND V",    4357,  4458}, {"BAND VI", 4387, 4413}
};
// http://niviuk.free.fr/lte_band.php
static const nameRangeMap EULTRAband[] =
{
            {"EUTRAN BAND1",      0,   599}, {"EUTRAN BAND2",    600,  1199},
            {"EUTRAN BAND3",   1200,  1949}, {"EUTRAN BAND4",   1950,  2399},
            {"EUTRAN BAND5",   2400,  2649}, {"EUTRAN BAND6",   2650,  2749},
            {"EUTRAN BAND7",   2750,  3449}, {"EUTRAN BAND8",   3450,  3799},
            {"EUTRAN BAND9",   3800,  4149}, {"EUTRAN BAND10",  4150,  4749},
            {"EUTRAN BAND11",  4750,  4999}, {"EUTRAN BAND12",  5000,  5179},
            {"EUTRAN BAND13",  5180,  5279}, {"EUTRAN BAND14",  5280,  5379},
            {"EUTRAN BAND17",  5730,  5849}, {"EUTRAN BAND18",  5850,  5999},
            {"EUTRAN BAND19",  6000,  6149}, {"EUTRAN BAND20",  6150,  6449},
            {"EUTRAN BAND21",  6450,  6525}, {"EUTRAN BAND22",  6600,  7399},
            {"EUTRAN BAND23",  7500,  7699}, {"EUTRAN BAND24",  7700,  8039},
            {"EUTRAN BAND25",  8040,  8689}, {"EUTRAN BAND26",  8690,  9039},
            {"EUTRAN BAND27",  9040,  9209}, {"EUTRAN BAND28",  9210,  9659},
            {"EUTRAN BAND29",  9660,  9769}, {"EUTRAN BAND30",  9770,  9869},
            {"EUTRAN BAND31",  9870,  9919}, {"EUTRAN BAND32",  9920, 10359},
            {"EUTRAN BAND33", 36000, 36199}, {"EUTRAN BAND34", 36200, 36349},
            {"EUTRAN BAND35", 36350, 36949}, {"EUTRAN BAND36", 36950, 37549},
            {"EUTRAN BAND37", 37550, 37749}, {"EUTRAN BAND38", 37750, 38249},
            {"EUTRAN BAND39", 38250, 38649}, {"EUTRAN BAND40", 38650, 39649},
            {"EUTRAN BAND41", 39650, 41589}, {"EUTRAN BAND42", 41590, 43589},
            {"EUTRAN BAND43", 43590, 45589}, {"EUTRAN BAND44", 45590, 46589}
};
namespace MTS {
    namespace IO {
        class CellularRadio : NonCopyable {
            public:
                static const std::string DEFAULT_RADIO_PORT;
                static const std::string DEFAULT_RADIO_DIR;
                static const std::string VALUE_UNKNOWN;
                static const std::string VALUE_UNAVAILABLE;
                static const std::string VALUE_NOT_SUPPORTED;
                //Special Payload Characters
                static const char ETX;  //Ends socket connection
                static const char DLE;  //Escapes ETX and DLE within Payload
                static const char CR;
                static const char NL;
                static const char CTRL_Z;
                static const std::string RSP_OK;
                static const std::string RSP_ERROR;
                //Registration Values
                enum REGISTRATION : uint8_t {
                    NOT_REGISTERED = 0,
                    REGISTERED = 1,
                    SEARCHING=2,
                    DENIED=3,
                    UNKNOWN=4,
                    ROAMING=5
                };
                enum SERVICEDOMAIN : uint8_t {
                    NO_SERVICE = 0,
                    CS_ONLY = 1,
                    PS_ONLY = 2,
                    CSPS = 3
                };
                enum ACTIVEBAND : uint8_t {
                    GSM_850 = 0,
                    GSM_900 = 1,
                    DCS_1800 = 2,
                    PCS_1900 = 3
                };
                enum CODE : uint8_t {
                    SUCCESS = 0,
                    ERROR,
                    FAILURE,
                    NO_RESPONSE,
                    NOT_APPLICABLE,
                    INVALID_ARGS
                };
                enum SIMSTATUS : uint8_t {
                    READY = 0,
                    LOCKED,
                    BLOCKED,
                    NOT_INSERTED
                };
                static const std::string VALUE_NOT_REGISTERED;
                static const std::string VALUE_REGISTERED;
                static const std::string VALUE_SEARCHING;
                static const std::string VALUE_DENIED;
                static const std::string VALUE_ROAMING;
                //Static Data
                static const std::string KEY_TYPE;          //!< GSM or CDMA
                static const std::string KEY_CODE;          //!< Product Code : H5, H6, C2, EV3, G3
                static const std::string KEY_MODEL;         //!< Model : HE910, CE910, DE910, GE910
                static const std::string KEY_MANUFACTURER;  //!< Manufacturer: Telit
                static const std::string KEY_HARDWARE;      //!< Radio Hardware Version
                static const std::string KEY_FIRMWARE;      //!< Radio Firmware Version
                static const std::string KEY_IMEI;          //!< International Mobile Station Equipment Identity
                static const std::string KEY_MEID;          //!< Mobile Equipment Identifier
                static const std::string KEY_IMSI;          //!< International Mobile Subscriber Identity
                static const std::string KEY_MSID;          //!< Mobil Station ID (MSID) aka MIN aka MSIN aka Last few digits of IMSI
                static const std::string KEY_MDN;           //!< Mobile Directory Number : Actual phone number dialed to reach radio
                static const std::string KEY_CARRIER;       //!< Cellular Service Provider (Home Network)
                static const std::string KEY_ICCID;         //!< Integrated Circuit Card Identifier
                static const std::string KEY_MSL;           //!< Master Subsidy Lock
                //Network Status Data
                static const std::string KEY_ROAMING;       //!< Indicates whether or not using Home Network
                static const std::string KEY_DATETIME;      //!< Date and Time from tower
                static const std::string KEY_SERVICE;       //!< Service Connection Type [GPRS, EGPRS, WCDMA, HSDPA, 1xRTT, EVDO]
                static const std::string KEY_NETWORK;       //!< Cellular Service Provider
                static const std::string KEY_CID;           //!< Cellular ID (Tower) in HEX
                static const std::string KEY_LAC;           //!< Location Area Code in HEX
                static const std::string KEY_RAC;           //!< Routing Area Code in HEX
                static const std::string KEY_RSSI;          //!< Received Signal Strength Indication
                static const std::string KEY_RSSIDBM;       //!< Received Signal Strength Indication in dBm
                static const std::string KEY_MCC;           //!< Mobile Country Code
                static const std::string KEY_MNC;           //!< Mobile Network (Operator) Code
                static const std::string KEY_CHANNEL;       //!< ARFCN or UARFCN Assigned Radio Channel
                static const std::string KEY_TXPWR;         //!< Transmit Power
                static const std::string KEY_PSC;           //!< Active Primary Synchronization Code (PSC)
                static const std::string KEY_ECIO;          //!< Active Ec/Io (chip energy per total wideband power in dBm)
                static const std::string KEY_RSCP;          //!< Active RSCP (Received Signal Code Power in dBm)
                static const std::string KEY_DRX;           //!< Discontinuous reception cycle length (ms)
                static const std::string KEY_MM;            //!< Mobility Management State
                static const std::string KEY_RR;            //!< Radio Resource State
                static const std::string KEY_NOM;           //!< Network Operator Mode
                static const std::string KEY_ABND;          //!< Active Band
                static const std::string KEY_BLER;          //!< Block Error Rate (percentage)
                static const std::string KEY_SD;            //!< Service Domain
                static const std::string KEY_DEBUG;         //!< Debug Information
                static const std::string KEY_MIP;                //!< Mobile IP Information
                static const std::string KEY_MIP_ID;             //!< MIP Profile ID
                static const std::string KEY_MIP_ENABLED;         //!< MIP Profile Enabled/Disabled
                static const std::string KEY_MIP_NAI;            //!< Network Access Identifier
                static const std::string KEY_MIP_HOMEADDRESS;    //!< Home Address
                static const std::string KEY_MIP_PRIMARYHA;      //!< Primary Home Agent
                static const std::string KEY_MIP_SECONDARYHA;    //!< Secondary Home Agent
                static const std::string KEY_MIP_MNAAASPI;       //!< Mobile Node Authentication, Authorization, and Accounting Server Security Parameter Index
                static const std::string KEY_MIP_MNHASPI;        //!< Mobile Node Home Agent Security Server Parameter Index
                static const std::string KEY_MIP_REVTUN;         //!< Reverse Tunneling Enabled
                static const std::string KEY_MIP_MNAAASS;        //!< Mobile Node Authentication, Authorization, and Accounting Server Shared Secret
                static const std::string KEY_MIP_MNHASS;         //!< Mobile Node Home Agent Shared Secret
                //Values - Type
                static const std::string VALUE_TYPE_LTE;
                static const std::string VALUE_TYPE_GSM;
                static const std::string VALUE_TYPE_CDMA;
                //Values - Carrier
                static const std::string VALUE_CARRIER_VERIZON;
                static const std::string VALUE_CARRIER_AERIS;
                static const std::string VALUE_CARRIER_SPRINT;
                static const std::string VALUE_CARRIER_ATT;
                static const std::string VALUE_CARRIER_TMOBILE;
                static const std::string VALUE_SD_NO_SERVICE;
                static const std::string VALUE_SD_CS_ONLY;
                static const std::string VALUE_SD_PS_ONLY;
                static const std::string VALUE_SD_CSPS;
                static const std::string VALUE_ABND_GSM_850;
                static const std::string VALUE_ABND_GSM_900;
                static const std::string VALUE_ABND_DCS_1800;
                static const std::string VALUE_ABND_PCS_1900;
                static const std::vector DEFAULT_BAIL_STRINGS;
                typedef std::function IsNeedMoreData;
                typedef std::function UpdateCb;
                virtual ~CellularRadio();
                virtual bool initialize(uint32_t iTimeoutMillis = 5000);
                virtual bool resetRadio(uint32_t iTimeoutMillis = 5000);
                virtual bool resetConnection(uint32_t iTimeoutMillis = 5000);
                virtual void shutdown();
                const std::string& getName() const;
                virtual CODE getModel(std::string& sModel);
                static CODE convertModelToType(const std::string& sModel, std::string& sType);
                static CODE convertModelToMtsShortCode(const std::string& sModel, std::string& sCode);
                static CODE convertServiceDomainToString(SERVICEDOMAIN eSd, std::string& sSd);
                static CODE convertActiveBandToString(ACTIVEBAND eBand, std::string& sBand);
                virtual CODE getFirmware(std::string& sFirmware);
                virtual CODE getHardware(std::string& sHardware);
                virtual CODE getManufacturer(std::string& sManufacturer);
                virtual CODE getImei(std::string& sImei);
                virtual CODE getMeid(std::string& sMeid);
                virtual CODE getImsi(std::string& sImsi);
                virtual CODE getSimStatus(std::string& sSimStatus);
                virtual CODE getIccid(std::string& sIccid);
                virtual CODE getService(std::string& sService);
                virtual CODE getLac(std::string& sLac);
                virtual CODE getMdn(std::string& sMdn);
                virtual CODE getMsid(std::string& sMsid);
                virtual CODE getType(std::string& sType);
                virtual CODE getCarrier(std::string& sCarrier);
                virtual CODE getNetwork(std::string& sNetwork);
                virtual CODE getTower(std::string& sTower);
                virtual CODE getTime(std::string& sDate, std::string& sTime, std::string& sTimeZone);
                virtual CODE getRoaming(bool& bRoaming);
                virtual CODE getSignalStrength(int32_t& iRssi);
                virtual CODE convertSignalStrengthTodBm(const int32_t& iRssi, int32_t& dBm);
                virtual CODE convertdBmToSignalStrength(const int32_t& dBm, int32_t& iRssi);
                virtual CODE getRegistration(REGISTRATION& eRegistration);
                virtual CODE convertRegistrationToString(REGISTRATION eRegistration, std::string& sRegistration);
                //! Gather details of the radio's Mobile IP Profile
                /*!
                 \param Json::Value object that will be populated with MIP data
                 \return Returns result code of gathering MIP
                 */
                virtual CODE getMipProfile(Json::Value& jMipProfile);
                /*
                 * jArgs = {
                 *     "msl" : "Master Subsidy Lock (Aeris, Sprint): STRING"
                 * }
                 */
                virtual CODE validateMsl(const Json::Value& jArgs);
                /*
                 * jArgs = {
                 *     "mdn" : "Mobile Directory Number : STRING",
                 *     "msl" : "[OPTIONAL] Master Subsidy Lock (Aeris, Sprint): STRING"
                 * }
                 */
                virtual CODE setMdn(const Json::Value& jArgs);
                /*
                 * jArgs = {
                 *     "msid" : "Mobil Station ID (MSID) aka MIN aka MSIN : STRING",
                 *     "msl" : "[OPTIONAL] Master Subsidy Lock (Aeris, Sprint): STRING"
                 * }
                 */
                virtual CODE setMsid(const Json::Value& jArgs);
                /*
                 * jArgs = {
                 *     "activeProfile" : "Set active profile: STRING"
                 * }
                 */
                virtual CODE setMipActiveProfile(const Json::Value& jArgs);
                /*
                 * jArgs = {
                 *     "nai" : "Network Access Identifier : STRING"
                 * }
                 */
                virtual CODE setMipNai(const Json::Value& jArgs);
                /*
                 * jArgs = {
                 *     "homeIp" : "Home Address : STRING"
                 * }
                 */
                virtual CODE setMipHomeIp(const Json::Value& jArgs);
                /*
                 * jArgs = {
                 *     "primaryHa" : "Primary Home Agent : STRING"
                 * }
                 */
                virtual CODE setMipPrimaryHa(const Json::Value& jArgs);
                /*
                 * jArgs = {
                 *     "secondaryHa" : "Secondary Home Agent : STRING"
                 * }
                 */
                virtual CODE setMipSecondaryHa(const Json::Value& jArgs);
                /*
                 * jArgs = {
                 *     "mnAaaSpi" : "Mobile Node Authentication, Authorization, and Accounting Server Security Parameter Index : STRING"
                 * }
                 */
                virtual CODE setMipMnAaaSpi(const Json::Value& jArgs);
                /*
                 * jArgs = {
                 *     "mnHaSpi" : "Mobile Node Home Agent Security Server Parameter Index : STRING"
                 * }
                 */
                virtual CODE setMipMnHaSpi(const Json::Value& jArgs);
                /*
                 * jArgs = {
                 *     "revTun" : "[DESCRIPTION] : STRING"
                 * }
                 */
                virtual CODE setMipRevTun(const Json::Value& jArgs);
                /*
                 * jArgs = {
                 *     "mnAaaSs" : "Mobile Node Authentication, Authorization, and Accounting Server Shared Secret : STRING"
                 * }
                 */
                virtual CODE setMipMnAaaSs(const Json::Value& jArgs);
                /*
                 * jArgs = {
                 *     "mnHaSs" : "Mobile Node Home Agent Shared Secret : STRING"
                 * }
                 */
                virtual CODE setMipMnHaSs(const Json::Value& jArgs);
                /*
                 * jArgs = null
                 */
                virtual CODE updateDc(const Json::Value& jArgs, UpdateCb& stepCb);
                /*
                 * jArgs = null
                 */
                virtual CODE updatePrl(const Json::Value& jArgs, UpdateCb& stepCb);
                /*
                 * jArgs = null
                 */
                virtual CODE updateFumo(const Json::Value& jArgs, UpdateCb& stepCb);
                /*
                 * jArgs = {
                 *     "msl" : "Master Subsidy Lock (Sprint): STRING"
                 * }
                 */
                virtual CODE resetHfa(const Json::Value& jArgs, UpdateCb& stepCb);
                /*
                 * jArgs = {
                 *     "mdn" : "Mobile Directory Number (Aeris): STRING"
                 *     "msid" : "Mobile Station ID (Aeris): STRING"
                 * }
                 */
                virtual CODE activate(const Json::Value& jArgs, UpdateCb& stepCb);
                /*
                 * jArgs = {
                 *     "enabled" : "RX Diversity Enabled ("0" or "1"): STRING"
                 * }
                 */
                virtual CODE setRxDiversity(const Json::Value& jArgs)=0;
                virtual CODE getEcho(bool& bEnabled);
                virtual CODE setEcho(bool bEnabled = true);
                virtual CODE getStaticInformation(Json::Value& jData);
                virtual CODE getNetworkStatus(Json::Value& jData);
                virtual CODE sendBasicCommand(const std::string& sCmd, int32_t timeoutMillis = 100, const char& ESC = CR);
                virtual std::string sendCommand(const std::string& sCmd,
                                                const std::vector& vBail = DEFAULT_BAIL_STRINGS,
                                                int32_t timeoutMillis = 100,
                                                const char& ESC = CR);
                static std::string sendCommand(MTS::AutoPtr& apIo,
                                               const std::string& sCmd,
                                               const std::vector& vBail = DEFAULT_BAIL_STRINGS,
                                               int32_t timeoutMillis = 100,
                                               const char& ESC = CR);
                virtual std::string sendCommand(const std::string& sCmd,
                                                IsNeedMoreData& isNeedMoreData,
                                                int32_t timeoutMillis = 100,
                                                const char& ESC = CR);
                static std::string sendCommand(MTS::AutoPtr& apIo,
                                               const std::string& sCmd,
                                               IsNeedMoreData& isNeedMoreData,
                                               int32_t timeoutMillis = 100,
                                               const char& ESC = CR);
                static CODE test(MTS::AutoPtr& apIo, uint32_t timeoutSeconds = 30);
                static std::string extractModelFromResult(const std::string& sResult);
                static std::string getCodeAsString(CODE code);
            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);
                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);
            private:
                class RadioBandMap : NonCopyable {
                    public:
                    	RadioBandMap()
                    	{
                            m_sChannel = CellularRadio::VALUE_UNKNOWN;
                            m_iChannel = 0;
                            m_sRadioType = CellularRadio::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;
                };
                std::string m_sName;
                std::string m_sRadioPort;
                std::string m_sFirmware;
                std::string m_sCarrier;
                MTS::AutoPtr m_apIo;
                bool m_bEchoEnabled;
                bool m_bEnableEchoOnClose;
                std::string queryLteLac();
                std::string queryCGREGstring();
                void setCGREG(std::string value);
        };
    }
}
#endif /* MTS_IO_CELLULARRADIO_H_ */