/// <summary>
        /// Main entry point
        /// </summary>
        /// <param name="args">command line args</param>
        public static void Main(string[] args)
        {
            ParameterHelper parameters = new ParameterHelper();
            Program         app        = new Program();

            try
            {
                parameters.ParseCommandLine(args);
            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message);
                Console.WriteLine();
                Console.WriteLine(GeneralUsageMessage);
                return;
            }

            if (parameters.HasFlag(ParameterHelper.HelpFlag))
            {
                Console.WriteLine(GeneralUsageMessage);
                return;
            }

            if (!parameters.HasParameter(ParameterHelper.FullAddress) || !parameters.HasParameter(ParameterHelper.WdpUser) || !parameters.HasParameter(ParameterHelper.WdpPassword))
            {
                Console.WriteLine("Missing one or more required parameter(s). Must provide address, user, and pwd");
                Console.WriteLine();
                Console.WriteLine(GeneralUsageMessage);
                return;
            }

            IDevicePortalConnection connection = new DefaultDevicePortalConnection(parameters.GetParameterValue(ParameterHelper.FullAddress), parameters.GetParameterValue(ParameterHelper.WdpUser), parameters.GetParameterValue(ParameterHelper.WdpPassword));
            DevicePortal            portal     = new DevicePortal(connection);

            Task connectTask = portal.Connect(updateConnection: false);

            connectTask.Wait();

            if (portal.ConnectionHttpStatusCode != HttpStatusCode.OK)
            {
                if (!string.IsNullOrEmpty(portal.ConnectionFailedDescription))
                {
                    Console.WriteLine(string.Format("Failed to connect to WDP (HTTP {0}) : {1}", (int)portal.ConnectionHttpStatusCode, portal.ConnectionFailedDescription));
                }
                else
                {
                    Console.WriteLine("Failed to connect to WDP for unknown reason.");
                }

                return;
            }

            string directory = "MockData";

            if (parameters.HasParameter("directory"))
            {
                directory = parameters.GetParameterValue("directory");
            }

            if (!Directory.Exists(directory))
            {
                Directory.CreateDirectory(directory);
            }

            if (parameters.HasParameter("endpoint"))
            {
                HttpMethods httpMethod = HttpMethods.Get;

                if (parameters.HasParameter("method"))
                {
                    // This is case sensitive. Since it's only used while generating mocks which is a development time action,
                    // that seems okay. If we want to revisit I'd prefer keeping the casing of the enum and using a switch or
                    // if/else block to manually convert.
                    httpMethod = (HttpMethods)Enum.Parse(typeof(HttpMethods), parameters.GetParameterValue("method"));
                }

                string endpoint = parameters.GetParameterValue("endpoint");

                string requestBodyFile = parameters.GetParameterValue("requestbody");

                if (!string.IsNullOrEmpty(requestBodyFile))
                {
                    if (parameters.HasFlag("requestbodymultipartfile"))
                    {
                        string boundaryString = Guid.NewGuid().ToString();

                        using (MemoryStream dataStream = new MemoryStream())
                        {
                            byte[] data;

                            FileInfo fi = new FileInfo(requestBodyFile);
                            data = Encoding.ASCII.GetBytes(string.Format("\r\n--{0}\r\n", boundaryString));
                            dataStream.Write(data, 0, data.Length);
                            CopyFileToRequestStream(fi, dataStream);

                            // Close the multipart request data.
                            data = Encoding.ASCII.GetBytes(string.Format("\r\n--{0}--\r\n", boundaryString));
                            dataStream.Write(data, 0, data.Length);

                            dataStream.Position = 0;
                            string contentType = string.Format("multipart/form-data; boundary={0}", boundaryString);

                            Task saveResponseTask = portal.SaveEndpointResponseToFile(endpoint, directory, httpMethod, dataStream, contentType);
                            saveResponseTask.Wait();
                        }
                    }
                    else
                    {
                        Stream fileStream = new FileStream(requestBodyFile, FileMode.Open);

                        Task saveResponseTask = portal.SaveEndpointResponseToFile(endpoint, directory, httpMethod, fileStream, "application/json");
                        saveResponseTask.Wait();
                    }
                }
                else
                {
                    Task saveResponseTask = portal.SaveEndpointResponseToFile(endpoint, directory, httpMethod);
                    saveResponseTask.Wait();
                }
            }
            else
            {
                foreach (Endpoint endpoint in Endpoints)
                {
                    HttpMethods httpMethod    = endpoint.Method;
                    string      finalEndpoint = endpoint.Value;

                    try
                    {
                        Task saveResponseTask = portal.SaveEndpointResponseToFile(finalEndpoint, directory, httpMethod);
                        saveResponseTask.Wait();
                    }
                    catch (Exception e)
                    {
                        // Print an error message if possible but continue on.
                        // Not all APIs are available on all device types.
                        if (e.InnerException is DevicePortalException)
                        {
                            DevicePortalException exception = e.InnerException as DevicePortalException;

                            Console.WriteLine(string.Format("Failed to generate .dat for {0} with status {1} ({2}).", endpoint, exception.HResult, exception.Reason));
                        }
                    }
                }
            }

            Console.WriteLine("Data generated in directory {0}.", directory);
            Console.WriteLine();
            Console.WriteLine("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
            Console.WriteLine("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
            Console.WriteLine("Please make sure to remove any personally identifiable information from the\n" +
                              "response(s) (such as alias/emails, ip addresses, and machine names) before\n" +
                              "adding them as mock responses!");
            Console.WriteLine("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
            Console.WriteLine("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");

            // If a debugger is attached, don't close but instead loop here until
            // closed.
            while (Debugger.IsAttached)
            {
                Thread.Sleep(0);
            }
        }