package advisor

// Copyright (c) Microsoft and contributors.  All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//
// See the License for the specific language governing permissions and
// limitations under the License.
//
// Code generated by Microsoft (R) AutoRest Code Generator.
// Changes may cause incorrect behavior and will be lost if the code is regenerated.

import (
	"encoding/json"
	"github.com/Azure/go-autorest/autorest"
	"github.com/Azure/go-autorest/autorest/azure"
	"github.com/Azure/go-autorest/autorest/date"
	"github.com/Azure/go-autorest/autorest/to"
	"github.com/satori/go.uuid"
	"net/http"
)

// Category enumerates the values for category.
type Category string

const (
	// Cost ...
	Cost Category = "Cost"
	// HighAvailability ...
	HighAvailability Category = "HighAvailability"
	// Performance ...
	Performance Category = "Performance"
	// Security ...
	Security Category = "Security"
)

// Impact enumerates the values for impact.
type Impact string

const (
	// High ...
	High Impact = "High"
	// Low ...
	Low Impact = "Low"
	// Medium ...
	Medium Impact = "Medium"
)

// Risk enumerates the values for risk.
type Risk string

const (
	// Error ...
	Error Risk = "Error"
	// None ...
	None Risk = "None"
	// Warning ...
	Warning Risk = "Warning"
)

// ARMErrorResponseBody ARM error response body.
type ARMErrorResponseBody struct {
	autorest.Response `json:"-"`
	// Message - Gets or sets the string that describes the error in detail and provides debugging information.
	Message *string `json:"message,omitempty"`
	// Code - Gets or sets the string that can be used to programmatically identify the error.
	Code *string `json:"code,omitempty"`
}

// ConfigData the Advisor configuration data structure.
type ConfigData struct {
	// ID - The resource Id of the configuration resource.
	ID *string `json:"id,omitempty"`
	// Type - The type of the configuration resource.
	Type *string `json:"type,omitempty"`
	// Name - The name of the configuration resource.
	Name *string `json:"name,omitempty"`
	// Properties - The list of property name/value pairs.
	Properties *ConfigDataProperties `json:"properties,omitempty"`
}

// ConfigDataProperties the list of property name/value pairs.
type ConfigDataProperties struct {
	// AdditionalProperties - Unmatched properties from the message are deserialized this collection
	AdditionalProperties map[string]interface{} `json:""`
	// Exclude - Exclude the resource from Advisor evaluations. Valid values: False (default) or True.
	Exclude *bool `json:"exclude,omitempty"`
	// LowCPUThreshold - Minimum percentage threshold for Advisor low CPU utilization evaluation. Valid only for subscriptions. Valid values: 5 (default), 10, 15 or 20.
	LowCPUThreshold *string `json:"low_cpu_threshold,omitempty"`
}

// MarshalJSON is the custom marshaler for ConfigDataProperties.
func (cd ConfigDataProperties) MarshalJSON() ([]byte, error) {
	objectMap := make(map[string]interface{})
	if cd.Exclude != nil {
		objectMap["exclude"] = cd.Exclude
	}
	if cd.LowCPUThreshold != nil {
		objectMap["low_cpu_threshold"] = cd.LowCPUThreshold
	}
	for k, v := range cd.AdditionalProperties {
		objectMap[k] = v
	}
	return json.Marshal(objectMap)
}

// ConfigurationListResult the list of Advisor configurations.
type ConfigurationListResult struct {
	autorest.Response `json:"-"`
	// Value - The list of configurations.
	Value *[]ConfigData `json:"value,omitempty"`
	// NextLink - The link used to get the next page of configurations.
	NextLink *string `json:"nextLink,omitempty"`
}

// OperationDisplayInfo the operation supported by Advisor.
type OperationDisplayInfo struct {
	// Description - The description of the operation.
	Description *string `json:"description,omitempty"`
	// Operation - The action that users can perform, based on their permission level.
	Operation *string `json:"operation,omitempty"`
	// Provider - Service provider: Microsoft Advisor.
	Provider *string `json:"provider,omitempty"`
	// Resource - Resource on which the operation is performed.
	Resource *string `json:"resource,omitempty"`
}

