1// Copyright 2016 Circonus, Inc. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5// Worksheet API support - Fetch, Create, Update, Delete, and Search
6// See: https://login.circonus.com/resources/api/calls/worksheet
7
8package api
9
10import (
11	"encoding/json"
12	"fmt"
13	"net/url"
14	"regexp"
15
16	"github.com/circonus-labs/circonus-gometrics/api/config"
17)
18
19// WorksheetGraph defines a worksheet cid to be include in the worksheet
20type WorksheetGraph struct {
21	GraphCID string `json:"graph"` // string
22}
23
24// WorksheetSmartQuery defines a query to include multiple worksheets
25type WorksheetSmartQuery struct {
26	Name  string   `json:"name"`
27	Order []string `json:"order"`
28	Query string   `json:"query"`
29}
30
31// Worksheet defines a worksheet. See https://login.circonus.com/resources/api/calls/worksheet for more information.
32type Worksheet struct {
33	CID          string                `json:"_cid,omitempty"`          // string
34	Description  *string               `json:"description"`             // string or null
35	Favorite     bool                  `json:"favorite"`                // boolean
36	Graphs       []WorksheetGraph      `json:"graphs"`                  // [] len >= 0
37	Notes        *string               `json:"notes"`                   // string or null
38	SmartQueries []WorksheetSmartQuery `json:"smart_queries,omitempty"` // [] len >= 0
39	Tags         []string              `json:"tags"`                    // [] len >= 0
40	Title        string                `json:"title"`                   // string
41}
42
43// NewWorksheet returns a new Worksheet (with defaults, if applicable)
44func NewWorksheet() *Worksheet {
45	return &Worksheet{
46		Graphs: []WorksheetGraph{}, // graphs is a required attribute and cannot be null
47	}
48}
49
50// FetchWorksheet retrieves worksheet with passed cid.
51func (a *API) FetchWorksheet(cid CIDType) (*Worksheet, error) {
52	if cid == nil || *cid == "" {
53		return nil, fmt.Errorf("Invalid worksheet CID [none]")
54	}
55
56	worksheetCID := string(*cid)
57
58	matched, err := regexp.MatchString(config.WorksheetCIDRegex, worksheetCID)
59	if err != nil {
60		return nil, err
61	}
62	if !matched {
63		return nil, fmt.Errorf("Invalid worksheet CID [%s]", worksheetCID)
64	}
65
66	result, err := a.Get(string(*cid))
67	if err != nil {
68		return nil, err
69	}
70
71	if a.Debug {
72		a.Log.Printf("[DEBUG] fetch worksheet, received JSON: %s", string(result))
73	}
74
75	worksheet := new(Worksheet)
76	if err := json.Unmarshal(result, worksheet); err != nil {
77		return nil, err
78	}
79
80	return worksheet, nil
81}
82
83// FetchWorksheets retrieves all worksheets available to API Token.
84func (a *API) FetchWorksheets() (*[]Worksheet, error) {
85	result, err := a.Get(config.WorksheetPrefix)
86	if err != nil {
87		return nil, err
88	}
89
90	var worksheets []Worksheet
91	if err := json.Unmarshal(result, &worksheets); err != nil {
92		return nil, err
93	}
94
95	return &worksheets, nil
96}
97
98// UpdateWorksheet updates passed worksheet.
99func (a *API) UpdateWorksheet(cfg *Worksheet) (*Worksheet, error) {
100	if cfg == nil {
101		return nil, fmt.Errorf("Invalid worksheet config [nil]")
102	}
103
104	worksheetCID := string(cfg.CID)
105
106	matched, err := regexp.MatchString(config.WorksheetCIDRegex, worksheetCID)
107	if err != nil {
108		return nil, err
109	}
110	if !matched {
111		return nil, fmt.Errorf("Invalid worksheet CID [%s]", worksheetCID)
112	}
113
114	jsonCfg, err := json.Marshal(cfg)
115	if err != nil {
116		return nil, err
117	}
118
119	if a.Debug {
120		a.Log.Printf("[DEBUG] update worksheet, sending JSON: %s", string(jsonCfg))
121	}
122
123	result, err := a.Put(worksheetCID, jsonCfg)
124	if err != nil {
125		return nil, err
126	}
127
128	worksheet := &Worksheet{}
129	if err := json.Unmarshal(result, worksheet); err != nil {
130		return nil, err
131	}
132
133	return worksheet, nil
134}
135
136// CreateWorksheet creates a new worksheet.
137func (a *API) CreateWorksheet(cfg *Worksheet) (*Worksheet, error) {
138	if cfg == nil {
139		return nil, fmt.Errorf("Invalid worksheet config [nil]")
140	}
141
142	jsonCfg, err := json.Marshal(cfg)
143	if err != nil {
144		return nil, err
145	}
146
147	if a.Debug {
148		a.Log.Printf("[DEBUG] create annotation, sending JSON: %s", string(jsonCfg))
149	}
150
151	result, err := a.Post(config.WorksheetPrefix, jsonCfg)
152	if err != nil {
153		return nil, err
154	}
155
156	worksheet := &Worksheet{}
157	if err := json.Unmarshal(result, worksheet); err != nil {
158		return nil, err
159	}
160
161	return worksheet, nil
162}
163
164// DeleteWorksheet deletes passed worksheet.
165func (a *API) DeleteWorksheet(cfg *Worksheet) (bool, error) {
166	if cfg == nil {
167		return false, fmt.Errorf("Invalid worksheet config [nil]")
168	}
169	return a.DeleteWorksheetByCID(CIDType(&cfg.CID))
170}
171
172// DeleteWorksheetByCID deletes worksheet with passed cid.
173func (a *API) DeleteWorksheetByCID(cid CIDType) (bool, error) {
174	if cid == nil || *cid == "" {
175		return false, fmt.Errorf("Invalid worksheet CID [none]")
176	}
177
178	worksheetCID := string(*cid)
179
180	matched, err := regexp.MatchString(config.WorksheetCIDRegex, worksheetCID)
181	if err != nil {
182		return false, err
183	}
184	if !matched {
185		return false, fmt.Errorf("Invalid worksheet CID [%s]", worksheetCID)
186	}
187
188	_, err = a.Delete(worksheetCID)
189	if err != nil {
190		return false, err
191	}
192
193	return true, nil
194}
195
196// SearchWorksheets returns worksheets matching the specified search
197// query and/or filter. If nil is passed for both parameters all
198// worksheets will be returned.
199func (a *API) SearchWorksheets(searchCriteria *SearchQueryType, filterCriteria *SearchFilterType) (*[]Worksheet, error) {
200	q := url.Values{}
201
202	if searchCriteria != nil && *searchCriteria != "" {
203		q.Set("search", string(*searchCriteria))
204	}
205
206	if filterCriteria != nil && len(*filterCriteria) > 0 {
207		for filter, criteria := range *filterCriteria {
208			for _, val := range criteria {
209				q.Add(filter, val)
210			}
211		}
212	}
213
214	if q.Encode() == "" {
215		return a.FetchWorksheets()
216	}
217
218	reqURL := url.URL{
219		Path:     config.WorksheetPrefix,
220		RawQuery: q.Encode(),
221	}
222
223	result, err := a.Get(reqURL.String())
224	if err != nil {
225		return nil, fmt.Errorf("[ERROR] API call error %+v", err)
226	}
227
228	var worksheets []Worksheet
229	if err := json.Unmarshal(result, &worksheets); err != nil {
230		return nil, err
231	}
232
233	return &worksheets, nil
234}
235