/*
* This file is part of LibrePlan
*
* Copyright (C) 2009-2010 Fundación para o Fomento da Calidade Industrial e
* Desenvolvemento Tecnolóxico de Galicia
* Copyright (C) 2010-2011 Igalia, S.L.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.libreplan.web.resources.criterion;
import static org.libreplan.web.I18nHelper._;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Set;
import org.apache.commons.lang3.Validate;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.libreplan.business.common.IntegrationEntity;
import org.libreplan.business.common.daos.IConfigurationDAO;
import org.libreplan.business.common.entities.EntityNameEnum;
import org.libreplan.business.common.exceptions.InstanceNotFoundException;
import org.libreplan.business.common.exceptions.ValidationException;
import org.libreplan.business.resources.daos.ICriterionDAO;
import org.libreplan.business.resources.daos.ICriterionTypeDAO;
import org.libreplan.business.resources.daos.IResourceDAO;
import org.libreplan.business.resources.entities.Criterion;
import org.libreplan.business.resources.entities.CriterionType;
import org.libreplan.business.resources.entities.ICriterionType;
import org.libreplan.business.resources.entities.Resource;
import org.libreplan.business.resources.entities.Worker;
import org.libreplan.web.common.IntegrationEntityModel;
import org.libreplan.web.common.concurrentdetection.OnConcurrentModification;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
/**
* Model for criterions. <br />
*
* @author Óscar González Fernández <ogonzalez@igalia.com>
* @author Diego Pino García <ogonzalez@igalia.com>
*/
@Service
@Scope(BeanDefinition.SCOPE_PROTOTYPE)
@OnConcurrentModification(goToPage = "/resources/criterions/criterions.zul")
public class CriterionsModel extends IntegrationEntityModel implements ICriterionsModel {
private static final Log log = LogFactory.getLog(CriterionsModel.class);
@Autowired
private ICriterionDAO criterionDAO;
@Autowired
private ICriterionTypeDAO criterionTypeDAO;
@Autowired
private IResourceDAO resourceDAO;
@Autowired
private IConfigurationDAO configurationDAO;
private CriterionType criterionType;
private Criterion criterion;
private ICriterionTreeModel criterionTreeModel;
@Override
@Transactional(readOnly = true)
public List<CriterionType> getTypes() {
return criterionTypeDAO.getCriterionTypes();
}
@Override
public ICriterionType<?> getCriterionType() {
return criterionType;
}
@Override
@Transactional(readOnly = true)
public Collection<Criterion> getCriterionsFor(ICriterionType<?> type) {
return criterionDAO.findByType(type);
}
@Override
public Criterion getCriterion() {
return criterion;
}
@Override
public ICriterionTreeModel getCriterionTreeModel() {
return criterionTreeModel;
}
@Override
@Transactional(readOnly=true)
public void prepareForCreate() {
this.criterionType = CriterionType.create("");
initializeCriterionTypeCode();
this.criterionTreeModel = new CriterionTreeModel(criterionType);
}
private void initializeCriterionTypeCode() {
boolean generateCode = configurationDAO.getConfiguration()
.getGenerateCodeForCriterion();
if (generateCode) {
setDefaultCode();
}
this.criterionType.setCodeAutogenerated(generateCode);
}
private void generateCriterionCodes() {
criterionTreeModel
.regenerateCodeForUnsavedCriteria(getNumberOfDigitsCode());
}
@Override
public void prepareForCreate(CriterionType criterionType) {
this.criterionType = criterionType;
this.criterion = (Criterion) criterionType
.createCriterionWithoutNameYet();
}
@Override
@Transactional(readOnly = true)
public void prepareForEdit(CriterionType criterionType) {
Validate.notNull(criterionType);
this.criterionType = getFromDB(criterionType);
this.criterionTreeModel = new CriterionTreeModel(this.criterionType);
initOldCodes();
}
@Override
@Transactional
public void confirmRemove(CriterionType criterionType) {
try {
criterionTypeDAO.remove(criterionType.getId());
} catch (InstanceNotFoundException e) {
throw new RuntimeException(e);
}
}
@Transactional(readOnly = true)
private CriterionType getFromDB(CriterionType criterionType) {
try {
return criterionTypeDAO.find(criterionType.getId());
} catch (InstanceNotFoundException e) {
throw new RuntimeException(e);
}
}
@Override
@Transactional(readOnly = true)
public ICriterionType<?> getTypeFor(Criterion criterion) {
for (ICriterionType<?> each : getTypes()) {
if (each.contains(criterion)) {
return each;
}
}
throw new RuntimeException(_("{0} not found type for criterion ", criterion));
}
@Override
@Transactional
public void saveCriterionType() throws ValidationException {
if (criterionType.isCodeAutogenerated()) {
generateCriterionCodes();
}
criterionTreeModel.saveCriterions(criterionType);
criterionTypeDAO.save(criterionType);
}
@Override
public boolean isEditing() {
return criterion != null;
}
@Override
@Transactional(readOnly = true)
public boolean isApplyableToWorkers(Criterion criterion) {
ICriterionType<?> type = getTypeFor(criterion);
return type != null && type.criterionCanBeRelatedTo(Worker.class);
}
@Override
@Transactional(readOnly = true)
public <T extends Resource> List<T> getResourcesSatisfyingCurrentCriterionOfType(
Class<T> klass) {
if (criterion == null) {
return new ArrayList<T>();
}
return getResourcesSatisfying(klass, criterion);
}
private <T extends Resource> List<T> getResourcesSatisfying(
Class<T> resourceType, Criterion criterion) {
Validate.notNull(resourceType, _("Resource type cannot be empty"));
Validate.notNull(criterion, _("Criterion cannot be empty"));
List<T> result = new ArrayList<T>();
for (T r : resourceDAO.list(resourceType)) {
if (criterion.isSatisfiedBy(r)) {
result.add(r);
}
}
return result;
}
@Override
@Transactional(readOnly = true)
public List<Worker> getAllWorkers() {
return resourceDAO.getWorkers();
}
@Override
public boolean getAllowHierarchy(){
return this.criterionType.allowHierarchy();
}
@Override
@Transactional(readOnly = true)
public void reloadCriterionType() {
this.criterionType = getFromDB(criterionType);
this.criterionTreeModel = new CriterionTreeModel(this.criterionType);
this.initOldCodes();
}
@Override
@Transactional(readOnly = true)
public int numberOfRelatedEntities(Criterion criterion) {
if (criterion.isNewObject()) {
return 0;
}
return criterionDAO.numberOfRelatedRequirements(criterion)
+ criterionDAO.numberOfRelatedSatisfactions(criterion);
}
@Override
@Transactional(readOnly = true)
public boolean isDeletable(Criterion criterion) {
return criterion.isNewObject()
|| (criterion.getChildren().isEmpty() && (numberOfRelatedEntities(criterion) == 0));
}
@Override
public void addForRemoval(Criterion criterion) {
criterionType.getCriterions().remove(criterion);
}
@Override
@Transactional(readOnly = true)
public boolean canRemove(CriterionType criterionType) {
reattachCriterions(criterionType);
for (Criterion each : criterionType.getCriterions()) {
if (numberOfRelatedEntities(each) != 0) {
return false;
}
}
return true;
}
private void reattachCriterions(CriterionType criterionType) {
criterionTypeDAO.reattach(criterionType);
criterionType.getCriterions().size();
}
public EntityNameEnum getEntityName() {
return EntityNameEnum.CRITERION;
}
public Set<IntegrationEntity> getChildren() {
return (Set<IntegrationEntity>) (criterionType != null ? criterionType
.getCriterions() : new ArrayList<IntegrationEntity>());
}
public IntegrationEntity getCurrentEntity() {
return this.criterionType;
}
}