// OperationEntity the operation supported by Advisor.
type OperationEntity struct {
	// Name - Operation name: {provider}/{resource}/{operation}.
	Name *string `json:"name,omitempty"`
	// Display - The operation supported by Advisor.
	Display *OperationDisplayInfo `json:"display,omitempty"`
}

// OperationEntityListResult the list of Advisor operations.
type OperationEntityListResult struct {
	autorest.Response `json:"-"`
	// NextLink - The link used to get the next page of operations.
	NextLink *string `json:"nextLink,omitempty"`
	// Value - The list of operations.
	Value *[]OperationEntity `json:"value,omitempty"`
}

// OperationEntityListResultIterator provides access to a complete listing of OperationEntity values.
type OperationEntityListResultIterator struct {
	i    int
	page OperationEntityListResultPage
}

// Next advances to the next value.  If there was an error making
// the request the iterator does not advance and the error is returned.
func (iter *OperationEntityListResultIterator) Next() error {
	iter.i++
	if iter.i < len(iter.page.Values()) {
		return nil
	}
	err := iter.page.Next()
	if err != nil {
		iter.i--
		return err
	}
	iter.i = 0
	return nil
}

// NotDone returns true if the enumeration should be started or is not yet complete.
func (iter OperationEntityListResultIterator) NotDone() bool {
	return iter.page.NotDone() && iter.i < len(iter.page.Values())
}

// Response returns the raw server response from the last page request.
func (iter OperationEntityListResultIterator) Response() OperationEntityListResult {
	return iter.page.Response()
}

// Value returns the current value or a zero-initialized value if the
// iterator has advanced beyond the end of the collection.
func (iter OperationEntityListResultIterator) Value() OperationEntity {
	if !iter.page.NotDone() {
		return OperationEntity{}
	}
	return iter.page.Values()[iter.i]
}

// IsEmpty returns true if the ListResult contains no values.
func (oelr OperationEntityListResult) IsEmpty() bool {
	return oelr.Value == nil || len(*oelr.Value) == 0
}

// operationEntityListResultPreparer prepares a request to retrieve the next set of results.
// It returns nil if no more results exist.
func (oelr OperationEntityListResult) operationEntityListResultPreparer() (*http.Request, error) {
	if oelr.NextLink == nil || len(to.String(oelr.NextLink)) < 1 {
		return nil, nil
	}
	return autorest.Prepare(&http.Request{},
		autorest.AsJSON(),
		autorest.AsGet(),
		autorest.WithBaseURL(to.String(oelr.NextLink)))
}

// OperationEntityListResultPage contains a page of OperationEntity values.
type OperationEntityListResultPage struct {
	fn   func(OperationEntityListResult) (OperationEntityListResult, error)
	oelr OperationEntityListResult
}

// Next advances to the next page of values.  If there was an error making
// the request the page does not advance and the error is returned.
func (page *OperationEntityListResultPage) Next() error {
	next, err := page.fn(page.oelr)
	if err != nil {
		return err
	}
	page.oelr = next
	return nil
}

// NotDone returns true if the page enumeration should be started or is not yet complete.
func (page OperationEntityListResultPage) NotDone() bool {
	return !page.oelr.IsEmpty()
}

// Response returns the raw server response from the last page request.
func (page OperationEntityListResultPage) Response() OperationEntityListResult {
	return page.oelr
}

// Values returns the slice of values for the current page or nil if there are no values.
func (page OperationEntityListResultPage) Values() []OperationEntity {
	if page.oelr.IsEmpty() {
		return nil
	}
	return *page.oelr.Value
}

