private static IEnumerable <Link> GeneratePageLinks <TPage>(TPage page, Func <TemplateParameter <int?>, TemplateParameter <int?>, Maybe <Link> > linkFactory)
            where TPage : ICollectionPage
        {
            var perPageParameter = page.pageSize == PaginationConstants.DEFAULT_PAGE_SIZE
                                ? TemplateParameter.Force <int?>(null)
                                : TemplateParameter.Force <int?>(page.pageSize);

            var currentPageParameter = page.currentPage == PaginationConstants.FIRST_PAGE
                                ? TemplateParameter.Force <int?>(null)
                                : TemplateParameter.Force <int?>(page.currentPage);

            var previousPage = page.currentPage - 1;
            var nextPage     = page.currentPage + 1;

            var selfLink = linkFactory(currentPageParameter, perPageParameter);

            var firstLink =
                PaginationConstants.FIRST_PAGE == page.currentPage ? selfLink
                                : linkFactory(TemplateParameter.Force <int?>(null), perPageParameter);

            var lastLink =
                page.lastPage == page.currentPage ? selfLink
                                : page.lastPage == PaginationConstants.FIRST_PAGE ? firstLink
                                : linkFactory(TemplateParameter.Force <int?>(page.lastPage), perPageParameter);

            var nextLink =
                nextPage > page.lastPage ? Maybe.None <Link>()
                                : nextPage == page.lastPage ? lastLink
                                : linkFactory(TemplateParameter.Force <int?>(nextPage), perPageParameter);

            var previousLink =
                previousPage <PaginationConstants.FIRST_PAGE?Maybe.None <Link>()
                              : previousPage == PaginationConstants.FIRST_PAGE?firstLink
                              : previousPage> page.lastPage ? null
                                : previousPage == page.lastPage ? lastLink
                                : linkFactory(TemplateParameter.Force <int?>(previousPage), perPageParameter);

            var specificLink =
                PaginationConstants.FIRST_PAGE == page.lastPage ? null
                                : linkFactory(TemplateParameter.Create <int?>(), perPageParameter).SetDescription("Specific page");

            selfLink.SetSelf();
            firstLink.AddRel <FirstRelation>();
            lastLink.AddRel <LastRelation>();
            nextLink.AddRel <NextRelation>();
            previousLink.AddRel <PreviousRelation>();

            return(new[] { specificLink, selfLink, firstLink, lastLink, nextLink, previousLink }
                   .Where(x => x.HasValue)
                   .Select(x => x.Value)
                   .Distinct()
                   .Select(x => SetDescription(x, page.currentPage, page.lastPage)));
        }
        public Maybe <Link> ToAction(MethodInfo method, ReadOnlyCollection <Expression> arguments)
        {
            var parameters = method.GetParameters();
            var isTemplate = false;

            var wrappedValues = Enumerable.Range(0, arguments.Count).Select(x =>
            {
                var argument        = arguments[x];
                var unaryExpression = argument as UnaryExpression;
                TemplateParameter value;

                if (unaryExpression != null && unaryExpression.Operand.Type.GetTypeInfo().IsSubclassOf(typeof(TemplateParameter)))
                {
                    value = Expression.Lambda(unaryExpression.Operand).Compile().DynamicInvoke() as TemplateParameter;
                }
                else
                {
                    value = TemplateParameter.Force(Expression.Lambda(argument).Compile().DynamicInvoke());
                }

                return(new
                {
                    Name = parameters[x].Name,
                    Value = value
                });
            })
                                .ToDictionary(x => x.Name, x => x.Value);

            var actionAttribute = ExtractActionAttribute(method);

            if (actionAttribute != null && HttpContext != null && HttpContext.RequestServices != null)
            {
                var task = actionAttribute.ExecuteSuitableValidationsAsync(HttpContext.RequestServices, wrappedValues);

                var problem = task.WaitAndGetValue();

                if (problem.HasValue)
                {
                    return(Maybe.None <Link>());
                }
            }

            var values = wrappedValues.ToDictionary(
                x => x.Key,
                x =>
            {
                if (x.Value.ForceValue)
                {
                    return(x.Value.ForcedValue);
                }
                else
                {
                    isTemplate = true;
                    return(string.Format("{{{0}}}", x.Value.CustomText ?? x.Key));
                }
            });

            var link = new Link()
            {
                Href = ExtractUrl(method, values)
            };

            if (isTemplate)
            {
                link.Href = link.Href?.Replace("%7B", "{").Replace("%7D", "}");
                link.Relation.Add <TemplateRelation>();
            }

            if (actionAttribute != null)
            {
                actionAttribute.UpdateLinkMethodInfo(link);
            }

            return(Maybe.From(link));
        }