/// <summary>
        /// Creates an instance of a users class specific to an environment
        /// </summary>
        /// <param name="environmentName">name of environment</param>
        /// <returns>instance of class</returns>
        public static UsersStats Instance(string environmentName)
        {
            if (instance == null)
            {
                lock (syncRoot)
                {
                    instance = new UsersStats();
                    instance.Init(environmentName).Wait();
                }
            }

            return(instance);
        }
        /// <summary>
        /// Main program. Will print simple statistics
        /// </summary>
        /// <param name="args">command line arguments</param>
        public static void Main(string[] args)
        {
            ParseParams(args);

            var appStats  = AppsStats.Instance(environmentName);
            var userStats = UsersStats.Instance(environmentName);
            var userHandlesWithUpdatedProfiles = UserHandlesWithUpdatedProfiles.Instance(environmentName);
            var jsonCommandArgs = new JProperty("CommandArgs", JsonConvert.SerializeObject(args));

            Console.ResetColor();

            // 1. Get all the app Handles
            List <string> appHandles = appStats.GetAllAppHandles();

            Console.WriteLine("Number of AppHandles: " + appHandles.Count);
            JObject statsManifest = new JObject(jsonCommandArgs);

            statsManifest.Add(new JProperty("AppHandles", JsonConvert.SerializeObject(appHandles)));

            // 2. For each app handle, get its profile and all its user handles
            JObject jsonFragmentAppNames    = new JObject();
            JObject jsonFragmentUserHandles = new JObject();

            foreach (var appHandle in appHandles)
            {
                string        appName     = appStats.GetAppName(appHandle);
                List <string> userHandles = userStats.GetAllUserProfiles(appHandle);

                Console.WriteLine("  AppHandle: {0}", appHandle);
                Console.WriteLine("    Name: {0}", appName);
                Console.WriteLine("    Number of UserHandles: {0}", userHandles.Count);
                jsonFragmentAppNames.Add(appHandle, appName);

                JArray jsonUserHandles = new JArray();
                foreach (string userHandle in userHandles)
                {
                    jsonUserHandles.Add(userHandle);
                }

                jsonFragmentUserHandles[appHandle] = jsonUserHandles;
            }

            // 3. For each app handle, get user profiles that have been updated after the specified DateTime
            JObject jsonFragmentUpdatedUserHandles = new JObject();

            if (userProfileDateTime.HasValue)
            {
                foreach (var appHandle in appHandles)
                {
                    List <string> updatedUserHandles = userHandlesWithUpdatedProfiles.GetUpdatedUserHandles(appHandle, userProfileDateTime.Value);
                    Console.WriteLine("  AppHandle: {0}", appHandle);
                    Console.WriteLine("    Number of updated UserHandles: {0}", updatedUserHandles.Count);
                    JArray jsonUserHandles = new JArray();
                    foreach (string userHandle in updatedUserHandles)
                    {
                        jsonUserHandles.Add(userHandle);
                    }

                    jsonFragmentUpdatedUserHandles[appHandle] = jsonUserHandles;
                }
            }

            statsManifest.Add("AppNames", jsonFragmentAppNames);
            statsManifest.Add("UserHandlesPerApp", jsonFragmentUserHandles);
            statsManifest.Add("UpdatedUserHandlesPerApp", jsonFragmentUpdatedUserHandles);

            // write json to file
            if (noJson == false)
            {
                DateTime ts       = DateTime.Now;
                string   fileName = string.Format(@".\stats_manifest_{0}_{1}-{2}-{3}_{4}-{5}-{6}.json", environmentName, ts.Year, ts.Month.ToString("00"), ts.Day.ToString("00"), ts.Hour.ToString("00"), ts.Minute.ToString("00"), ts.Second.ToString("00"));
                System.IO.File.WriteAllText(fileName, statsManifest.ToString());
                Console.WriteLine("\nManifest file written to " + fileName);
            }
        }