/*
* 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.reports;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import net.sf.jasperreports.engine.JRDataSource;
import net.sf.jasperreports.engine.JREmptyDataSource;
import net.sf.jasperreports.engine.data.JRBeanCollectionDataSource;
import org.libreplan.business.materials.daos.IMaterialCategoryDAO;
import org.libreplan.business.materials.daos.IMaterialDAO;
import org.libreplan.business.materials.entities.Material;
import org.libreplan.business.materials.entities.MaterialAssignment;
import org.libreplan.business.materials.entities.MaterialCategory;
import org.libreplan.business.materials.entities.MaterialStatusEnum;
import org.libreplan.business.orders.daos.IOrderDAO;
import org.libreplan.business.orders.daos.IOrderElementDAO;
import org.libreplan.business.orders.entities.Order;
import org.libreplan.business.orders.entities.OrderElement;
import org.libreplan.business.planner.daos.ITaskElementDAO;
import org.libreplan.business.planner.daos.ITaskSourceDAO;
import org.libreplan.business.planner.entities.TaskElement;
import org.libreplan.business.reports.dtos.TimeLineRequiredMaterialDTO;
import org.libreplan.business.scenarios.IScenarioManager;
import org.libreplan.business.scenarios.entities.Scenario;
import org.libreplan.web.security.SecurityUtils;
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;
import org.zkoss.ganttz.util.MutableTreeModel;
import org.zkoss.zul.TreeModel;
/**
* Susana Montes Pedreira <smontes@wirelessgalicia.com>
*/
@Service
@Scope(BeanDefinition.SCOPE_PROTOTYPE)
public class TimeLineRequiredMaterialModel implements
ITimeLineRequiredMaterialModel {
@Autowired
IOrderElementDAO orderElementDAO;
@Autowired
IOrderDAO orderDAO;
@Autowired
ITaskSourceDAO taskSourceDAO;
@Autowired
ITaskElementDAO taskElementDAO;
@Autowired
IMaterialDAO materialDAO;
@Autowired
private IMaterialCategoryDAO categoryDAO;
private Date startingDate;
private Date endingDate;
private List<MaterialAssignment> listMaterialAssignment = new ArrayList<MaterialAssignment>();
private MutableTreeModel<Object> allMaterialCategories = MutableTreeModel
.create(Object.class);
@Autowired
private IScenarioManager scenarioManager;
private List<Order> selectedOrders = new ArrayList<Order>();
private List<Order> allOrders = new ArrayList<Order>();
@Override
@Transactional(readOnly = true)
public void init() {
selectedOrders.clear();
allOrders.clear();
loadAllOrders();
}
private void loadAllOrders() {
allOrders = orderDAO.getOrdersByReadAuthorizationByScenario(
SecurityUtils.getSessionUserLoginName(),
scenarioManager.getCurrent());
Collections.sort(allOrders);
}
@Override
public List<Order> getOrders() {
return allOrders;
}
private void initializeOrderElements(List<OrderElement> orderElements) {
for (OrderElement each: orderElements) {
initializeOrderElement(each);
}
}
private void initializeOrderElement(OrderElement orderElement) {
orderElement.getName();
}
@Override
public void removeSelectedOrder(Order order) {
this.selectedOrders.remove(order);
}
@Override
public boolean addSelectedOrder(Order order) {
if (this.selectedOrders.contains(order)) {
return false;
}
this.selectedOrders.add(order);
return true;
}
@Override
public List<Order> getSelectedOrders() {
return selectedOrders;
}
private void reattachmentOrder(Order order) {
orderDAO.reattachUnmodifiedEntity(order);
initializeOrderElements(order.getAllOrderElements());
}
@Override
@Transactional(readOnly = true)
public JRDataSource getTimeLineRequiredMaterial(Date startingDate,
Date endingDate, MaterialStatusEnum status, List<Order> listOrders,
List<MaterialCategory> categories, List<Material> materials) {
List<Order> orders = listOrders;
if (listOrders.isEmpty()) {
orders = allOrders;
}
for (Order each : orders) {
reattachmentOrder(each);
}
Scenario currentScenario = scenarioManager.getCurrent();
for (Order each : orders) {
each.useSchedulingDataFor(currentScenario);
}
List<TimeLineRequiredMaterialDTO> result = filterConsult(startingDate,
endingDate, status, orders, categories, materials);
if (result != null && !result.isEmpty()) {
return new JRBeanCollectionDataSource(result);
} else {
return new JREmptyDataSource();
}
}
@Override
@Transactional(readOnly = true)
public List<TimeLineRequiredMaterialDTO> filterConsult(Date startingDate,
Date endingDate, MaterialStatusEnum status, List<Order> listOrders,
List<MaterialCategory> categories, List<Material> materials) {
this.startingDate = startingDate;
this.endingDate = endingDate;
listMaterialAssignment = materialDAO.getFilterMaterial(status,
listOrders, categories, materials);
loadDataMaterial();
List<TimeLineRequiredMaterialDTO> result = new ArrayList<TimeLineRequiredMaterialDTO>();
result = sort(filterAndCreateMaterialDTOs());
return result;
}
private List<TimeLineRequiredMaterialDTO> filterAndCreateMaterialDTOs() {
List<TimeLineRequiredMaterialDTO> result = new ArrayList<TimeLineRequiredMaterialDTO>();
for (MaterialAssignment material : listMaterialAssignment) {
OrderElement order = orderDAO.loadOrderAvoidingProxyFor(material
.getOrderElement());
// Load scheduling states
order.getSchedulingState();
TaskElement task = findTaskBy(material);
reloadTask(task);
Date startDate;
Date endDate;
if(task != null){
startDate = task.getStartDate();
endDate = task.getEndDate();
}else{
startDate = order.getInitDate();
endDate = order.getInitDate();
}
// check if the dates match
if(acceptDates(startDate,endDate)){
result.add(new TimeLineRequiredMaterialDTO(material, task,
startDate, order));
}
}
return result;
}
private void reloadTask(TaskElement task) {
if (task != null) {
task.getOrderElement().getName();
}
}
private void loadDataMaterial() {
for (MaterialAssignment material : listMaterialAssignment) {
material.getOrderElement().getName();
material.getMaterial().getCode();
}
}
private TaskElement findTaskBy(MaterialAssignment material) {
// look up into the order elements tree
TaskElement task = lookToUpAssignedTask(material);
if (task != null) {
return task;
}
// look down into the order elements tree
task = lookToDownAssignedTask(material);
if (task != null) {
return task;
}
// not exist assigned task
return null;
}
private TaskElement lookToUpAssignedTask(MaterialAssignment material) {
OrderElement current = material.getOrderElement();
while (current != null) {
if (current.isSchedulingPoint()) {
return current.getAssociatedTaskElement();
}
current = current.getParent();
}
return null;
}
private TaskElement lookToDownAssignedTask(MaterialAssignment material) {
OrderElement current = material.getOrderElement();
Date lessDate = null;
TaskElement resultTask = null;
for (OrderElement child : current.getAllChildren()) {
if (child.isSchedulingPoint()) {
TaskElement task = child.getAssociatedTaskElement();
if ((task != null)
&& ((lessDate == null) || (lessDate.after(task
.getStartDate())))) {
lessDate = task.getStartDate();
resultTask = task;
}
}
}
return resultTask;
}
private boolean acceptDates(Date startDate, Date endDate) {
if (startDate == null || endDate == null) {
return false;
}
return ((startDate.compareTo(startingDate) >= 0) && (endDate
.compareTo(endingDate) <= 0));
}
public List<TimeLineRequiredMaterialDTO> sort(
List<TimeLineRequiredMaterialDTO> list) {
List<TimeLineRequiredMaterialDTO> result = new ArrayList<TimeLineRequiredMaterialDTO>();
if ((list != null) && (!list.isEmpty())) {
result.add(list.get(0));
for (int i = 1; i < list.size(); i++) {
int j = 0;
while ((j < result.size())
&& isGreaterDate(result.get(j), list.get(i))) {
j++;
}
if (j >= result.size()) {
result.add(list.get(i));
} else {
result.add(j, list.get(i));
}
}
}
return result;
}
private boolean isGreaterDate(TimeLineRequiredMaterialDTO dto,
TimeLineRequiredMaterialDTO dtoToOrder) {
if (dto != null) {
return dto.getInitDate().after(dtoToOrder.getInitDate());
}
return true;
}
/**
* Operation to filter by categories and materials
*/
@Transactional(readOnly = true)
public TreeModel getAllMaterialCategories() {
if (allMaterialCategories.isEmpty()) {
feedTree(allMaterialCategories, categoryDAO.getAll());
}
return allMaterialCategories;
}
private void feedTree(MutableTreeModel<Object> tree,
List<MaterialCategory> materialCategories) {
for (MaterialCategory each : materialCategories) {
initializeMaterialCategory(each);
addCategory(tree, each);
}
}
private void initializeMaterials(Collection<Material> materials) {
for (Material each : materials) {
initializeMaterial(each);
}
}
protected void initializeMaterialCategories(
Collection<MaterialCategory> materialCategories) {
for (MaterialCategory each : materialCategories) {
initializeMaterialCategory(each);
}
}
protected void initializeMaterialCategory(MaterialCategory materialCategory) {
materialCategory.getName();
initializeMaterials(materialCategory.getMaterials());
initializeMaterialCategories(materialCategory.getSubcategories());
}
private void initializeMaterial(Material material) {
material.getDescription();
material.getCategory().getName();
}
/**
* Adds category to treeModel If category.parent is not in treeModel add it
* to treeModel recursively.
*/
private void addCategory(MutableTreeModel<Object> materialCategories,
MaterialCategory materialCategory) {
categoryDAO.reattach(materialCategory);
final MaterialCategory parent = materialCategory.getParent();
if (!materialCategories.contains(parent, materialCategory)) {
if (parent == null) {
materialCategories.addToRoot(materialCategory);
} else {
addCategory(materialCategories, parent);
materialCategories.add(parent, materialCategory);
}
addMaterials(materialCategories, materialCategory);
}
}
private void addMaterials(MutableTreeModel<Object> materialCategories,
MaterialCategory materialCategory) {
for (Material material : materialCategory.getMaterials()) {
materialCategories.add(materialCategory, material);
}
}
}