/***************************************************************************
 * HumanResourcePanel.java  -  description
 * -------------------
 * begin                : jun 2003
 * copyright            : to the world :)
 * email                : alexthomas(at)ganttproject.org
 ***************************************************************************/
/*******************************************************************************
 * * This program is free software; you can redistribute it and/or modify * it
 * under the terms of the GNU General Public License as published by * the Free
 * Software Foundation; either version 2 of the License, or * (at your option)
 * any later version. * *
 ******************************************************************************/
package net.sourceforge.ganttproject;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.ComponentOrientation;
import java.awt.Dimension;
import java.awt.Point;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.AdjustmentEvent;
import java.awt.event.AdjustmentListener;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.List;

import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.BorderFactory;
import javax.swing.JComponent;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JScrollBar;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.KeyStroke;
import javax.swing.ListSelectionModel;
import javax.swing.border.EtchedBorder;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.event.TreeExpansionEvent;
import javax.swing.event.TreeExpansionListener;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.TreePath;
import javax.swing.tree.TreeSelectionModel;

import org.jdesktop.swingx.treetable.DefaultMutableTreeTableNode;

import net.sourceforge.ganttproject.GanttTree2.GanttTreeExpansionListener;
import net.sourceforge.ganttproject.action.DeleteAssignmentAction;
import net.sourceforge.ganttproject.action.GPAction;
import net.sourceforge.ganttproject.action.ResourceActionSet;
import net.sourceforge.ganttproject.action.resource.ResourcePropertiesAction;
import net.sourceforge.ganttproject.gui.GanttDialogInfo;
import net.sourceforge.ganttproject.gui.ResourceTreeUIFacade;
import net.sourceforge.ganttproject.gui.TableHeaderUIFacade;
import net.sourceforge.ganttproject.gui.UIFacade;
import net.sourceforge.ganttproject.gui.zoom.ZoomEvent;
import net.sourceforge.ganttproject.gui.zoom.ZoomListener;
import net.sourceforge.ganttproject.language.GanttLanguage;
import net.sourceforge.ganttproject.resource.AssignmentContext;
import net.sourceforge.ganttproject.resource.AssignmentNode;
import net.sourceforge.ganttproject.resource.HumanResource;
import net.sourceforge.ganttproject.resource.ProjectResource;
import net.sourceforge.ganttproject.resource.ResourceContext;
import net.sourceforge.ganttproject.resource.ResourceEvent;
import net.sourceforge.ganttproject.resource.ResourceNode;
import net.sourceforge.ganttproject.resource.ResourceView;
import net.sourceforge.ganttproject.task.ResourceAssignment;
import net.sourceforge.ganttproject.util.BrowserControl;

