/*******************************************************************************
 *	PuServer.cc	PuServer process
 *			T.Barnaby,	BEAM Ltd,	2007-02-07
 *******************************************************************************
 */
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <Debug.h>
#include <PuServer.h>
#include <Control.h>
#include <main.h>

#define GETDATA_LOG	0		// Log all getdata() calls

const int	numConnections = 4;

PuServer::PuServer(Control& control, UInt32 number, int physNumber) : ocontrol(control){
	onumber = number;
	ophysNumber = physNumber;
#ifdef ZAP
	for(int n = 0; n < numConnections; n++){
		oconns.append(new PuServerConnection);
	}
#endif
}

PuServer::~PuServer(){
}

BError PuServer::init(){
	BError		err;
	BString		url;
	BIter		i;

	disconnect();
	
	if(ocontrol.boapnsHost() != ""){
		url = BString("//") + ocontrol.boapnsHost() + "/";
	}
	
	if(err = opuControl.connectService(url + "puControl-" + ophysNumber))
		return err;
	if(err = opuProcess.connectService(url + "puProcess-" + ophysNumber))
		return err;

	if(err = opuControl1.connectService(url + "puControl-" + ophysNumber))
		return err;
	if(err = opuProcess1.connectService(url + "puProcess-" + ophysNumber))
		return err;

	// Set high priority on these connections
	opuControl1.setConnectionPriority(BoapPriorityHigh);
	opuControl1.setProcessPriority(PriorityHigh);
	
	// Set timeouts
	opuControl.setTimeout(10000000);
	opuProcess.setTimeout(10000000);
	opuControl1.setTimeout(10000000);
	opuProcess1.setTimeout(10000000);
	
	err = opuProcess1.addEventServer(url + "tmsEvent" + ocontrol.ring());

#ifdef ZAP
	for(oconns.start(i); !oconns.isEnd(i); oconns.next(i)){
		oconns[i]->opuControl.connectService(url + "puControl-" + ophysNumber);
		oconns[i]->opuProcess.connectService(url + "puProcess-" + ophysNumber);
	}
#endif
	
	return err;
}

BError PuServer::disconnect(){
	BError		err;
	BIter		i;

	opuControl.disconnectService();
	opuProcess.disconnectService();

	opuControl1.disconnectService();
	opuProcess1.disconnectService();

#ifdef ZAP
	for(oconns.start(i); !oconns.isEnd(i); oconns.next(i)){
		oconns[i]->opuControl.disconnectService();
		oconns[i]->opuProcess.disconnectService();
	}
#endif
	
	return err;
}

UInt32 PuServer::getNumber(){
	return onumber;
}

BError PuServer::handleError(BError err, int e){
	BError	errRet;

	dprintf(DBG_MISC, "PuServer::handleError: %d\n", err.getErrorNo());
	if((err.getErrorNo() == -EPIPE) && (e < 2)){
		// Try a reconnect
		disconnect();
		init();
	}
	else if(err.getErrorNo() == -ECONNREFUSED){
		errRet.set(err.getErrorNo(), BString("PuConnection Module: ") + onumber + ": Error: " + err.getString());
	}
	else {
		errRet.set(err.getErrorNo(), BString("Module: ") + onumber + ": Error: " + err.getString());
	}
	
	return errRet;
}

BError PuServer::initCmd(){
	BError	err;
	int	n = 0;
	
	while(err = opuControl.init()){
		if(err = handleError(err, n++))
			break;
	}
	
	return err;
}

BError	PuServer::configure(BUInt ring, ConfigInfo configInfo){
	BError	err;
	int	n = 0;
	
	while(err = opuControl.configure(ring, configInfo)){
		if(err = handleError(err, n++))
			break;
	}
	
	return err;
}

BError	PuServer::test(BList<BError>& errors){
	BError	err;
	int	n = 0;
	
	while(err = opuControl.test(errors)){
		if(err = handleError(err, n++))
			break;
	}

	return err;
}

BError	PuServer::getStatus(BList<NameValue>& statusList){
	BError	err;
	int	n = 0;
	
	while(err = opuControl.getStatus(statusList)){
		if(err = handleError(err, n++))
			break;
	}

	return err;
}

BError	PuServer::getStatistics(BList<NameValue>& statsList){
	BError	err;
	int	n = 0;
	
	while(err = opuControl.getStatistics(statsList)){
		if(err = handleError(err, n++))
			break;
	}

	return err;
}

