// Copyright 2013 The Prometheus Authors
// 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.

package model

import (
	
	
	
	
	
)

// ZeroSample is the pseudo zero-value of Sample used to signal a
// non-existing sample. It is a Sample with timestamp Earliest, value 0.0,
// and metric nil. Note that the natural zero value of Sample has a timestamp
// of 0, which is possible to appear in a real Sample and thus not suitable
// to signal a non-existing Sample.
var ZeroSample = Sample{Timestamp: Earliest}

// Sample is a sample pair associated with a metric. A single sample must either
// define Value or Histogram but not both. Histogram == nil implies the Value
// field is used, otherwise it should be ignored.
type Sample struct {
	Metric    Metric           `json:"metric"`
	Value     SampleValue      `json:"value"`
	Timestamp Time             `json:"timestamp"`
	Histogram *SampleHistogram `json:"histogram"`
}

// Equal compares first the metrics, then the timestamp, then the value. The
// semantics of value equality is defined by SampleValue.Equal.
func ( *Sample) ( *Sample) bool {
	if  ==  {
		return true
	}

	if !.Metric.Equal(.Metric) {
		return false
	}
	if !.Timestamp.Equal(.Timestamp) {
		return false
	}
	if .Histogram != nil {
		return .Histogram.Equal(.Histogram)
	}
	return .Value.Equal(.Value)
}

func ( Sample) () string {
	if .Histogram != nil {
		return fmt.Sprintf("%s => %s", .Metric, SampleHistogramPair{
			Timestamp: .Timestamp,
			Histogram: .Histogram,
		})
	}
	return fmt.Sprintf("%s => %s", .Metric, SamplePair{
		Timestamp: .Timestamp,
		Value:     .Value,
	})
}

// MarshalJSON implements json.Marshaler.
func ( Sample) () ([]byte, error) {
	if .Histogram != nil {
		 := struct {
			    Metric              `json:"metric"`
			 SampleHistogramPair `json:"histogram"`
		}{
			: .Metric,
			: SampleHistogramPair{
				Timestamp: .Timestamp,
				Histogram: .Histogram,
			},
		}
		return json.Marshal(&)
	}
	 := struct {
		 Metric     `json:"metric"`
		  SamplePair `json:"value"`
	}{
		: .Metric,
		: SamplePair{
			Timestamp: .Timestamp,
			Value:     .Value,
		},
	}
	return json.Marshal(&)
}

// UnmarshalJSON implements json.Unmarshaler.
func ( *Sample) ( []byte) error {
	 := struct {
		    Metric              `json:"metric"`
		     SamplePair          `json:"value"`
		 SampleHistogramPair `json:"histogram"`
	}{
		: .Metric,
		: SamplePair{
			Timestamp: .Timestamp,
			Value:     .Value,
		},
		: SampleHistogramPair{
			Timestamp: .Timestamp,
			Histogram: .Histogram,
		},
	}

	if  := json.Unmarshal(, &);  != nil {
		return 
	}

	.Metric = .
	if ..Histogram != nil {
		.Timestamp = ..Timestamp
		.Histogram = ..Histogram
	} else {
		.Timestamp = ..Timestamp
		.Value = ..Value
	}

	return nil
}

// Samples is a sortable Sample slice. It implements sort.Interface.
type Samples []*Sample

func ( Samples) () int {
	return len()
}

// Less compares first the metrics, then the timestamp.
func ( Samples) (,  int) bool {
	switch {
	case [].Metric.Before([].Metric):
		return true
	case [].Metric.Before([].Metric):
		return false
	case [].Timestamp.Before([].Timestamp):
		return true
	default:
		return false
	}
}

func ( Samples) (,  int) {
	[], [] = [], []
}

// Equal compares two sets of samples and returns true if they are equal.
func ( Samples) ( Samples) bool {
	if len() != len() {
		return false
	}

	for ,  := range  {
		if !.Equal([]) {
			return false
		}
	}
	return true
}

// SampleStream is a stream of Values belonging to an attached COWMetric.
type SampleStream struct {
	Metric     Metric                `json:"metric"`
	Values     []SamplePair          `json:"values"`
	Histograms []SampleHistogramPair `json:"histograms"`
}

func ( SampleStream) () string {
	 := len(.Values)
	 := make([]string, +len(.Histograms))
	for ,  := range .Values {
		[] = .String()
	}
	for ,  := range .Histograms {
		[+] = .String()
	}
	return fmt.Sprintf("%s =>\n%s", .Metric, strings.Join(, "\n"))
}

