package com.dlsc.flexgantt.showcase.demo.relationships;

import java.awt.BorderLayout;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;

import javax.swing.JDialog;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.SwingUtilities;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

import com.dlsc.flexgantt.showcase.AbstractDemo;
import com.dlsc.flexgantt.showcase.DemoControlsPanel;
import com.dlsc.flexgantt.model.TimeSpan;
import com.dlsc.flexgantt.model.gantt.GanttChartModelEvent;
import com.dlsc.flexgantt.model.gantt.IGanttChartModelListener;
import com.dlsc.flexgantt.model.gantt.IRelationship;
import com.dlsc.flexgantt.model.scheduling.ConstraintViolationMessage;
import com.dlsc.flexgantt.model.scheduling.DefaultModelValidator;
import com.dlsc.flexgantt.model.scheduling.IConstraint;
import com.dlsc.flexgantt.model.scheduling.IModelValidator;
import com.dlsc.flexgantt.policy.IPolicyProvider;
import com.dlsc.flexgantt.policy.layer.DefaultConstraintPolicy;
import com.dlsc.flexgantt.policy.layer.IRelationshipPolicy;
import com.dlsc.flexgantt.swing.GanttChart;
import com.dlsc.flexgantt.swing.GanttChartFrame;
import com.dlsc.flexgantt.swing.IMessage;
import com.dlsc.flexgantt.swing.layer.system.IRelationshipSelectionModelListener;
import com.dlsc.flexgantt.swing.layer.system.RelationshipLayer;
import com.dlsc.flexgantt.swing.layer.system.RelationshipSelectionEvent;
import com.dlsc.flexgantt.swing.scheduling.ConstraintSettingsPanel;
import com.dlsc.flexgantt.swing.scheduling.ConstraintViolationMessageTable;

public class RelationshipDemo extends AbstractDemo implements
        IRelationshipSelectionModelListener, IGanttChartModelListener,
        ChangeListener {

    private IModelValidator validator = new DefaultModelValidator();

    private ConstraintSettingsPanel settingsPanel;
    private GanttChart gc;

    private JDialog dialog;

    public RelationshipDemo() {
        super("Relationships");
    }

    @Override
    public String[] getSourceCodeFileNames() {
        return new String[] { "RelationshipDemo", "RelationshipGanttChartModel" };
    }

    @Override
    public void run(boolean embedded) {
        RelationshipGanttChartModel model = new RelationshipGanttChartModel();
        model.addGanttChartModelListener(this);

        gc = createGanttChart(model);
        IPolicyProvider pp = gc.getLayerContainer().getPolicyProvider();
        pp.setPolicy(IRelationshipPolicy.class, new DefaultConstraintPolicy());

        TimeSpan span = new TimeSpan(2008, 0, 1, 2008, 2, 31);
        gc.setTimeSpan(span);

        JPanel controls = new DemoControlsPanel(this);
        settingsPanel = new ConstraintSettingsPanel(gc.getLayerContainer());
        settingsPanel.addChangeListener(this);
        controls.add(settingsPanel);

        RelationshipLayer rel = gc.getLayerContainer().getSystemLayer(
                RelationshipLayer.class);
        rel.getSelectionModel().addRelationshipSelectionModelListener(this);

        GanttChartFrame frame = createFrame("Relationships / Constraints", gc,
                embedded);
        frame.add(BorderLayout.EAST, controls);

        frame.setSize(1000, 800);
        frame.center();
        frame.setVisible(true);

        gc.expandAll();
        gc.optimizeColumnWidth();
        gc.resetToPreferredSizes();

        ConstraintViolationMessageTable messageTable = new ConstraintViolationMessageTable(
                gc.getLayerContainer());
        JScrollPane scrollPane = new JScrollPane(messageTable);

        dialog = new JDialog(frame);
        dialog.setLocationRelativeTo(settingsPanel);
        dialog.setTitle("Constraint Violations");
        dialog.add(scrollPane);
        dialog.setSize(400, 300);
    }

    @SuppressWarnings("unchecked")
    private void validateModel() {
        gc.clearMessages();
        List<IMessage> messages = validator.validate(gc.getModel());
        List<ConstraintViolationMessage> conMessages = new ArrayList<ConstraintViolationMessage>();
        conMessages
                .addAll((Collection<? extends ConstraintViolationMessage>) messages);
        Collections.sort(conMessages, new ConstraintViolationMessageComparator(
                gc.getTreeTable()));
        for (IMessage m : conMessages) {
            gc.addMessage(m);
        }

        if (conMessages.size() > 0) {
            dialog.setVisible(true);
        }
    }

    @Override
    public void ganttChartChanged(GanttChartModelEvent evt) {
        SwingUtilities.invokeLater(new Runnable() {

            @Override
            public void run() {
                validateModel();
            }
        });
    }

    @Override
    public void valueChanged(RelationshipSelectionEvent evt) {
        if (evt.getId().equals(
                RelationshipSelectionEvent.ID.RELATIONSHIPS_ADDED)) {
            IRelationship rel = evt.getRelationships().iterator().next();
            if (rel instanceof IConstraint) {
                settingsPanel.setConstraint((IConstraint) rel);
            }
        }
    }

    @Override
    public void stateChanged(ChangeEvent evt) {
        validateModel();
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new RelationshipDemo());
    }
}