// RecommendationProperties the properties of the recommendation.
type RecommendationProperties struct {
	// Category - The category of the recommendation. Possible values include: 'HighAvailability', 'Security', 'Performance', 'Cost'
	Category Category `json:"category,omitempty"`
	// Impact - The business impact of the recommendation. Possible values include: 'High', 'Medium', 'Low'
	Impact Impact `json:"impact,omitempty"`
	// ImpactedField - The resource type identified by Advisor.
	ImpactedField *string `json:"impactedField,omitempty"`
	// ImpactedValue - The resource identified by Advisor.
	ImpactedValue *string `json:"impactedValue,omitempty"`
	// LastUpdated - The most recent time that Advisor checked the validity of the recommendation.
	LastUpdated *date.Time `json:"lastUpdated,omitempty"`
	// Metadata - The recommendation metadata.
	Metadata map[string]interface{} `json:"metadata"`
	// RecommendationTypeID - The recommendation-type GUID.
	RecommendationTypeID *string `json:"recommendationTypeId,omitempty"`
	// Risk - The potential risk of not implementing the recommendation. Possible values include: 'Error', 'Warning', 'None'
	Risk Risk `json:"risk,omitempty"`
	// ShortDescription - A summary of the recommendation.
	ShortDescription *ShortDescription `json:"shortDescription,omitempty"`
	// SuppressionIds - The list of snoozed and dismissed rules for the recommendation.
	SuppressionIds *[]uuid.UUID `json:"suppressionIds,omitempty"`
}

// MarshalJSON is the custom marshaler for RecommendationProperties.
func (rp RecommendationProperties) MarshalJSON() ([]byte, error) {
	objectMap := make(map[string]interface{})
	objectMap["category"] = rp.Category
	objectMap["impact"] = rp.Impact
	if rp.ImpactedField != nil {
		objectMap["impactedField"] = rp.ImpactedField
	}
	if rp.ImpactedValue != nil {
		objectMap["impactedValue"] = rp.ImpactedValue
	}
	if rp.LastUpdated != nil {
		objectMap["lastUpdated"] = rp.LastUpdated
	}
	if rp.Metadata != nil {
		objectMap["metadata"] = rp.Metadata
	}
	if rp.RecommendationTypeID != nil {
		objectMap["recommendationTypeId"] = rp.RecommendationTypeID
	}
	objectMap["risk"] = rp.Risk
	if rp.ShortDescription != nil {
		objectMap["shortDescription"] = rp.ShortDescription
	}
	if rp.SuppressionIds != nil {
		objectMap["suppressionIds"] = rp.SuppressionIds
	}
	return json.Marshal(objectMap)
}

// RecommendationsGetGenerateStatusFuture an abstraction for monitoring and retrieving the results of a
// long-running operation.
type RecommendationsGetGenerateStatusFuture struct {
	azure.Future
	req *http.Request
}

// Result returns the result of the asynchronous operation.
// If the operation has not completed it will return an error.
func (future RecommendationsGetGenerateStatusFuture) Result(client RecommendationsClient) (ar autorest.Response, err error) {
	var done bool
	done, err = future.Done(client)
	if err != nil {
		err = autorest.NewErrorWithError(err, "advisor.RecommendationsGetGenerateStatusFuture", "Result", future.Response(), "Polling failure")
		return
	}
	if !done {
		return ar, azure.NewAsyncOpIncompleteError("advisor.RecommendationsGetGenerateStatusFuture")
	}
	if future.PollingMethod() == azure.PollingLocation {
		ar, err = client.GetGenerateStatusResponder(future.Response())
		if err != nil {
			err = autorest.NewErrorWithError(err, "advisor.RecommendationsGetGenerateStatusFuture", "Result", future.Response(), "Failure responding to request")
		}
		return
	}
	var req *http.Request
	var resp *http.Response
	if future.PollingURL() != "" {
		req, err = http.NewRequest(http.MethodGet, future.PollingURL(), nil)
		if err != nil {
			return
		}
	} else {
		req = autorest.ChangeToGet(future.req)
	}
	resp, err = autorest.SendWithSender(client, req,
		autorest.DoRetryForStatusCodes(client.RetryAttempts, client.RetryDuration, autorest.StatusCodesForRetry...))
	if err != nil {
		err = autorest.NewErrorWithError(err, "advisor.RecommendationsGetGenerateStatusFuture", "Result", resp, "Failure sending request")
		return
	}
	ar, err = client.GetGenerateStatusResponder(resp)
	if err != nil {
		err = autorest.NewErrorWithError(err, "advisor.RecommendationsGetGenerateStatusFuture", "Result", resp, "Failure responding to request")
	}
	return
}

