1package api
2
3import (
4	"fmt"
5	"net/http"
6	"net/url"
7	"strconv"
8	"strings"
9)
10
11const (
12	defaultPerPage = 100
13	defaultPage    = 1
14)
15
16const nextPageHeader = "X-Next-Page"
17
18type pageInfo struct {
19	startIndex int
20	endIndex   int
21	nextPage   int
22}
23
24type searchCriterion struct {
25	Search string `url:"search"`
26	Status string `url:"status"`
27}
28
29func newSearchCriterion(query url.Values) *searchCriterion {
30	if len(query) == 0 {
31		return nil
32	}
33
34	search := query.Get("search")
35	status := query.Get("status")
36
37	if status == "" && search == "" {
38		return nil
39	}
40
41	return &searchCriterion{Search: search, Status: status}
42}
43
44func (c *searchCriterion) withStatus(name string) bool {
45	return c.Status == "" || strings.EqualFold(name, c.Status)
46}
47
48func (c *searchCriterion) searchIn(values ...string) bool {
49	if c.Search == "" {
50		return true
51	}
52
53	for _, v := range values {
54		if strings.Contains(strings.ToLower(v), strings.ToLower(c.Search)) {
55			return true
56		}
57	}
58
59	return false
60}
61
62func pagination(request *http.Request, max int) (pageInfo, error) {
63	perPage, err := getIntParam(request, "per_page", defaultPerPage)
64	if err != nil {
65		return pageInfo{}, err
66	}
67
68	page, err := getIntParam(request, "page", defaultPage)
69	if err != nil {
70		return pageInfo{}, err
71	}
72
73	startIndex := (page - 1) * perPage
74	if startIndex != 0 && startIndex >= max {
75		return pageInfo{}, fmt.Errorf("invalid request: page: %d, per_page: %d", page, perPage)
76	}
77
78	endIndex := startIndex + perPage
79	if endIndex >= max {
80		endIndex = max
81	}
82
83	nextPage := 1
84	if page*perPage < max {
85		nextPage = page + 1
86	}
87
88	return pageInfo{startIndex: startIndex, endIndex: endIndex, nextPage: nextPage}, nil
89}
90
91func getIntParam(request *http.Request, key string, defaultValue int) (int, error) {
92	raw := request.URL.Query().Get(key)
93	if raw == "" {
94		return defaultValue, nil
95	}
96
97	value, err := strconv.Atoi(raw)
98	if err != nil || value <= 0 {
99		return 0, fmt.Errorf("invalid request: %s: %d", key, value)
100	}
101	return value, nil
102}
103