package net.sourceforge.ganttproject.gui.taskproperties;

import java.awt.BorderLayout;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import javax.swing.JComponent;
import javax.swing.JPanel;

import net.sourceforge.ganttproject.IGanttProject;
import net.sourceforge.ganttproject.gui.IPropertySheetBuilder;
import net.sourceforge.ganttproject.gui.UIFacade;
import net.sourceforge.ganttproject.gui.UIUtil;
import net.sourceforge.ganttproject.gui.options.OptionsPageBuilder;
import net.sourceforge.ganttproject.gui.options.model.DefaultBooleanOption;
import net.sourceforge.ganttproject.gui.options.model.DefaultEnumerationOption;
import net.sourceforge.ganttproject.gui.options.model.DefaultStringOption;
import net.sourceforge.ganttproject.gui.options.model.GPOption;
import net.sourceforge.ganttproject.gui.options.model.GPOptionGroup;
import net.sourceforge.ganttproject.gui.options.model.ValidationException;
import net.sourceforge.ganttproject.gui.taskproperties.EditableList.SelectionListener;
import net.sourceforge.ganttproject.language.GanttLanguage;
import net.sourceforge.ganttproject.resource.HumanResource;
import net.sourceforge.ganttproject.resource.HumanResourceManager;
import net.sourceforge.ganttproject.resource.ProjectResource;
import net.sourceforge.ganttproject.roles.Role;
import net.sourceforge.ganttproject.roles.RoleManager;
import net.sourceforge.ganttproject.task.ResourceAssignment;
import net.sourceforge.ganttproject.task.ResourceAssignmentCollection;
import net.sourceforge.ganttproject.task.ResourceAssignmentMutator;
import net.sourceforge.ganttproject.task.Task;
import net.sourceforge.ganttproject.task.TaskMutator;
import net.sourceforge.ganttproject.task.dependency.TaskDependency;

/**
 * @author Dmitry.Barashev
 */
public class TaskAllocationsPanel implements IPropertySheetComponent {
    private HumanResourceManager myHRManager;

    private RoleManager myRoleManager;

    private Task myTask;

    private boolean isCollapsed;

    private boolean isHidden;

    ResourceAssignmentMutator myMutator;

    private GPOptionGroup myOptionGroup;
    
    public TaskAllocationsPanel() {
    }

    public JComponent getComponent() {
        return constructResourcesPanel(getTask().getAssignmentCollection());
    }

    private Task getTask() {
        return myTask;
    }

    private JComponent constructResourcesPanel(final ResourceAssignmentCollection assignments) {
        List<ResourceAssignment> allAssignments = new ArrayList<ResourceAssignment>();
        ResourceAssignmentMutator fakeMutator = assignments.createMutator();
        for (ProjectResource resource : myHRManager.getResourcesArray()) {
            ResourceAssignment newAssignment = fakeMutator.addAssignment(resource);
            allAssignments.add(newAssignment);
        }
        
        myMutator = assignments.createMutator();
        List<ResourceAssignment> assignedResources = 
            new ArrayList<ResourceAssignment>(Arrays.asList(assignments.getAssignments()));
        EditableList<ResourceAssignment> list = new EditableList<ResourceAssignment>(
                assignedResources, allAssignments) {
                    @Override
                    protected String getStringValue(ResourceAssignment assignment) {
                        return assignment.getResource().getName();
                    }
                    @Override
                    protected ResourceAssignment createValue(ResourceAssignment prototype) {
                        ResourceAssignment newAssignment = myMutator.addAssignment(prototype.getResource());
                        newAssignment.setLoad(100);
                        newAssignment.setRoleForAssignment(
                                ((HumanResource) newAssignment.getResource()).getRole());
                        return newAssignment;
                    }
                    @Override
                    protected void deleteValue(ResourceAssignment value) {
                        myMutator.deleteAssignment(value.getResource());
                    }
                    @Override
                    protected ResourceAssignment updateValue(
                            ResourceAssignment prototype, ResourceAssignment curValue) {
                        ResourceAssignment newAssignment = createValue(prototype);
                        newAssignment.setLoad(curValue.getLoad());
                        newAssignment.setCoordinator(curValue.isCoordinator());
                        newAssignment.setRoleForAssignment(curValue.getRoleForAssignment());
                        
                        deleteValue(curValue);
                        return newAssignment;
                    }
        };
        JComponent fieldsComponent = createFieldsComponent(list);
        ListAndFieldsPanel<ResourceAssignment> panel = 
            new ListAndFieldsPanel<ResourceAssignment>(list, fieldsComponent);
        return panel.getComponent();
    }    
    