// Resource an Azure resource.
type Resource struct {
	// ID - The resource ID.
	ID *string `json:"id,omitempty"`
	// Name - The name of the resource.
	Name *string `json:"name,omitempty"`
	// Type - The type of the resource.
	Type *string `json:"type,omitempty"`
}

// ResourceRecommendationBase advisor Recommendation.
type ResourceRecommendationBase struct {
	autorest.Response `json:"-"`
	// RecommendationProperties - The properties of the recommendation.
	*RecommendationProperties `json:"properties,omitempty"`
	// ID - The resource ID.
	ID *string `json:"id,omitempty"`
	// Name - The name of the resource.
	Name *string `json:"name,omitempty"`
	// Type - The type of the resource.
	Type *string `json:"type,omitempty"`
}

// UnmarshalJSON is the custom unmarshaler for ResourceRecommendationBase struct.
func (rrb *ResourceRecommendationBase) UnmarshalJSON(body []byte) error {
	var m map[string]*json.RawMessage
	err := json.Unmarshal(body, &m)
	if err != nil {
		return err
	}
	for k, v := range m {
		switch k {
		case "properties":
			if v != nil {
				var recommendationProperties RecommendationProperties
				err = json.Unmarshal(*v, &recommendationProperties)
				if err != nil {
					return err
				}
				rrb.RecommendationProperties = &recommendationProperties
			}
		case "id":
			if v != nil {
				var ID string
				err = json.Unmarshal(*v, &ID)
				if err != nil {
					return err
				}
				rrb.ID = &ID
			}
		case "name":
			if v != nil {
				var name string
				err = json.Unmarshal(*v, &name)
				if err != nil {
					return err
				}
				rrb.Name = &name
			}
		case "type":
			if v != nil {
				var typeVar string
				err = json.Unmarshal(*v, &typeVar)
				if err != nil {
					return err
				}
				rrb.Type = &typeVar
			}
		}
	}

	return nil
}

// ResourceRecommendationBaseListResult the list of Advisor recommendations.
type ResourceRecommendationBaseListResult struct {
	autorest.Response `json:"-"`
	// NextLink - The link used to get the next page of recommendations.
	NextLink *string `json:"nextLink,omitempty"`
	// Value - The list of recommendations.
	Value *[]ResourceRecommendationBase `json:"value,omitempty"`
}

// ResourceRecommendationBaseListResultIterator provides access to a complete listing of ResourceRecommendationBase
// values.
type ResourceRecommendationBaseListResultIterator struct {
	i    int
	page ResourceRecommendationBaseListResultPage
}

// Next advances to the next value.  If there was an error making
// the request the iterator does not advance and the error is returned.
func (iter *ResourceRecommendationBaseListResultIterator) Next() error {
	iter.i++
	if iter.i < len(iter.page.Values()) {
		return nil
	}
	err := iter.page.Next()
	if err != nil {
		iter.i--
		return err
	}
	iter.i = 0
	return nil
}

// NotDone returns true if the enumeration should be started or is not yet complete.
func (iter ResourceRecommendationBaseListResultIterator) NotDone() bool {
	return iter.page.NotDone() && iter.i < len(iter.page.Values())
}

// Response returns the raw server response from the last page request.
func (iter ResourceRecommendationBaseListResultIterator) Response() ResourceRecommendationBaseListResult {
	return iter.page.Response()
}

