///////////////////////////////////////////////////////////////////////////////
//                                                         
// CegoAdmMon.cc  
// -------------                                                        
// Cego admin monitor
//
// Design and Implementation by Bjoern Lemke
//     
// (C)opyright 2000-2011 Bjoern Lemke
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2, or (at your option)
// any later version.
// 
// This program 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 General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; see the file COPYING.  If not, write to
// the Free Software Foundation, 59 Temple Place - Suite 330,
// Boston, MA 02111-1307, USA.
//
// IMPLEMENTATION MODULE
//
// Class: CegoAdmMon
// 
// Description: 
//
// Status: QS-2.6
//
///////////////////////////////////////////////////////////////////////////////

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

#include "CegoAdmMon.h"

#define COL_HEADER_PASSIVE 1
#define COL_HEADER_ACTIVE 2
#define COL_TITLE 3
#define COL_CONTENT 4

#define LEFTOFFSET 1
#define TOPOFFSET 2

#define POOLMODE 'p'
#define DBTHREADMODE 'd'
#define ADMTHREADMODE 'a'
#define LOGTHREADMODE 'l'
#define TSLISTMODE 's'
#define REFRESHMODE 'r'
#define QUITMODE 'q'

#define DEFREFINT 3000

CegoAdmMon::CegoAdmMon(CegoAdminHandler *pAH) 
{
    _pAH = pAH;
    
    /*  Initialize ncurses  */
    
    if ( (_mainwin = initscr()) == NULL ) 
    {
	throw Exception(EXLOC, Chain("Error initializing ncurses"));
    }

    curs_set(0);    
    start_color();    
    
    init_pair(COL_HEADER_PASSIVE,  COLOR_CYAN,     COLOR_BLACK);    
    init_pair(COL_HEADER_ACTIVE,  COLOR_BLACK,     COLOR_YELLOW);
    init_pair(COL_TITLE,  COLOR_WHITE,     COLOR_BLACK);
    init_pair(COL_CONTENT,  COLOR_YELLOW,     COLOR_BLACK);

    noecho();                  /*  Turn off key echoing                 */
    keypad(_mainwin, TRUE);     /*  Enable the keypad for non-char keys  */
    
    timeout(0);

    _refreshMenu.Insert(Chain("1 sec delay"));
    _refreshMenu.Insert(Chain("3 sec delay"));
    _refreshMenu.Insert(Chain("10 sec delay"));
    _refreshMenu.Insert(Chain("30 sec delay"));
    _refreshOpt.Insert(1000);
    _refreshOpt.Insert(3000);
    _refreshOpt.Insert(10000);
    _refreshOpt.Insert(30000);

}

CegoAdmMon::~CegoAdmMon()  
{    
    delwin(_mainwin);
    endwin();
    refresh();
}

void CegoAdmMon::showMonitor()
{    
    int ch = POOLMODE;

    _refInterval = DEFREFINT;
    _nextTSRefresh = 0;
    _nextTSListRefresh = 0;
    _nextDBRefresh = 0;
    _nextAdmRefresh = 0;
    _nextLogRefresh = 0;
    _nextPoolRefresh = 0;

    _tsSelected = 1;

    int savedmode;

    while ( ch != QUITMODE ) 
    {

	savedmode=_mode;
	bool pollIt = false;

	if ( ch == ERR
	     || ch == POOLMODE 
	     || ch == DBTHREADMODE 
	     || ch == ADMTHREADMODE 
	     || ch == LOGTHREADMODE
	     || ch == TSLISTMODE
	     || ch == REFRESHMODE )
	{
	    if ( ch != ERR )
		_mode = ch;
	    pollIt = true;
	}
	
	if ( _mode == REFRESHMODE )
	{
	    int i = showMenu(Chain("Select refresh interval"), _refreshMenu);
	    _refInterval = _refreshOpt[i];
	    _mode = savedmode;
	}
	    
	clear();
	showHeader();

	if ( pollIt == true )
	{
	    switch ( _mode )
	    {
	    case POOLMODE:
	    {
		showPool();
		ch = getch();
		break;
	    }
	    case DBTHREADMODE:
	    {
		showDBThread();
		ch = getch();
		break;
	    }
	    case ADMTHREADMODE:
	    {
		showAdmThread();
		ch = getch();
		break;
	    }
	    case LOGTHREADMODE:
	    {
		showLogThread();
		ch = getch();
		break;
	    }
	    case TSLISTMODE:
	    {
		ch = showTableSetList();
		break;
	    }
	    }
	}
	else
	{
	    ch = getch();
	}

	refresh();	
	timeout(_refInterval);
    }
}

