/*******************************************************************************
 * Copyright (c) 2005 Intel Corporation.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *    Vishnu K Naikawadi, Intel - Sample client for launching an agent that has console
 *								  input/output, redirecting that I/O to the client.
 *
 * $Id: LaunchAgentClient.cpp,v 1.2 2005/11/05 00:52:23 koleary Exp $
 *
 *******************************************************************************/ 

#include <iostream>
#include <stdlib.h>
#include <stdio.h>
using namespace std;

#include "tptp/client/NodeFactory.h"
#include "tptp/client/Collector.h"
#include "TimeDataProcessor.h"
using namespace TPTP::Client;

/**
 *********************************************************
 *                                                       
 * @brief                                                
 *    Client for launching an agent with console I/O.
 *
 *********************************************************/
int main(int argc, char* argv[])
{
	int rc = 0 ;
	char* hostName = "localhost";
	int portNum = 10006;
	INode* TargetNode = 0;
	AgentController* ACProxy = 0;

	// Create a Node object for the target system.
	TargetNode = NodeFactory::createNode(hostName);
	if (!TargetNode)
	{
		cout<<"ERROR: Failed to create the Node object."<<endl;
		cout<<"Press any key to exit..."<<endl;
		getchar();
		return -1;
	}

	// Establish a connection with an Agent Controller on the
	// target system.  The port number specified must match
	// that defined in the configuration file for the desired
	// Agent Controller.
	ACProxy = TargetNode->connect(portNum);
	
	if (!ACProxy)
	{
		cout<<"ERROR: Unable to connect to the Agent Controller running on "<<hostName<<" at port number "<<portNum<<endl;
		cout<<"Press any key to exit..."<<endl;
		getchar();
		return -1;
	}

	
	cout<<endl<<"Connected to the Agent Controller on \""<<hostName<<"\" at port number "<<portNum<<endl;

	// We are launching an agent with console I/O that we want redirected to this
	// client.  In order to get the console I/O to come here, the launch of the
	// agent is done directly by the client so that the console connection is
	// established with this client. The getAgent() interface does not allow this.

	// Create an instance of an IProcess object, populating it with the
	// launch parameters for the agent executable to be launched. Note that this is
	// not the agent's name, rather it is the executable pathname.
	IProcess* aProcess = ACProxy->createNewProcess();
	aProcess->setExecutable("C:\\tptpDev\\org.eclipse.tptp.platform.agentcontroller\\src-native-new\\bin\\TimeCollector.exe");	

	// Setup the console data handler.  In this case, the TimeDataProcessor is used
	// which simply echoes the incoming data.
	IConsole* aProcessConsole = aProcess->getConsole();
	aProcessConsole->setDataProcessor(new TimeDataProcessor());

	// Launch the agent executable.
	aProcess->launch();

	//aProcessConsole->write("This is console input.\n") ;

	// Now we want to get a handle to this agent, so that we can use it like any
	// other agent. This sleep gives the agent time to startup and register itself
	// with the Agent Controller.
	// TBD: Use the queryRunningAgents interface to determine when we can
	// get a handle for this agent.
	Sleep(1000);
	

	// Create a client-side representative of a Collector object from which
	// a TimeCollector is derived, specifying the name of the desired collector
	// as it has been installed in the agents directory.
	Collector* timeCollector = new Collector("org.eclipse.tptp.TimeCollector");
	
	// Get a handle to the actual TimeCollector agent, storing it in the collector
	// object.  If the call is successful, the TimeCollector agent is running and
	// ready to respond to requests.
	// Note that the Agent Controller manages the life of an agent, so it will start
	// one running if needed.
	// We request controller access to the collector since we want to perform
	// actions like start and stop. However, the TimeCollector is not checking
	// access levels on incoming requests at this time (TBD). Therefore, running
	// multiple instances of this client simultaneously (w/o exiting the TimeCollector) 
	// will cause both clients to use the same instance of the agent resulting in
	// erratic behavior as they both start/stop it.
	if (-1 == ACProxy->getAgent(timeCollector, TPTP_CONTROLLER_ACCESS))
	{
		cout<<"ERROR: Unable to get agent org.eclipse.tptp.TimeCollector"<<endl;			
		cout<<"Press any key to exit..."<<endl;
		getchar();
		return -1;
	}

	cout<<endl<<"The Time Collector Agent ID: "<<timeCollector->getAgentID()<<endl;

	// Create a bi-directional data connection between client and agent,
	// storing the resulting connection ID in the collector object.
	if (0 > timeCollector->createDataConnection(TPTP_DATA_PATH_TWOWAY))
	{
		cout<<"ERROR: Failed to establish a data channel with the agent."<<endl;
		cout<<"Press any key to exit..."<<endl;
		getchar();
		return -1;
	}

	cout<<endl<<"Established a data channel with the agent."<<endl;

	// Create an instance of an IDataProcessor object with an
	// incomingData() method. Adding this object as a listener for
	// the collector results in data coming over the channel
	// just established being sent to the incomingData() method
	// for handling.
	// The TimeDataProcessor's incomingData() method merely prints the data.
	TimeDataProcessor* dataProcessor = new TimeDataProcessor();
	timeCollector->addDataListener(dataProcessor);

	// We are now setup to exchange information with the TimeCollector in
	// whatever form the collector understands.
	// Our TimeCollector will print a copy of any data sent to it over the
	// data channel, so we send some strings below.
	cout<<endl<<"Sending 5 Hello messages over data channel to TimeCollector ..."<<endl;
	
	char buffer[1024];
	for(int i=0;i<5;i++)
	{
		// Create a "hello" string
		sprintf(buffer, "Hello from Sample Client to Time Collector Agent - Count %d !", i);

		// send the string to the agent.
		timeCollector->sendData(buffer, strlen(buffer)+1);			
	}
	
	// A standard collector agent supports a known set of commands as defined in
	// Collector.h (run, stop, cancel, pause, resume). The run command in this context
	// means to begin the action of collecting something. Recall that the agent itself
	// is already executing, waiting for requests from the client.
	// Below, we request the TimeCollector agent to run.
	//
	// Our TimeCollector's response to a run request is to take a snapshot of the
	// system's time and then loop, sending an occassional "hello" message to the
	// client across the data channel. The TimeDataProcessor which we established
	// as the data listener will print these messages for us.
	//
	cout<<endl<<"Start the TimeCollector ..."<<endl<<endl;
	timeCollector->run();

	// Wait for some arbitrary time period to allow the TimeCollector to send us
	// a few messages. 
	Sleep(1000);

	// Tell the TimeCollector to stop (i.e., halt whatever action the run command
	// started).
	cout<<endl<<"Stop the TimeCollector ..."<<endl<<endl;
	timeCollector->stop();

	// Wait for data to finish coming over channel.
	// Note: A protocol for recognizing end of data is TBD.
	Sleep(2000);

	// Release resources allocated by the Agent Controller
	timeCollector->destroyDataConnection();
	timeCollector->releaseAgent();
	ACProxy->disconnect();
	
	// Release client side resources
	delete dataProcessor;
	delete timeCollector;
	ACProxy->destroy();
	NodeFactory::deleteNode(TargetNode);
	
	cout<<"All finished"<<endl;
	cout<<"Press any key to exit..."<<endl;
	getchar();
	return 0;
}


