///////////////////////////////////////////////////////////////////////////////
//                                                         
// CegoBeatThread.cc  
// ----------------                                                     
// Cego beat thread class implementation
//                                                         
// Design and Implementation by Bjoern Lemke
//               
// (C)opyright 2000-2010 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: CegoBeatThread
// 
// Description: 
//
// Status: QG-2.6
//
///////////////////////////////////////////////////////////////////////////////

// INCLUDES

#include "CegoXMLdef.h"

#include <lfc/Exception.h>
#include <lfc/Host.h>

#include "CegoBeatThread.h"

#include <signal.h>
#include <stdlib.h>
#include <string.h>


CegoBeatThread::CegoBeatThread(CegoDatabaseManager *pDBMng)
{
    _pDBMng = pDBMng;
    _terminated = false;

    init();

    install(SIGINT);
#ifndef HAVE_MINGW32
    install(SIGPIPE);
#endif

    _modId = _pDBMng->getModId("CegoBeatThread");
}

CegoBeatThread::~CegoBeatThread()  
{
}

void CegoBeatThread::beat()
{

    Host h;
    ListT<Chain> beatList;
    _pDBMng->getMedList(h.getName(), beatList);
    
    // remove lost connections
    CegoBeatConnection** pBC = _actBeatList.First();
    while ( pBC )
    {
	if ( beatList.Find((*pBC)->getHostName()) == 0 )
	{
#ifdef DEBUG
	    _pDBMng->log(_modId, Logger::DEBUG, Chain("Removing beat connection to ") + (*pBC)->getHostName() + Chain(" ..."));
#endif

	    (*pBC)->disconnect();
	    
	    _pDBMng->setHostStatus((*pBC)->getHostName(), XML_OFFLINE_VALUE);

	    _actBeatList.Remove(*pBC);
	    delete *pBC;
	    pBC = _actBeatList.First();

	}
	else
	{
	    pBC = _actBeatList.Next();
	}
    }

    // get new connetions
    Chain* pBeatHost = beatList.First();
    while ( pBeatHost )
    {
	
	CegoBeatConnection** pBC = _actBeatList.First();
	bool notFound = true;
	while ( pBC && notFound )
	{
	    if ( (*pBC)->getHostName() == *pBeatHost )
		notFound = false;
	    else
		pBC = _actBeatList.Next();
	}
	
	if ( notFound )
	{

#ifdef DEBUG
	    _pDBMng->log(_modId, Logger::DEBUG, Chain("Adding beat connection to ") + *pBeatHost + Chain(" ..."));
#endif

	    int adminPort;
	    Chain adminUser;
	    Chain adminPasswd;
	    
	    _pDBMng->getAdminPort(adminPort);
	    _pDBMng->getAdminUser(adminUser, adminPasswd);
	    
	    CegoBeatConnection* pBeatCon = new CegoBeatConnection(*pBeatHost, adminPort, adminUser, adminPasswd, _pDBMng);

	    pBeatCon->connect();
	    
	    _actBeatList.Insert(pBeatCon);
	}
	
	pBeatHost = beatList.Next();
	
    }

    // beat to active connetions    

    pBC = _actBeatList.First();
    while ( pBC )
    {
	_pDBMng->log(_modId, Logger::DEBUG,  Chain("Sending beat to ") + (*pBC)->getHostName() + Chain(" ..."));

	ListT<Chain> tsList;
	ListT<Chain> runList;
	ListT<Chain> syncList;
	
	_pDBMng->getTSforMedAndPrim((*pBC)->getHostName(), h.getName(), tsList);

	Chain *pTS = tsList.First();
	while ( pTS ) 
	{
	    runList.Insert( _pDBMng->getTableSetRunState(*pTS) );
	    syncList.Insert( _pDBMng->getTableSetSyncState(*pTS) );	    
	    pTS = tsList.Next();
	}

	(*pBC)->beat(tsList, runList, syncList);

	_pDBMng->setHostStatus((*pBC)->getHostName(), XML_ONLINE_VALUE);

	pBC = _actBeatList.Next();
    }
}

void CegoBeatThread::sigCatch(int sig)
{
    
    try
    {
    
	install(SIGINT);
#ifndef HAVE_MINGW32
	install(SIGPIPE);
#endif
	
	if ( sig == SIGINT )
	{
	    cout << "Received interrupt signal ..." << endl;
	    
	    _pDBMng->log(_modId, Logger::NOTICE, Chain("Received interrupt signal"));

	    _terminated = true;
	    
	    CegoBeatConnection** pBC = _actBeatList.First();
	    while ( pBC )
	    {
		_pDBMng->log(_modId, Logger::DEBUG, Chain("Removing beat connection to ") + (*pBC)->getHostName() + Chain(" ..."));
		(*pBC)->disconnect();
		_actBeatList.Remove(*pBC);
		delete *pBC;
		pBC = _actBeatList.First();
	    }
	}
	else
	{
	    _pDBMng->log(_modId, Logger::DEBUG, Chain("Receiving broken pipe signal, ignoring  ..."));
	}
    }
    catch ( Exception e )
    {
	
	Chain msg;
	e.pop(msg);
	
	_pDBMng->log(_modId, Logger::LOGERR, msg);
    }
}

bool CegoBeatThread::isTerminated()
{
    return _terminated;
}

    