void CegoAdmMon::showHeader()
{
    int colno=LEFTOFFSET;

    color_set(COL_TITLE, NULL);
    mvprintw(0, colno, "Choice:");
    colno+=8;

    if ( _mode == POOLMODE )
	color_set(COL_HEADER_ACTIVE, NULL);
    else
	color_set(COL_HEADER_PASSIVE, NULL);
    mvprintw(0, colno, "Pool(%c)", POOLMODE);
    colno+=8;

    if ( _mode == DBTHREADMODE )
	color_set(COL_HEADER_ACTIVE, NULL);
    else
	color_set(COL_HEADER_PASSIVE, NULL);
    mvprintw(0, colno, "DB(%c)", DBTHREADMODE);
    colno+=6;

    if ( _mode == ADMTHREADMODE )
	color_set(COL_HEADER_ACTIVE, NULL);
    else
	color_set(COL_HEADER_PASSIVE, NULL);
    mvprintw(0, colno, "Adm(%c)", ADMTHREADMODE);
    colno+=7;

    if ( _mode == LOGTHREADMODE )
	color_set(COL_HEADER_ACTIVE, NULL);
    else
	color_set(COL_HEADER_PASSIVE, NULL);
    mvprintw(0, colno, "Log(%c)", LOGTHREADMODE);
    colno+=7;

    if ( _mode == TSLISTMODE )
	color_set(COL_HEADER_ACTIVE, NULL);
    else
	color_set(COL_HEADER_PASSIVE, NULL);
    mvprintw(0, colno, "TS(%c)", TSLISTMODE);
    colno+=6;

    color_set(COL_HEADER_PASSIVE, NULL);
    mvprintw(0, colno, "Int(%c)", REFRESHMODE);
    colno+=7;

    color_set(COL_HEADER_PASSIVE, NULL);
    mvprintw(0, colno, "Quit(%c)", QUITMODE);

    color_set(COL_HEADER_PASSIVE, NULL);
    mvprintw(1, LEFTOFFSET, "-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+");

    refresh();
}

void CegoAdmMon::showPool()
{
    Datetime ts;
    if ( _nextPoolRefresh < ts.asInt())
    {
	_poolinfo1.Empty();
	_poolinfo2.Empty();

	CegoAdminHandler::ResultType res;
	CegoTableObject oe;
	
	res = _pAH->reqPoolInfo();
	// handleMedResult(res, true);    
	
	res = _pAH->reqPoolInfo();
	_pAH->getPoolInfo(oe, _poolinfo1, _poolinfo2);	    	    
	
	_nextPoolRefresh = ts.asInt() + ( _refInterval / 1000 );
    }

    WINDOW *poolWin1;
    WINDOW *poolWin2;

    poolWin1 = newwin(10, 41, 2, 2);
    keypad(poolWin1, TRUE);

    poolWin2 = newwin(9, 41, 12, 2);
    keypad(poolWin2, TRUE);

    box(poolWin1, 0, 0);
    box(poolWin2, 0, 0);

    int rowno=1; 
       
    ListT<CegoFieldValue> *pFVL = _poolinfo1.First();
    
    while ( pFVL )
    {
	int colno=2;    

	CegoFieldValue *pFV = pFVL->First();
	if ( pFV )
	{		       
	    wcolor_set(poolWin1, COL_TITLE, NULL);
	    mvwprintw(poolWin1, rowno, colno, "%s", (char*)pFV->valAsChain());
	}
	colno+=18;

	pFV = pFVL->Next();
	if ( pFV )
	{
	    wcolor_set(poolWin1, COL_CONTENT, NULL);
	    mvwprintw(poolWin1, rowno, colno, "%s", (char*)pFV->valAsChain());
	}
	rowno++;
	pFVL = _poolinfo1.Next();
    }

    rowno=1; 
    pFVL = _poolinfo2.First();
    
    while ( pFVL )
    {
	int colno=2;    

	CegoFieldValue *pFV = pFVL->First();
	if ( pFV )
	{		       
	    wcolor_set(poolWin2, COL_TITLE, NULL);
	    mvwprintw(poolWin2, rowno, colno, "%s", (char*)pFV->valAsChain());
	}
	colno+=18;

	pFV = pFVL->Next();
	if ( pFV )
	{
	    wcolor_set(poolWin2, COL_CONTENT, NULL);
	    mvwprintw(poolWin2, rowno, colno, "%s", (char*)pFV->valAsChain());
	}
	rowno++;
	pFVL = _poolinfo2.Next();
    }


    wrefresh(poolWin1);
    wrefresh(poolWin2);
}

