/*
* Copyright 2016 Google Inc.
*
* 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.android.libraries.remixer.serialization;
import com.google.android.libraries.remixer.ItemListVariable;
import com.google.android.libraries.remixer.RangeVariable;
import com.google.android.libraries.remixer.Variable;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonPrimitive;
import java.util.ArrayList;
/**
* Helper object that abstracts the type-dependent parts of parsing a Variable from Json and
* converting it from a java object into its JSON representation.
* @param <RuntimeType> the data type that the remixer core framework uses.
* @param <SerializableType> the data type to use during serialization.
*/
public abstract class ValueConverter<RuntimeType, SerializableType> {
/**
* The data type this converter is used for.
*/
protected String dataType;
public ValueConverter(String dataType) {
this.dataType = dataType;
}
/**
* Gets the data type name for this converter.
*/
public String getDataType() {
return dataType;
}
/**
* Returns an object of type SerializableType that holds the value in the current Json Element.
*/
public abstract SerializableType parseValue(JsonElement element);
/**
* Returns a JsonElement that represents the value passed in.
*/
public abstract JsonElement valueToJson(SerializableType value);
/**
* Converts values from the runtime type to the serializable type.
*/
public abstract SerializableType fromRuntimeType(RuntimeType value);
/**
* Converts values from the serializable type to the runtime type.
*/
public abstract RuntimeType toRuntimeType(SerializableType value);
/**
* Deserializes a JsonElement that contains a StoredVariable.
*/
public StoredVariable<SerializableType> deserialize(JsonElement json) {
StoredVariable<SerializableType> result = new StoredVariable<>();
JsonObject object = json.getAsJsonObject();
result.selectedValue = parseValue(object.get(StoredVariable.SELECTED_VALUE));
result.constraintType = object.get(StoredVariable.CONSTRAINT_TYPE).getAsString();
if (StoredVariable.ITEM_LIST_VARIABLE_CONSTRAINT.equals(result.constraintType)) {
deserializeLimitedToValues(result, object.get(StoredVariable.LIMITED_TO_VALUES));
} else if (StoredVariable.RANGE_VARIABLE_CONSTRAINT.equals(result.constraintType)) {
deserializeRangeProperties(result, object);
}
result.dataType = dataType;
result.key = object.getAsJsonPrimitive(StoredVariable.KEY).getAsString();
result.title = object.getAsJsonPrimitive(StoredVariable.TITLE).getAsString();
return result;
}
private void deserializeRangeProperties(StoredVariable<SerializableType> result, JsonObject object) {
result.minValue = parseValue(object.getAsJsonPrimitive(StoredVariable.MIN_VALUE));
result.maxValue = parseValue(object.getAsJsonPrimitive(StoredVariable.MAX_VALUE));
result.increment = parseValue(object.getAsJsonPrimitive(StoredVariable.INCREMENT));
}
private void deserializeLimitedToValues(
StoredVariable<SerializableType> result, JsonElement limitedToValuesElement) {
if (limitedToValuesElement != null) {
JsonArray array = limitedToValuesElement.getAsJsonArray();
result.limitedToValues = new ArrayList<>();
for (JsonElement arrayElement : array) {
result.limitedToValues.add(parseValue(arrayElement));
}
}
}
/**
* Serializes a StoredVariable into a JsonElement.
*/
public JsonElement serialize(StoredVariable<SerializableType> src) {
JsonObject object = new JsonObject();
object.add(StoredVariable.KEY, new JsonPrimitive(src.key));
object.add(StoredVariable.TITLE, new JsonPrimitive(src.title));
object.add(StoredVariable.DATA_TYPE, new JsonPrimitive(src.dataType));
object.add(StoredVariable.SELECTED_VALUE, valueToJson(src.selectedValue));
object.add(StoredVariable.CONSTRAINT_TYPE, new JsonPrimitive(src.constraintType));
if (StoredVariable.ITEM_LIST_VARIABLE_CONSTRAINT.equals(src.constraintType)) {
JsonArray limitedToValues = new JsonArray();
for (SerializableType item : src.limitedToValues) {
limitedToValues.add(valueToJson(item));
}
object.add(StoredVariable.LIMITED_TO_VALUES, limitedToValues);
}
if (StoredVariable.RANGE_VARIABLE_CONSTRAINT.equals(src.constraintType)) {
object.add(StoredVariable.MIN_VALUE, valueToJson(src.minValue));
object.add(StoredVariable.MAX_VALUE, valueToJson(src.maxValue));
object.add(StoredVariable.INCREMENT, valueToJson(src.increment));
}
return object;
}
/**
* Creates a StoredVariable that represents the data in {@code variable} if {@code item} is of
* this type.
* @throws IllegalArgumentException if {@code item} does not match this type.
*/
@SuppressWarnings("unchecked")
public StoredVariable<SerializableType> fromVariable(Variable<?> var) {
if (var.getDataType().getName().equals(dataType)) {
StoredVariable<SerializableType> storage = new StoredVariable<>();
storage.setDataType(dataType);
storage.setSelectedValue(fromRuntimeType((RuntimeType) var.getSelectedValue()));
if (var instanceof ItemListVariable) {
ArrayList<SerializableType> possibleValues = new ArrayList<>();
for (RuntimeType value : ((ItemListVariable<RuntimeType>) var).getLimitedToValues()) {
possibleValues.add(fromRuntimeType(value));
}
storage.setLimitedToValues(possibleValues);
}
return storage;
}
throw new IllegalArgumentException(
"Passed an incompatible object to convert to StoredVariable for type " + dataType);
}
}