/*
* 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.IncompatibleRemixerItemsWithSameKeyException;
import com.google.android.libraries.remixer.Variable;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
/**
* A copy of the Remixer data structure in an easily serializable form.
*
* <p>This representation discards any runtime details (number of variables with the same key,
* callbacks, etc) to just focus on data. This object will be serialized to Json and back to get the
* full status of Remixer across the entire app.
*/
public class SerializableRemixerContents {
/**
* Mapping from variable key to the variable's representation in Serializable format.
*
* <p>Notice that while {@link com.google.android.libraries.remixer.Remixer#keyMap} contains more
* than one item per key, all of those items contain the same data (same value for variables), so
* we only keep one of them here.
*
* <p>This is never used for anything other than storage and syncing. It is meant as a
* serializable copy of {@link com.google.android.libraries.remixer.Remixer}. When adding
* variables, the value should be synced to whatever is already stored here, or copied here if it
* does not exist.
*/
private Map<String, StoredVariable> keyToDataMap;
public SerializableRemixerContents() {
keyToDataMap = new HashMap<>();
}
/**
* Adds an item to the map, converting it to a StoredVariable.
*
* <p>It only keeps one per key, as explained in {@link #keyToDataMap}
*/
public void addItem(Variable item) {
addItem(StoredVariable.fromVariable(item));
}
/**
* Adds an item to the map.
*
* <p>It only keeps one per key, as explained in {@link #keyToDataMap}
*/
public void addItem(StoredVariable item) {
StoredVariable existingItem = keyToDataMap.get(item.key);
if (existingItem == null) {
keyToDataMap.put(item.key, item);
} else if (!existingItem.isCompatibleWith(item)) {
throw new IncompatibleRemixerItemsWithSameKeyException(
String.format(
Locale.getDefault(),
"Two variables with the same key, %s, have incompatible configurations "
+ "(data types %s, %s)",
item.key,
existingItem.dataType,
item.dataType));
}
// If it is already there and compatible we need to do nothing here. The syncing mechanism needs
// to sync the value across different instances though.
}
public Set<String> keySet() {
return keyToDataMap.keySet();
}
public StoredVariable getItem(String key) {
return keyToDataMap.get(key);
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null || getClass() != obj.getClass()) {
return false;
}
SerializableRemixerContents serializableRemixerContents = (SerializableRemixerContents) obj;
return keyToDataMap.equals(serializableRemixerContents.keyToDataMap);
}
@Override
public int hashCode() {
return keyToDataMap.hashCode();
}
/**
* Sets the value for the StoredVariable with key {@code variable.getKey()}. Must be called only
* after calling {@link #addItem(Variable)} or {@link #addItem(StoredVariable)} for a variable
* with this key.
*/
@SuppressWarnings("unchecked")
public void setValue(Variable variable) {
StoredVariable storedVariable = StoredVariable.fromVariable(variable);
setValue(storedVariable);
}
/**
* Sets the value for the StoredVariable with key {@code storedVariable.key}. Must be called only
* after calling {@link #addItem(Variable)} or {@link #addItem(StoredVariable)} for a variable
* with this key.
*/
public void setValue(StoredVariable storedVariable) {
StoredVariable existingStoredVariable = keyToDataMap.get(storedVariable.key);
if (!existingStoredVariable.isCompatibleWith(storedVariable)) {
throw new IncompatibleRemixerItemsWithSameKeyException(
String.format(
Locale.getDefault(),
"Setting value for key %s using incompatible variable. Existing data type is: %s, "
+ "new value data type is: %s",
storedVariable.key,
existingStoredVariable.dataType,
storedVariable.dataType));
}
existingStoredVariable.selectedValue = storedVariable.selectedValue;
}
}