void CegoAdmMon::showDBThread()
{

    Datetime ts;
    if ( _nextDBRefresh < ts.asInt())
    {
	_dbthreadinfo.Empty();

	CegoAdminHandler::ResultType res;
	CegoTableObject oe;
	Chain format;    

	res = _pAH->reqDbThreadInfo();
	_pAH->getDbThreadInfo(oe, _dbthreadinfo, format);

	_nextDBRefresh = ts.asInt() + ( _refInterval / 1000 );
    }

    int rowno=TOPOFFSET;
    int colno=LEFTOFFSET;
    
    color_set(COL_TITLE, NULL);
    
    mvprintw(rowno, colno, "%s", "Thread Id");
    colno = colno + 25;
    mvprintw(rowno, colno, "%s", "NumConReq");
    colno = colno + 15;
    mvprintw(rowno, colno, "%s", "NumQueryReq");
    colno = colno + 15;
    mvprintw(rowno, colno, "%s", "Status");
    rowno++;
    
    color_set(COL_CONTENT, NULL);
    ListT<CegoFieldValue> *pFVL = _dbthreadinfo.First();
    while ( pFVL )
    {
	
	colno=LEFTOFFSET;
	CegoFieldValue *pFV = pFVL->First();
	if ( pFV )
	{		       
	    mvprintw(rowno, colno, "%s", (char*)pFV->valAsChain());
	    pFV = pFVL->Next();			
	    colno = colno + 25;
	}
	if ( pFV )
	{		       
	    mvprintw(rowno, colno, "%s", (char*)pFV->valAsChain());
	    pFV = pFVL->Next();			
	    colno = colno + 15;
	}
	if ( pFV )
	{
	    mvprintw(rowno, colno, "%s", (char*)pFV->valAsChain());
	    pFV = pFVL->Next();			
	    colno = colno + 15;
	}
	if ( pFV )
	{
	    mvprintw(rowno, colno, "%s", (char*)pFV->valAsChain());
	}
	
	rowno++;
	pFVL = _dbthreadinfo.Next();
    }       
}

void CegoAdmMon::showAdmThread()
{

    Datetime ts;
    if ( _nextAdmRefresh < ts.asInt())
    {
	_admthreadinfo.Empty();

	CegoAdminHandler::ResultType res;
	CegoTableObject oe;
	Chain format;    

	res = _pAH->reqAdmThreadInfo();
	_pAH->getAdmThreadInfo(oe, _admthreadinfo, format);

	_nextAdmRefresh = ts.asInt() + ( _refInterval / 1000 );
    }

    int rowno=TOPOFFSET;
    int colno=LEFTOFFSET;
    
    color_set(COL_TITLE, NULL);
    
    mvprintw(rowno, colno, "%s", "Thread Id");
    colno = colno + 25;
    mvprintw(rowno, colno, "%s", "NumRequest");
    colno = colno + 15;
    mvprintw(rowno, colno, "%s", "Status");
    rowno++;
    
    color_set(COL_CONTENT, NULL);
    ListT<CegoFieldValue> *pFVL = _admthreadinfo.First();
    while ( pFVL )
    {
	
	colno=LEFTOFFSET;
	CegoFieldValue *pFV = pFVL->First();
	if ( pFV )
	{		       
	    mvprintw(rowno, colno, "%s", (char*)pFV->valAsChain());
	    pFV = pFVL->Next();			
	    colno = colno + 25;
	}
	if ( pFV )
	{
	    mvprintw(rowno, colno, "%s", (char*)pFV->valAsChain());
	    pFV = pFVL->Next();			
	    colno = colno + 15;
	}
	if ( pFV )
	{
	    mvprintw(rowno, colno, "%s", (char*)pFV->valAsChain());
	}
	
	rowno++;
	pFVL = _admthreadinfo.Next();
    }

}

