/// <summary>
 /// Finds the list of users that match the criteria.
 /// </summary>
 /// <param name="filter">Filters the results to only users that match.</param>
 /// <param name="tablesorterMetadata">The tablesorter metadata.</param>
 /// <returns>
 /// The list of users that match the criteria.
 /// </returns>
 public UserList FindUsers(UserSearchCriteria filter, TablesorterMetadata tablesorterMetadata = null)
 {
     return this.DoFindUsers(filter, tablesorterMetadata);
 }
        /// <summary>
        /// Finds the list of users that match the criteria.
        /// </summary>
        /// <param name="filter">Filters the results to only users that match.</param>
        /// <param name="tablesorterMetadata">The tablesorter metadata.</param>
        /// <returns>
        /// The list of users that match the criteria.
        /// </returns>
        protected override UserList DoFindUsers(UserSearchCriteria filter, TablesorterMetadata tablesorterMetadata = null)
        {
            MongoCollection<BsonDocument> collection = this.database.GetCollection(iApplyDb.UserAccess._COLLECTION_NAME);

            QueryDocument outerQuery = new QueryDocument();
            List<IMongoQuery> orQueries = new List<IMongoQuery>();

            if (filter.OrganisationIds != null && filter.OrganisationIds.Any())
            {
                orQueries.AddRange(filter.OrganisationIds.Select(organisationId => Query.Exists(string.Format("{0}.{1}", iApplyDb.UserAccess.ORGANISATIONS, organisationId))));
            }

            if (filter.IncludeNoOrganisationUsers)
            {
                orQueries.Add(Query.NotExists(iApplyDb.UserAccess.ORGANISATIONS));
                orQueries.Add(Query.EQ(iApplyDb.UserAccess.ORGANISATIONS, new BsonDocument()));
            }

            if (!filter.IncludeServiceUsers)
            {
                outerQuery.AddRange(Query.NE(iApplyDb.UserAccess.ACCOUNT_TYPE, new BsonString(AccountType.Service.ToString())).ToBsonDocument());
            }

            if (filter.RoleIds != null && filter.RoleIds.Any())
            {
                orQueries.AddRange(filter.RoleIds.Select(roleId => Query.Exists(string.Format("{0}.{1}", iApplyDb.UserAccess.ROLES, roleId))));
            }

            IMongoQuery subQuery;
            if (orQueries.Count > 0)
            {
                subQuery = Query.Or(orQueries);
                outerQuery.AddRange(subQuery.ToBsonDocument());
            }

            if (filter.UserIds != null && filter.UserIds.Any())
            {
                BsonArray bsonUserIds = new BsonArray();
                bsonUserIds.AddRange(filter.UserIds.Select(u => new BsonObjectId(new ObjectId(u))));
                subQuery = Query.In(iApplyDb.UserAccess._ID, bsonUserIds);
                outerQuery.AddRange(subQuery.ToBsonDocument());
            }

            if (filter.Usernames != null && filter.Usernames.Any())
            {
                BsonArray bsonUserNames = new BsonArray();
                bsonUserNames.AddRange(filter.Usernames.Select(u => new BsonString(u)));
                subQuery = Query.In(iApplyDb.UserAccess.USERNAME, bsonUserNames);
                outerQuery.AddRange(subQuery.ToBsonDocument());
            }

            if (filter.ExternalIds != null && filter.ExternalIds.Any())
            {
                BsonArray bsonExternalIds = new BsonArray();
                bsonExternalIds.AddRange(filter.ExternalIds.Select(u => new BsonString(u)));
                subQuery = Query.In(iApplyDb.UserAccess.EXTERNAL_ID, bsonExternalIds);
                outerQuery.AddRange(subQuery.ToBsonDocument());
            }

            if (tablesorterMetadata != null && tablesorterMetadata.SearchFilters != null)
            {
                for (int i = 0; i < tablesorterMetadata.SearchFilters.Length; i++)
                {
                    var fieldName = tablesorterMetadata.HeaderList[i];
                    var searchTerm = tablesorterMetadata.SearchFilters[i];

                    if (string.IsNullOrWhiteSpace(fieldName) || string.IsNullOrWhiteSpace(searchTerm))
                    {
                        continue;
                    }

                    subQuery = Query.EQ(fieldName, new BsonRegularExpression(searchTerm.Trim(), "i"));
                    outerQuery.AddRange(subQuery.ToBsonDocument());
                }
            }

            MongoCursor<BsonDocument> documents = collection.Find(outerQuery);
            if (tablesorterMetadata != null)
            {
                tablesorterMetadata.TotalRows = Convert.ToInt32(collection.Count(outerQuery));
                documents.SetSkip(tablesorterMetadata.PageSize * tablesorterMetadata.PageIndex).SetLimit(tablesorterMetadata.PageSize);

                if (tablesorterMetadata.SortOrder != null)
                {
                    SortByBuilder newSortByBuilder = new SortByBuilder();
                    foreach (int[] sortCriteria in tablesorterMetadata.SortOrder)
                    {
                        var columnNum = sortCriteria[0];
                        var sortOrder = sortCriteria[1];
                        if (sortOrder == 1)
                        {
                            newSortByBuilder.Descending(tablesorterMetadata.HeaderList[columnNum]);
                        }
                        else
                        {
                            newSortByBuilder.Ascending(tablesorterMetadata.HeaderList[columnNum]);
                        }
                    }

                    documents.SetSortOrder(newSortByBuilder);
                }
            }

            UserList users = BsonConverter.ConvertToObjectViaJson<UserList>(documents);
            return users;
        }
 /// <summary>
 /// Finds the list of users that match the criteria.
 /// </summary>
 /// <param name="filter">Filters the results to only users that match.</param>
 /// <param name="tablesorterMetadata">The tablesorter metadata.</param>
 /// <returns>
 /// The list of users that match the criteria.
 /// </returns>
 protected abstract UserList DoFindUsers(UserSearchCriteria filter, TablesorterMetadata tablesorterMetadata = null);