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 javax.swing.SpringLayout;

import net.sourceforge.ganttproject.GPLogger;
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.DefaultEnumerationOption;
import net.sourceforge.ganttproject.gui.options.model.DefaultIntegerOption;
import net.sourceforge.ganttproject.gui.options.model.DefaultStringOption;
import net.sourceforge.ganttproject.gui.options.model.EnumerationOption;
import net.sourceforge.ganttproject.gui.options.model.GPOption;
import net.sourceforge.ganttproject.gui.options.model.GPOptionGroup;
import net.sourceforge.ganttproject.gui.options.model.IntegerOption;
import net.sourceforge.ganttproject.gui.options.model.ValidationException;
import net.sourceforge.ganttproject.gui.taskproperties.EditableList.SelectionListener;
import net.sourceforge.ganttproject.task.DurationParsingException;
import net.sourceforge.ganttproject.task.Task;
import net.sourceforge.ganttproject.task.TaskLength;
import net.sourceforge.ganttproject.task.TaskManager;
import net.sourceforge.ganttproject.task.TaskMutator;
import net.sourceforge.ganttproject.task.dependency.MutableTaskDependencyCollection;
import net.sourceforge.ganttproject.task.dependency.TaskDependency;
import net.sourceforge.ganttproject.task.dependency.TaskDependencyCollection;
import net.sourceforge.ganttproject.task.dependency.TaskDependencyCollectionMutator;
import net.sourceforge.ganttproject.task.dependency.TaskDependencyConstraint;
import net.sourceforge.ganttproject.task.dependency.TaskDependencyException;
import net.sourceforge.ganttproject.task.dependency.TaskDependencySlice;
import net.sourceforge.ganttproject.task.dependency.TaskDependency.Hardness;

/**
 * @author Dmitry.Barashev
 */
public class TaskDependenciesPanel implements IPropertySheetComponent {
    private boolean isCollapsed;
    private boolean isHidden;
    private Task myTask;
    private TaskDependencyCollectionMutator myMutator;
    private GPOptionGroup myOptionGroup;