void CegoAdmMon::showLogThread()
{

    Datetime ts;
    if ( _nextLogRefresh < ts.asInt())
    {
	_logthreadinfo.Empty();

	CegoAdminHandler::ResultType res;
	CegoTableObject oe;
	Chain format;    

	res = _pAH->reqLogThreadInfo();
	_pAH->getLogThreadInfo(oe, _logthreadinfo, format);

	_nextLogRefresh = ts.asInt() + ( _refInterval / 1000 );
    }

    int rowno=TOPOFFSET;
    int colno=LEFTOFFSET;
    
    color_set(COL_TITLE, NULL);
    
    mvprintw(rowno, colno, "%s", "Thread Id");
    colno = colno + 25;
    mvprintw(rowno, colno, "%s", "NumRequest");
    colno = colno + 15;
    mvprintw(rowno, colno, "%s", "Status");
    rowno++;
    
    color_set(COL_CONTENT, NULL);
    ListT<CegoFieldValue> *pFVL = _logthreadinfo.First();
    while ( pFVL )
    {
	
	colno=LEFTOFFSET;
	CegoFieldValue *pFV = pFVL->First();
	if ( pFV )
	{		       
	    mvprintw(rowno, colno, "%s", (char*)pFV->valAsChain());
	    pFV = pFVL->Next();			
	    colno = colno + 25;
	}
	if ( pFV )
	{
	    mvprintw(rowno, colno, "%s", (char*)pFV->valAsChain());
	    pFV = pFVL->Next();			
	    colno = colno + 15;
	}
	if ( pFV )
	{
	    mvprintw(rowno, colno, "%s", (char*)pFV->valAsChain());
	}
	
	rowno++;
	pFVL = _logthreadinfo.Next();
    }

}

