/****************************************************************************
** ui.h extension file, included from the uic-generated form implementation.
**
** If you want to add, delete, or rename functions or slots, use
** Qt Designer to update this file, preserving your code.
**
** You should not define a constructor or destructor in this file.
** Instead, write your code in functions called init() and destroy().
** These will automatically be called by the form's constructor and
** destructor.
*****************************************************************************/
#include <qmessagebox.h>
#include <qlistview.h>
#include <qtimer.h>

#include <time.h>
#include <netdb.h>
#include <arpa/inet.h>

#ifdef HAVE_CONFIG_H
#include <../../config.h>
#endif

#include "../../src/cshmem.h"
#include "../../src/gldefs.h"
#include "../../src/structs.h"
#include "../../src/glfunc.h"
#include "../../src/clog.h"


// Prototypes
bool displayMonParams(CMainPanel &c);
bool updateParamsList(CMainPanel &c, lpsapp_config lpsac);
bool displayLastEvents(CMainPanel &c);
int getUserConfig(suser_config *psuc);
int sendMsgToNetClients(CMainPanel &c, suser_config suc, const char *szMessage);

// last registered event
static time_t tlast_ref;
// main timer
QTimer *tmr;

// implementation

void CMainPanel::fileExit()
{
}


void CMainPanel::helpAbout()
{
	QMessageBox::about( this, "About PowerSoft Plus Control Panel",
        "PowerSoft Plus Control Panel is a user interface \n"
		"for PowerSoft Plus monitoring program.\n"
		"It displays all parameters available for selected UPS type.\n\n"
        "Property rights 2004-2006 EVER Sp. z o.o.\n"
        "http://www.ever.com.pl\n" );
}


bool CMainPanel::dataRefresh()
{
	handleFormControls();
	displayLastEvents(*this);
	displayMonParams(*this);
	return true;
}


bool displayMonParams(CMainPanel &c)
{
	bool bRet;
	QString str;
	CShMem *pMain = new CShMem();
	if (pMain==NULL) {
		str.sprintf("%s (%s)", TXT_ERR_MEMALLOC, strerror(errno));
		QMessageBox::critical(0, "PowerSoft Plus", str);
		return false;
	}
		
	if (pMain->createkey(SHM_PATHNAME, SHM_PROJID)!=SHM_SUCCESS) {
		str.sprintf("%s (%s)", TXT_ERR_SHAREMEMCREATE, strerror(errno));
		QMessageBox::critical(0, "PowerSoft Plus", str);
		return false;
	} else {
		if (pMain->open(PS_SHM_SIZE)==SHM_SUCCESS) {
			sapp_config *pacfg = new sapp_config;
			if (pacfg!=NULL) {
				pMain->read(pacfg, APPCFG_OFFSET, sizeof(sapp_config), true);
				bRet = updateParamsList(c, pacfg);
				delete pacfg;
				pMain->close();
				if (!bRet) {
					delete pMain;
					return false;
				}
			} else {
				str = "Can't allocate memory!\n";
				QMessageBox::critical(0, "PowerSoft Plus", str);
				delete pMain;
				return false;
			}
		} else {
			//str = "PowerSoft Plus monitoring service is not started!\n";
			//QMessageBox::critical(0, "PowerSoft Plus", str);
			delete pMain;
			return false;
		}
	}
	delete pMain;
	
	return true;
}

