// Copyright 2012 Google Inc. All Rights Reserved.
//
// 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 com.google.collide.clientlibs.navigation;
import com.google.collide.json.shared.JsonArray;
import com.google.collide.json.shared.JsonStringMap;
import com.google.collide.json.shared.JsonStringMap.IterationCallback;
import com.google.collide.shared.util.JsonCollections;
import com.google.collide.shared.util.StringUtils;
/**
* A serializer which serializes all data in each {@link NavigationToken}'s map to the url. The
* resulting url is not really that pretty.
*
*/
class DefaultUrlSerializer implements UrlSerializer {
static final char KEY_VALUE_SEPARATOR = '=';
private final UrlComponentEncoder encoder;
public DefaultUrlSerializer(UrlComponentEncoder encoder) {
this.encoder = encoder;
}
@Override
public JsonArray<NavigationToken> deserialize(String url) {
JsonArray<NavigationToken> tokens = JsonCollections.createArray();
// Simple parser, we pass the first PATH_SEPARATOR then split the string and
// look for a place name followed by any mapped contents it may have.
JsonArray<String> components = StringUtils.split(url.substring(1), PATH_SEPARATOR);
for (int i = 0; i < components.size();) {
String encodedPlace = components.get(i);
String decodedPlace = encoder.decode(encodedPlace);
// Create a token for the decoded place
NavigationToken token = new NavigationTokenImpl(decodedPlace);
tokens.add(token);
// Loop through adding map values until we encounter the next place
for (i++; i < components.size(); i++) {
String encodedKeyValue = components.get(i);
int separatorIndex = encodedKeyValue.indexOf(KEY_VALUE_SEPARATOR);
if (separatorIndex == -1) {
// we are back to a place and should let the outer loop restart
break;
}
// Grab the encoded values
String encodedKey = encodedKeyValue.substring(0, separatorIndex);
String encodedValue = encodedKeyValue.substring(separatorIndex + 1);
// decode and place in the map
String decodedKey = encoder.decode(encodedKey);
String decodedValue = encoder.decode(encodedValue);
token.getBookmarkableState().put(decodedKey, decodedValue);
}
}
return tokens;
}
/**
* This serializes a URL into a simple format consisting of /place/key=value/key=value/place/...
*
* @return This serializer will never return null and can always serialize a list of
* {@link NavigationToken}s.
*/
@Override
public String serialize(JsonArray<? extends NavigationToken> tokens) {
final StringBuilder urlBuilder = new StringBuilder();
for (int i = 0; i < tokens.size(); i++) {
NavigationToken token = tokens.get(i);
String encodedName = encoder.encode(token.getPlaceName());
urlBuilder.append(PATH_SEPARATOR).append(encodedName);
JsonStringMap<String> tokenData = token.getBookmarkableState();
tokenData.iterate(new IterationCallback<String>() {
@Override
public void onIteration(String key, String value) {
// omit explicit nulls
if (value == null) {
return;
}
String encodedKey = encoder.encode(key);
String encodedValue = encoder.encode(value);
urlBuilder.append(PATH_SEPARATOR)
.append(encodedKey).append(KEY_VALUE_SEPARATOR).append(encodedValue);
}
});
}
return urlBuilder.toString();
}
}