int CegoAdmMon::showTableSetList()
{
    
    WINDOW* tswin = 0;

    int c = 0;
    
    bool isSelected=false;

    Chain tableSet;

    while( isSelected == false )
    {	
	
	if ( tswin )
	    delwin(tswin);

	Datetime ts;
	if ( _nextTSListRefresh < ts.asInt())
	{
	    _tsList.Empty();

	    CegoAdminHandler::ResultType res;
	    CegoTableObject oe;	

	    
	    res = _pAH->medGetTableSetList(true);
	    _pAH->getTableSetList(oe, _tsList, true);

	    _nextTSListRefresh = ts.asInt() + ( _refInterval / 1000 );
	}
	
	tswin = newwin(_tsList.Size() + 3, 60, 2, 1);
	
	noecho();
	
	wtimeout(tswin, 0);
	
	keypad(tswin, TRUE);
	
	box(tswin, 0, 0);
	
	switch(c)
	{	
	case KEY_UP:
	    if (_tsSelected == 1)
		_tsSelected = _tsList.Size();
	    else
		--_tsSelected;
	    break;
	case KEY_DOWN:
	    if( _tsSelected == _tsList.Size() )
		_tsSelected = 1;
	    else 
		++_tsSelected;
	    break;
	case 10:
	    isSelected = true;
	    if ( tableSet.length() > 0 )
		return showTableSet(tableSet);
	    else
		return TSLISTMODE;
	case POOLMODE:
	case DBTHREADMODE :
	case ADMTHREADMODE:
	case LOGTHREADMODE:
	case TSLISTMODE:
	case REFRESHMODE:
	case QUITMODE:
	    delwin(tswin);
	    return c;
	}
	
	int rowno=1;
	int colno=1;
	
	wcolor_set(tswin, COL_TITLE, NULL);
	
	mvwprintw(tswin, rowno, colno, "%s", "Name");
	colno = colno + 10;
	mvwprintw(tswin, rowno, colno, "%s", "RunState");
	colno = colno + 10;
	mvwprintw(tswin, rowno, colno, "%s", "SyncState");
	colno = colno + 10;
	mvwprintw(tswin, rowno, colno, "%s", "SysUsage");
	colno = colno + 10;
	mvwprintw(tswin, rowno, colno, "%s", "TempUsage");
	colno = colno + 10;
	mvwprintw(tswin, rowno, colno, "%s", "AppUsage");
	rowno++;
	
	int pos=0;
	ListT<CegoFieldValue> *pFVL = _tsList.First();
	
	wcolor_set(tswin, COL_CONTENT, NULL);
	int tsRow=1;
	while ( pFVL )
	{
	    
	    colno=LEFTOFFSET;
	    
	    if ( _tsSelected == tsRow )
		wattron(tswin, A_REVERSE); 
	    
	    CegoFieldValue *pFV = pFVL->First();
	    if ( pFV )
	    {		       
		if ( _tsSelected == tsRow )
		    tableSet = pFV->valAsChain();
		mvwprintw(tswin, rowno, colno, "%s", (char*)pFV->valAsChain());
		pFV = pFVL->Next();			
		colno = colno + 10;
	    }
	    if ( pFV )
	    {
		mvwprintw(tswin, rowno, colno, "%s", (char*)pFV->valAsChain());
		pFV = pFVL->Next();			
		colno = colno + 10;
	    }
	    if ( pFV )
	    {
		mvwprintw(tswin, rowno, colno, "%s", (char*)pFV->valAsChain());
		pFV = pFVL->Next();			
		colno = colno + 10;
	    }
	    if ( pFV )
	    {
		mvwprintw(tswin, rowno, colno, "%s", (char*)pFV->valAsChain());
		pFV = pFVL->Next();			
		colno = colno + 10;
	    }
	    if ( pFV )
	    {
		mvwprintw(tswin, rowno, colno, "%s", (char*)pFV->valAsChain());
		pFV = pFVL->Next();			
		colno = colno + 10;
	    }
	    
	    if ( pFV )
	    {
		mvwprintw(tswin, rowno, colno, "%s", (char*)pFV->valAsChain());
	    }
	    
	    if ( _tsSelected == tsRow )
		wattroff(tswin, A_REVERSE); 		

	    tsRow++;
	    rowno++;
	    pFVL = _tsList.Next();
	}

	wrefresh(tswin);

	wtimeout(tswin, _refInterval);
	c = wgetch(tswin);
	
    }
    return c;
}

