package scpd

import (
	
	
	
)

const (
	SCPDXMLNamespace = "urn:schemas-upnp-org:service-1-0"
)

func cleanWhitespace( *string) {
	* = strings.TrimSpace(*)
}

// SCPD is the service description as described by section 2.5 "Service
// description" in
// http://upnp.org/specs/arch/UPnP-arch-DeviceArchitecture-v1.1.pdf
type SCPD struct {
	XMLName        xml.Name        `xml:"scpd"`
	ConfigId       string          `xml:"configId,attr"`
	SpecVersion    SpecVersion     `xml:"specVersion"`
	Actions        []Action        `xml:"actionList>action"`
	StateVariables []StateVariable `xml:"serviceStateTable>stateVariable"`
}

// Clean attempts to remove stray whitespace etc. in the structure. It seems
// unfortunately common for stray whitespace to be present in SCPD documents,
// this method attempts to make it easy to clean them out.
func ( *SCPD) () {
	cleanWhitespace(&.ConfigId)
	for  := range .Actions {
		.Actions[].clean()
	}
	for  := range .StateVariables {
		.StateVariables[].clean()
	}
}

func ( *SCPD) () []Action {
	 := append([]Action{}, .Actions...)
	sort.SliceStable(, func(,  int) bool {
		return [].Name < [].Name
	})
	return 
}

func ( *SCPD) ( string) *StateVariable {
	for  := range .StateVariables {
		 := &.StateVariables[]
		if .Name ==  {
			return 
		}
	}
	return nil
}

func ( *SCPD) ( string) *Action {
	for  := range .Actions {
		 := &.Actions[]
		if .Name ==  {
			return 
		}
	}
	return nil
}

// SpecVersion is part of a SCPD document, describes the version of the
// specification that the data adheres to.
type SpecVersion struct {
	Major int32 `xml:"major"`
	Minor int32 `xml:"minor"`
}

type Action struct {
	Name      string     `xml:"name"`
	Arguments []Argument `xml:"argumentList>argument"`
}

func ( *Action) () {
	cleanWhitespace(&.Name)
	for  := range .Arguments {
		.Arguments[].clean()
	}
}

func ( *Action) () []*Argument {
	var  []*Argument
	for  := range .Arguments {
		 := &.Arguments[]
		if .IsInput() {
			 = append(, )
		}
	}
	return 
}

func ( *Action) () []*Argument {
	var  []*Argument
	for  := range .Arguments {
		 := &.Arguments[]
		if .IsOutput() {
			 = append(, )
		}
	}
	return 
}

type Argument struct {
	Name                 string `xml:"name"`
	Direction            string `xml:"direction"`            // in|out
	RelatedStateVariable string `xml:"relatedStateVariable"` // ?
	Retval               string `xml:"retval"`               // ?
}

func ( *Argument) () {
	cleanWhitespace(&.Name)
	cleanWhitespace(&.Direction)
	cleanWhitespace(&.RelatedStateVariable)
	cleanWhitespace(&.Retval)
}

func ( *Argument) () bool {
	return .Direction == "in"
}

func ( *Argument) () bool {
	return .Direction == "out"
}

type StateVariable struct {
	Name              string             `xml:"name"`
	SendEvents        string             `xml:"sendEvents,attr"` // yes|no
	Multicast         string             `xml:"multicast,attr"`  // yes|no
	DataType          DataType           `xml:"dataType"`
	DefaultValue      string             `xml:"defaultValue"`
	AllowedValueRange *AllowedValueRange `xml:"allowedValueRange"`
	AllowedValues     []string           `xml:"allowedValueList>allowedValue"`
}

func ( *StateVariable) () {
	cleanWhitespace(&.Name)
	cleanWhitespace(&.SendEvents)
	cleanWhitespace(&.Multicast)
	.DataType.clean()
	cleanWhitespace(&.DefaultValue)
	if .AllowedValueRange != nil {
		.AllowedValueRange.clean()
	}
	for  := range .AllowedValues {
		cleanWhitespace(&.AllowedValues[])
	}
}

type AllowedValueRange struct {
	Minimum string `xml:"minimum"`
	Maximum string `xml:"maximum"`
	Step    string `xml:"step"`
}

func ( *AllowedValueRange) () {
	cleanWhitespace(&.Minimum)
	cleanWhitespace(&.Maximum)
	cleanWhitespace(&.Step)
}

type DataType struct {
	Name string `xml:",chardata"`
	Type string `xml:"type,attr"`
}

func ( *DataType) () {
	cleanWhitespace(&.Name)
	cleanWhitespace(&.Type)
}