// Value returns the current value or a zero-initialized value if the
// iterator has advanced beyond the end of the collection.
func (iter ResourceRecommendationBaseListResultIterator) Value() ResourceRecommendationBase {
	if !iter.page.NotDone() {
		return ResourceRecommendationBase{}
	}
	return iter.page.Values()[iter.i]
}

// IsEmpty returns true if the ListResult contains no values.
func (rrblr ResourceRecommendationBaseListResult) IsEmpty() bool {
	return rrblr.Value == nil || len(*rrblr.Value) == 0
}

// resourceRecommendationBaseListResultPreparer prepares a request to retrieve the next set of results.
// It returns nil if no more results exist.
func (rrblr ResourceRecommendationBaseListResult) resourceRecommendationBaseListResultPreparer() (*http.Request, error) {
	if rrblr.NextLink == nil || len(to.String(rrblr.NextLink)) < 1 {
		return nil, nil
	}
	return autorest.Prepare(&http.Request{},
		autorest.AsJSON(),
		autorest.AsGet(),
		autorest.WithBaseURL(to.String(rrblr.NextLink)))
}

// ResourceRecommendationBaseListResultPage contains a page of ResourceRecommendationBase values.
type ResourceRecommendationBaseListResultPage struct {
	fn    func(ResourceRecommendationBaseListResult) (ResourceRecommendationBaseListResult, error)
	rrblr ResourceRecommendationBaseListResult
}

// Next advances to the next page of values.  If there was an error making
// the request the page does not advance and the error is returned.
func (page *ResourceRecommendationBaseListResultPage) Next() error {
	next, err := page.fn(page.rrblr)
	if err != nil {
		return err
	}
	page.rrblr = next
	return nil
}

// NotDone returns true if the page enumeration should be started or is not yet complete.
func (page ResourceRecommendationBaseListResultPage) NotDone() bool {
	return !page.rrblr.IsEmpty()
}

// Response returns the raw server response from the last page request.
func (page ResourceRecommendationBaseListResultPage) Response() ResourceRecommendationBaseListResult {
	return page.rrblr
}

// Values returns the slice of values for the current page or nil if there are no values.
func (page ResourceRecommendationBaseListResultPage) Values() []ResourceRecommendationBase {
	if page.rrblr.IsEmpty() {
		return nil
	}
	return *page.rrblr.Value
}

// ShortDescription a summary of the recommendation.
type ShortDescription struct {
	// Problem - The issue or opportunity identified by the recommendation.
	Problem *string `json:"problem,omitempty"`
	// Solution - The remediation action suggested by the recommendation.
	Solution *string `json:"solution,omitempty"`
}

// SuppressionContract the details of the snoozed or dismissed rule; for example, the duration, name, and GUID
// associated with the rule.
type SuppressionContract struct {
	autorest.Response `json:"-"`
	// SuppressionProperties - The properties of the suppression.
	*SuppressionProperties `json:"properties,omitempty"`
	// ID - The resource ID.
	ID *string `json:"id,omitempty"`
	// Name - The name of the resource.
	Name *string `json:"name,omitempty"`
	// Type - The type of the resource.
	Type *string `json:"type,omitempty"`
}

// UnmarshalJSON is the custom unmarshaler for SuppressionContract struct.
func (sc *SuppressionContract) UnmarshalJSON(body []byte) error {
	var m map[string]*json.RawMessage
	err := json.Unmarshal(body, &m)
	if err != nil {
		return err
	}
	for k, v := range m {
		switch k {
		case "properties":
			if v != nil {
				var suppressionProperties SuppressionProperties
				err = json.Unmarshal(*v, &suppressionProperties)
				if err != nil {
					return err
				}
				sc.SuppressionProperties = &suppressionProperties
			}
		case "id":
			if v != nil {
				var ID string
				err = json.Unmarshal(*v, &ID)
				if err != nil {
					return err
				}
				sc.ID = &ID
			}
		case "name":
			if v != nil {
				var name string
				err = json.Unmarshal(*v, &name)
				if err != nil {
					return err
				}
				sc.Name = &name
			}
		case "type":
			if v != nil {
				var typeVar string
				err = json.Unmarshal(*v, &typeVar)
				if err != nil {
					return err
				}
				sc.Type = &typeVar
			}
		}
	}

	return nil
}

