//------------------------------------------------------------------------------
// <copyright file="HelloWorldCLI.cs" company="Microsoft">
//      Copyright (c) Microsoft Corporation.  All rights reserved.
// </copyright>
// <summary>
//      Sample Command Line Interface (CLI) demonstrating how to interact with
//      a custom SOA service (HelloWorldService) that runs Excel on a cluster.
// </summary>
//------------------------------------------------------------------------------

namespace HelloWorldCLI
{
    using System;
    using System.ServiceModel;
    using System.Threading;
    using HelloWorldCLI.HelloWorldService;
    using Microsoft.Hpc.Scheduler.Properties;
    using Microsoft.Hpc.Scheduler.Session;
    using Microsoft.Hpc.Scheduler.Session.Internal;
    
    /// <summary>
    /// Class implementing Hello World sample client.
    /// </summary>
    public class HelloWorld
    {
        /// <summary>
        /// Main method invoked by command line. Accepts cluster head node name and number of cores 
        /// along with a workbook path relative to the compute nodes. The name to say hello to and 
        /// number of hellos controls the contents and number of SOA messages.
        /// </summary>
        /// <param name="args">Command line parameters</param>
        public static void Main(string[] args)
        {
            // Syntax Usage Check 
            if (args.Length != 5)
            {
                Console.WriteLine("HelloWorldCLI <Workbook Path> <headnode> <Max Cores> <Recipient Name> <Number of Hellos>");
                return;
            }

            // Set command line parameter variables
            string workbookPath = args[0];
            string headNode = args[1];
            string recipientName = args[3];
            
            // Test workbook for existance
            if (!System.IO.File.Exists(workbookPath))
            {
                Console.Error.WriteLine("Invalid workbook path: " + workbookPath);
                return;
            }

            // Initialize maximum number of cores
            int maxCores;
            
            // Parse maximum number of cores
            if (int.TryParse(args[2], out maxCores))
            {
                // Check for validity
                if (maxCores <= 0)
                {
                    Console.Error.WriteLine("Max cores must be greater than 0");
                    return;
                }
            }
            else
            {
                // Parsing Error
                Console.Error.WriteLine("Invalid value for <Max Cores>: " + args[2]);
                return;
            }

            // Initialize number of requests 
            int totalRequests;

            // Parse number of requests
            if(int.TryParse(args[4], out totalRequests))
            {
                // Check for validity
                if (totalRequests <= 0 || totalRequests > 10000)
                {
                    Console.Error.WriteLine("Number of hellos must be greater than 0 and less than 10000.");
                    return;
                }
            }
            else
            {
                // Parsing Error
                Console.Error.WriteLine("Invalid value for <Number of Hellos>: " + args[4]);
                return;
            }

            // Initialize Session and Client objects
            Session session = null;
            BrokerClient<IHelloWorldService> client = null;
            try
            {
                // Create new session
                SessionStartInfo info = InitSession(JobUnitType.Core, 1, maxCores, headNode);
                session = Session.CreateSession(info);

                // Create client for the session
                client = new BrokerClient<IHelloWorldService>(session);

                // Initialize response variables
                int helloCount = 0;
                object countLock = new object();
                AutoResetEvent allDone = new AutoResetEvent(false);

                // Set the response handler
                client.SetResponseHandler(delegate(BrokerResponse<SayHiResponse> response)
                {
                    // Extract hello message from response and print to command line
                    try
                    {
                        string message = response.Result.SayHiResult;
                        Console.WriteLine(message);
                    }
                    catch (FaultException ex)
                    {
                        // Print any application errors in the service
                        Console.Error.WriteLine("Fault Exception: " + ex.Message);
                    }
                    catch (Exception ex)
                    {
                        // Non-application errors may be fatal, and the program should be allowed to finish
                        Console.Error.WriteLine("\nThere has been an error: {0}", ex.Message);
                        allDone.Set();
                        return;
                    }

                    // Update the number of responses received 
                    Interlocked.Increment(ref helloCount);
                    if (helloCount == totalRequests)
                    {
                            // All responses have been received
                            allDone.Set();
                    }
                });

                // Send a new request for each hello
                for (int recipientNumber = 1; recipientNumber <= totalRequests; recipientNumber++)
                {
                    // For each request, send the recipient name and an identifier
                    SayHiRequest myReq = new SayHiRequest(workbookPath, recipientName, recipientNumber);
                    client.SendRequest<SayHiRequest>(myReq);
                }

                // Complete batch of requests and wait for all respones to be received
                client.EndRequests();
                allDone.WaitOne();           
            }
            catch (Exception ex)
            {
                Console.Error.WriteLine("\nThere has been an error: {0}", ex.Message);
            }
            finally
            {
                // Close the client and session if they were created
                if (client != null)
                {
                    client.Close();
                }

                if (session != null)
                {
                    session.Close();
                }
            }
        } // main

        /// <summary>
        /// Initialize the session start information with supplied values and defaults
        /// </summary>
        /// <param name="type"> granularity of resource requested </param>
        /// <param name="min"> minimum number of resource units </param>
        /// <param name="max"> maximum number of resource units </param>
        /// <param name="headNode"> name of the head node </param>
        /// <returns> start information for session creation </returns>
        private static SessionStartInfo InitSession(JobUnitType type, int min, int max, string headNode)
        {
            // Use HelloWorldService for sample
            SessionStartInfo info = new SessionStartInfo(headNode, "HelloWorldService");
            info.ResourceUnitType = type;
            info.MinimumUnits = min;
            info.MaximumUnits = max;
            info.Secure = true;
            
            return info;
        } // InitSession
    } // Class
} // Namespace