public class GanttResourcePanel extends JPanel implements ResourceView,
        ResourceContext, AssignmentContext, ProjectEventListener, ResourceTreeUIFacade, ZoomListener {

    private final ResourceTreeTableModel model;

    public final ResourceTreeTable table;

    public final GanttProject appli;

    private GanttLanguage lang = GanttLanguage.getInstance();

    private JScrollBar vbar;

    private ResourceActionSet myResourceActionSet;

    public final ResourceLoadGraphicArea area;

    private JScrollPane scrollpane;

    private JPanel left;

    //private JPanel myImagePanel;

    private final ResourceContext myContext = (ResourceContext) this;

    //private JSplitPane mySplitPane = null;
    
    private ProjectResource [] clipboard = null;
    private boolean isCut = false;
    
    private final GPAction myMoveUpAction = new GPAction() {
        protected String getIconFilePrefix() {
            return "up_";
        }
        public void actionPerformed(ActionEvent e) {
            upResource();
        }
        protected String getLocalizedName() {
            return getI18n("upTask");
        }        
    };
    
    private GPAction myMoveDownAction = new GPAction() {
        protected String getIconFilePrefix() {
            return "down_";
        }
        public void actionPerformed(ActionEvent e) {
            downResource();
        }
        protected String getLocalizedName() {
            return getI18n("downTask");
        }        
    };
    private GPAction myPropertiesAction = new GPAction() {
        protected String getIconFilePrefix() {
            return "";
        }
        public void actionPerformed(ActionEvent e) {
            List<DefaultMutableTreeTableNode> selectedNodes = table.getSelectedNodes();
            if (selectedNodes.size()!=1) {
                return;
            }
            if (selectedNodes.get(0) instanceof ResourceNode) {
                getResourcePropertiesAction().actionPerformed(null);
            }
            else if (selectedNodes.get(0) instanceof AssignmentNode) {
                AssignmentNode assignmentNode = (AssignmentNode) selectedNodes.get(0);
                Mediator.getTaskSelectionManager().clear();
                Mediator.getTaskSelectionManager().addTask(assignmentNode.getTask());
                getTaskPropertiesAction().actionPerformed(null);
            }
        }
        protected String getLocalizedName() {
            return "";
        }            	
    };
    private final ListSelectionListener myContextListener;

    private final ResourcePropertiesAction myResourcePropertiesAction;

    private Action myTaskPropertiesAction;

    private final UIFacade myUIFacade;

    private final DeleteAssignmentAction myDeleteAssignmentAction;
    
    public GanttResourcePanel(final GanttProject prj, GanttTree2 tree, UIFacade uiFacade) {
        super();
        myUIFacade = uiFacade;
        myDeleteAssignmentAction = new DeleteAssignmentAction(
                prj.getProject().getHumanResourceManager(),
                (AssignmentContext)this, prj);
        
        prj.addProjectEventListener(this);
        appli = prj;
        model = new ResourceTreeTableModel(appli.getHumanResourceManager());
        table = new ResourceTreeTable(
                appli.getProject(), uiFacade, model, 
                tree.getTaskSelectionManager(), appli.getHumanResourceManager());
        table.setRowHeight(20);

//        setLayout(new BorderLayout());
//
//        scrollpane = new JScrollPane(table);
//        left = new JPanel(new BorderLayout());
////      
////
////      
////      
//
//      left.add(scrollpane, BorderLayout.CENTER);
////        setLayout(new BorderLayout());
////        add(scrollpane, BorderLayout.CENTER);
//        //scrollpane.getViewport().add(table);
//        scrollpane
//                .setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_NEVER);
////
//        vbar = scrollpane.getVerticalScrollBar();
//        final JPanel jp = new JPanel(new BorderLayout());
//        jp.add(vbar, BorderLayout.CENTER);
//        // jp.setBorder(BorderFactory.createEmptyBorder(2,1,2,0));
//        // jp.setBorder(BorderFactory.createBevelBorder(BevelBorder.LOWERED));
//        jp.setBorder(BorderFactory.createEtchedBorder(EtchedBorder.LOWERED));
//        jp.setVisible(false);
//        left.add(jp, BorderLayout.WEST);
//        vbar.addAdjustmentListener(new AdjustmentListener() {
//            public void adjustmentValueChanged(AdjustmentEvent e) {
//                if (table.getSize().getHeight() - 20 < e.getAdjustable()
//                        .getMaximum())
//                    jp.setVisible(true);
//                else
//                    jp.setVisible(false);
//                repaint();
//            }
//        });
//      vbar.addAdjustmentListener(new GanttAdjustmentListener());
//        table.getTree().addTreeExpansionListener(new TreeExpansionListener() {
//            public void treeCollapsed(TreeExpansionEvent event) {
//                updateScrollbar();
//            }
//
//            public void treeExpanded(TreeExpansionEvent event) {
//                updateScrollbar();
//            }
//
//            private void updateScrollbar() {
//                System.err.println("update scrollbar");
//                revalidate();
//                
//            }
//        });
//        

        // A splitpane is use
//        mySplitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT);

        area = new ResourceLoadGraphicArea(prj, prj
                .getZoomManager()) {
            public boolean isExpanded(ProjectResource pr) {
                return getResourceTreeTable().isExpanded(pr);
            }
            
            protected int getRowHeight(){
                return table.getRowHeight();
            }
        };
        prj.getZoomManager().addZoomListener(area.getZoomListener());
        area.getChartModel().setRowHeight(table.getRowHeight());
        
//        JPanel right =  new JPanel(new BorderLayout());
//        //scrollPane2 = new CustomScrollPane(area);   
//
//        setLayout(new BorderLayout());
//        //add(scrollPane2, BorderLayout.CENTER);
//        right.add(area, BorderLayout.CENTER);
   
        table.setBackground(new Color(1.0f, 1.0f, 1.0f));
        table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);

        this.setBackground(new Color(0.0f, 0.0f, 0.0f));
        applyComponentOrientation(lang.getComponentOrientation());

        table.addKeyListener(prj); // callback for keyboard pressed
        // Add listener for mouse click
        MouseListener ml = new MouseAdapter() {
            public void mousePressed(MouseEvent e) {
                TreePath selPath = table.getTreeTable().getPathForLocation(
                        e.getX(), e.getY());
                table.getTreeTable().getTreeSelectionModel().setSelectionPath(selPath);
                handlePopupTrigger(e);
            }

            public void mouseReleased(MouseEvent e) {
                handlePopupTrigger(e);
            }

            public void mouseClicked(MouseEvent e) {
                e.consume();
                if (e.getClickCount()==2 && e.getButton()==MouseEvent.BUTTON1) {
                    handleDoubleClick(e);
                }
                else {
                    handlePopupTrigger(e);
                }
            }
        };
        table.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, KeyEvent.ALT_DOWN_MASK), "properties");
        table.getActionMap().put("properties", myPropertiesAction);
        table.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_DELETE, 0), "delete");
        table.getActionMap().put("delete", myDeleteAssignmentAction);
        table.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(GPAction.getKeyStroke("newArtifact.shortcut")
                , "newHuman");
        table.getActionMap().put("newHuman", new AbstractAction() {
            public void actionPerformed(ActionEvent e) {
                prj.newHumanResource();
            }
        });
        if (!prj.isOnlyViewer) {
            table.addMouseListener(ml);
            table.getTreeTable().addMouseListener(ml);
        }
        myResourcePropertiesAction = new ResourcePropertiesAction(prj.getProject(), prj.getUIFacade()); 
        myContextListener = new ListSelectionListener() {
            public void valueChanged(ListSelectionEvent e) {
                myResourcePropertiesAction.setContext(getContext());
            }
        };
        table.getTable().getSelectionModel().addListSelectionListener(myContextListener);
    }

    public void setActions()
    {
        table.setAction(appli.getCopyAction());
        table.setAction(appli.getPasteAction());
        table.setAction(appli.getCutAction());
    }
    
    private void handlePopupTrigger(MouseEvent e) {
        if (e.isPopupTrigger() || e.getButton()==MouseEvent.BUTTON3) {
            List<DefaultMutableTreeTableNode> selectedNodes = table.getSelectedNodes();
            if (selectedNodes.size()==1 && selectedNodes.get(0) instanceof AssignmentNode) {
                AssignmentNode assignmentNode = (AssignmentNode) selectedNodes.get(0);
                Mediator.getTaskSelectionManager().clear();
                Mediator.getTaskSelectionManager().addTask(assignmentNode.getTask());
                Point popupPoint = getPopupMenuPoint(e);
                getUIFacade().showPopupMenu(this, new Action[] {getTaskPropertiesAction(), myDeleteAssignmentAction}, popupPoint.x, popupPoint.y);
            }
            else {
                createPopupMenu(e);
            }
        }    	
    }
    
    private void handleDoubleClick(MouseEvent e) {
        myPropertiesAction.actionPerformed(null);
    }

    private Point getPopupMenuPoint(MouseEvent popupTriggerEvent) {
        final int x = popupTriggerEvent.getX();
        final int y = popupTriggerEvent.getY();
        return new Point(x,y);
    }
    /* Create the popup menu */
    private void createPopupMenu(MouseEvent e) {
        JPopupMenu menu = new JPopupMenu();
        AbstractAction[] resourceActions = myResourceActionSet.getActions();
        menu.add(resourceActions[0]);
        if (table.getSelectedNodes().size() == 1) {
            menu.add(myResourcePropertiesAction);
            for (int i = 1; i < resourceActions.length; i++) {
                menu.add(resourceActions[i]);
            }
            menu.add(appli.createNewItem(GanttProject.correctLabel(lang
                    .getText("sendMail")), "/icons/send_mail_16.gif"));
            menu.addSeparator();
            menu.add(myMoveUpAction);
            menu.add(myMoveDownAction);
            menu.addSeparator();
            menu.add(appli.getCutAction());
            menu.add(appli.getCopyAction());
            menu.add(appli.getPasteAction());
        }
        menu.applyComponentOrientation(lang.getComponentOrientation());
        Point popupPoint = getPopupMenuPoint(e);
        menu.show(this, popupPoint.x, popupPoint.y);
    }

    /** Function called when the language is changed */
    public void refresh(GanttLanguage language) {
        lang = language;
    }

    public void resourceAdded(ResourceEvent event) {
        newHuman((HumanResource) event.getResource());
    }

    public void resourcesRemoved(ResourceEvent event) {
        table.getTable().editingStopped(new ChangeEvent(table.getTable()));
        model.deleteResources(event.getResources());
    }
    
    public void resourceChanged(ResourceEvent e) {
        model.resourceChanged(e.getResource());
        repaint();
    }

    public void resourceAssignmentsChanged(ResourceEvent e) {
        model.resourceAssignmentsChanged(e.getResources());
    }    
    
    // //////////////////////////////////////////////////////////////////////////
    // ResourceContext interface
    public ProjectResource[] getResources() {
        // ProjectResource[] res;
        // List allRes = model.getAllResouces();
        // res = new ProjectResource[allRes.size()];
        // model.getAllResouces().toArray(res);
        // return res;
        ProjectResource[] res;
        List<DefaultMutableTreeTableNode> tNodes = table.getSelectedNodes();
        if (tNodes.isEmpty()) {
            return new ProjectResource[0];
        }
        int nbProjectResource = 0;
        for (DefaultMutableTreeTableNode node : tNodes) {
            if (node instanceof ResourceNode) {
                nbProjectResource++;
            }
        }
        int i=0;
        res = new ProjectResource[nbProjectResource];
        for (DefaultMutableTreeTableNode node : tNodes) {
            if (node instanceof ResourceNode) {
                res[i++] = (ProjectResource)node.getUserObject();
            }
        }
        return res;
    }
    /**
     * Listener when scrollbar moves
     */
    public class GanttAdjustmentListener implements AdjustmentListener {
        public void adjustmentValueChanged(AdjustmentEvent e) {
            if (area != null) {
                area.setScrollBar(e.getValue());
                area.repaint();
            }
        }
    }

    /** Create a new Human */
    public void newHuman(HumanResource people) {
        if (people != null) {
            DefaultMutableTreeTableNode result = model.addResource(people);
            table.getTree().scrollPathToVisible(new TreePath(result.getPath()));
        }
    }

    /** Send an Email to the current resource */
    public void sendMail(GanttProject parent) {
        if(table != null && !table.getSelectedNodes().isEmpty())
        {
            HumanResource people = (HumanResource) table.getSelectedNodes().get(0).getUserObject();
            if (people != null) {
                try {
                    BrowserControl.displayURL("mailto:" + people.getMail());
                } catch (Exception e) {
                    System.err.println(e);
                }
            }
        }
        else
        {
            GanttDialogInfo gdi = new GanttDialogInfo(
                    appli, GanttDialogInfo.INFO,
                    GanttDialogInfo.YES_OPTION, GanttLanguage.getInstance()
                            .getText("msg26"),
                    GanttLanguage.getInstance().getText("sendMail"));
            gdi.show();    	
        }
    }

    /** Move up the selected resource */
    private void upResource() {
        table.upResource();
    }

    /** Move down the selected resource */
    private void downResource() {
        table.downResource();
    }

    /** Return the list of the person */
    public List getPeople() {
        return model.getAllResouces();
    }

    public ResourceTreeTable getResourceTreeTable() {
        return table;
    }

    public ResourceTreeTableModel getResourceTreeTableModel() {
        return model;
    }

    /** Return the number of people on the list */
    public int nbPeople() {
        return model.getAllResouces().size();
    }

    /** Reset all human... */
    public void reset() {
        model.reset();
    }

    public void setResourceActions(ResourceActionSet actionSet) {
        myResourceActionSet = actionSet;
    }

    public ResourceContext getContext() {
        return myContext;
    }

    public ResourceAssignment[] getResourceAssignments() {
        ResourceAssignment[] res = null;
        List<DefaultMutableTreeTableNode> tNodes = table.getSelectedNodes();
        if (!tNodes.isEmpty()) {
            int nbAssign = 0;
            for (DefaultMutableTreeTableNode node : tNodes) {
                if (node instanceof AssignmentNode) {
                    nbAssign++;
                }
            }
            res = new ResourceAssignment[nbAssign];
            for (int i = 0; i < nbAssign; i++) {
                if (tNodes.get(i) instanceof AssignmentNode) {
                    res[i] = (ResourceAssignment)tNodes.get(i).getUserObject();
                }
            }
        }
        return res;
    }

    public void projectModified() {
        // TODO Auto-generated method stub
        
    }

    public void projectSaved() {
        // TODO Auto-generated method stub
        
    }

    public void projectClosed() {
        area.repaint();
        reset();
    }
    
    public void projectWillBeOpened() {
    }
    public void projectOpened() {
    }

    public void copySelection()
    {
        this.saveSelectionToClipboard(false);
        this.isCut = false;
    }
    
    public void cutSelection()
    {
        this.saveSelectionToClipboard(true);
        this.isCut = true;
    }
    
    public void pasteSelection()
    {
        if(this.clipboard == null)
            return;
        
        for(int i=0; i<this.clipboard.length; i++)
        {
            if(this.isCut)
            {
                this.appli.getHumanResourceManager().add(this.clipboard[i]);
            }
            else
            {
                this.appli.getHumanResourceManager().add(clipboard[i].unpluggedClone());
            }
        }
        
        /*if the selection was cut, we clear the clipboard after pasting*/
        if(this.isCut)
        {
            this.isCut = false;
        }
        model.updateResources();
    }
    
    public void saveSelectionToClipboard(boolean cut)
    {
        List<DefaultMutableTreeTableNode> selectedNodes = this.table.getSelectedNodes();
        
        if(selectedNodes.isEmpty())
            return;
            
        /*count instances of ResourceNode*/
        int count=0;
        for(DefaultMutableTreeTableNode node : selectedNodes) {
            if(node instanceof ResourceNode) {
                count++;
            }
        }
        
        this.clipboard = new ProjectResource[count];
        
        int index=0;
        for(DefaultMutableTreeTableNode node : selectedNodes) {
            if(node instanceof ResourceNode) {
                ResourceNode rn = (ResourceNode)node;
                
                this.clipboard[index] = (HumanResource)rn.getUserObject();
                if(cut) {
                    this.appli.getHumanResourceManager().remove(this.clipboard[index], this.appli.getUndoManager());
                }                
                index++;
            }
        }
    }

    public Action getMoveUpAction() {
        return myMoveUpAction;
    }

    public Action getMoveDownAction() {
        return myMoveDownAction;
    }

    public Component getUIComponent() {
        return table;
    }
    
    public void zoomChanged(ZoomEvent e) {
    }
    public Action getResourcePropertiesAction() {
        return myResourcePropertiesAction;
    }
    
    void setTaskPropertiesAction(Action action) {
        myTaskPropertiesAction = action;
    }
    
    private Action getTaskPropertiesAction() {
        return myTaskPropertiesAction;
    }
    
    private UIFacade getUIFacade() {
        return myUIFacade;
    }

    public TableHeaderUIFacade getVisibleFields() {
        return table.getVisibleFields();
    }
}
