/// <summary>
 /// The method of forming a string name = Last Name + First Name, which will be added to the list.
 /// Called by method Connect To Server ConnectToServer.
 /// For Storage3.
 /// </summary>
 /// <param name="context">The context of the interaction with the database.</param>
 /// <param name="f">The object to be added such as Friends.</param>
 /// <param name="listOfFriends">Friend list.</param>
 /// <returns>The format string "{Last Name} + {First Name}".</returns>
 public string FindFriendsStorage3(Storage3Context context, Friends f, List<int> listOfFriends)
 {
     var queryFriend = context.User.Where(x => x.Id == f.Friend_Id);
     var elementToAdd = queryFriend.ToList();
     listOfFriends.Add(elementToAdd[0].Id);
     return (elementToAdd[0].Last_Name + ' ' + elementToAdd[0].First_Name);
 }
 /// <summary>
 /// Cached Storage3.
 /// </summary>
 private static void CacheThreadStorage3()
 {
     using (Storage3Context connection = new Storage3Context())
     {
         var entity = connection.User.ToList().FirstOrDefault();
     }
 }
        /// <summary>
        /// Methods of adding a record in the database (Storage3).
        /// Called from the methods TransactionScopeWithStorage.
        /// </summary>
        /// <param name="context">The context of the interaction with the database.</param>
        /// <param name="entity">The object to add the type of User.</param>
        /// <param name="count">Counter.</param>
        /// <param name="commitCount">Meaning - "every time commitCount doing SaveChanges()".</param>
        /// <param name="recreateContext">It must be true.</param>
        /// <returns>The context of the interaction with the database.</returns>
        private static Storage3Context AddToStorage3(Storage3Context context, User entity, int count, int commitCount, bool recreateContext)
        {
            context.Set<User>().Add(entity);

            if (count%commitCount != 0)
                return context;

            context.SaveChanges();

            if (!recreateContext)
                return context;

            context.Dispose();
            context = new Storage3Context();
            context.Configuration.AutoDetectChangesEnabled = false;

            return context;
        }
        /// <summary>
        /// The method for forming transactions with Storage3.
        /// Called from an event handler btnFill_Click.
        /// </summary>
        /// <param name="users">The list of users you want to add.</param>
        public void TransactionScopeWithStorage3(List<User> users)
        {
            using (var scope = new TransactionScope())
            {
                Storage3Context context = null;
                try
                {
                    context = new Storage3Context();
                    context.Configuration.AutoDetectChangesEnabled = false;

                    var count = 0;
                    foreach (var entityToInsert in users)
                    {
                        ++count;
                        context = AddToStorage3(context, entityToInsert, count, 100, true);
                    }

                    context.SaveChanges();
                }
                finally
                {
                    context?.Dispose();
                }

                scope.Complete();
            }
        }
        /// <summary>
        /// Event: Make all friends.
        /// </summary>
        /// <param name="sender">Sender</param>
        /// <param name="e">Event Args</param>
        override protected void btnFriends_Click(object sender, RoutedEventArgs e)
        {
            var arrayNumberFriends = new int[500000];

            for (var i = 0; i < 500000; i++) arrayNumberFriends[i] = 0;

            var rnd = new Random();

            var storage1Context = new Storage1Context();
            var storage2Context = new Storage2Context();
            var storage3Context = new Storage3Context();
            var storage4Context = new Storage4Context();
            var storage5Context = new Storage5Context();

            storage1Context.Configuration.AutoDetectChangesEnabled = false;
            storage2Context.Configuration.AutoDetectChangesEnabled = false;
            storage3Context.Configuration.AutoDetectChangesEnabled = false;
            storage4Context.Configuration.AutoDetectChangesEnabled = false;
            storage5Context.Configuration.AutoDetectChangesEnabled = false;

            for (var i = 0; i < 500000; i++)
            {
                if (arrayNumberFriends[i] == 5)
                    continue;

                var shortage = 5 - arrayNumberFriends[i];
                for (var j = 0; j < shortage; j++)
                {
                    var friendId = rnd.Next(1, 500001);
                    if (i == friendId)
                        friendId = rnd.Next(1, 500001);

                    if (i <= 100000)
                    {
                        storage1Context.Friends.Add(new Friends { User_Id = i + 1, Friend_Id = friendId });
                        storage1Context.SaveChanges();
                        arrayNumberFriends[i]++;
                    }
                    else if (i > 100000 && i < 200000)
                    {
                        storage2Context.Friends.Add(new Friends { User_Id = i, Friend_Id = friendId });
                        storage2Context.SaveChanges();
                        arrayNumberFriends[i]++;
                    }
                    else if (i > 200000 && i < 300000)
                    {
                        storage3Context.Friends.Add(new Friends { User_Id = i, Friend_Id = friendId });
                        storage3Context.SaveChanges();
                        arrayNumberFriends[i]++;
                    }
                    else if (i > 300000 && i < 400000)
                    {
                        storage4Context.Friends.Add(new Friends { User_Id = i, Friend_Id = friendId });
                        storage4Context.SaveChanges();
                        arrayNumberFriends[i]++;
                    }
                    else if (i > 400000 && i < 500000)
                    {
                        storage5Context.Friends.Add(new Friends { User_Id = i, Friend_Id = friendId });
                        storage5Context.SaveChanges();
                        arrayNumberFriends[i]++;
                    }

                    if (friendId > 1 && friendId < 100000)
                    {
                        storage1Context.Friends.Add(new Friends { User_Id = friendId, Friend_Id = (i <= 100000) ? i + 1 : i });
                        storage1Context.SaveChanges();
                        arrayNumberFriends[friendId]++;
                    }
                    else if (friendId > 100000 && friendId < 200000)
                    {
                        storage2Context.Friends.Add(new Friends { User_Id = friendId, Friend_Id = (i <= 100000) ? i + 1 : i });
                        storage2Context.SaveChanges();
                        arrayNumberFriends[friendId]++;
                    }
                    else if (friendId > 200000 && friendId < 300000)
                    {
                        storage3Context.Friends.Add(new Friends { User_Id = friendId, Friend_Id = (i <= 100000) ? i + 1 : i });
                        storage3Context.SaveChanges();
                        arrayNumberFriends[friendId]++;
                    }
                    else if (friendId > 300000 && friendId < 400000)
                    {
                        storage4Context.Friends.Add(new Friends { User_Id = friendId, Friend_Id = (i <= 100000) ? i + 1 : i });
                        storage4Context.SaveChanges();
                        arrayNumberFriends[friendId]++;
                    }
                    else if (friendId > 400000 && friendId < 500000)
                    {
                        storage5Context.Friends.Add(new Friends { User_Id = friendId, Friend_Id = (i <= 100000) ? i + 1 : i });
                        storage5Context.SaveChanges();
                        arrayNumberFriends[friendId]++;
                    }
                }
            }
        }
        /// <summary>
        /// Determine the database with which it is necessary to make the connection.
        /// The method for the modal form.
        /// </summary>
        /// <param name="userId">User ID.</param>
        /// <param name="frm">An instance of a modal form.</param>
        private void Connected(int userId, InfoWindow frm)
        {
            try
            {
                var localDb = new DataBase();

                if (userId <= 100000)
                {
                    using (var context = new Storage1Context())
                    {
                        localDb.ConnectToServer1(context, userId, _services, _logging, _friend, lstFriends, frm);
                    }
                }
                else if (userId > 100000 && userId <= 200000)
                {
                    using (var context = new Storage2Context())
                    {
                        localDb.ConnectToServer2(context, userId, _services, _logging, _friend, lstFriends, frm);
                    }
                }
                else if (userId > 200000 && userId <= 300000)
                {
                    using (var context = new Storage3Context())
                    {
                        localDb.ConnectToServer3(context, userId, _services, _logging, _friend, lstFriends, frm);
                    }
                }
                else if (userId > 300000 && userId <= 400000)
                {
                    using (var context = new Storage4Context())
                    {
                        localDb.ConnectToServer4(context, userId, _services, _logging, _friend, lstFriends, frm);
                    }
                }
                else if (userId > 400000 && userId <= 500000)
                {
                    using (var context = new Storage5Context())
                    {
                        localDb.ConnectToServer5(context, userId, _services, _logging, _friend, lstFriends, frm);
                    }
                }
            }
            catch (ArgumentOutOfRangeException ex)
            {
                _logging.ProcessingException(ex);
                MessageBox.Show(ex.Message, "Connection error", MessageBoxButton.OK, MessageBoxImage.Error);
            }
        }
        /// <summary>
        /// Event: Get detailed information about a friend.
        /// </summary>
        /// <param name="sender">Sender</param>
        /// <param name="e">Event Args</param>
        private void lstFriends_MouseDoubleClick(object sender, MouseButtonEventArgs e)
        {
            #region The code required for diagnosis - measures the time
            var spectator = new Stopwatch();
            spectator.Start();
            #endregion

            if (lstFriends.SelectedItem == null)
                return;

            var userId = _listOfFriends[lstFriends.SelectedIndex];
            var frm = new InfoWindow {ShowInTaskbar = false /* Do not show on the taskbar. */};

            if (userId <= 100000)
            {
                using (var context = new Storage1Context())
                {
                    ConnectToServer1(context, userId, frm);
                }
            }
            else if (userId > 100000 && userId < 200000)
            {
                using (var context = new Storage2Context())
                {
                    ConnectToServer2(context, userId, frm);
                }
            }
            else if (userId > 200000 && userId < 300000)
            {
                using (var context = new Storage3Context())
                {
                    ConnectToServer3(context, userId, frm);
                }
            }
            else if (userId > 300000 && userId < 400000)
            {
                using (var context = new Storage4Context())
                {
                    ConnectToServer4(context, userId, frm);
                }
            }
            else if (userId > 400000 && userId < 500000)
            {
                using (var context = new Storage5Context())
                {
                    ConnectToServer5(context, userId, frm);
                }
            }

            #region The code required for diagnosis - measures the time
            spectator.Stop();
            var ts = spectator.Elapsed;
            frm.TimeParam = $"Lead time: {ts.Hours:00}:{ts.Minutes:00}:{ts.Seconds:00}.{ts.Milliseconds/10:00}";
            #endregion
            frm.Show();
        }
        /// <summary>
        /// The connection method to Storage5.
        /// Called from an event handler lstFriends_MouseDoubleClick.
        /// </summary>
        /// <param name="context">The context of the interaction with the database.</param>
        /// <param name="userId">User ID.</param>
        /// <param name="frm">Instance a modal window.</param>
        private void ConnectToServer5(Storage5Context context, int userId, InfoWindow frm)
        {
            RedisOrSQLStorage5(context, userId, frm);

            var queryFriendsStorage = context.Friends.Where(x => x.User_Id == userId);
            var friends = queryFriendsStorage.ToList();
            foreach (var f in friends)
            {
                if (f.Friend_Id < 100000)
                {
                    using (var storage1Context = new Storage1Context())
                    {
                        frm.FriendsParam = FindFriendsStorage1(storage1Context, f, frm);
                    }
                }
                else if (f.Friend_Id > 100000 && f.Friend_Id < 200000)
                {
                    using (var storage2Context = new Storage2Context())
                    {
                        frm.FriendsParam = FindFriendsStorage2(storage2Context, f, frm);
                    }
                }
                else if (f.Friend_Id > 200000 && f.Friend_Id < 300000)
                {
                    using (var storage3Context = new Storage3Context())
                    {
                        frm.FriendsParam = FindFriendsStorage3(storage3Context, f, frm);
                    }
                }
                else if (f.Friend_Id > 300000 && f.Friend_Id < 400000)
                {
                    using (var storage4Context = new Storage4Context())
                    {
                        frm.FriendsParam = FindFriendsStorage4(storage4Context, f, frm);
                    }
                }
                else if (f.Friend_Id > 400000 && f.Friend_Id < 500000)
                {
                    frm.FriendsParam = FindFriendsStorage5(context, f, frm);
                }
            }
        }
 /// <summary>
 /// Methods of forming a string name = Last Name + First Name, which will be added to the list.
 /// Called from the methods GetUserInfoFromStorage.
 /// </summary>
 /// <param name="context">The context of the interaction with the database.</param>
 /// <param name="f">The object to be added.</param>
 /// <param name="frm">Instance a modal window.</param>
 private static string FindFriendsStorage3(Storage3Context context, Friends f, InfoWindow frm)
 {
     var queryFriend = context.User.Where(x => x.Id == f.Friend_Id);
     var elementToAdd = queryFriend.ToList();
     frm.ListOfFriendsParam = elementToAdd[0].Id;
     return (elementToAdd[0].Last_Name + ' ' + elementToAdd[0].First_Name);
 }
        /// <summary>
        /// Check Method cached user in Redis or not.
        /// If the user is not cached in Redis then its cache.
        /// Called from the method ConnectToServer (modal).
        /// </summary>
        /// <param name="context">The context of the interaction with the database.</param>
        /// <param name="userId">User ID.</param>
        /// <param name="frm">Instance a modal window.</param>
        private void RedisOrSQLStorage3(Storage3Context context, int userId, InfoWindow frm)
        {
            IDatabase db = null;
            if (_redisIsStarted)
            {
                using (var redisClient = ConnectionMultiplexer.Connect("localhost"))
                {
                    db = redisClient.GetDatabase();
                    string value = db.StringGet($"user:{userId}");

                    if (string.IsNullOrEmpty(value))
                    {
                        var queryUserStorage = context.User.Where(x => x.Id == userId);
                        GetDataFromSQL(queryUserStorage, db, true, frm);
                    }
                    else
                    {
                        GetDataFromRedis(value, frm);
                    }
                }
            }
            else
            {
                var queryUserStorage = context.User.Where(x => x.Id == userId);
                GetDataFromSQL(queryUserStorage, db, false, frm);
            }
        }
        /// <summary>
        /// The connection method to Storage4 (modal).
        /// Called from an event handler lstFriends_MouseDoubleClick.
        /// </summary>
        /// <param name="context">The context of the interaction with the database.</param>
        /// <param name="userId">User ID.</param>
        /// <param name="services">Services class object to check - whether our services work.</param>
        /// <param name="logging">Logging class object to create the log.</param>
        /// <param name="friend">User friend.</param>
        /// <param name="lstFriends">ListBox control where your friends list will be added.</param>
        /// <param name="frm">Instance a modal window.</param>
        public void ConnectToServer4(Storage4Context context, int userId, Services services, Logging logging, Friend friend, System.Windows.Controls.ListBox lstFriends, InfoWindow frm)
        {
            RedisOrSQLStorage4(context, userId, services, logging, frm);

            var queryFriendsStorage = context.Friends.Where(x => x.User_Id == userId);
            var friends = queryFriendsStorage.ToList();
            foreach (var f in friends)
            {
                if (f.Friend_Id < 100000)
                {
                    using (var storage1Context = new Storage1Context())
                    {
                        frm.FriendsParam = friend.FindFriendsStorage1(storage1Context, f, frm);
                    }
                }
                else if (f.Friend_Id > 100000 && f.Friend_Id < 200000)
                {
                    using (var storage2Context = new Storage2Context())
                    {
                        frm.FriendsParam = friend.FindFriendsStorage2(storage2Context, f, frm);
                    }
                }
                else if (f.Friend_Id > 200000 && f.Friend_Id < 300000)
                {
                    using (var storage3Context = new Storage3Context())
                    {
                        frm.FriendsParam = friend.FindFriendsStorage3(storage3Context, f, frm);
                    }
                }
                else if (f.Friend_Id > 300000 && f.Friend_Id < 400000)
                {
                    frm.FriendsParam = friend.FindFriendsStorage4(context, f, frm);
                }
                else if (f.Friend_Id > 400000 && f.Friend_Id < 500000)
                {
                    using (var storage5Context = new Storage5Context())
                    {
                        frm.FriendsParam = friend.FindFriendsStorage5(storage5Context, f, frm);
                    }
                }
            }
        }
        /// <summary>
        /// The connection method to Storage5.
        /// Called from an event handler btnConnected_Click.
        /// </summary>
        /// <param name="context">The context of the interaction with the database.</param>
        /// <param name="userId">User ID.</param>
        /// <param name="listOfFriends">User's friends list.</param>
        /// <param name="services">Services class object to check - whether our services work.</param>
        /// <param name="logging">Logging class object to create the log.</param>
        /// <param name="friend">User friend.</param>
        /// <param name="view">View class object to display the changes.</param>
        /// <param name="textboxs">An array of text fields to fill.</param>
        /// <param name="lstFriends">ListBox control where your friends list will be added.</param>
        public void ConnectToServer5(Storage5Context context, int userId, List<int> listOfFriends, Services services, Logging logging, Friend friend, View.View view, System.Windows.Controls.TextBox[] textboxs, System.Windows.Controls.ListBox lstFriends)
        {
            RedisOrSQLStorage5(context, userId, services, logging, view, textboxs);

            var queryFriendsStorage = context.Friends.Where(x => x.User_Id == userId);
            var friends = queryFriendsStorage.ToList();
            foreach (var f in friends)
            {
                if (f.Friend_Id < 100000)
                {
                    using (var storage1Context = new Storage1Context())
                    {
                        lstFriends.Items.Add(friend.FindFriendsStorage1(storage1Context, f, listOfFriends));
                    }
                }
                else if (f.Friend_Id > 100000 && f.Friend_Id < 200000)
                {
                    using (var storage2Context = new Storage2Context())
                    {
                        lstFriends.Items.Add(friend.FindFriendsStorage2(storage2Context, f, listOfFriends));
                    }
                }
                else if (f.Friend_Id > 200000 && f.Friend_Id < 300000)
                {
                    using (var storage3Context = new Storage3Context())
                    {
                        lstFriends.Items.Add(friend.FindFriendsStorage3(storage3Context, f, listOfFriends));
                    }
                }
                else if (f.Friend_Id > 300000 && f.Friend_Id < 400000)
                {
                    using (var storage4Context = new Storage4Context())
                    {
                        lstFriends.Items.Add(friend.FindFriendsStorage4(storage4Context, f, listOfFriends));
                    }
                }
                else if (f.Friend_Id > 400000 && f.Friend_Id < 500000)
                {
                    lstFriends.Items.Add(friend.FindFriendsStorage5(context, f, listOfFriends));
                }
            }
        }
        /// <summary>
        /// Check Method cached user in Redis or not.
        /// If the user is not cached in Redis then its cache.
        /// Called from the method ConnectToServer.
        /// </summary>
        /// <param name="context">The context of the interaction with the database.</param>
        /// <param name="userId">User ID.</param>
        /// <param name="services">Services class object to check - whether our services work.</param>
        /// <param name="logging">Logging class object to create the log.</param>
        /// <param name="view">View class object to display the changes.</param>
        /// <param name="textboxs">An array of text fields to fill.</param>
        private static void RedisOrSQLStorage3(Storage3Context context, int userId, Services services, Logging logging, View.View view, System.Windows.Controls.TextBox[] textboxs)
        {
            IDatabase db = null;
            if (services.RedisIsStarted)
            {
                using (var redisClient = ConnectionMultiplexer.Connect("localhost"))
                {
                    db = redisClient.GetDatabase();
                    string value = db.StringGet($"user:{userId}");

                    if (string.IsNullOrEmpty(value))
                    {
                        var queryUserStorage = context.User.Where(x => x.Id == userId);
                        GetDataFromSQL(queryUserStorage, db, true, logging, view, textboxs);
                    }
                    else
                    {
                        GetDataFromRedis(value, view, textboxs);
                    }
                }
            }
            else
            {
                var queryUserStorage = context.User.Where(x => x.Id == userId);
                GetDataFromSQL(queryUserStorage, db, false, logging, view, textboxs);
            }
        }