/*
* Copyright (c) 2017 OBiBa. All rights reserved.
*
* This program and the accompanying materials
* are made available under the terms of the GNU Public License v3.0.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.obiba.magma.datasource.hibernate.converter;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import javax.annotation.Nullable;
import org.obiba.magma.Category;
import org.obiba.magma.MagmaRuntimeException;
import org.obiba.magma.Variable;
import org.obiba.magma.Variable.Builder;
import org.obiba.magma.datasource.hibernate.domain.CategoryState;
import org.obiba.magma.datasource.hibernate.domain.VariableState;
public class VariableConverter extends AttributeAwareConverter implements HibernateConverter<VariableState, Variable> {
public static VariableConverter getInstance() {
return new VariableConverter();
}
private VariableConverter() {
}
@Nullable
public VariableState getStateForVariable(Variable variable, HibernateMarshallingContext context) {
for(VariableState state : context.getValueTable().getVariables()) {
if (state == null) continue; //MAGMA-255
if(state.getName().equals(variable.getName())) return state;
}
return null;
}
@Override
public VariableState marshal(Variable magmaObject, HibernateMarshallingContext context) {
VariableState variableState = getStateForVariable(magmaObject, context);
if(variableState == null) {
variableState = new VariableState(context.getValueTable(), magmaObject);
context.getValueTable().getVariables().add(variableState);
} else {
variableState.copyVariableFields(magmaObject);
}
if(variableState.getValueType() != magmaObject.getValueType()) {
throw new MagmaRuntimeException(
"Changing the value type of a variable is not supported. Cannot modify variable '" + magmaObject.getName() +
"' in table '" + context.getValueTable().getName() + "'");
}
setAttributes(magmaObject, variableState);
marshalCategories(magmaObject, variableState);
variableState.setUpdated(new Date());
return variableState;
}
private void marshalCategories(Variable variable, VariableState variableState) {
// Make sure the ordering of the categories is correct
int categoryIndex = 0;
for(Category category : variable.getCategories()) {
CategoryState categoryState;
int currentCategoryIndex = variableState.getCategoryIndex(category.getName());
if(currentCategoryIndex == -1) {
// Category does not exist
categoryState = new CategoryState(category.getName(), category.getCode(), category.isMissing());
variableState.addCategory(categoryIndex, categoryState);
} else {
categoryState = variableState.getCategories().get(currentCategoryIndex);
if(categoryIndex != currentCategoryIndex) {
// Swap their positions
CategoryState previousCategory = variableState.getCategories().set(categoryIndex, categoryState);
variableState.getCategories().set(currentCategoryIndex, previousCategory);
}
}
categoryState.setMissing(category.isMissing());
categoryState.setUpdated(new Date());
setAttributes(category, categoryState);
categoryIndex++;
}
// Remaining categories needs to be deleted
deleteRemainingCategories(variableState, categoryIndex);
}
private void deleteRemainingCategories(VariableState variableState, int categoryIndex) {
int nbCategories = variableState.getCategories().size();
if(categoryIndex < nbCategories) {
Collection<CategoryState> toDelete = new ArrayList<>();
for(int i = categoryIndex; i < nbCategories; i++) {
toDelete.add(variableState.getCategories().get(i));
}
variableState.getCategories().removeAll(toDelete);
}
}
@Override
public Variable unmarshal(VariableState jpaObject, @Nullable HibernateMarshallingContext context) {
Variable.Builder builder = Variable.Builder
.newVariable(jpaObject.getName(), jpaObject.getValueType(), jpaObject.getEntityType());
builder.mimeType(jpaObject.getMimeType()).occurrenceGroup(jpaObject.getOccurrenceGroup())
.referencedEntityType(jpaObject.getReferencedEntityType()).unit(jpaObject.getUnit())
.index(jpaObject.getIndex());
if(jpaObject.isRepeatable()) {
builder.repeatable();
}
buildAttributeAware(builder, jpaObject);
unmarshalCategories(builder, jpaObject);
return builder.build();
}
private void unmarshalCategories(Builder builder, VariableState variableState) {
for(CategoryState categoryState : variableState.getCategories()) {
Category.Builder categoryBuilder = Category.Builder.newCategory(categoryState.getName())
.withCode(categoryState.getCode()).missing(categoryState.isMissing());
buildAttributeAware(categoryBuilder, categoryState);
builder.addCategory(categoryBuilder.build());
}
}
}