public TwitterAccountProvider(IWebClient webClient, UserCredential userCredential)
            :base(webClient)
        {
            if (userCredential.AccessToken == null)
            {
                throw new ArgumentException("TwitterAccountProvider didn't receive AccessToken");
            }
            if (userCredential.AccessTokenSecret == null)
            {
                throw new ArgumentException("TwitterAccountProvider didn't receive AccessTokenSecret");
            }
            if (userCredential.ConsumerKey == null)
            {
                throw new ArgumentException("TwitterAccountProvider didn't receive ConsumerKey");
            }
            if (userCredential.ConsumerSecret == null)
            {
                throw new ArgumentException("TwitterAccountProvider didn't receive ConsumerSecret");
            }

            _accessToken = userCredential.AccessToken;
            _accessTokenSecret = userCredential.AccessTokenSecret;
            _consumerKey = userCredential.ConsumerKey;
            _consumerSecret = userCredential.ConsumerSecret;
        }
        public FacebookAccountProvider(IWebClient webClient, UserCredential userCredential)
            :base(webClient)
        {
            if (userCredential.AccessToken == null)
            {
                throw new ArgumentException("FacebookAccountProvider didn't receive accessToken");
            }

            var accessToken = userCredential.AccessToken;
            UserInfoUrl = String.Format(@"https://graph.facebook.com/v2.0/me?access_token={0}&fields=id,first_name,last_name,name,gender,email,birthday,timezone,location,picture.type(large)",
                    accessToken);
        }
        public void Setup()
        {
            _kernel = new StandardKernel(new AccountProviderModule());

            _accessToken = "some access token";

            _userCredentials = new UserCredential
            {
                Email = "some email",
                SocialNetworkId = "some user id in social network",
                AccessToken = _accessToken,
                SocialNetworkName = "some social network",
                AccessTokenExpiresIn = "24:00:00",
                ConsumerSecret = "some consumer secret",
                ConsumerKey = "some consumer key",
                AccessTokenSecret = "some access token secret"
            };

            _userCredentialsParam = new ConstructorArgument("userCredential", _userCredentials);
        }
        public VkAccountProvider(IWebClient webClient, UserCredential userCredential)
            :base(webClient)
        {
            if (userCredential.AccessToken == null)
            {
                throw new ArgumentException("VKAccountProvider didn't receive Accesstoken");
            }
            if (userCredential.SocialNetworkId == null)
            {
                throw new ArgumentException("VKAccountProvider didn't receive SocialNetworkId");
            }

            var userId = userCredential.SocialNetworkId;
            var accessToken = userCredential.AccessToken;

            UserInfoUrl = String.Format(
                @"https://api.vk.com/method/users.get?user_id={0}&fields=screen_name,bdate,sex,city,country,photo_max_orig,timezone&v=5.23&access_token={1}",
                userId,
                accessToken);
        }
        public GoogleAccountProvider(IWebClient webClient, UserCredential userCredential)
            :base(webClient)
        {
            if (userCredential.SocialNetworkId == null)
            {
                throw new ArgumentException("GoogleAccountProvider didn't receive SocialNetworkId");
            }
            if (userCredential.AccessToken == null)
            {
                throw new ArgumentException("GoogleAccountProvider didn't receive AccessToken");
            }

            var userId = userCredential.SocialNetworkId;
            var accessToken = userCredential.AccessToken;
            UserInfoUrl =
                String.Format(
                    @"https://www.googleapis.com/plus/v1/people/{0}?access_token={1}&fields=birthday%2CdisplayName%2Cemails%2Cgender%2Cimage%2Cname(familyName%2CgivenName)%2CplacesLived",
                    userId,
                    accessToken);
        }
        public static IAccountProvider GetAccountProvider(UserCredential credential)
        {
            var userCredential = new ConstructorArgument("userCredential", credential);

            return MvcApplication.Container.Get<IAccountProvider>(credential.SocialNetworkName, userCredential);
        }
        public bool SaveOrUpdateUserData(User user, UserCredential userCredential, AzimuthIdentity loggedIdentity)
        {
            using (var unitOfWork = _unitOfWorkFactory.NewUnitOfWork())
            {
                var _userSNRepository = unitOfWork.GetTypedRepository<IUserSocialNetworkRepository>();
                var _snRepository = unitOfWork.GetTypedRepository<ISocialNetworkRepository>();
                var _playlistRepository = unitOfWork.GetRepository<Playlist>();
                try
                {
                    User loggedUser = null;
                    if (loggedIdentity != null)
                    {
                        loggedUser = unitOfWork.UserRepository.GetOne(x => x.Email == loggedIdentity.UserCredential.Email);
                    }
                    var userSn = _userSNRepository.GetByThirdPartyId(userCredential.SocialNetworkId);
                    if (userSn != null)
                    {
                        if (loggedUser != null)
                        {
                            user.Id = loggedUser.Id;
                            // If we login again with the same social network, skip updating (merging accounts)
                            if (loggedUser.Id != userSn.User.Id)
                            {
                                var playlistLikerRepository =
                                        unitOfWork.GetTypedRepository<PlaylistLikerRepository>();
                                var notificationRepository =
                                    unitOfWork.GetTypedRepository<INotificationRepository>();
                                var userRepository = unitOfWork.GetTypedRepository<IUserRepository>();

                                var allAccounts =
                                    _userSNRepository.Get(account => account.User.Id == userSn.User.Id).ToList();
                                var userToDelete = userSn.User;
                                foreach (var userSocialNetwork in allAccounts)
                                {
                                    // Getting unlogged user's account playlists
                                    var userPlaylists = _playlistRepository.Get(s => s.Creator.Id == userSocialNetwork.User.Id).ToList();
                                    // Taking playlists which he liked or favourited


                                    var notUserPlaylists = playlistLikerRepository.Get(s => s.Liker.Id == userSocialNetwork.User.Id).ToList();
                                    if (notUserPlaylists.Any())
                                        userPlaylists.AddRange(notUserPlaylists.Select(s => s.Playlist));

                                    // Find if user liked/favourited his another account's playlists 
                                    var recordsTodelete =
                                        userPlaylists.SelectMany(s => s.PlaylistLikes).Where(
                                            item => item.Playlist.Creator.Id == loggedUser.Id).ToList();
                                    // Getting user's unauthorized account activity
                                    var notifications =
                                        notificationRepository.Get(item => item.User.Id == userSocialNetwork.User.Id).ToList();

                                    foreach (var playlistLike in recordsTodelete)
                                    {
                                        // Notifications like/unlike and favourite/unfavourited of his another account playlists should be deleted
                                        var notificationsToDelete = notifications.Where(
                                            s =>
                                                s.RecentlyPlaylist == playlistLike.Playlist &&
                                                s.NotificationType == Notifications.FavoritedPlaylist ||
                                                s.NotificationType == Notifications.LikedPlaylist ||
                                                s.NotificationType == Notifications.UnfavoritedPlaylist ||
                                                s.NotificationType == Notifications.UnlikedPlaylist).ToList();

                                        // Get all records of unauthorizedd user's account from likes table
                                        var likeRecord = playlistLikerRepository.GetOne(item => item.Id == playlistLike.Id);
                                        // Kill connection between notifications which would be deleted with playlists
                                        foreach (var notification in notificationsToDelete)
                                        {
                                            likeRecord.Playlist.Notifications.Remove(notification);
                                        }

                                        // Delete notifications
                                        notifications.Where(
                                            s =>
                                                s.RecentlyPlaylist == playlistLike.Playlist &&
                                                (s.NotificationType == Notifications.FavoritedPlaylist ||
                                                s.NotificationType == Notifications.LikedPlaylist ||
                                                s.NotificationType == Notifications.UnfavoritedPlaylist ||
                                                s.NotificationType == Notifications.UnlikedPlaylist)).ForEach(item => notificationRepository.DeleteItem(item));

                                        // Kill connection playlist -> like record of playlist (like/unlike && favourite/unfavouriteown playlists of another account)
                                        likeRecord.Playlist.PlaylistLikes.Remove(playlistLike);
                                        // Kill connection user -> like record of user (like/unlike && favourite/unfavouriteowne own playlists of another account)
                                        likeRecord.Liker.PlaylistFollowing.Remove(playlistLike);
                                        // Delete like/unlike && favourite/unfavouriteowne  playlists of another users's account 
                                        playlistLikerRepository.DeleteItem(playlistLike);
                                    }
                                    // Normal user's activity should change user link
                                    userPlaylists.SelectMany(list => list.PlaylistLikes).ForEach(item => item.Liker = loggedUser);
                                    // Added normal user's playlists should also change user link
                                    userPlaylists.ForEach(item => item.Creator = loggedUser);
                                    // Other notifications have to change their user
                                    notifications.Where(
                                        s =>
                                            s.User.Id == userSocialNetwork.User.Id).ForEach(item => item.User = loggedUser);

                                    userSocialNetwork.User = loggedUser;
                                    _userSNRepository.ChangeUserId(userSocialNetwork);

                                }
                                userRepository.DeleteItem(userToDelete);
                            }
                            else
                            {
                                userSn.AccessToken = userCredential.AccessToken;
                            }
                        }
                        else
                        {
                            // If user exists in database check his data fields for updating
                            if (user.ToString() != userSn.User.ToString())
                            {
                                userSn.User.Name = new Name
                                {
                                    FirstName = user.Name.FirstName,
                                    LastName = user.Name.LastName
                                };
                                userSn.User.ScreenName = user.ScreenName;
                                userSn.User.Gender = user.Gender;
                                userSn.User.Email = user.Email;
                                userSn.User.Birthday = user.Birthday;
                                userSn.User.Location = new Location
                                {
                                    Country = user.Location.Country,
                                    City = user.Location.City
                                };
                                userSn.User.Timezone = user.Timezone;
                                userSn.User.Photo = userSn.Photo = user.Photo ?? String.Empty;
                                userSn.UserName = (user.Name.FirstName ??
                                    String.Empty) + ((user.Name.LastName != null) ? (" " + user.Name.LastName) : String.Empty);
                            }
                            user.Id = userSn.User.Id;
                        }
                    }
                    else
                    {
                        var currentSN = _snRepository.GetByName(userCredential.SocialNetworkName);

                        if (loggedIdentity == null)
                        {
                            unitOfWork.UserRepository.AddItem(user);
                        }
                        _userSNRepository.AddItem(new UserSocialNetwork
                        {
                            User = loggedUser ?? user, 
                            SocialNetwork = currentSN,
                            ThirdPartId = userCredential.SocialNetworkId,
                            AccessToken = userCredential.AccessToken,
                            TokenExpires = userCredential.AccessTokenExpiresIn,
                            Photo = user.Photo,
                            UserName = (user.Name.FirstName ??
                                    String.Empty) + ((user.Name.LastName != null) ? (" " + user.Name.LastName) : String.Empty)
                        });
                    }

                    unitOfWork.Commit();
                }
                catch (Exception)
                {
                    unitOfWork.Rollback();
                    return false;
                }
            }
            return true;
        }