// The MAIN function for the server software, which starts up the XmlRpc (http server), 
// as well as Open Transactions.
//
int main(int argc, char* argv[])
{
	OTLog::vOutput(0, "\n\nWelcome to Open Transactions... Test Server -- version %s\n"
				   "(transport build: OTMessage -> OTEnvelope -> ZMQ )\n\n", OTLog::Version());
	// -----------------------------------------------------------------------

#ifdef _WIN32
	WSADATA wsaData;
	WORD wVersionRequested = MAKEWORD( 2, 2 );
	int nWSA = WSAStartup( wVersionRequested, &wsaData );
	OT_ASSERT_MSG(0 != nWSA, "Error calling WSAStartup.\n");	
#endif
	
	// -----------------------------------------------------------------------
	// I instantiate this here (instead of globally) so that I am assured all the globals
	// are ready to go before the server is created.  I still have it as a global pointer, though,
	// so I can get to it wherever I need to.
	g_pServer = new OTServer;
	// (This file you are reading is a wrapper for OTServer, which adds the transport layer.)

	OT_ASSERT_MSG(NULL != g_pServer, "Unable to instantiate OT server...\n");
	
	// -----------------------------------------------------------------------
	// The beginnings of an INI file!!
	
    OTString strIniFileDefault;
    OTLog::TransformFilePath(OT_INI_FILE_DEFAULT, strIniFileDefault);
	
	OTString strPath, strRawPath(SERVER_PATH_DEFAULT);
	
	{
		CSimpleIniA ini;
		
		SI_Error rc = ini.LoadFile(strIniFileDefault.Get());
		
		if (rc >=0)
		{
            {
                const char * pVal = ini.GetValue("paths", "server_path", SERVER_PATH_DEFAULT); // todo stop hardcoding.
                
                if (NULL != pVal)
                {
                    strRawPath.Set(pVal);
                    OTLog::vOutput(0, "Reading ini file (%s). \n Found Server data_folder path: %s \n", 
                                   strIniFileDefault.Get(), strRawPath.Get());
                }
                else
                {
                    strRawPath.Set(SERVER_PATH_DEFAULT);
                    OTLog::vOutput(0, "Reading ini file (%s): \n Failed reading Server data_folder path. Using: %s \n", 
                                   strIniFileDefault.Get(), strRawPath.Get());
                }
            }            
		}
		else 
		{
			strRawPath.Set(SERVER_PATH_DEFAULT);
			OTLog::vOutput(0, "Unable to load ini file (%s) to find data_folder path\n Will assume that server data_folder is at path: %s \n", 
						   strIniFileDefault.Get(), strRawPath.Get());
		}
	}
        
	// -----------------------------------------------------------------------

	OTString strCAFile, strDHFile, strKeyFile;  //, strSSLPassword;
	
    OTLog::TransformFilePath(strRawPath.Get(), strPath);
    
    OTLog::SetMainPath(strPath.Get());
    	
	OTLog::vOutput(0, "Using data_folder path:  %s\n", OTLog::Path());
	
	strCAFile. Format("%s%s%s", OTLog::Path(), OTLog::PathSeparator(), CA_FILE);
	strDHFile. Format("%s%s%s", OTLog::Path(), OTLog::PathSeparator(), DH_FILE);
	strKeyFile.Format("%s%s%s", OTLog::Path(), OTLog::PathSeparator(), KEY_FILE);
	
	
	
	// -----------------------------------------------------------------------
	
	// Initialize SSL -- This MUST occur before any Private Keys are loaded!
	SSL_library_init();
	SSL_load_error_strings();
	
	// Init loads up server's nym so it can decrypt messages sent in envelopes.
	// It also does various other initialization work.
	//
	// (Envelopes prove that ONLY someone who actually had the server contract,
	// and had loaded it into his wallet, could ever connect to the server or 
	// communicate with it. And if that person is following the contract, there
	// is only one server he can connect to, and one key he can use to talk to it.)
	
	OTLog::vOutput(0, 
				   "\nNow loading the server nym, which will also ask you for a password, to unlock\n"
				   "its private key. (Default password is \"%s\".)\n", KEY_PASSWORD);
	
	g_pServer->Init(); // Keys, etc are loaded here.
	
	// -----------------------------------------------------------------------

	// We're going to listen on the same port that is listed in our server contract.
	//
	//
	OTString	strHostname;	// The hostname of this server, according to its own contract.
	int			nPort=0;		// The port of this server, according to its own contract.
	
	OT_ASSERT_MSG(g_pServer->GetConnectInfo(strHostname, nPort),
				  "Unable to find my own connect info (which is in my server contract BTW.)\n");
	
	const int	nServerPort = nPort;
	
	//	int nSFSocketInit = SFSocketInit(socket,
	//									 strCAFile.Get(), 
	//									 strDHFile.Get(), 
	//									 strKeyFile.Get(),
	//									 strSSLPassword.Get(), 
	//									 NULL);
	
	// -----------------------------------------------------------------------
	
	// For re-occuring actions (like markets and payment plans.)
	//
	g_pServer->ActivateCron();

	// -----------------------------------
	
	//  Prepare our context and socket
	zmq::context_t context(1);
	zmq::socket_t socket(context, ZMQ_REP);

	OTString strBindPath; strBindPath.Format("%s%d", "tcp://*:", nServerPort);

	socket.bind(strBindPath.Get());

	// -----------------------------------------------------------------------
	// Let's get the HTTP server up and running...
	// Switching out XmlRpc for 0MQ (ZeroMQ)
	//
//	XmlRpc::setVerbosity(1);
//
//	// Create the server socket on the specified port
//	theXmlRpcServer.bindAndListen(nServerPort);
//
//	// Enable introspection, so clients can see what services this server supports. (Open Transactions...)
//	theXmlRpcServer.enableIntrospection(true);

	// -----------------------------------------------------------------------

	//  Initialize poll set
	zmq::pollitem_t items [] =
	{
		{ socket, 0, ZMQ_POLLIN, 0 },
	};

	// ----------------------------------------------------------
	
	do  // THE HEARTBEAT LOOP FOR THE OPEN-TRANSACTIONS SERVER!
	{
		// The Server now processes certain things on a regular basis.
		// ProcessCron is what gives it the opportunity to do that.
		// All of the Cron Items (including market trades, and payment plans...) have their hooks here...
		//
		g_pServer->ProcessCron();
		
		// -----------------------------------------------------------------------
		
		// Wait for client http requests (and process replies out to them.)
		//
//		theXmlRpcServer.work(10.0); // supposedly milliseconds -- but it's actually seconds.

		// Loop: process up to 10 client requests, then sleep for 1/10th second.
		// 
		// Then: check for shutdown.
		//
		// Then: go back to the top and repeat.... process cron, loop 10 client requests, sleep, check for shutdown, etc.
		//
		//
        
        
		for (int i = 0; i < /*10*/OTServer::GetHeartbeatNoRequests(); i++) 
		{
			// Switching to ZeroMQ library.
			zmq::message_t message;

			zmq::poll(&items[0], 1, 0);  // non-blocking
//			zmq::poll(&items[0], 1, -1);

			if ((items[0].revents & ZMQ_POLLIN) && socket.recv(&message, ZMQ_NOBLOCK))
			{
//				socket.recv(&message);

				// Convert the ZMQ message to a std::string
				std::string str_Message;
				str_Message.reserve(message.size());
				str_Message.append(static_cast<const char *>(message.data()), message.size());

				//  Process task
				std::string str_Reply; // Output.
				ProcessMessage_ZMQ(str_Message, str_Reply);

				// -----------------------------------------------
				
				// Convert the std::string (reply) into a ZMQ message
				zmq::message_t reply (str_Reply.length());

				if (str_Reply.length() > 0)
					memcpy((void *) reply.data(), str_Reply.c_str(), str_Reply.length());

				// --------------------------------
				//  Send reply back to client

				int		nSendTries = 0;
				bool	bSuccessSending = false;
				
				// HALF-SECOND DELAY IF FAILURE SENDING REPLY...
				// (While it tries to re-send 5 times.)
				//
				while ((nSendTries++ < OTLog::GetLatencySendNoTries()/*5*/) && (false == (bSuccessSending = socket.send(reply, ZMQ_NOBLOCK))))
					OTLog::SleepMilliseconds(/*100*/OTLog::GetLatencySendMs());
				
				if (false == bSuccessSending)
					OTLog::vError("Socket error: failed while trying to send reply back to client! \n\n MESSAGE:\n%s\n\nREPLY:\n%s\n\n", 
								  str_Message.c_str(), str_Reply.c_str());
			}
		} //  for		
		// -----------------------------------------------------------------------
		
		// Now go to sleep for a tenth of a second.
		// (The main loop processes ten times per second, currently.)
		
		OTLog::SleepMilliseconds(/*100*/OTServer::GetHeartbeatMsBetweenBeats()); // 100 ms == (1 second / 10)
		
		// -----------------------------------------------------------------------
		// ARTIFICIAL LIMIT:
		// 10 requests per heartbeat, 10 rounds per second == 100 requests per second.
		//
		// *** ONE HUNDRED CLIENT MESSAGES PER SECOND is the same as:
		// 
		//     6000 PER MINUTE == 360,000 PER HOUR == 8,640,000 PER DAY***
		//
		// Speeding it up is just a matter of adjusting the above numbers, and TESTING to see if OT can handle it.
		// (Not counting optimization of course.)
		//
		// -----------------------------------------------------------------------

		if (g_pServer->IsFlaggedForShutdown())
		{
			OTLog::Output(0, "Server is shutting down gracefully....\n");
			break;
		}
    } while (1);
	
	
	// TODO: cleanup OpenSSL here.
	
#ifdef _WIN32
	WSACleanup();
#endif
	
	return 0;
}
// *********************************************************************************************************
//
//
//             *** SERVER MAIN ***
//
//
// The MAIN function for the server software, which starts up the ZMQ listener, as well
// as well as the Open Transactions library and the OT Server object.
//
// After initialization, this function becomes the "main loop" of OT server.
//
int main(int argc, char* argv[])
{
	OTLog::vOutput(0, "\n\nWelcome to Open Transactions... Test Server -- version %s\n"
				   "(transport build: OTMessage -> OTEnvelope -> ZMQ )\n\n", OTLog::Version());

	// WINSOCK WINDOWS
	// -----------------------------------------------------------------------
#ifdef _WIN32

	WORD wVersionRequested;
	WSADATA wsaData;
	int err;

	/* Use the MAKEWORD(lowbyte, highbyte) macro declared in Windef.h */
	wVersionRequested = MAKEWORD(2, 2);

	err = WSAStartup(wVersionRequested, &wsaData);
	if (err != 0) {
	/* Tell the user that we could not find a usable		*/
	/* Winsock DLL.											*/
		printf("WSAStartup failed with error: %d\n", err);
		return 1;
	}

	/*	Confirm that the WinSock DLL supports 2.2.			*/
	/*	Note that if the DLL supports versions greater		*/
	/*	than 2.2 in addition to 2.2, it will still return	*/
	/*	2.2 in wVersion since that is the version we		*/
	/*	requested.											*/

	if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2) {
		/* Tell the user that we could not find a usable */
		/* WinSock DLL.                                  */
		printf("Could not find a usable version of Winsock.dll\n");
		WSACleanup();
		return 1;
	}
	else
		printf("The Winsock 2.2 dll was found okay\n");

	/* The Winsock DLL is acceptable. Proceed to use it. */
	/* Add network programming using Winsock here */
	/* then call WSACleanup when done using the Winsock dll */