BError	PuServer::getMasterPuChannel(PuChannel& puChannel){
	BError	err;
	int	n = 0;
	
	while(err = opuControl.getMasterPuChannel(puChannel)){
		if(err = handleError(err, n++))
			break;
	}

	return err;
}


// Test functions
BError	PuServer::setTestMode(PuChannel puChannel, UInt32 testOutput, UInt32 timingDisableMask){
	BError	err;
	int	n = 0;
	
	while(err = opuControl.setTestMode(puChannel, testOutput, timingDisableMask)){
		if(err = handleError(err, n++))
			break;
	}

	return err;
}

BError	PuServer::setTimingSignals(PuChannel puChannel, UInt32 timingSignals){
	BError	err;
	int	n = 0;
	
	while(err = opuControl.setTimingSignals(puChannel, timingSignals)){
		if(err = handleError(err, n++))
			break;
	}

	return err;
}

BError	PuServer::captureDiagnostics(PuChannel puChannel, TestCaptureInfo captureInfo, BArray<UInt64>& data){
	BError	err;
	int	n = 0;
	
	while(err = opuControl.captureDiagnostics(puChannel, captureInfo, data)){
		if(err = handleError(err, n++))
			break;
	}

	return err;
}

BError	PuServer::setTestData(PuChannel puChannel, Int32 on, BArray<UInt32> data){
	BError	err;
	int	n = 0;
	
	while(err = opuControl.setTestData(puChannel, on, data)){
		if(err = handleError(err, n++))
			break;
	}

	return err;
}

BError PuServer::setPupeConfig(PuChannel puPhysChannel, PupeConfig pupeConfig){
	BError	err;
	int	n = 0;
	
	while(err = opuControl.setPupeConfig(puPhysChannel, pupeConfig)){
		if(err = handleError(err, n++))
			break;
	}

	return err;
}

BError PuServer::getPupeConfig(PuChannel puPhysChannel, PupeConfig& pupeConfig){
	BError	err;
	int	n = 0;
	
	while(err = opuControl.getPupeConfig(puPhysChannel, pupeConfig)){
		if(err = handleError(err, n++))
			break;
	}

	return err;
}



BError	PuServer::setControlInfo(CycleParam params){
	BError	err;
	int	n = 0;
	
	while(err = opuControl.setControlInfo(params)){
		if(err = handleError(err, n++))
			break;
	}

	return err;
}

BError	PuServer::setNextCycle(UInt32 cycleNumber, BString cycleType){
	BError	err;
	int	n = 0;
	
	while(err = opuControl1.setNextCycle(cycleNumber, cycleType)){
		if(err = handleError(err, n++))
			break;
	}

	return err;
}

BError	PuServer::getStatus(PuChannel puChannel, PuStatus& puStatus){
	BError	err;
	int	n = 0;
	
	while(err = opuProcess.getStatus(puChannel, puStatus)){
		if(err = handleError(err, n++))
			break;
	}

	return err;
}

BError PuServer::getCycleInformation(UInt32 cycleNumber, CycleInformation& cycleInformation){
	BError	err;
	int	n = 0;

	while(err = opuProcess.getCycleInformation(cycleNumber, cycleInformation)){
		if(err = handleError(err, n++))
			break;
	}

	return err;
}

BError	PuServer::getData(PuChannel puChannel, DataInfo dataInfo, Data& data, UInt32& orbitNumber){
	BError	err;
	int	n = 0;

#if GETDATA_LOG	
	dfprintf("PuServer::getData: Chan: %d Period: %d StartTime: %d Orbit: %d Bunch: %d Function: %d NumValues: %d Beyond: %d\n",
		dataInfo.channel,
		dataInfo.cyclePeriod, dataInfo.startTime, dataInfo.orbitNumber, dataInfo.bunchNumber,
		dataInfo.function, dataInfo.numValues, dataInfo.beyondPeriod);
#endif
	while(err = opuProcess.getData(puChannel, dataInfo, data, orbitNumber)){
		if(err = handleError(err, n++))
			break;
	}
#if GETDATA_LOG	
	dfprintf("PuServer::getData: End: NumValues: %d\n", dataInfo.numValues);
#endif
	return err;
}

BError	PuServer::requestData(PuChannel puChannel, DataInfo dataInfo){
	BError	err;
	int	n = 0;
	
	while(err = opuProcess.requestData(puChannel, dataInfo)){
		if(err = handleError(err, n++))
			break;
	}

	return err;
}