// SuppressionContractListResult the list of Advisor suppressions.
type SuppressionContractListResult struct {
	autorest.Response `json:"-"`
	// NextLink - The link used to get the next page of suppressions.
	NextLink *string `json:"nextLink,omitempty"`
	// Value - The list of suppressions.
	Value *[]SuppressionContract `json:"value,omitempty"`
}

// SuppressionContractListResultIterator provides access to a complete listing of SuppressionContract values.
type SuppressionContractListResultIterator struct {
	i    int
	page SuppressionContractListResultPage
}

// Next advances to the next value.  If there was an error making
// the request the iterator does not advance and the error is returned.
func (iter *SuppressionContractListResultIterator) Next() error {
	iter.i++
	if iter.i < len(iter.page.Values()) {
		return nil
	}
	err := iter.page.Next()
	if err != nil {
		iter.i--
		return err
	}
	iter.i = 0
	return nil
}

// NotDone returns true if the enumeration should be started or is not yet complete.
func (iter SuppressionContractListResultIterator) NotDone() bool {
	return iter.page.NotDone() && iter.i < len(iter.page.Values())
}

// Response returns the raw server response from the last page request.
func (iter SuppressionContractListResultIterator) Response() SuppressionContractListResult {
	return iter.page.Response()
}

// Value returns the current value or a zero-initialized value if the
// iterator has advanced beyond the end of the collection.
func (iter SuppressionContractListResultIterator) Value() SuppressionContract {
	if !iter.page.NotDone() {
		return SuppressionContract{}
	}
	return iter.page.Values()[iter.i]
}

// IsEmpty returns true if the ListResult contains no values.
func (sclr SuppressionContractListResult) IsEmpty() bool {
	return sclr.Value == nil || len(*sclr.Value) == 0
}

// suppressionContractListResultPreparer prepares a request to retrieve the next set of results.
// It returns nil if no more results exist.
func (sclr SuppressionContractListResult) suppressionContractListResultPreparer() (*http.Request, error) {
	if sclr.NextLink == nil || len(to.String(sclr.NextLink)) < 1 {
		return nil, nil
	}
	return autorest.Prepare(&http.Request{},
		autorest.AsJSON(),
		autorest.AsGet(),
		autorest.WithBaseURL(to.String(sclr.NextLink)))
}

// SuppressionContractListResultPage contains a page of SuppressionContract values.
type SuppressionContractListResultPage struct {
	fn   func(SuppressionContractListResult) (SuppressionContractListResult, error)
	sclr SuppressionContractListResult
}

// Next advances to the next page of values.  If there was an error making
// the request the page does not advance and the error is returned.
func (page *SuppressionContractListResultPage) Next() error {
	next, err := page.fn(page.sclr)
	if err != nil {
		return err
	}
	page.sclr = next
	return nil
}

// NotDone returns true if the page enumeration should be started or is not yet complete.
func (page SuppressionContractListResultPage) NotDone() bool {
	return !page.sclr.IsEmpty()
}

// Response returns the raw server response from the last page request.
func (page SuppressionContractListResultPage) Response() SuppressionContractListResult {
	return page.sclr
}

// Values returns the slice of values for the current page or nil if there are no values.
func (page SuppressionContractListResultPage) Values() []SuppressionContract {
	if page.sclr.IsEmpty() {
		return nil
	}
	return *page.sclr.Value
}

// SuppressionProperties the properties of the suppression.
type SuppressionProperties struct {
	// SuppressionID - The GUID of the suppression.
	SuppressionID *string `json:"suppressionId,omitempty"`
	// TTL - The duration for which the suppression is valid.
	TTL *string `json:"ttl,omitempty"`
}