bool updateParamsList(CMainPanel &c, lpsapp_config lpsac)
{
	QString str, strv, strd;
	bool bFirstTime;
	char szBatteryState[5][64]={
		TXT_PARAM_BS_CHARGING,TXT_PARAM_BS_FULL,TXT_PARAM_BS_DISCHARGING,
		TXT_PARAM_BS_DISCHARGED,TXT_PARAM_BS_DEPLETED};
	unsigned int *uiValTmp, *uiDivTmp;
	char szTmpVal[256];
	
	lpsparams_binder lpspb = new sparams_binder[INT_MAX_PROGRAMPARAMS];
	
	if (lpspb!=NULL) {
		if (fill_params_struct(lpspb, &lpsac->supsi.sUpsParameters) < INT_MAX_PROGRAMPARAMS) {
			delete [] lpspb;
			return false;
		}
		str.sprintf("%s", lpsac->supsi.sUpsParameters.sz__uid_model);
		c.lineEdit1->setText(str);
		// status
		if (getUpsStateString(szTmpVal, lpsac->supsi.ulUpsStateMask, lpsac->supsi.ulUpsState, 0)==1) {
			str.sprintf("%s", szTmpVal);
		} else {
			str.sprintf("%s", TXT_EVENT_UNKNOWNSTATE);
		}
		c.lineEdit2->setText(str);
		// alarm
		if (getUpsStateString(szTmpVal, lpsac->supsi.ulUpsStateMask, lpsac->supsi.ulUpsState, 1)==1) {
			str.sprintf("%s", szTmpVal);
		} else {
			str.sprintf("-");
		}
		c.lineEdit3->setText(str);
		str.sprintf("%s", getenv("USERNAME"));
		c.lineEdit4->setText(str);
		str.sprintf("%s", getenv("HOSTNAME"));
		c.lineEdit5->setText(str);
				
		QListViewItem *lvi, *llvi = NULL;
		
		bFirstTime = (c.listView1->childCount() == 0) ? true : false;
		
		if (bFirstTime) {
			str.sprintf("%s", lpsac->sdrvcfg.szBmpFileName);
			QPixmap * qp = new QPixmap(str);
			c.pixDevice->setPixmap(*qp);
		}
		
		for (int i = 0; i < INT_MAX_PROGRAMPARAMS; i++) {
			if (!flag_check(lpsac->supsi.sUpsParameters.iMask, lpspb[i].iId))
				continue;
			if (lpspb[i].bIntegral) {
				uiValTmp = (unsigned int *)(lpspb[i].lpVarPtr);
				uiDivTmp = (unsigned int *)(lpspb[i].lpDivPtr);
				if (uiDivTmp != NULL)
					if ((*uiDivTmp != 1) && (*uiDivTmp != (unsigned int)-1))
						sprintf(szTmpVal, "%.1f", ((float)(*uiValTmp) / (float)(*uiDivTmp)));
					else
						sprintf(szTmpVal, "%.0f", ((float)(*uiValTmp) / (float)(*uiDivTmp)));
				else
					if (lpspb[i].iId == UP_BATTERYSTATE)
						sprintf(szTmpVal, "%s", (char *)szBatteryState[(*uiValTmp)]);
					else
						sprintf(szTmpVal, "%d", *uiValTmp);
			} else {
				if (lpspb[i].lpVarPtr!=NULL)
					sprintf(szTmpVal, "%s", (char *)lpspb[i].lpVarPtr);
			}
			str.sprintf("%s", lpspb[i].szName);
			strv.sprintf("%s", szTmpVal);
			if (lpspb[i].bIntegral && lpspb[i].iId!=UP_BATTERYSTATE)
				strd.sprintf("%s", lpspb[i].szDesc);
			else
				strd = ("");
			if (bFirstTime) {	// upload list
				lvi = new QListViewItem( c.listView1, llvi, str, strv, strd );
				c.listView1->insertItem(lvi);
				llvi = lvi;
			} else {			// update list
				lvi = c.listView1->findItem(str, 0, Qt::ExactMatch);
				if (lvi != 0) {
					lvi->setText(1, strv);
				}
			}
			
		}
		delete [] lpspb;

		unsigned int w = c.listView1->visibleWidth();
		c.listView1->setColumnWidth(0, (w * 40) / 100);
		c.listView1->setColumnWidth(1, (w * 45) / 100);
		c.listView1->setColumnWidth(2, (w * 15) / 100);
	
	} else {
		str.sprintf("%s (%s)", TXT_ERR_MEMALLOC, strerror(errno));
		QMessageBox::critical(0, "PowerSoft Plus", str);
	}
	return true;
}

