private bool RecordMatch(FundraisingMenuResult r, DataTableParameters query)
        {
            IEnumerable<ColumnData> validColumns = query.columns.Where(c => !String.IsNullOrEmpty(c.data));

            // Check for a column search value match.
            IEnumerable<ColumnData> columnsWithQueries = validColumns
                .Where(c => !String.IsNullOrEmpty(c.search.value));
            bool filterMatch = columnsWithQueries.Count() == 0 ||
                columnsWithQueries.Select(delegate(ColumnData c)
                {
                    bool match = false;

                    SearchParameters searchParams = JsonConvert.DeserializeObject<SearchParameters>(c.search.value);
                    if (searchParams.payload.Count > 0)
                    {
                        if (_dataMap.ContainsKey(c.data))
                        {
                            foreach (string searchValue in searchParams.payload)
                            {
                                match = match || _dataMap[c.data].TextSearchMatch(searchValue, r);
                            }
                        }
                    }

                    return match;
                }).Aggregate(false, (a, b) => a || b);

            // Check for a text search value match in all columns
            bool textSearchMatch = String.IsNullOrEmpty(query.search.value) ||
                validColumns.Select(delegate(ColumnData c)
                {
                    return _dataMap.ContainsKey(c.data) &&
                        _dataMap[c.data].TextSearchMatch(query.search.value, r);
                }).Aggregate(false, (a, b) => a || b);

            return filterMatch && textSearchMatch;
        }
        /// <summary>
        /// Order menu records. This function always orders first by package.
        /// </summary>
        /// <param name="allProjects"></param>
        /// <param name="parameters"></param>
        /// <returns></returns>
        private List<FundraisingMenuResult> OrderProjectRecords(List<FundraisingMenuResult> allProjects, DataTableParameters parameters)
        {
            IOrderedEnumerable<FundraisingMenuResult> orderedData = allProjects
                .OrderBy(r => r.ProjectPackage[0].Priority)
                .ThenBy(r => r.ProjectPackage[0].PackageName);

            foreach (var orderByClause in parameters.order)
            {
                var evalFunc = EvaluateOrderBy(orderByClause.column, parameters.columns);
                if (evalFunc != null)
                {
                    bool asc = orderByClause.dir == OrderingData.OrderingDirection.asc;
                    orderedData = asc ?
                        orderedData.ThenBy(evalFunc) :
                        orderedData.ThenByDescending(evalFunc);
                }
            }
            return orderedData.ToList();
        }
        public DataTableResult<FundraisingMenuResult> SearchSortAndFilter(DataTableParameters query)
        {
            DataTableResult<FundraisingMenuResult> result = GetAllFundraisingMenuProjects();

            //  Add virtual projects for packages containing no projects.
            AddVirtualProjects(result.data);

            // Expand by package.
            result.data = ExpandByPackage(result.data);

            result.draw = query.draw;
            result.recordsTotal = result.data.Where(r => r.HubId != null).Count();

            // Search
            result.data = result.data.Where(r => RecordMatch(r, query)).ToList();
            result.recordsFiltered = result.data.Where(r => r.HubId != null).Count();

            // Order
            result.data = OrderProjectRecords(result.data, query);

            // Page
            result.data = PageResults(query, result.data);
            return result;
        }
        /// <summary>
        /// We need to use a more advanced paging strategy because there
        /// are virtual records that will not be displayed in the table.
        /// So instead of using the start and length arguments from the
        /// query as a hard Skip/Take boundary, we need to count how many
        /// virtual records preceeded the current page and we need to take
        /// records up to the query length, but excluding virtual records
        /// from the count.
        /// </summary>
        /// <param name="query"></param>
        /// <param name="data"></param>
        /// <returns></returns>
        private static List<FundraisingMenuResult> PageResults(DataTableParameters query, List<FundraisingMenuResult> data)
        {
            // Count how many "virtual" records there are before the page begins
            int virtualRecordsBeforeStart = data.Take(query.start).Where(r => r.HubId == null).Count();
            // That's our starting point.
            IEnumerable<FundraisingMenuResult> recordsFromStart = data.Skip(query.start + virtualRecordsBeforeStart);

            // Take an initial set of records using the page size.
            IEnumerable<FundraisingMenuResult> pagedResult = recordsFromStart.Take(query.length);

            // Take more records until we have query.length real records or we hit the end of the list.
            int totalLength = recordsFromStart.Count();
            int currentCount = pagedResult.Count();
            int virtualCount = pagedResult.Where(r => r.HubId == null).Count();
            while (currentCount - virtualCount < query.length && currentCount + virtualCount < totalLength)
            {
                pagedResult = recordsFromStart.Take(currentCount + virtualCount);
                currentCount = pagedResult.Count();
                virtualCount = pagedResult.Where(r => r.HubId == null).Count();
            }

            return pagedResult.ToList();
        }
 public ActionResult SearchData(DataTableParameters parameters)
 {
     FundraisingMenuSearchServices _fmss = new FundraisingMenuSearchServices();
     DataTableResult<FundraisingMenuResult> result = _fmss.SearchSortAndFilter(parameters);
     return Json(result);
 }