/***************************************************************************
 * 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.ImageIcon;
import javax.swing.JComponent;
import javax.swing.JMenuItem;
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.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.TreePath;

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.UIFacade;
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.HumanResourceManager;
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.task.Task;
import net.sourceforge.ganttproject.task.TaskNode;
import net.sourceforge.ganttproject.util.BrowserControl;

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

    private final ResourceTreeTableModel model;

    private final ResourceTreeTable table;

    public final GanttProject appli;

    private GanttLanguage lang = GanttLanguage.getInstance();

    private JScrollBar vbar;

    private ResourceActionSet myResourceActionSet;

    public 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) {
        	DefaultMutableTreeNode[] selectedNodes = table.getSelectedNodes();
        	if (selectedNodes.length!=1) {
        		return;
        	}
        	if (selectedNodes[0] instanceof ResourceNode) {
        		getResourcePropertiesAction().actionPerformed(null);
        	}
        	else if (selectedNodes[0] instanceof AssignmentNode) {
        		AssignmentNode assignmentNode = (AssignmentNode) selectedNodes[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(), model);

        setLayout(new BorderLayout());

        GanttImagePanel but = new GanttImagePanel("big.png", 300, 42);
        myImagePanel = but;
        left = new JPanel(new BorderLayout());
        table.setRowHeight(20);
        left.add(but, "North");
        left.setBackground(new Color(102, 153, 153));
        
        scrollpane = new JScrollPane();
        setLayout(new BorderLayout());
        add(scrollpane, BorderLayout.CENTER);
        scrollpane.getViewport().add(table);
        scrollpane
                .setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_NEVER);

        vbar = table.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);
        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();
            }
        });
        left.add(jp, BorderLayout.WEST);

        vbar.addAdjustmentListener(new GanttAdjustmentListener());

        left.add(scrollpane, "Center");

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

        area = new ResourceLoadGraphicArea(prj, prj
                .getZoomManager()) {
            protected int getHeaderHeight() {
                return myImagePanel.getHeight()
                        + table.getTable().getTableHeader().getHeight();
            }

            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());
        if (lang.getComponentOrientation() == ComponentOrientation.LEFT_TO_RIGHT) {
            mySplitPane.setLeftComponent(left);
            mySplitPane.setRightComponent(area);
        } else {
            mySplitPane.setRightComponent(left);
            mySplitPane.setLeftComponent(area);
            mySplitPane.setDividerLocation((int) (Toolkit.getDefaultToolkit()
                    .getScreenSize().getWidth() - left.getPreferredSize()
                    .getWidth()));

        }
        mySplitPane.setOneTouchExpandable(true);
        mySplitPane.setPreferredSize(new Dimension(800, 500));

        add(mySplitPane, BorderLayout.CENTER);
        scrollpane.getViewport().setBackground(new Color(1.0f, 1.0f, 1.0f));
        left.setBackground(new Color(1.0f, 1.0f, 1.0f));
        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) {
                handlePopupTrigger(e);
            }

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

            public void mouseClicked(MouseEvent e) {
                e.consume();
                
                TreePath selPath = table.getTreeTable().getPathForLocation(
                        e.getX(), e.getY());
                if (selPath != null) {
                    table.getTreeTable().getTree().setSelectionPath(selPath);
                }
                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().getParent().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) {
        	DefaultMutableTreeNode[] selectedNodes = table.getSelectedNodes();
        	if (selectedNodes.length==0) {
        		return;
        	}
        	if (selectedNodes.length==1 && selectedNodes[0] instanceof AssignmentNode) {
        		AssignmentNode assignmentNode = (AssignmentNode) selectedNodes[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() - scrollpane.getHorizontalScrollBar().getValue()
        + (vbar.isVisible() ? vbar.getWidth() : 0);
    	final int y = popupTriggerEvent.getY() + table.getRowHeight() +
        + myImagePanel.getHeight();
    	return new Point(x,y);
    }
    /* Create the popup menu */
    private void createPopupMenu(MouseEvent e) {
        JPopupMenu menu = new JPopupMenu();
        AbstractAction[] resourceActions = myResourceActionSet.getActions();
        menu.add(myResourcePropertiesAction);
        for (int i = 0; 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;
        model.changeLanguage(lang);
    }

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

    public void resourcesRemoved(ResourceEvent event) {
        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;
        DefaultMutableTreeNode[] tNodes = table.getSelectedNodes();
        if (tNodes==null) {
        	return new ProjectResource[0];
        }
        int nbProjectResource = 0;
        for (int i = 0; i < tNodes.length; i++)
            if (tNodes[i] instanceof ResourceNode)
                nbProjectResource++;

        res = new ProjectResource[nbProjectResource];
        for (int i = 0; i < nbProjectResource; i++)
            if (tNodes[i] instanceof ResourceNode)
                res[i] = (ProjectResource) ((ResourceNode) tNodes[i])
                        .getUserObject();
        return res;
    }

    /**
     * Listener when scrollbar move
     */
    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) {
            DefaultMutableTreeNode 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()!=null && table.getSelectedNodes().length>0)
    	{
    		HumanResource people = (HumanResource) table.getSelectedNodes()[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;
        DefaultMutableTreeNode[] tNodes = table.getSelectedNodes();
        if (tNodes != null) {
            int nbAssign = 0;
            for (int i = 0; i < tNodes.length; i++)
                if (tNodes[i] instanceof AssignmentNode)
                    nbAssign++;

            res = new ResourceAssignment[nbAssign];
            for (int i = 0; i < nbAssign; i++)
                if (tNodes[i] instanceof AssignmentNode)
                    res[i] = (ResourceAssignment) ((AssignmentNode) tNodes[i])
                            .getUserObject();
        }
        return res;
    }

    public void setDividerLocation(int location) {
        mySplitPane.setDividerLocation(location);
    }

    public int getDividerLocation() {
        return mySplitPane.getDividerLocation();
    }

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

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

    public void projectClosed() {
        area.repaint();
        reset();
    }
    
    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;
    	}
    }
    
    public void saveSelectionToClipboard(boolean cut)
    {
    	DefaultMutableTreeNode selectedNodes[] = this.table.getSelectedNodes();
    	
    	if(selectedNodes == null)
    		return;
    		
    	/*count instances of ResourceNode*/
    	int count=0;
    	for(int i=0; i<selectedNodes.length; i++)
    	{
    		if(selectedNodes[i] instanceof ResourceNode)
    		{
    			count++;
    		}
    	}
    	
    	this.clipboard = new ProjectResource[count];
    	
    	int index=0;
    	for(int i=0; i<selectedNodes.length; i++)
    	{
    		if(selectedNodes[i] instanceof ResourceNode)
    		{
    			ResourceNode rn = (ResourceNode)selectedNodes[i];
    			
    			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 this;
    }

    public Action getResourcePropertiesAction() {
    	return myResourcePropertiesAction;
    }
    
    void setTaskPropertiesAction(Action action) {
    	myTaskPropertiesAction = action;
    }
    
    private Action getTaskPropertiesAction() {
    	return myTaskPropertiesAction;
    }
    
    private UIFacade getUIFacade() {
    	return myUIFacade;
    }
}