bool displayLastEvents(CMainPanel &c)
{
	char messageType[6][32] = {
		"Alert", "Critical", "Error", "Warning", "Notice", "Information"
	};
	QString strt, strd, strtype;
	CLog elog;
	struct tm t;
	time_t ttmp = 0, tcur = 0;
	msgtype m;
	long lcnt = 0;
	QListViewItem *lvi, *llvi = NULL;
	char logbuff[256] = "";
	
	elog.open_read_buff(APP_FILE_EVENTLOG);
	elog.get_linecount(&lcnt);
	
	if (lcnt>0) {
		if (c.listViewLastEv->childCount() == 0) {
			// first time after start
			if (lcnt>=3) {
				for (long i=lcnt-3; i<lcnt; i++) {
					elog.read_msg(&t, &m, logbuff, sizeof(logbuff), &i);
					tcur = mktime(&t);
					strt.sprintf("%d-%d-%d %02d:%02d:%02d", t.tm_mday, t.tm_mon+1, t.tm_year+1900, t.tm_hour, t.tm_min, t.tm_sec);
					strd.sprintf("%s", logbuff);
					strtype.sprintf("%s", messageType[m-1]);
					lvi = new QListViewItem(c.listViewLastEv, NULL, strt, strd, strtype);
					c.listViewLastEv->insertItem(lvi);
					llvi = lvi;
				}
			}
			tlast_ref = tcur;
		} else {
			for (long i=lcnt-1; i>=0; i--) {
				elog.read_msg(&t, &m, logbuff, sizeof(logbuff), &i);
				tcur = mktime(&t);
				if (i==lcnt-1)
					ttmp = tcur;
				if (difftime(tlast_ref, tcur) == 0) {
					tlast_ref = ttmp;
					break;
				}
				strt.sprintf("%d-%d-%d %02d:%02d:%02d", t.tm_mday, t.tm_mon+1, t.tm_year+1900, t.tm_hour, t.tm_min, t.tm_sec);
				strd.sprintf("%s", logbuff);
				strtype.sprintf("%s", messageType[m-1]);
				lvi = new QListViewItem(c.listViewLastEv, llvi, strt, strd, strtype);
				c.listViewLastEv->insertItem(lvi);
				llvi = lvi;
			}
			//tlast_ref = ttmp;
		}
	}
	elog.close();
	
	unsigned int w = c.listViewLastEv->visibleWidth();
	c.listViewLastEv->setColumnWidth(0, (w * 17) / 100);
	c.listViewLastEv->setColumnWidth(1, (w * 71) / 100);
	c.listViewLastEv->setColumnWidth(2, (w * 12) / 100);
	return false;
}

int getUserConfig(suser_config *psuc)
{
	if (psuc==NULL)
		return 0;
	CShMem *pMain = new CShMem();
	if (pMain->createkey(SHM_PATHNAME, SHM_PROJID)!=SHM_SUCCESS) {
		return 0;
	} else {
		if (pMain->open(PS_SHM_SIZE)==SHM_SUCCESS) {
			pMain->read(psuc, USRCFG_OFFSET, sizeof(suser_config), true);
			pMain->close();
		} else {
			delete pMain;
			return 0;
		}
	}
	delete pMain;
	return 1;
}

void CMainPanel::init()
{
	listView1->setSorting(-1, TRUE);
	listViewLastEv->setSorting(-1, TRUE);
    
	// set timer to automatically refresh all data
	tmr = new QTimer(this);
	connect( tmr, SIGNAL(timeout()), this, SLOT(dataRefresh()) );
	tmr->start(5000, FALSE);
	
	netClnListRefresh();
}


void CMainPanel::destroy()
{
	if (tmr != NULL) {
		tmr->stop();
		delete tmr;
	}
}


int CMainPanel::enableMonitoring()
{
	setCursor(WaitCursor);
	// make sure that no unprivileged users will make use of this function
	if (!is_root()) {
		QString str = "In order to execute this function, it is necessary to have a superuser privileges.";
		setCursor(ArrowCursor);
		return 0;
	} else {
		char scmd[MAX_PATHBUFF];
		sprintf(scmd, "%s", APP_PATHNAME);
		if (system(scmd)==-1) {
			QMessageBox::critical(0, "PowerSoft Plus", TXT_ERR_FAILTOEXECUTE);
		}
	}
	setCursor(ArrowCursor);
	return 1;
}


int CMainPanel::disableMonitoring()
{
	setCursor(WaitCursor);
	// make sure that no unprivileged users will make use of this function
	if (!is_root()) {
		QString str = "In order to execute this function, it is necessary to have a superuser privileges.";
		setCursor(ArrowCursor);
		return 0;
	} else {
		char scmd[MAX_PATHBUFF];
		sprintf(scmd, "%s -t", APP_PATHNAME);
		if (system(scmd)==-1) {
			QMessageBox::critical(0, "PowerSoft Plus", TXT_ERR_FAILTOEXECUTE);
		}
	}
	setCursor(ArrowCursor);
	return 1;
}