#endif





	// ***********************************************************************
    // INITIALIZATION and CLEANUP (for the OT library, and for this server application.)
    //
    class __ot_server_
    {
        OTServer * m_pServer;
    public:
        OTServer * GetServer() { return m_pServer; }
        // -----------------------------------
        __ot_server_() : m_pServer(NULL) // INIT 
        {
            // -----------------------------------------------------------------------   
	
            // -----------------------------------------------------------------------
            // OTLog class exists on both client and server sides.
            // #define OT_NO_SIGNAL_HANDLING if you want to turn off OT's signal handling.
            //
#if defined(OT_SIGNAL_HANDLING)
            OTLog::SetupSignalHandler(); // This is optional! (I, of course, am using it in this test app...)
#endif
            // -----------------------------------------------------------------------    
            // I instantiate this here (instead of globally) so that I am assured that any globals and other
            // setup is already done before we instantiate the server object itself.
            //
            OT_ASSERT_MSG(NULL == m_pServer, "server main(): ASSERT: NULL == m_pServer.");
            m_pServer = new OTServer;
            //
            // (This .cpp file you are currently reading is a wrapper for OTServer,
            // which adds the transport layer.)
            //
            OT_ASSERT_MSG(NULL != m_pServer, "server main(): ASSERT: Unable to instantiate OT server.\n");

			OTString pathUserAppDataPath, pathIniFileLocation;

			pathUserAppDataPath = GetRoamingAppDataLocation();
			pathIniFileLocation.Format("%s%s%s", pathUserAppDataPath.Get(), OTLog::PathSeparator(), SERVER_INI_FILE_DEFAULT);


			OTString pathOTServerDataLocation;

			OTLog::vOutput(0, "\nFound ot_init.cfg in: \n     %s \nNow checking to see if it contains the OT Server path...", pathIniFileLocation.Get());
			// Read the File, If successful use result

			if (false == GetOTAppDataFolderLocation(pathIniFileLocation, pathOTServerDataLocation))
			{
				OTLog::vOutput(0, "Path not found... Will attempt default!... \n");
				// Not successfull will will assume it is in default location:
				pathOTServerDataLocation.Format("%s%s%s", pathUserAppDataPath.Get(), OTLog::PathSeparator(), SERVER_PATH_DEFAULT);
			};

			OTLog::vOutput(0, "     %s \n", pathOTServerDataLocation.Get());


			OTLog::SetMainPath(pathOTServerDataLocation.Get());              // <============ SET MAIN PATH
            OTLog::vOutput(0, "Using server_data path:  %s\n", OTLog::Path());


            // -----------------------------------------------------------------------    
            
            OTCrypto::It()->Init();  // <========== (OpenSSL gets initialized here.)
            
        }
        // ****************************************
        //
        ~__ot_server_()  // CLEANUP
        {
            OTLog::vOutput(0, "\n\n OT version %s, shutting down and cleaning up.\n",
                           OTLog::Version());

            // ------------------------------
            if (NULL != m_pServer)
                delete m_pServer;
            m_pServer = NULL;
            // ------------------------------
            // We clean these up in reverse order from the Init function, which just seems
            // like the best default, in absence of any brighter ideas.
            //
            OTCrypto::It()->Cleanup();  // <======= (OpenSSL gets cleaned up here.)

            // -------------------------
            // (This is at the bottom, since we do the cleanup in the 
            // reverse order from initialization.)
#ifdef _WIN32
            WSACleanup();
#endif
        }
    };	
	// ***********************************************************************
    //
    // INSTANTIATE and INITIALIZE...
    //
    // (Cleanup happens automatically when this object goes out of scope.)
    //
    __ot_server_  the_server_obj;
    OTServer * pServer = the_server_obj.GetServer();
    OT_ASSERT(NULL != pServer);
    // -----------------------------------------------------------------------
