1package gojsonld
2
3type Context struct {
4	table map[string]interface{}
5
6	options         *Options
7	termDefinitions map[string]interface{}
8	inverse         map[string]interface{}
9}
10
11// public Context() {
12//     this(new JsonLdOptions());
13// }
14// public Context(JsonLdOptions opts) {
15//     super();
16//     init(opts);
17// }
18// public Context(Map<String, Object> map, JsonLdOptions opts) {
19//     super(map);
20//     init(opts);
21// }
22// public Context(Map<String, Object> map) {
23//     super(map);
24//     init(new JsonLdOptions());
25// }
26
27// public Context(Object context, JsonLdOptions opts) {
28//     // TODO: load remote context
29//     super(context instanceof Map ? (Map<String, Object>) context : null);
30//     init(opts);
31// }
32
33func (c *Context) init(options *Options) {
34	c.options = options
35	c.termDefinitions = make(map[string]interface{}, 0)
36	c.table = make(map[string]interface{}, 0)
37	if len(options.Base) > 0 {
38		c.table["@base"] = options.Base
39	} else {
40		c.table["@base"] = ""
41	}
42}
43
44// String compactIri(String iri, boolean relativeToVocab) {
45//     return compactIri(iri, null, relativeToVocab, false);
46// }
47
48// String compactIri(String iri) {
49//     return compactIri(iri, null, false, false);
50// }
51
52func (c *Context) clone() *Context {
53	var clonedContext *Context = new(Context)
54	if !isNil(c.table) {
55		clonedContext.table = make(map[string]interface{}, 0)
56		for key, value := range c.table {
57			clonedContext.table[key] = deepCopy(value)
58		}
59	}
60	if !isNil(c.inverse) {
61		clonedContext.inverse = make(map[string]interface{}, 0)
62		for key, value := range c.inverse {
63			clonedContext.inverse[key] = deepCopy(value)
64		}
65	}
66	if !isNil(c.termDefinitions) {
67		clonedContext.termDefinitions = make(map[string]interface{}, 0)
68		for key, value := range c.termDefinitions {
69			clonedContext.termDefinitions[key] = deepCopy(value)
70		}
71	}
72	clonedContext.options = &Options{
73		Base:                  c.options.Base,
74		CompactArrays:         c.options.CompactArrays,
75		ExpandContext:         deepCopy(c.options.ExpandContext),
76		DocumentLoader:        c.options.DocumentLoader,
77		Embed:                 c.options.Embed,
78		Explicit:              c.options.Explicit,
79		UseRdfType:            c.options.UseRdfType,
80		UseNativeTypes:        c.options.UseNativeTypes,
81		ProduceGeneralizedRdf: c.options.ProduceGeneralizedRdf,
82		Format:                c.options.Format,
83		UseNamespaces:         c.options.UseNamespaces,
84		OutputForm:            c.options.OutputForm,
85	}
86	return clonedContext
87}
88
89func (c *Context) getContainer(property string) string {
90	if "@graph" == property {
91		return "@set"
92	}
93	if isKeyword(property) {
94		return property
95	}
96	td, hasTermDefinition := c.termDefinitions[property]
97	if !hasTermDefinition {
98		return ""
99	}
100	container, hasContainer := td.(map[string]interface{})["@container"]
101	if hasContainer {
102		return container.(string)
103	} else {
104		return ""
105	}
106}
107
108func (c *Context) isReverseProperty(property string) bool {
109	td, isMap := c.termDefinitions[property].(map[string]interface{})
110	if td == nil || !isMap {
111		return false
112	}
113	reverse := td["@reverse"]
114	reverseBool, isBool := reverse.(bool)
115	return isBool && reverseBool
116}
117
118func (c *Context) getTypeMapping(property string) (string, bool) {
119	td := c.termDefinitions[property]
120	if tdMap, ok := td.(map[string]interface{}); ok {
121		typeMapping, okMapping := tdMap["@type"].(string)
122		return typeMapping, okMapping
123	} else {
124		return "", false
125	}
126}
127
128func (c *Context) getLanguageMapping(property string) (string, bool) {
129	td := c.termDefinitions[property]
130	if tdMap, ok := td.(map[string]interface{}); ok {
131		languageMapping, okMapping := tdMap["@language"].(string)
132		return languageMapping, okMapping
133	} else {
134		return "", false
135	}
136}
137
138func (c *Context) getTermDefinition(key string) (map[string]interface{}, bool) {
139	termDefinition, ok := c.termDefinitions[key]
140	if !ok {
141		return nil, false
142	}
143	termDefinitionMap, okMap := termDefinition.(map[string]interface{})
144	return termDefinitionMap, okMap
145}
146
147// public Object expandValue(String activeProperty, Object value) throws JsonLdError {
148//     final Map<String, Object> rval = new LinkedHashMap<String, Object>();
149//     final Map<String, Object> td = getTermDefinition(activeProperty);
150//     // 1)
151//     if (td != null && "@id".equals(td.get("@type"))) {
152//         // TODO: i'm pretty sure value should be a string if the @type is
153//         // @id
154//         rval.put("@id", expandIri(value.toString(), true, false, null, null));
155//         return rval;
156//     }
157//     // 2)
158//     if (td != null && "@vocab".equals(td.get("@type"))) {
159//         // TODO: same as above
160//         rval.put("@id", expandIri(value.toString(), true, true, null, null));
161//         return rval;
162//     }
163//     // 3)
164//     rval.put("@value", value);
165//     // 4)
166//     if (td != null && td.containsKey("@type")) {
167//         rval.put("@type", td.get("@type"));
168//     }
169//     // 5)
170//     else if (value instanceof String) {
171//         // 5.1)
172//         if (td != null && td.containsKey("@language")) {
173//             final String lang = (String) td.get("@language");
174//             if (lang != null) {
175//                 rval.put("@language", lang);
176//             }
177//         }
178//         // 5.2)
179//         else if (this.get("@language") != null) {
180//             rval.put("@language", this.get("@language"));
181//         }
182//     }
183//     return rval;
184// }
185
186// public Object getContextValue(String activeProperty, String string) throws JsonLdError {
187//     throw new JsonLdError(Error.NOT_IMPLEMENTED,
188//             "getContextValue is only used by old code so far and thus isn't implemented");
189// }
190
191func (c *Context) serialize() (map[string]interface{}, error) {
192	context := make(map[string]interface{})
193	if base, hasBase := c.table["@base"]; hasBase && base != c.options.Base {
194		context["@base"] = base
195	}
196	if language, hasLanguage := c.table["@language"]; hasLanguage {
197		context["@language"] = language
198	}
199	if vocab, hasVocab := c.table["@vocab"]; hasVocab {
200		context["@vocab"] = vocab
201	}
202	for term := range c.termDefinitions {
203		definition := c.termDefinitions[term].(map[string]interface{})
204		_, hasType := definition["@type"]
205		container, hasContainer := definition["@container"]
206		language, hasLanguage := definition["@language"]
207		reverse, hasReverse := definition["@reverse"]
208		reverseBool, isBool := reverse.(bool)
209		if !hasLanguage &&
210			!hasContainer &&
211			!hasType &&
212			(!hasReverse || (isBool && reverseBool == false)) {
213			id := definition["@id"].(string)
214			compactID, compactErr := compactIri(c, &id, nil, false, false)
215			if compactErr != nil {
216				return nil, compactErr
217			}
218			if term == *compactID {
219				context[term] = id
220			} else {
221				context[term] = *compactID
222			}
223		} else {
224			defn := make(map[string]interface{}, 0)
225			id := definition["@id"].(string)
226			compactID, compactErr := compactIri(c, &id, nil, false, false)
227			if compactErr != nil {
228				return nil, compactErr
229			}
230			var reverseProperty bool
231			if isBool && reverseBool == true {
232				reverseProperty = true
233			} else {
234				reverseProperty = false
235			}
236			if !(term == *compactID && !reverseProperty) {
237				if reverseProperty {
238					defn["@reverse"] = *compactID
239				} else {
240					defn["@id"] = *compactID
241				}
242			}
243			typeMapping, hasTypeMapping := definition["@type"].(string)
244			if hasTypeMapping {
245				if isKeyword(typeMapping) {
246					defn["@type"] = typeMapping
247				} else {
248					compactType, compactErr := compactIri(c, &typeMapping,
249						nil, true, false)
250					if compactErr != nil {
251						return nil, compactErr
252					}
253					defn["@type"] = *compactType
254				}
255			}
256			if hasContainer {
257				defn["@container"] = container
258			}
259			if hasLanguage {
260				languageBool, isBool := language.(bool)
261				if isBool && languageBool == false {
262					defn["@language"] = nil
263				} else {
264					defn["@language"] = language
265				}
266			}
267			context[term] = defn
268		}
269	}
270	returnValue := make(map[string]interface{}, 0)
271	if !(context == nil || len(context) == 0) {
272		returnValue["@context"] = context
273	}
274	return returnValue, nil
275}
276