1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
use crate::description::TypeID;
use crate::syntax::{SOAP_NS_ENCODING, SOAP_NS_ENVELOPE};
/**

```http
POST path of control URL HTTP/1.1
HOST: host of control URL:port of control URL
CONTENT-LENGTH: bytes in body
CONTENT-TYPE: text/xml; charset="utf-8"
SOAPACTION: "urn:schemas-upnp-org:service:serviceType:v#actionName"

<?xml version="1.0"?>
<s:Envelope
   xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"
   s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
   <s:Body>
      <u:actionName xmlns:u="urn:schemas-upnp-org:service:serviceType:v">
         <argumentName>in arg value</argumentName>
         other in args and their values go here, if any
      </u:actionName>
   </s:Body>
</s:Envelope>
```
*/
use std::collections::HashMap;
use std::fmt::{Display, Error, Formatter};

// ------------------------------------------------------------------------------------------------
// Public Types
// ------------------------------------------------------------------------------------------------

#[derive(Clone, Debug)]
pub struct Action {
    service: TypeID,
    action: String,
}

#[derive(Clone, Debug)]
pub enum Body {
    Action {
        action: Action,
        argumments: HashMap<String, String>,
    },
    Response {
        action: Action,
        argumments: HashMap<String, String>,
    },
    Fault {
        code: String,
        string: String,
        upnp_code: String,
        upnp_description: String,
    },
}

#[derive(Clone, Debug)]
pub struct Envelope {
    #[allow(dead_code)]
    schema: String,
    #[allow(dead_code)]
    encoding_style: String,
    #[allow(dead_code)]
    body: Body,
}

// ------------------------------------------------------------------------------------------------
// Implementations
// ------------------------------------------------------------------------------------------------

impl Action {
    pub fn new(service: TypeID, action: String) -> Self {
        Action { service, action }
    }

    pub fn copy_to(&self, action: String) -> Self {
        Action {
            service: self.service.clone(),
            action,
        }
    }
}

impl Display for Action {
    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> {
        write!(f, "{}#{}", self.service, self.action)
    }
}

// ------------------------------------------------------------------------------------------------

impl Envelope {
    pub fn new(action: Action) -> Self {
        Self::new_with(action, Default::default())
    }

    pub fn new_with(action: Action, argumments: HashMap<String, String>) -> Self {
        Envelope {
            schema: SOAP_NS_ENVELOPE.to_string(),
            encoding_style: SOAP_NS_ENCODING.to_string(),
            body: Body::Action { action, argumments },
        }
    }

    pub fn new_response(action: Action, argumments: HashMap<String, String>) -> Self {
        Envelope {
            schema: SOAP_NS_ENVELOPE.to_string(),
            encoding_style: SOAP_NS_ENCODING.to_string(),
            body: Body::Response { action, argumments },
        }
    }
}

// ------------------------------------------------------------------------------------------------
// Private Functions
// ------------------------------------------------------------------------------------------------

// ------------------------------------------------------------------------------------------------
// Modules
// ------------------------------------------------------------------------------------------------