//	OTString strCAFile, strDHFile, strKeyFile;  //, strSSLPassword;
//	strCAFile. Format("%s%s%s", OTLog::Path(), OTLog::PathSeparator(), CA_FILE);
//	strDHFile. Format("%s%s%s", OTLog::Path(), OTLog::PathSeparator(), DH_FILE);
//	strKeyFile.Format("%s%s%s", OTLog::Path(), OTLog::PathSeparator(), KEY_FILE);
	// -----------------------------------------------------------------------
    //
    // UPDATE: This was moved to OTLog::OT_Init(), which is called above, by the
    // nested cleanup class.
    //
	// Initialize SSL -- This MUST occur before any Private Keys are loaded!
//	SSL_library_init();
//	SSL_load_error_strings();
	
	// -----------------------------------------------------------------------
	// OTServer::Init loads up server's nym so it can decrypt messages sent in
    // envelopes. It also does various other initialization work.
	//
	// (Envelopes prove that ONLY someone who actually had the server contract,
	//  and had loaded it into his wallet, could ever connect to the server or 
	//  communicate with it. And if that person is following the contract, there
	//  is only one server he can connect to, and one key he can use to talk to it.)
	//
	OTLog::vOutput(0, 
				   "\nNow loading the server nym, which will also ask you for a password, to unlock\n"
				   "its private key. (Default password is \"%s\".)\n", KEY_PASSWORD);
	
	pServer->Init(); // Keys, etc are loaded here. ===> Assumes main path is set! <===
	
	// -----------------------------------------------------------------------
	// We're going to listen on the same port that is listed in our server contract.
	//
	//
	OTString	strHostname;	// The hostname of this server, according to its own contract.
	int			nPort=0;		// The port of this server, according to its own contract.
	
    const bool bConnectInfo = pServer->GetConnectInfo(strHostname, nPort);
    
	OT_ASSERT_MSG(bConnectInfo, "server main: Unable to find my own connect info (which SHOULD be in my server contract, BTW.) Perhaps you failed trying to open that contract? Have you tried the test password? (\"test\")\n");
	
	const int   nServerPort = nPort;
	
	// -----------------------------------------------------------------------
    // OT CRON
    //
    // A heartbeat for recurring transactions, such as markets, payment plans,
    // and smart contracts.

	pServer->ActivateCron();

    // NOTE: Currently we trigger OT Cron's processing internally, but there's no reason why, in the
    // future, we can't make an actual cron job that triggers a script, that fires a message
    // to OT, causing OT to process its Cron (even if we were single-threaded we could do this...)
    //
    // Have to put some thought into it...
    //
    // Wouldn't require much security, since OT can still be smart enough not to process cron any
    // more often than X minutes, no matter HOW many times the ProcessCron script fires.
    // Thing is, though, that with this setup, we can't really guarantee that cron will EVER be
    // triggered -- whereas the way OT is now, at least we know it WILL fire every X seconds.
    //
    
	// --------------------------------------
    //
    // NETWORK
    //
	// Prepare our context and listening socket...

	OTSocket theSocket;
	OTString strBindPath; strBindPath.Format("%s%d", "tcp://*:", nServerPort);
	theSocket.Listen(strBindPath);
    
    // ******************************************************************************************
    //
    //      *** MAIN LOOP ***
    //
	do // ---------------------------
	{
        // =-=-=- HEARTBEAT -=-=-=
		//
		// The Server now processes certain things on a regular basis.
		// ProcessCron is what gives it the opportunity to do that.
		// All of the Cron Items (including market trades, payment plans, smart contracts...) 
		// they all have their hooks here...
		//
		pServer->ProcessCron();  // Internally this is smart enough to know how often to actually activate itself.
                                   // Most often it just returns doing nothing (waiting for its timer.)		
		// -----------------------------------------------------------------------
		// Wait for client http requests (and process replies out to them.)
		// ----------------------------------------------------------------------
		// Number of requests to process per heartbeat: OTServer::GetHeartbeatNoRequests()
		//
		// Loop: process up to 10 client requests, then sleep for 1/10th second.
		// That's a total of 100 requests per second. Can the computers handle it? 
		// Is it too much or too little? Todo: load testing.
		//
		// Then: check for shutdown flag.
		//
		// Then: go back to the top ("do") and repeat the loop.... process cron, 
		// process 10 client requests, sleep, check for shutdown, etc.
		//
		//
                
		Timer t;	// start timer
		t.start();
		const double tick1 = t.getElapsedTimeInMilliSec();
		// -----------------------------------------------------
		//
        // PROCESS X NUMBER OF REQUESTS (THIS PULSE.)
        //
        // Theoretically the "number of requests" that we process EACH PULSE.
        // (The timing code here is still pretty new, need to do some load testing.)
        //
		for (int i = 0; i < /*10*/OTServer::GetHeartbeatNoRequests(); i++) 
		{
			std::string	str_Message;
			
			// With 100ms heartbeat, receive will try 100 ms, then 200 ms, then 400 ms, total of 700.
			// That's about 15 Receive() calls every 10 seconds. Therefore if I want the ProcessCron()
			// to trigger every 10 seconds, I need to set the cron interval to roll over every 15 heartbeats.
			// Therefore I will be using a real Timer for Cron, instead of the damn intervals.
			//
			bool bReceived = theSocket.Receive(str_Message);  
			
			if  (bReceived)
			{
				std::string str_Reply; // Output.
				
				if (str_Message.length() <= 0)
				{
					OTLog::Error("server main: Received a message, but of 0 length or less. Weird. (Skipping it.)\n");
				}
				else // ------------------------------------
				{
                    // true  == YES, DISCONNECT m_pSocket, something must have gone wrong.
                    // false ==  NO, do NOT disconnect m_pSocket, everything went wonderfully!
                    //
					const bool bShouldDisconnect = ProcessMessage_ZMQ(*pServer, str_Message, str_Reply); // <================== PROCESS the message!
					// --------------------------------------------------

					if ((str_Reply.length() <= 0) || bShouldDisconnect)
					{
						OTLog::vOutput(0, "server main: ERROR: Unfortunately, not every client request is "
                                       "legible or worthy of a server response. :-)  "
									   "Msg:\n\n%s\n\n", str_Message.c_str());
                        
                        theSocket.Listen();
					}
					else
					{
						bool bSuccessSending = theSocket.Send(str_Reply); // <===== SEND THE REPLY
						
						if (false == bSuccessSending)
							OTLog::vError("server main: Socket ERROR: failed while trying to send reply "
                                          "back to client! \n\n MESSAGE:\n%s\n\nREPLY:\n%s\n\n", 
										  str_Message.c_str(), str_Reply.c_str());
						// --------------------------------------------------
					}
				}
			}
		} //  for
		
		// -----------------------------------------------------------------------
		//
        // IF the time we had available wasn't all used up -- if some of it is still
        // available, then SLEEP until we reach the NEXT PULSE. (In practice, we will 
        // probably use TOO MUCH time, not too little--but then again OT isn't ALWAYS
        // processing a message. There could be plenty of dead time in between...)
        //
		const	double tick2	= t.getElapsedTimeInMilliSec();
		const	long elapsed	= static_cast<long>(tick2 - tick1);
		long	lSleepMS		= 0;
			
		if (elapsed < /*100*/OTServer::GetHeartbeatMsBetweenBeats()) 
		{
			lSleepMS = OTServer::GetHeartbeatMsBetweenBeats() - elapsed;

			// Now go to sleep.
			// (The main loop processes ten times per second, currently.)		
			OTLog::SleepMilliseconds(lSleepMS); // 100 ms == (1 second / 10)
		}
		
		// -----------------------------------------------------------------------
		// ARTIFICIAL LIMIT:
		// 10 requests per heartbeat, 10 rounds per second == 100 requests per second.
		//
		// *** ONE HUNDRED CLIENT MESSAGES PER SECOND is the same as:
		// 
		//     6000 PER MINUTE == 360,000 PER HOUR == 8,640,000 PER DAY***
		//
		// Speeding it up is just a matter of adjusting the above numbers, and LOAD TESTING,
        // to see if OT can handle it. (Not counting optimization of course.)
		//
		// -----------------------------------------------------------------------

		if (pServer->IsFlaggedForShutdown())
		{
			OTLog::Output(0, "main: OT Server is shutting down gracefully....\n");
			break;
		}
        
    } while (1);  // (MAIN LOOP)
    
	// ------------------------------------
    
	return 0;
}