1/*
2	Copyright (c) 2012 Kier Davis
3
4	Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
5	associated documentation files (the "Software"), to deal in the Software without restriction,
6	including without limitation the rights to use, copy, modify, merge, publish, distribute,
7	sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
8	furnished to do so, subject to the following conditions:
9
10	The above copyright notice and this permission notice shall be included in all copies or substantial
11	portions of the Software.
12
13	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
14	NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
15	NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES
16	OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
17	CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
18*/
19
20package gojsonld
21
22import (
23	"fmt"
24	"math/rand"
25	"strings"
26)
27
28// A Term is the value of a subject, predicate or object i.e. a IRI reference, blank node or
29// literal.
30type Term interface {
31	// Method String should return the NTriples representation of this term.
32	String() string
33	// Returns the value without formatting
34	RawValue() string
35	// Method Equal should return whether this term is equal to another.
36	Equal(Term) bool
37}
38
39// A Resource is an URI / IRI reference.
40type Resource struct {
41	URI string
42}
43
44// Function NewResource returns a new resource object.
45func NewResource(uri string) (term Term) {
46	return Term(&Resource{URI: uri})
47}
48
49// Method String returns the NTriples representation of this resource.
50func (term Resource) String() (str string) {
51	return fmt.Sprintf("<%s>", term.URI)
52}
53
54// Method Equal returns whether this resource is equal to another.
55func (term Resource) Equal(other Term) bool {
56	if spec, ok := other.(*Resource); ok {
57		return term.URI == spec.URI
58	}
59
60	return false
61}
62
63func (term Resource) RawValue() string {
64	return term.URI
65}
66
67// A Literal is a textual value, with an associated language or datatype.
68type Literal struct {
69	Value    string
70	Language string
71	Datatype Term
72}
73
74// Function NewLiteral returns a new literal with the given value.
75func NewLiteral(value string) (term Term) {
76	return Term(&Literal{Value: value})
77}
78
79// Function NewLiteralWithLanguage returns a new literal with the given value and language.
80func NewLiteralWithLanguage(value string, language string) (term Term) {
81	return Term(&Literal{Value: value, Language: language})
82}
83
84// Function NewLiteralWithDatatype returns a new literal with the given value and datatype.
85func NewLiteralWithDatatype(value string, datatype Term) (term Term) {
86	return Term(&Literal{Value: value, Datatype: datatype})
87}
88
89// Function NewLiteralWithLanguageAndDatatype returns a new literal with the given value, language
90// and datatype. Technically a literal cannot have both a language and a datatype, but this function
91// is provided to allow creation of literal in a context where this check has already been made,
92// such as in a parser.
93func NewLiteralWithLanguageAndDatatype(value string, language string, datatype Term) (term Term) {
94	return Term(&Literal{Value: value, Language: language, Datatype: datatype})
95}
96
97// Method String returns the NTriples representation of this literal.
98func (term Literal) String() (str string) {
99	str = term.Value
100	str = strings.Replace(str, "\\", "\\\\", -1)
101	str = strings.Replace(str, "\"", "\\\"", -1)
102	str = strings.Replace(str, "\n", "\\n", -1)
103	str = strings.Replace(str, "\r", "\\r", -1)
104	str = strings.Replace(str, "\t", "\\t", -1)
105
106	str = fmt.Sprintf("\"%s\"", str)
107
108	if term.Language != "" {
109		str += "@" + term.Language
110	} else if term.Datatype != nil {
111		str += "^^" + term.Datatype.String()
112	}
113
114	return str
115}
116
117// Method Equal returns whether this literal is equivalent to another.
118func (term Literal) Equal(other Term) bool {
119	spec, ok := other.(*Literal)
120	if !ok {
121		return false
122	}
123
124	if term.Value != spec.Value {
125		return false
126	}
127
128	if term.Language != spec.Language {
129		return false
130	}
131
132	if (term.Datatype == nil && spec.Datatype != nil) || (term.Datatype != nil && spec.Datatype == nil) {
133		return false
134	}
135
136	if term.Datatype != nil && spec.Datatype != nil && !term.Datatype.Equal(spec.Datatype) {
137		return false
138	}
139
140	return true
141}
142
143func (term Literal) RawValue() string {
144	return term.Value
145}
146
147// A BlankNode is an RDF blank node i.e. an unqualified URI/IRI.
148type BlankNode struct {
149	ID string
150}
151
152// Function NewBlankNode returns a new blank node with the given ID.
153func NewBlankNode(id string) (term Term) {
154	return Term(&BlankNode{ID: id})
155}
156
157// Function NewAnonNode returns a new blank node with a pseudo-randomly generated ID.
158func NewAnonNode() (term Term) {
159	return Term(&BlankNode{ID: fmt.Sprintf("anon%016x", rand.Int63())})
160}
161
162// Method String returns the NTriples representation of the blank node.
163func (term BlankNode) String() (str string) {
164	return "_:" + term.ID
165}
166
167// Method Equal returns whether this blank node is equivalent to another.
168func (term BlankNode) Equal(other Term) bool {
169	if spec, ok := other.(*BlankNode); ok {
170		return term.ID == spec.ID
171	}
172
173	return false
174}
175
176func (term BlankNode) RawValue() string {
177	return term.ID
178}
179
180func isTermBlankNode(term Term) bool {
181	_, isBlankNode := term.(*BlankNode)
182	return isBlankNode
183}
184
185func isTermResource(term Term) bool {
186	_, isResource := term.(*Resource)
187	return isResource
188}
189
190func isTermLiteral(term Term) bool {
191	_, isLiteral := term.(*Literal)
192	return isLiteral
193}
194