func ( SampleStream) () ([]byte, error) {
	if len(.Histograms) > 0 && len(.Values) > 0 {
		 := struct {
			     Metric                `json:"metric"`
			     []SamplePair          `json:"values"`
			 []SampleHistogramPair `json:"histograms"`
		}{
			:     .Metric,
			:     .Values,
			: .Histograms,
		}
		return json.Marshal(&)
	} else if len(.Histograms) > 0 {
		 := struct {
			     Metric                `json:"metric"`
			 []SampleHistogramPair `json:"histograms"`
		}{
			:     .Metric,
			: .Histograms,
		}
		return json.Marshal(&)
	} else {
		 := struct {
			 Metric       `json:"metric"`
			 []SamplePair `json:"values"`
		}{
			: .Metric,
			: .Values,
		}
		return json.Marshal(&)
	}
}

func ( *SampleStream) ( []byte) error {
	 := struct {
		     Metric                `json:"metric"`
		     []SamplePair          `json:"values"`
		 []SampleHistogramPair `json:"histograms"`
	}{
		:     .Metric,
		:     .Values,
		: .Histograms,
	}

	if  := json.Unmarshal(, &);  != nil {
		return 
	}

	.Metric = .
	.Values = .
	.Histograms = .

	return nil
}

// Scalar is a scalar value evaluated at the set timestamp.
type Scalar struct {
	Value     SampleValue `json:"value"`
	Timestamp Time        `json:"timestamp"`
}

func ( Scalar) () string {
	return fmt.Sprintf("scalar: %v @[%v]", .Value, .Timestamp)
}

// MarshalJSON implements json.Marshaler.
func ( Scalar) () ([]byte, error) {
	 := strconv.FormatFloat(float64(.Value), 'f', -1, 64)
	return json.Marshal([...]interface{}{.Timestamp, string()})
}

// UnmarshalJSON implements json.Unmarshaler.
func ( *Scalar) ( []byte) error {
	var  string
	 := [...]interface{}{&.Timestamp, &}

	if  := json.Unmarshal(, &);  != nil {
		return 
	}

	,  := strconv.ParseFloat(, 64)
	if  != nil {
		return fmt.Errorf("error parsing sample value: %w", )
	}
	.Value = SampleValue()
	return nil
}

// String is a string value evaluated at the set timestamp.
type String struct {
	Value     string `json:"value"`
	Timestamp Time   `json:"timestamp"`
}

func ( *String) () string {
	return .Value
}

// MarshalJSON implements json.Marshaler.
func ( String) () ([]byte, error) {
	return json.Marshal([]interface{}{.Timestamp, .Value})
}

// UnmarshalJSON implements json.Unmarshaler.
func ( *String) ( []byte) error {
	 := [...]interface{}{&.Timestamp, &.Value}
	return json.Unmarshal(, &)
}

// Vector is basically only an alias for Samples, but the
// contract is that in a Vector, all Samples have the same timestamp.
type Vector []*Sample

func ( Vector) () string {
	 := make([]string, len())
	for ,  := range  {
		[] = .String()
	}
	return strings.Join(, "\n")
}

func ( Vector) () int      { return len() }
func ( Vector) (,  int) { [], [] = [], [] }

// Less compares first the metrics, then the timestamp.
func ( Vector) (,  int) bool {
	switch {
	case [].Metric.Before([].Metric):
		return true
	case [].Metric.Before([].Metric):
		return false
	case [].Timestamp.Before([].Timestamp):
		return true
	default:
		return false
	}
}

// Equal compares two sets of samples and returns true if they are equal.
func ( Vector) ( Vector) bool {
	if len() != len() {
		return false
	}

	for ,  := range  {
		if !.Equal([]) {
			return false
		}
	}
	return true
}

// Matrix is a list of time series.
type Matrix []*SampleStream

func ( Matrix) () int           { return len() }
func ( Matrix) (,  int) bool { return [].Metric.Before([].Metric) }
func ( Matrix) (,  int)      { [], [] = [], [] }

func ( Matrix) () string {
	 := make(Matrix, len())
	copy(, )
	sort.Sort()

	 := make([]string, len())

	for ,  := range  {
		[] = .String()
	}

	return strings.Join(, "\n")
}