//------------------------------------------------------------------------------------
// <copyright file="BoilerplateCORBAServer.h" company="LiquidRobotics">
//
// Copyright (c) 2014 Liquid Robotics, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
// This software is associated with a release.  Liquid Robotics makes no
// representation that the design, interfaces or component distribution will
// remain unchanged in future releases.
//
// </copyright>
//
// <summary>
//	Defines a template class for the "boilerplate" or typical startup sequence in main.
// </summary>
//
// <owner></owner>
//------------------------------------------------------------------------------------

#ifndef BOILERPLATECORBASERVER_H_
#define BOILERPLATECORBASERVER_H_

#include "LqrSMACObjectBroker.h"
#include "LqrSMACSharedLib.h"
#include "LqrSMACStdOutLogger.h"
#include "PayloadManagerClient.h"
#include <string>
#include <time.h>

namespace LiquidRobotics {
namespace EventLib {

template<typename Settings, typename Program>
class BoilerplateCORBAServer
{
public:

	// Standard implementation of a CORBA server
	//
	// int main(int argc, char* argv[])
	// {
	//    return BoilerplateCORBAServer<MySettings,MyProgram>(argc, argv, "MyServer-config.xml");
	// }
	BoilerplateCORBAServer(int argc, char* argv[], const std::string& configFileName)
	: retcode(0)
	{
		using namespace std;
		using namespace LiquidRobotics::SMACFramework;
		using namespace CORBA;

		tzset();			// initialize time zone

		try
		{
			// instantiate a "settings" class and deserialize it from the
			// configuration XML file (typically uses boost serialization)
			Settings settings;
			settings.Load(configFileName);

			// Pull out the CORBA server name and kind
			const string serverName = settings.GetServerName();
			const string serverKind = settings.GetServerKind();

			// Create a logger based on the logger settings
			StdOutLogger logger(settings.GetLoggerSettings());

			// Instantiate a CORBA object broker based on program parameters
			ObjectBroker broker(true);
			broker.Initialize(argc, argv);

			// Instantiate the program object
			Program prog(broker, settings, logger);

			// Create a proxy class (tie) for the program instance
			PortableServer::ServantBase_var theServer = 0;
			theServer = new ::POA_LiquidRobotics::SMAC::ISensorWithEvents_tie<Program>(prog);

			// Advertise the instance using the server name and kind from the XML file
			Object_var serverRef = broker.AdvertizeInstance(theServer.in(), serverName.c_str(), serverKind.c_str());

			// Get the PayloadManangerClient settings and instantiate
			const PayloadManagerClientSettings& pmClientSettings = settings.GetPayloadManagerClientSettings();
			PayloadManagerClient::Ptr pmClient;
			pmClient.reset(new PayloadManagerClient(pmClientSettings, broker, prog));

			// initialize the server class: note that PayloadManagerClient is not
			// registered yet, so the board address is not final
			prog.Initialize(serverRef.in(), pmClient);

			// register PayloadManagerClient; DemoSensor derives from EventTransceiver,
			// and PayloadManagerClients needs that to be initialized before it can
			// register
			pmClient->Register(serverRef.in());

			// now listen for requests; this function will not return until the object
			// broker (broker) indicates an error or its "Shutdown" method is called
			// (use QueueShutdown from the server class)
			broker.ListenForRequests();
		}
		catch(CORBA::Exception& ex)
		{
			cerr << "Caught CORBA exception: " << DecodeCORBAException(ex) << endl;
			retcode = 1;
		}
		catch(exception& ex)
		{
			cerr << "Caught " << typeid(ex).name() << ": " << ex.what() << endl;
			retcode = 1;
		}
	}

	operator int()
	{
		return retcode;
	}

private:

	int retcode;
};

}
}

#endif /* LQRSMACBOILERPLATECORBASERVER_H_ */