int CegoAdmMon::showTableSet(const Chain& tableSet)
{
    
    WINDOW* tswin = 0;

    int c = 0;

    bool goBack=false;

    while( goBack == false )
    {	
	
	if ( tswin )
	    delwin(tswin);


	Datetime ts;
	if ( _nextTSRefresh < ts.asInt())
	{
	    _tsInfo.Empty();

	    CegoAdminHandler::ResultType res;
	    CegoTableObject oe;	
	    
	    res = _pAH->medGetDetailedTableSetInfo(tableSet);	
	    
	    while ( res == CegoAdminHandler::ADM_INFO )
	    {
		res = _pAH->nextInfo();	    
	    }
	    
	    _pAH->getDetailedTableSetInfo(oe, _tsInfo);

	    _nextTSRefresh = ts.asInt() + ( _refInterval / 1000 );
	}

	int attrwidth = 0;
	int valwidth = 0;
	ListT<CegoFieldValue> *pFVL = _tsInfo.First();	
	while ( pFVL )
	{
	    CegoFieldValue *pFV = pFVL->First();
	    if ( pFV )
	    {		       
		if ( pFV->valAsChain().length() > attrwidth )
		    attrwidth = pFV->valAsChain().length();
		pFV = pFVL->Next();
	    }
	    if ( pFV )
	    {
		if ( pFV->valAsChain().length() > valwidth )
		    valwidth = pFV->valAsChain().length();
		pFV = pFVL->Next();			
	    }
	    pFVL = _tsInfo.Next();
	}

	tswin = newwin(_tsInfo.Size() + 3, attrwidth + valwidth + 1, 5, 10);
	
	noecho();
	
	wtimeout(tswin, 0);
	
	keypad(tswin, TRUE);
	
	box(tswin, 0, 0);

	switch(c)
	{	
	case 10:
	    goBack = true;
	    return TSLISTMODE;
	case POOLMODE:
	case DBTHREADMODE :
	case ADMTHREADMODE:
	case LOGTHREADMODE:
	case TSLISTMODE:
	case REFRESHMODE:
	case QUITMODE:
	    delwin(tswin);
	    return c;
	}
	
	
	int rowno=1;
	int colno=1;
	
	wcolor_set(tswin, COL_TITLE, NULL);
	
	mvwprintw(tswin, rowno, colno, "%s", "Name");
	colno = colno + 20;
	mvwprintw(tswin, rowno, colno, "%s", "Value");
	colno = colno + 10;
	rowno++;
	
	
	int pos=0;
	pFVL = _tsInfo.First();
	
	wcolor_set(tswin, COL_CONTENT, NULL);
	int tsRow=1;
	while ( pFVL )
	{
	    
	    colno=LEFTOFFSET;
	    	    
	    CegoFieldValue *pFV = pFVL->First();
	    if ( pFV )
	    {		       
		mvwprintw(tswin, rowno, colno, "%s", (char*)pFV->valAsChain());
		pFV = pFVL->Next();			
		colno = colno + attrwidth;
	    }
	    if ( pFV )
	    {
		mvwprintw(tswin, rowno, colno, "%s", (char*)pFV->valAsChain());
		pFV = pFVL->Next();			
		colno = colno + 10;
	    }

	    tsRow++;
	    rowno++;
	    pFVL = _tsInfo.Next();
	}


	wrefresh(tswin);	

	wtimeout(tswin, _refInterval);
	c = wgetch(tswin);
	
    }
    return c;
}

int CegoAdmMon::showMenu(const Chain& title, const ListT<Chain>& menuList)
{

    int width = title.length() + 5;
    int height = menuList.Size() + 3;
 
    _highlight=1;
    int choice = 0;
    int c;
    
    int startx = (80 - width) / 2;
    int starty = (24 - height) / 2;
    
    _menuwin = newwin(height, width, starty, startx);

    noecho();

    keypad(_menuwin, TRUE);

    refresh();
    printMenu(title, menuList);

    bool isSelected=false;
    while( isSelected == false )
    {	
	c = wgetch(_menuwin);
	switch(c)
	{	
	case KEY_UP:
	    if (_highlight == 1)
		_highlight = menuList.Size();
	    else
		--_highlight;
	    break;
	case KEY_DOWN:
	    if(_highlight == menuList.Size() )
		_highlight = 1;
	    else 
		++_highlight;
	    break;
	case 10:
	    isSelected = true;
	    choice = _highlight;
	    break;
	}

	// printf("You chose choice %d", choice);
	printMenu(title, menuList);	    
    }
    delwin(_menuwin);

    clear();
    showHeader();

    return _highlight -1 ;
}
    
void CegoAdmMon::printMenu(const Chain& title, const ListT<Chain>& menuList)
{
    int x, y, i;	
    
    mvwprintw(_menuwin, 1, 1, "%s", (char*)title);
    x = 2;
    y = 2;
    box(_menuwin, 0, 0);
    for(i = 0; i < menuList.Size(); ++i)
    {	
	if (_highlight == i + 1) /* High light the present choice */
	{	
	    wattron(_menuwin, A_REVERSE); 
	    mvwprintw(_menuwin, y, x, "%s", (char*)menuList[i]);
	    wattroff(_menuwin, A_REVERSE);
	}
	else
	    mvwprintw(_menuwin, y, x, "%s", (char*)menuList[i]);
	++y;
    }

    wrefresh(_menuwin);
    
}