    public JComponent getComponent() {
        //return constructResourcesPanel(getTask().getAssignmentCollection());
        MutableTaskDependencyCollection fakeCollection = 
            myTask.getManager().getDependencyCollection().createMutator();
        List<TaskDependency> allDeps = new ArrayList<TaskDependency>();
        for (Task task : myTask.getManager().getTasks()) {
            try {
                allDeps.add(fakeCollection.createDependency(myTask, task));
            } catch (TaskDependencyException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        
        myMutator = myTask.getManager().getDependencyCollection().createMutator();
        TaskDependencySlice dependenciesAsDependant = myTask.getDependenciesAsDependant();
        List<TaskDependency> dependeeTasks = new ArrayList<TaskDependency>(
                Arrays.asList(dependenciesAsDependant.toArray())); 
        EditableList<TaskDependency> deps = new EditableList<TaskDependency>(
                dependeeTasks, allDeps) {
            @Override
            protected TaskDependency createValue(TaskDependency prototype) {
                try {
                    return myMutator.createDependency(myTask, prototype.getDependee());
                } catch (TaskDependencyException e) {
                    e.printStackTrace();
                    return null;
                }
            }
            @Override
            protected void deleteValue(TaskDependency value) {
                myMutator.deleteDependency(value);
            }
            @Override
            protected TaskDependency updateValue(TaskDependency newValue, TaskDependency curValue) {
                try {
                    TaskDependency result = myMutator.createDependency(myTask, newValue.getDependee());
                    result.setConstraint(curValue.getConstraint());
                    result.setHardness(curValue.getHardness());
                    result.setDifference(curValue.getDifference());
                    myMutator.deleteDependency(curValue);
                    return result;
                } catch (TaskDependencyException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                return null;
            }
            @Override
            protected String getStringValue(TaskDependency dep) {
                return dep.getDependee().getName();
            }
        };
        
        JComponent fieldsComponent = createFieldsComponent(deps);
        ListAndFieldsPanel<TaskDependency> panel= new ListAndFieldsPanel<TaskDependency>(deps, fieldsComponent);
        return panel.getComponent();
    }

    private JComponent createFieldsComponent(EditableList<TaskDependency> deps) {
        IPropertySheetBuilder builder = new OptionsPageBuilder();
        final LagOption lagOption = createLagOption();
        final TypeOption typeOption = createTypeOption();
        final HardnessOption hardnessOption = createHardnessOption();
        myOptionGroup = new GPOptionGroup(
                "taskProperties.dependencies.main", 
                new GPOption[] {typeOption, hardnessOption, lagOption}
        );
        myOptionGroup.lock();
        final JComponent result = builder.buildPlanePage(myOptionGroup);
        deps.addSelectionListener(new SelectionListener<TaskDependency>() {
            public void selectionChanged(TaskDependency dep) {
                myOptionGroup.commit();
                if (dep==null) {
                    UIUtil.setEnabledTree(result, false);
                }
                else {
                    UIUtil.setEnabledTree(result, true);
                    lagOption.reloadValue(dep);
                    hardnessOption.reloadValue(dep);
                    typeOption.reloadValue(dep);
                }
                myOptionGroup.lock();
            }
        });
        
        return result;
    }

    private HardnessOption createHardnessOption() {
        return new HardnessOption();
    }

    private TypeOption createTypeOption() {
        return new TypeOption();
    }

    
    static class HardnessOption extends DefaultEnumerationOption {
        static List<String> ourValues = new ArrayList<String>();
        static {
            ourValues.add("Strong");
            ourValues.add("Rubber");
        }       

        private TaskDependency myDep;
        public HardnessOption() {
            super("taskProperties.dependencies.hardness", ourValues);
        }
        @Override
        public void commit() {
            super.commit();
            String value = getValue();
            myDep.setHardness(TaskDependency.Hardness.parse(value));
        }        
        private void reloadValue(TaskDependency dep) {
            myDep = dep;
            super.setValue(dep.getHardness().getIdentifier(), true);
        }
    }
    
    static class TypeOption extends DefaultEnumerationOption {
        private TaskDependency myDep;
        public TypeOption() {
            super("taskProperties.dependencies.type", TaskDependencyConstraint.Type.values());
        }
        @Override
        public void commit() {
            super.commit();
            String value = getValue();
            myDep.setConstraint(getManager().createConstraint(TaskDependencyConstraint.Type.valueOf(value)));
        }
        private TaskManager getManager() {
            return myDep.getDependant().getManager();
        }
        @Override
        public void setValue(String value) {
            super.setValue(value);
        }
        private void reloadValue(TaskDependency dep) {
            myDep = dep;
            super.setValue(
                    TaskDependencyConstraint.Type.getType(dep.getConstraint()).toString(), 
                    true);
        }
        
    }
    class LagOption extends DefaultStringOption {
        private TaskDependency myDep;
        LagOption() {
            super("taskProperties.dependencies.lag");
        }

        public void reloadValue(TaskDependency dep) {
            super.setValue(getTask().getManager().encode(dep.getLag()), true);
            myDep = dep;
        }
        public void setValue(String value) {
            try {
                TaskLength taskLength = getTask().getManager().createLength(value);
                if (taskLength==null) {
                    throw new ValidationException();
                }
            }
            catch(DurationParsingException e) {
                throw new ValidationException(e);
            }
            super.setValue(value);
        }
        public void commit() {
            super.commit();
            try {
                TaskLength taskLength = getTask().getManager().createLength(getValue());
                myDep.setDifference((int) taskLength.getLength());
            }
            catch (RuntimeException e) {
                GPLogger.log(e);
            }
        }
        
    }
    private LagOption createLagOption() {
        return new LagOption();
    }

    private Task getTask() {
        return myTask;
    }
    
    public void onCommit() {
        myOptionGroup.commit();
        myMutator.commit();
    }
    public void onRollback() {
        // TODO Auto-generated method stub
        
    }

    public String getPageName() {
        return "Dependencies";
        //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) {
        myTask = task;
    }

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

    public String getTitle() {
        return "Dependencies";
    }

    public boolean isCollapsed() {
        return isCollapsed;
    }

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

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