/** * Copyright 2015 ArcBees 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.arcbees.gaestudio.client.application.entity.editor; import java.util.List; import java.util.Map; import java.util.Set; import javax.inject.Inject; import com.arcbees.gaestudio.client.application.visualizer.ParsedEntity; import com.arcbees.gaestudio.client.util.JsonUtils; import com.arcbees.gaestudio.shared.PropertyName; import com.arcbees.gaestudio.shared.PropertyType; import com.arcbees.gaestudio.shared.dto.entity.EntityDto; import com.google.common.base.Function; import com.google.common.collect.FluentIterable; import com.google.common.collect.Maps; import com.google.common.collect.Sets; import com.google.gwt.json.client.JSONBoolean; import com.google.gwt.json.client.JSONNull; import com.google.gwt.json.client.JSONObject; import com.google.gwt.json.client.JSONParser; import com.google.gwt.json.client.JSONString; import com.google.gwt.json.client.JSONValue; import com.google.inject.assistedinject.Assisted; import com.google.web.bindery.event.shared.EventBus; import com.gwtplatform.mvp.client.PresenterWidget; import static com.arcbees.gaestudio.client.application.entity.editor.EntityEditorPresenter.MyView; public class EntitiesEditorPresenter extends PresenterWidget<MyView> { private final JsonUtils jsonUtils; private final Set<ParsedEntity> parsedEntities; private final Map<String, PropertyType> allProperties; private final Map<String, JSONValue> commonValues; private final Map<String, PropertyEditor<?>> propertyEditors; private final Map<String, JSONValue> valuesPrototypes; private final Set<String> propertiesToIgnore; @Inject EntitiesEditorPresenter( EventBus eventBus, MyView view, PropertyEditorFactory propertyEditorFactory, JsonUtils jsonUtils, @Assisted Set<ParsedEntity> parsedEntities) { super(eventBus, view); this.jsonUtils = jsonUtils; this.parsedEntities = parsedEntities; allProperties = Maps.newLinkedHashMap(); commonValues = Maps.newHashMap(); propertyEditors = Maps.newLinkedHashMap(); valuesPrototypes = Maps.newHashMap(); propertiesToIgnore = Sets.newHashSet(); parseProperties(jsonUtils, parsedEntities); addEditors(propertyEditorFactory); } public List<EntityDto> flush() throws InvalidEntityFieldsException { for (Map.Entry<String, PropertyEditor<?>> editorEntry : propertyEditors.entrySet()) { String propertyKey = editorEntry.getKey(); JSONValue value = editorEntry.getValue().getJsonValue(); if (commonValueWasModified(propertyKey, value) || otherPropertyWasModified(propertyKey, value)) { for (ParsedEntity entity : parsedEntities) { JSONObject propertyMap = entity.getPropertyMap(); propertyMap.put(propertyKey, value); entity.getEntityDto().setJson(entity.getJson()); } } } return FluentIterable.from(parsedEntities) .transform(new Function<ParsedEntity, EntityDto>() { @Override public EntityDto apply(ParsedEntity input) { return input.getEntityDto(); } }).toList(); } private void parseProperties(JsonUtils jsonUtils, Set<ParsedEntity> parsedEntities) { Map<String, Integer> commonValuesCount = Maps.newHashMap(); for (ParsedEntity parsedEntity : parsedEntities) { for (String propertyKey : parsedEntity.propertyKeys()) { PropertyType propertyType = PropertyUtil.getPropertyType(parsedEntity.getProperty(propertyKey)); if (!PropertyType.KEY.equals(propertyType)) { allProperties.put(propertyKey, propertyType); JSONValue propertyValue = parsedEntity.getProperty(propertyKey); createPrototypeValue(propertyKey, propertyValue, allProperties.get(propertyKey)); checkIfCommonValue(jsonUtils, propertyKey, propertyValue, commonValuesCount); } } } cleanSingleValues(commonValuesCount); } private void cleanSingleValues(Map<String, Integer> commonValuesCount) { for (Map.Entry<String, Integer> commonValue : commonValuesCount.entrySet()) { if (commonValue.getValue() == 1) { commonValues.remove(commonValue.getKey()); } } } private void checkIfCommonValue(JsonUtils jsonUtils, String propertyKey, JSONValue propertyValue, Map<String, Integer> commonValuesCount) { if (!propertiesToIgnore.contains(propertyKey) && commonValues.containsKey(propertyKey)) { JSONValue currentValue = commonValues.get(propertyKey); if (!jsonUtils.compareObjects(currentValue, propertyValue)) { propertiesToIgnore.add(propertyKey); commonValues.remove(propertyKey); } else { commonValuesCount.put(propertyKey, commonValuesCount.get(propertyKey) + 1); } } else if (!propertiesToIgnore.contains(propertyKey)) { commonValues.put(propertyKey, propertyValue); commonValuesCount.put(propertyKey, 1); } } private void addEditors(PropertyEditorFactory propertyEditorFactory) { for (Map.Entry<String, PropertyType> propertyEntry : allProperties.entrySet()) { addEditor(propertyEditorFactory, valuesPrototypes, propertyEntry); } } private boolean otherPropertyWasModified(String propertyKey, JSONValue value) { return !commonValues.containsKey(propertyKey) && !jsonUtils.compareObjects(value, valuesPrototypes.get(propertyKey)); } private boolean commonValueWasModified(String propertyKey, JSONValue value) { return commonValues.containsKey(propertyKey) && !jsonUtils.compareObjects(value, commonValues.get(propertyKey)); } private void addEditor(PropertyEditorFactory propertyEditorFactory, Map<String, JSONValue> valuesPrototypes, Map.Entry<String, PropertyType> propertyEntry) { String key = propertyEntry.getKey(); JSONValue propertyValue = getPropertyValue(commonValues, valuesPrototypes, key); PropertyEditor<?> propertyEditor = propertyEditorFactory.create(key, propertyEntry.getValue(), propertyValue); getView().addPropertyEditor(propertyEditor); propertyEditors.put(key, propertyEditor); } private JSONValue getPropertyValue(Map<String, JSONValue> commonValues, Map<String, JSONValue> valuesPrototypes, String key) { JSONValue propertyValue; if (commonValues.containsKey(key)) { propertyValue = commonValues.get(key); } else { propertyValue = valuesPrototypes.get(key); } return propertyValue; } private void createPrototypeValue(String property, JSONValue propertyValue, PropertyType propertyType) { if (!valuesPrototypes.containsKey(property) || propertyType != null) { JSONObject prototype = JSONParser.parseStrict(propertyValue.toString()).isObject(); if (prototype == null) { prototype = new JSONObject(); prototype.put(PropertyName.GAE_PROPERTY_TYPE, new JSONString(PropertyType.STRING.name())); prototype.put(PropertyName.INDEXED, JSONBoolean.getInstance(false)); } prototype.put(PropertyName.VALUE, getDefaultPropertyValue(propertyType)); valuesPrototypes.put(property, prototype); } } private JSONValue getDefaultPropertyValue(PropertyType propertyType) { switch (propertyType) { case STRING: return new JSONString(""); default: return JSONNull.getInstance(); } } }