#ifndef BSSCOMM__H
#define BSSCOMM__H
/*******************************************************************

 Usage: Interwave network Management Protocol(IMP) interface for BSS OMC

 Interface function:
 {1}imp_init() -> init IMP interface for BSS OMC
	Step 0: init MySQL database (BssOmcDb)
			->connectDB();
			->initOMCR_COMMANDTable();
			->GetBssMaxConfigFromDB();
			->GetAllTableName();
	Step 1: init ImpConn structure
	Step 2: set CmdBuffer[CMD_BUFFER_SIZE] structure is available
	Step 3: get bssid,ip from MySQL database which has been added by BSS OMC operator
			->SELECT bssid,ip,name,uploaded FROM OMCR_BSSTABLE WHERE ip<>'';
			->AddImpConn(): put pBssConn->(bssid,ip..) to bsplus_down[]
	Step 4: Synchronize the OMCR_BSSTREE.MaxSeverity with OMCR_ALARMEVENT at startup
			->syncBssTreeAlarm()
	Step 5: init BssStatus Transmitter
			->initBssStatusTransmitter():check BSS OMC(hb_port.4957) is ok and initHeartbeatStruct()
				  
 {2}imp_timer()-> Call ImpConnMultiplexer() to Maintain a IMP connection with all the manageable iwbox
	Part 0: connect with BSS
	Part 1: if BSS start ,upload from BSS
	Part 2: if receive no event,
			->retrieveCmdFromDatabase()
			->ProcessUserCommand(tImpConn *pBssConn, char *pCommandString, u32 TransId)
			->DispatchNmiCommand(pBssConn):Send 1 command to each BSS in one cycle if queue is not empty
	Part 3: if receive imp message,
			Step 0: Copy previous buffer content into present buffer
			Step 1: Read IMP Length Header
			Step 2: Read the remaining IMP message
			Step 3: Whole message has been read
			Step 4: Process imp message
					State 1:(if event)ProcessEventMsg(),according eventname
							"FailureReport"   ->update_alarmevent_table
							"BtsMeasurements" ->update_BtsMeas_table
							"tstComplete"	  ->update_bootup_time
							"CardCreated"     ->update_cardcreated_event
							"TrxCreated"      ->update_trxcreated_event
							"Cser"or"ACN"     ->update_networkevent_table
					State 2: Decode IMP Response Message,according OperatorCode
							Create or Delete  ->ProcessCreateDeleteBody ->requestObjCfg
							Contents		  ->ProcessContentsBody		
							Set or Get		  ->ProcessSetGetBody		->updateBssCfg
							Action			  ->ProcessActionBody
 Bsplus monitoring server:
                      ---------               ---------
                     | bsscomm |             | monitor |				
					  ---------				  ---------
                                   add 
	tell monitor program                        according to the bsplus ip     ping
	the bsplus ip/bssid list  --------------->   Test connection with BSS    ------------> BSS
	   
                                   new
    Calling:restoreBssConn()
	Try to restore connection <---------------	if ping successful
    If reconnect,put the 
	connection in bsplus[]

	                               clr
    Calling:ClearBssConn()    <---------------   if ping fail(fail count >20)
	TCP connnection lost
	Move bsplus[i] to bsplus_down[]


 Code file list:
 
 bsscomm.c,bsscomm.h:     IMP(interWave Network Mannagement) interface for BSS OMC
 nmimp.c  ,nmimp.h  :     Methods for IMP data marshaling/unmarshaling.
 nmtypes.c,nmtypes.h:	  Definitions of fundamental data types.
 bss_hb.c ,bss_hb.h :     init and refresh BSS(BSC+BTS) status.
 alive.c				  monitoring the connection between Bsscomm and BSS
	
 Author:XChen
 Date:	2006-09-20
********************************************************************/

#include <stdio.h>
#include <stdlib.h>

#include <signal.h>
#include <ctype.h>
#include "unistd.h"
#include <errno.h>
/* 
 * Include ModImp header files here
 */
#include "iwtypes.h"
#include "nmtypes.h"
#include "nmstatus.h"
#include "nmimp.h"
/*
 * For ImpConnMultiplexer
 */
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/time.h>
#include <netdb.h>
#include <time.h>
/*
 * Max 12 BSC and 12x12 BTS
 */
#define NO_OF_BSS		12
#define NO_OF_BTSMgr	13
/*
 * MySQL connection
 */
#include "mysql.h"
#define DB            "BssOmcDb"
#define USERNAME      "application"
#define PASSWD        "noitacilpPA#68*"
#define SQLSTRING_LEN 16384      // 16384 = 2^14

MYSQL        mysql,*mysql_sock;
MYSQL_RES    *result;
MYSQL_ROW    row;
//MYSQL_FIELD  *field;
char         sqlstring[SQLSTRING_LEN];

/*
 * Store the name of MYSQL tablename at program startup
 */
#define MAX_NUM_OF_SQL_TABLE 100
int num_of_mysql_table;
char **mysql_tables;

