/*******************************************************************************
 * Copyright (c) 2005, 2008 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 implementation of a client engaging
 *								  the new Agent Controller and interacting with
 *								  an agent.
 *
 * $Id: SampleClient.cpp,v 1.23 2008/02/28 02:10:39 jkubasta 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  
 * This is a sample client program that uses the Agent Controller 
 * to get access to a simple agent called TimeCollector and have
 * that agent perform a few actions.
 *
 * Usage : SampleClient			<==defaults to localhost, port 10006
 *		 : SampleClient <HostName> <Port> 
 *		 : For e.g. SampleClient
 *					SampleClient "lab-system-001" 10006
 *
 * Expected output:
 *		The TimeCollector displays:
 *			- five "Received data" messages sent to it by the client
 *			- start and stop time
 *			- final line displayed, "Press enter key to exit...".
 *
 *		The SampleClient displays: 
 *			- several messages indicating progress
 *			- approximately 10 "Incoming data" messages from the TimeCollector
 *			- final line displayed, "Press enter key to exit...".
 *
 *
 * Source Code Files:
 *		SampleClient.cpp - Sample Client Application 
 *		TimeDataProcessor.cpp - Data Listener Class, implements the IDataProcessor to receive data
 *
 *
 *********************************************************/
int main(int argc, char* argv[])
{
	int rc = 0 ;
	char* hostName = "localhost";
	int portNum = 10006;
	INode* TargetNode = 0;
	AgentController* ACProxy = 0;
	
	if ((argc == 2) || (argc > 3))
	{
		cout<<"Usage: SampleClient or SampleClient <HostName> <Port> "<<endl;
		cout<<"Press enter key to exit..."<<endl;
		getchar();
		return -1;
	}

	// Use the host name and port number if provided on the command line.
	if (argc == 3)
	{
		hostName = argv[1];
		portNum = atoi(argv[2]);
	}
	

	// Create a Node object for the target system of choice.
	TargetNode = NodeFactory::createNode(hostName);
	if (!TargetNode)
	{
		cout<<"ERROR: Failed to create the Node object."<<endl;
		cout<<"Press enter 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 enter key to exit..."<<endl;
		getchar();
		return -1;
	}

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

	// 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 enter 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 enter 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 enter key to exit..."<<endl;
	getchar();
	return 0;
}