int CMainPanel::netClnListRefresh()
{
	QString str;
	suser_config *pucfg = new suser_config;
	
	setCursor(WaitCursor);

	if (pucfg != NULL) {
		if (getUserConfig(pucfg)) {
			// clear list content
			lbNetCln->clear();
			// insert all network computers into list box
			for (int i=0; i<pucfg->iNcCount; i++) {
				str.sprintf("%s", pucfg->snc[i].szComputer);
				lbNetCln->insertItem(str);
			}
		}
	}
	delete pucfg;
	
	setCursor(ArrowCursor);
	return 1;
}


void CMainPanel::netClnListSelectAll()
{
	lbNetCln->selectAll(true);
}


bool CMainPanel::netClnSend()
{
	suser_config *pucfg = new suser_config;
	
	setCursor(WaitCursor);

	if (pucfg != NULL) {
		if (getUserConfig(pucfg)) {
			QString msg = editMessageToNetCln->text();
			if (msg.length()>0) {
				if (sendMsgToNetClients(*this, *pucfg, msg) != 1)
					QMessageBox::critical(this, "PowerSoft Plus", "Network message sending error!");
			}
		}
	}
	delete pucfg;
	
	setCursor(ArrowCursor);
	
	return 1;
}


void CMainPanel::handleFormControls()
{
	if (isMonitoringActive()) {
		btnMonEnable->setEnabled(false);
		btnMonDisable->setEnabled(true);
	} else {
		btnMonEnable->setEnabled(true);
		btnMonDisable->setEnabled(false);
	}
}

int sendMsgToNetClients(CMainPanel &c, suser_config suc, const char *szMessage)
{
	u_short usPort=12321;
	char szNetBuff[2048], szNetBuff1[2048], szNetBuff2[2048];
	struct hostent *lphentry;
	struct sockaddr_in sai;
	int iLen, iRet;
	int fNetSock;
	unsigned long ulAddr;
	bool bDomainName;

	for (uint i=0; i<c.lbNetCln->count(); i++) {
		if (!c.lbNetCln->isSelected(i))
			continue;
		QString str = c.lbNetCln->item(i)->text();
		bDomainName=isalpha(*(const char*)str);
		if (bDomainName) {
			lphentry=gethostbyname(suc.snc[i].szComputer);
			if (lphentry!=NULL)
				sai.sin_addr = *((struct in_addr*)*lphentry->h_addr_list);
			else
				continue;
		} else {
			ulAddr=inet_addr((const char*)str);
			lphentry=gethostbyaddr((const char*)&ulAddr, 4, AF_INET);
			if (lphentry!=NULL)
				sai.sin_addr = *((struct in_addr*)*lphentry->h_addr_list);
			else
				sai.sin_addr.s_addr = ulAddr;
		}

		sai.sin_family = AF_INET;
		sai.sin_port = htons(usPort);
		
		fNetSock=socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
		if (fNetSock==-1) {
			return -1;
		}
		memset(szNetBuff, 0, sizeof(szNetBuff));
		memset(szNetBuff1, 0, sizeof(szNetBuff1));
		memset(szNetBuff2, 0, sizeof(szNetBuff2));
		sprintf(szNetBuff, APP_NET_MAGIC, APP_NET_VERSION_MAJOR, APP_NET_VERSION_MINOR);

		/* komunikat */
		memset(szNetBuff1, 0, sizeof(szNetBuff));
		memset(szNetBuff2, 0, sizeof(szNetBuff));
		strcpy(szNetBuff1, szNetBuff);
		iLen=strlen(szNetBuff);
		sprintf(szNetBuff2, APP_NET_CMDFMT, APP_NET_MAGIC01, APP_NET_MAGIC02, APP_NET_CMD_SHOWMESSAGE);
		iLen += APP_NET_CMDFMT_LEN;
		strcat(szNetBuff2, szMessage);
		iLen += strlen(szMessage);
		szNetBuff2[ iLen++ ] = '\0'; 

		strcat(szNetBuff1, szNetBuff2);
		
		iRet=sendto(fNetSock, szNetBuff1, iLen, 0, (struct sockaddr*)&sai, sizeof(sai));

		//shutdown(fNetSock, SHUT_RDWR);
		close(fNetSock);
		if (iRet==-1) {
			return -1;
		}
	}
	return 1;
}