#define NMIPORT 2112
#define BUFMAX 4096
#define MSG_BODY_SIZE 1024
#define SILENT_CODE ((u32)0x0)
#define WAIT_TIME 120
#define MEASUREMENT_INTERVAL 15
//#define BSSVERSION  "iw06_00.028"
/*
 * For BSS momitor
 */
#define MONITOR_PORT 5354
int monitor_fd=-1;

#define TIME_LEN 9

#define ADD 1
#define DEL 2
#define CLR 3
/*
 * For processing user command
 */
#define READ_CMD        0
#define READ_OBJECT     1
#define READ_PARMS      2
#define READ_END        3

#define BSSERROR        (-1)
#define ACTION          0
#define CONTENTS        1
#define CREATE          2
#define DELETE          3
#define GET             4
#define OID             5
#define SET             6
#define NEWBSS          7
#define DROPBSS         8
#define UPLOAD          9
/*
 * For alarm management
 */
#define SV_CEASED           0
#define SV_CRITICAL         1
#define SV_MAJOR            2
#define SV_MINOR            3
#define SV_WARNING          4
#define SV_INDETERMINATE    5
#define MAXSEVERITY SV_MAJOR      // The maxseverity in number of concern
                                  // You have to update alarmevent.php accordingly
#define HEARTBEAT_INTERVAL  10L
#define SELECT_INTERVAL  2L
/*
 * keep track the command status after PHP put the command on DB
 */
#define CMD_NEW           255
#define CMD_READ_FROM_DB  254
#define CMD_END           0

#define CONNECTED_STATE_MAX 255

#define GET_READ_ATTRIB   1
#define GET_ATTRIB_END    2

#define SET_READ_ATTRIB   1
#define SET_READ_INT      2
#define SET_READ_STRING   3
#define SET_READ_INTARRAY 4
#define SET_COMMAND_END   5
#define SET_ATTRIB_END    6
#define SET_INT_END       7
#define SET_STRING_END    8
#define SET_INTARRAY_END  9

#define BSSID_EXIST   1
#define BSSID_TOO_BIG 2
#define IP_EXIST      3

#define READ_BSSID     1
#define READ_BSSID_END 2
#define READ_IP        3
#define READ_IP_END    4

#define ObjectIdMaxLevel 6
/*
 * ImpConn structure definition
 * This stores the IMP connection from BSS
 */
struct ImpConn {
    int bssid;                // initialize to -1
    char ip[16];              // initialize to 0.0.0.0
    char bssname[80];         // initialize to BSS_<bssid>
    int port;                 // initialize to -1
    int sockfd;               // initialize to -1
    u32 SeqNum;               // initialize to 0
    tOid TheOid;              // initialize to OID_INIT
    tCID TheCid;              // initialize to NM_CLASS_UNDEFINED
    struct queue *pCmdQ;      // initialize to NULL
    struct queue *pCmdQEnd;   // initialize to NULL
    int uploaded;             // initialize to 0, already uploaded when = 1
    int connected;   
    int download_in_progress; // initialize to 0, connected when >= 1
    int last_Total;           // no of bytes read so far for an IMP packet
    u8 lastMsgRecvBuffer[IMP_MAX_HDR_LENGTH + MSG_BODY_SIZE];
    u32 bootupTime;           // initialize to 0L
    u32 last_TransId;         // TransId of the command in processing
                              // initialize to 0 (=not in processing)
    int upload_in_progress; // initialize to 0
    int current_upload_level; // initialize to 1
    u32 upload_TransId;
    time_t last_connected_abnormal;  
	time_t this_connected_abnormal;
};
typedef struct ImpConn tImpConn;

tImpConn *BssConn;
tImpConn **bsplus;
tImpConn **bsplus_down;
/*
 * ImpEvent structure definition
 * This stores the IMP event from BSS
 */
#define EVENTINFO_ARRAY_SIZE 512
#define MAX_OBJECTID_LEN 40
struct ImpEvent {
    char eventname[40];
    char objectid[MAX_OBJECTID_LEN];
    char classname[40];
    char eventtime[25];
    unsigned long eventsecond;                    /* no of sec from 1 Jan 1970*/
    unsigned long globaleventnumber;
    unsigned int eventcause;
    char alarmlevel[10];
    char eventinfo[EVENTINFO_ARRAY_SIZE][512];    /* Array of Evt Msg Body */
    int  eventinfosize;                           /* Array size */
    int  eventtype;
    int  severity;
};
typedef struct ImpEvent tImpEvent;
tImpEvent BssEvent;
/*
 * Use link list to maintain the queue of commands for each IMP connection
 * A shared buffer(array) is used to store the commands to different BSS
 * The command buffer is indexed from 0 to CMD_BUFFER_SIZE-1
 * CmdBufferPtr points to the first available command buffer
 */
#define CMD_BUFFER_SIZE 16000
#define CMD_BUFFER_FULL (-1)
#define CMD_SIZE        2048

struct queue {                    // A FIFO Queue
    char command[CMD_SIZE];
    struct queue *nextcmd;
    u32 TransId;
    bool available;
};
struct queue CmdBuffer[CMD_BUFFER_SIZE];
int CmdBufferPtr=0;
/*
 * Function declaration
 */
