1package cfclient
2
3import (
4	"encoding/json"
5	"fmt"
6	"io"
7	"io/ioutil"
8	"net/http"
9	"net/url"
10
11	"github.com/pkg/errors"
12)
13
14type ServicePlanVisibilitiesResponse struct {
15	Count     int                             `json:"total_results"`
16	Pages     int                             `json:"total_pages"`
17	NextUrl   string                          `json:"next_url"`
18	Resources []ServicePlanVisibilityResource `json:"resources"`
19}
20
21type ServicePlanVisibilityResource struct {
22	Meta   Meta                  `json:"metadata"`
23	Entity ServicePlanVisibility `json:"entity"`
24}
25
26type ServicePlanVisibility struct {
27	Guid             string `json:"guid"`
28	CreatedAt        string `json:"created_at"`
29	UpdatedAt        string `json:"updated_at"`
30	ServicePlanGuid  string `json:"service_plan_guid"`
31	OrganizationGuid string `json:"organization_guid"`
32	ServicePlanUrl   string `json:"service_plan_url"`
33	OrganizationUrl  string `json:"organization_url"`
34	c                *Client
35}
36
37func (c *Client) ListServicePlanVisibilitiesByQuery(query url.Values) ([]ServicePlanVisibility, error) {
38	var servicePlanVisibilities []ServicePlanVisibility
39	requestUrl := "/v2/service_plan_visibilities?" + query.Encode()
40	for {
41		var servicePlanVisibilitiesResp ServicePlanVisibilitiesResponse
42		r := c.NewRequest("GET", requestUrl)
43		resp, err := c.DoRequest(r)
44		if err != nil {
45			return nil, errors.Wrap(err, "Error requesting service plan visibilities")
46		}
47		resBody, err := ioutil.ReadAll(resp.Body)
48		if err != nil {
49			return nil, errors.Wrap(err, "Error reading service plan visibilities request:")
50		}
51
52		err = json.Unmarshal(resBody, &servicePlanVisibilitiesResp)
53		if err != nil {
54			return nil, errors.Wrap(err, "Error unmarshaling service plan visibilities")
55		}
56		for _, servicePlanVisibility := range servicePlanVisibilitiesResp.Resources {
57			servicePlanVisibility.Entity.Guid = servicePlanVisibility.Meta.Guid
58			servicePlanVisibility.Entity.CreatedAt = servicePlanVisibility.Meta.CreatedAt
59			servicePlanVisibility.Entity.UpdatedAt = servicePlanVisibility.Meta.UpdatedAt
60			servicePlanVisibility.Entity.c = c
61			servicePlanVisibilities = append(servicePlanVisibilities, servicePlanVisibility.Entity)
62		}
63		requestUrl = servicePlanVisibilitiesResp.NextUrl
64		if requestUrl == "" {
65			break
66		}
67	}
68	return servicePlanVisibilities, nil
69}
70
71func (c *Client) ListServicePlanVisibilities() ([]ServicePlanVisibility, error) {
72	return c.ListServicePlanVisibilitiesByQuery(nil)
73}
74
75func (c *Client) GetServicePlanVisibilityByGuid(guid string) (ServicePlanVisibility, error) {
76	r := c.NewRequest("GET", "/v2/service_plan_visibilities/"+guid)
77	resp, err := c.DoRequest(r)
78	if err != nil {
79		return ServicePlanVisibility{}, err
80	}
81	return respBodyToServicePlanVisibility(resp.Body, c)
82}
83
84//a uniqueID is the id of the service in the catalog and not in cf internal db
85func (c *Client) CreateServicePlanVisibilityByUniqueId(uniqueId string, organizationGuid string) (ServicePlanVisibility, error) {
86	q := url.Values{}
87	q.Set("q", fmt.Sprintf("unique_id:%s", uniqueId))
88	plans, err := c.ListServicePlansByQuery(q)
89	if err != nil {
90		return ServicePlanVisibility{}, errors.Wrap(err, fmt.Sprintf("Couldn't find a service plan with unique_id: %s", uniqueId))
91	}
92	return c.CreateServicePlanVisibility(plans[0].Guid, organizationGuid)
93}
94
95func (c *Client) CreateServicePlanVisibility(servicePlanGuid string, organizationGuid string) (ServicePlanVisibility, error) {
96	req := c.NewRequest("POST", "/v2/service_plan_visibilities")
97	req.obj = map[string]interface{}{
98		"service_plan_guid": servicePlanGuid,
99		"organization_guid": organizationGuid,
100	}
101	resp, err := c.DoRequest(req)
102	if err != nil {
103		return ServicePlanVisibility{}, err
104	}
105	if resp.StatusCode != http.StatusCreated {
106		return ServicePlanVisibility{}, errors.Wrapf(err, "Error creating service plan visibility, response code: %d", resp.StatusCode)
107	}
108	return respBodyToServicePlanVisibility(resp.Body, c)
109}
110
111func (c *Client) DeleteServicePlanVisibilityByPlanAndOrg(servicePlanGuid string, organizationGuid string, async bool) error {
112	q := url.Values{}
113	q.Set("q", fmt.Sprintf("organization_guid:%s;service_plan_guid:%s", organizationGuid, servicePlanGuid))
114	plans, err := c.ListServicePlanVisibilitiesByQuery(q)
115	if err != nil {
116		return errors.Wrap(err, fmt.Sprintf("Couldn't find a service plan visibility for service plan %s and org %s", servicePlanGuid, organizationGuid))
117	}
118	if len(plans) != 1 {
119		return fmt.Errorf("Query for a service plan visibility did not return exactly one result when searching for a service plan visibility for service plan %s and org %s",
120			servicePlanGuid, organizationGuid)
121	}
122	return c.DeleteServicePlanVisibility(plans[0].Guid, async)
123}
124
125func (c *Client) DeleteServicePlanVisibility(guid string, async bool) error {
126	req := c.NewRequest("DELETE", fmt.Sprintf("/v2/service_plan_visibilities/%s?async=%v", guid, async))
127	resp, err := c.DoRequest(req)
128	if err != nil {
129		return err
130	}
131	if resp.StatusCode != http.StatusNoContent {
132		return errors.Wrapf(err, "Error deleting service plan visibility, response code: %d", resp.StatusCode)
133	}
134	return nil
135}
136
137func (c *Client) UpdateServicePlanVisibility(guid string, servicePlanGuid string, organizationGuid string) (ServicePlanVisibility, error) {
138	req := c.NewRequest("PUT", "/v2/service_plan_visibilities/"+guid)
139	req.obj = map[string]interface{}{
140		"service_plan_guid": servicePlanGuid,
141		"organization_guid": organizationGuid,
142	}
143	resp, err := c.DoRequest(req)
144	if err != nil {
145		return ServicePlanVisibility{}, err
146	}
147	if resp.StatusCode != http.StatusCreated {
148		return ServicePlanVisibility{}, errors.Wrapf(err, "Error updating service plan visibility, response code: %d", resp.StatusCode)
149	}
150	return respBodyToServicePlanVisibility(resp.Body, c)
151}
152
153func respBodyToServicePlanVisibility(body io.ReadCloser, c *Client) (ServicePlanVisibility, error) {
154	bodyRaw, err := ioutil.ReadAll(body)
155	if err != nil {
156		return ServicePlanVisibility{}, err
157	}
158	servicePlanVisibilityRes := ServicePlanVisibilityResource{}
159	err = json.Unmarshal(bodyRaw, &servicePlanVisibilityRes)
160	if err != nil {
161		return ServicePlanVisibility{}, err
162	}
163	servicePlanVisibility := servicePlanVisibilityRes.Entity
164	servicePlanVisibility.Guid = servicePlanVisibilityRes.Meta.Guid
165	servicePlanVisibility.CreatedAt = servicePlanVisibilityRes.Meta.CreatedAt
166	servicePlanVisibility.UpdatedAt = servicePlanVisibilityRes.Meta.UpdatedAt
167	servicePlanVisibility.c = c
168	return servicePlanVisibility, nil
169}
170