    private JComponent createFieldsComponent(EditableList<ResourceAssignment> list) {
        IPropertySheetBuilder builder = new OptionsPageBuilder();
        final ResourceLoadOption loadOption = new ResourceLoadOption();
        final CoordinatorOption coordinatorOption = new CoordinatorOption();
        final RoleOption roleOption = new RoleOption(myRoleManager);
        myOptionGroup = new GPOptionGroup(
                "taskProperties.assignment.main", 
                new GPOption[] {loadOption, coordinatorOption, roleOption}
        );
        myOptionGroup.lock();
        final JComponent result = builder.buildPlanePage(myOptionGroup);
        list.addSelectionListener(new SelectionListener<ResourceAssignment>() {
            public void selectionChanged(ResourceAssignment assignment) {
                myOptionGroup.commit();
                if (assignment==null) {
                    UIUtil.setEnabledTree(result, false);
                }
                else {
                    UIUtil.setEnabledTree(result, true);
                    loadOption.reloadValue(assignment);
                    coordinatorOption.reloadValue(assignment);
                    roleOption.reloadValue(assignment);
                }
                myOptionGroup.lock();
            }
        });
        return result;
    }
    
    class ResourceLoadOption extends DefaultStringOption {
        private ResourceAssignment myAssignment;
        ResourceLoadOption() {
            super("taskProperties.allocations.load", "       ");
        }
        @Override
        public void setValue(String value) {
            try {
                int parsedValue = Integer.parseInt(value);
                if (parsedValue<0 || parsedValue>100) {
                    throw new ValidationException("");
                }
            }
            catch(NumberFormatException e) {
                throw new ValidationException("", e);
            }
            super.setValue(value);
        }
        @Override
        public void commit() {
            super.commit();
            if (getValue()!=null && myAssignment!=null) {
                myAssignment.setLoad(Integer.parseInt(getValue()));
            }
        }
        void reloadValue(ResourceAssignment assignment) {
            if (assignment!=null) {
                super.setValue(String.valueOf((int)assignment.getLoad()), true);
            }
            myAssignment = assignment;
        }
    }
    class CoordinatorOption extends DefaultBooleanOption {
        private ResourceAssignment myAssignment;
        CoordinatorOption() {
            super("taskProperties.allocations.coordinator");
        }
        @Override
        public void commit() {
            super.commit();
            if (myAssignment!=null) {
                myAssignment.setCoordinator(isChecked());
            }		
        }
        void reloadValue(ResourceAssignment assignment) {
            if (assignment!=null) {
                super.setValue(assignment.isCoordinator());
            }
            myAssignment = assignment;
        }
    }
    class RoleOption extends DefaultEnumerationOption {
        private final RoleManager myRoleManager;
        private ResourceAssignment myAssignment;
        RoleOption(RoleManager roleManager) {
            super("taskProperties.allocations.role", roleManager.getEnabledRoles());
            myRoleManager = roleManager;
        }
        protected String objectToString(Object enumerationObject) {
            return ((Role)enumerationObject).getName();
        }
        @Override
        public void commit() {
            super.commit();
            if (myAssignment!=null) {
                myAssignment.setRoleForAssignment(findRole(getValue()));
            }		
        }
        private Role findRole(String value) {
            for (Role nextRole : myRoleManager.getEnabledRoles()) {
                if (value.equals(objectToString(nextRole))) {
                    return nextRole;
                }
            }
            return null;
        }
        void reloadValue(ResourceAssignment assignment) {
            if (assignment!=null) {
                Role role = assignment.getRoleForAssignment();
                if (role!=null) {
                    setValue(objectToString(role), true);
                }
            }
            myAssignment = assignment;
        }
    }
    
    public void onCommit() {
        myOptionGroup.commit();
        myMutator.commit();
        
    }
    public void onRollback() {
        // TODO Auto-generated method stub
        
    }

    public String getPageName() {
        return GanttLanguage.getInstance().getText("taskProperties.tab.resources.label");
        //return GanttLanguage.getInstance().getText("taskProperties.tab.general.label");
    }

    public void init(Task task, TaskMutator taskMutator, IGanttProject project, UIFacade uifacade) {
        myHRManager = project.getHumanResourceManager();
        myRoleManager = project.getRoleManager();
        myTask = task;
    }

    public Object getAdapter(Class adapter) {
        if (JComponent.class.equals(adapter)) {
            return getComponent();
        }
        return null;
    }

    public String getTitle() {
        return "Resource assignments";
    }

    public boolean isCollapsed() {
        return isCollapsed;
    }

    public void setCollapsed(boolean collapsed) {
        isCollapsed = collapsed;
    }
    public boolean isHidden() {
        return isHidden;
    }

    public void setHidden(boolean hidden) {
        isHidden = hidden;
    }
}