//init imp structure
void initImpConn(tImpConn * pBssConn);
void initImpEvent(tImpEvent *pBssEvent);
void AddImpConn(int bssid, char *ipaddr, char *bssname, int uploaded);
//init Bss MySQL database
void connectDB();
void initOMCR_COMMANDTable();
void GetAllTableName();
void GetBssMaxConfigFromDB();
void syncBssTimeWithOMC(tImpConn *pBssConn, time_t tloc);
void syncBssTreeAlarm();
//connection management
void restoreBssConn(int bssid, char *ip);
void discBssConn(int bssid, char *ip, fd_set *readfds);
void clearBssConn(tImpConn *pBssConn,fd_set *readfds);
int  connectIwBox(char *target, int port);

void stopIwBoxMonitor();
void startIwBoxMonitor(char *hostname, int port);
void InformIwBoxMonitor(tImpConn *pBssConn, int action);
void GetMonitorResult(char *buffer, fd_set *readfds);

//get command
void addCmd2Queue(tImpConn *pBssConn,char *nmicommand,long SeqNum);
void retrieveCmdFromDatabase();
bool FindAvailCmdBufferPtr();
void DispatchNmiCommand(tImpConn *pBssConn);
//process command and encode imp message
int OidCommand(tImpConn * pBssConn,char *pImpCmdContName, u32 *pImpCmdIndex, ix ImpCmdIndexCount, u32 TransId);
int GetCommand(tImpConn * pBssConn, char *pImpCmd, u32 TransId);
int SetCommand(tImpConn * pBssConn, char *pImpCmd, u32 TransId);
int ActionCommand(tImpConn *pBssConn, char *pImpCmdContName, u32 *pImpCmdIndex,ix ImpCmdIndexCount, u32 TransId);
int CreateCommand(tImpConn * pBssConn, char *pImpCmdContName,u32 * pImpCmdIndex, u32 TransId);
int DeleteCommand(tImpConn * pBssConn, char *pImpCmdContName,u32 * pImpCmdIndex, u32 TransId);
int ContentsCommand(tImpConn *pBssConn, u32 TransId);
int AddDropBsplusCommand(char *pImpCmd, int action, u32 TransId);//Calling NewBsplus,DropBsplus

int ProcessCommandString(char *pCommandString,char *pObjName, u32 *pParameter, int *count);//Calling CommandType
int ProcessUserCommand(tImpConn *pBssConn, char *pCommandString, u32 TransId);
//decode imp message
unsigned int imp_response(tImpConn *pBssConn, tIMPHDR *pHeader,char *response);

static void    ProcessContentsBody(u8** ppBuf, char *response);
static void    ProcessSetGetBody(tImpConn *pBssConn, u8** ppBuf, char *response,u16 *responsecode, bool HasStatus);
static void    ProcessActionBody(tImpConn *pBssConn, u8** ppBuf,char *response);
static void    ProcessCreateDeleteBody(u8** ppBuf,char *strValue, u16 *intValue);
static void    ProcessEventBody(tImpConn *pBssConn, u8** ppBuf,tImpEvent *pBssEvent);
bool ProcessEventMsg(tImpConn *pBssConn, u8* pMsg, tImpEvent *pBssEvent);
bool ProcessMessage(tImpConn *pBssConn, u8* pMsg, tIMPHDR *pHeader, fd_set *readfds);
bool CheckForMessages(tImpConn *pBssConn, tIMPHDR *pHeader, fd_set *readfds, time_t last_heartbeat_time);

//according to imp response,update bss database
unsigned int update_bsstable_status(tImpConn *pBssConn);
unsigned int update_command_status(int resultcode, char *result,int responsecode, char *response, u32 TransId);
unsigned int update_BtsMeas_table(char *buffer, tImpConn *pBssConn,tImpEvent *pBssEvent, long *cellid);
unsigned int update_alarmevent_table(char *buffer, tImpConn *pBssConn, tImpEvent *pBssEvent, fd_set *readfds);
unsigned int update_acn_cser_event(char *buffer, tImpConn *pBssConn,tImpEvent *pBssEvent);
unsigned int update_cardcreated_event(tImpConn *pBssConn, tImpEvent *pBssEvent);
unsigned int update_trxcreated_event(tImpConn *pBssConn, tImpEvent *pBssEvent);
unsigned int update_networkevent_table(char *buffer, tImpConn *pBssConn,tImpEvent *pBssEvent);
void update_bootup_time(tImpConn *pBssConn, tImpEvent *pBssEvent);

int requestObjCfg(tImpConn *pBssConn, char *objectid,int objectidLevel);
int requestBssCfg(tImpConn *pBssConn);
int requestBtsCfg(tImpConn *pBssConn, char *btsmgrid);
int updateBssCfg(tImpConn *pBssConn, tIMPHDR *pHeader, char *response);
int checkBsType(int bssid);
//unsigned int generateBtsStatReport();
#endif /*BSSCOMM__H */
