/***************************************************************************
 * 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.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.AdjustmentEvent;
import java.awt.event.AdjustmentListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.List;
import java.util.Enumeration;
import java.util.Vector;

import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.BorderFactory;
import javax.swing.ImageIcon;
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.ListSelectionModel;
import javax.swing.border.EtchedBorder;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.TreePath;
import javax.swing.DefaultListModel;

import net.sourceforge.ganttproject.action.GPAction;
import net.sourceforge.ganttproject.action.ResourceActionSet;
import net.sourceforge.ganttproject.gui.GanttDialogInfo;
import net.sourceforge.ganttproject.gui.GanttDialogPerson;
import net.sourceforge.ganttproject.gui.ResourceTreeUIFacade;
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.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");
        }        
    };
    
    public GanttResourcePanel(GanttProject prj, GanttTree2 tree) {
        super();
        prj.addProjectEventListener(this);
        appli = prj;
        model = new ResourceTreeTableModel(appli.getHumanResourceManager());
        table = new ResourceTreeTable(model);

        setLayout(new BorderLayout());

        GanttImagePanel but = new GanttImagePanel("big.png", null, 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, tree, table.getTable(), prj
                .getZoomManager()) {
            protected int getHeaderHeight() {
                return myImagePanel.getHeight()
                        + table.getTableHeader().getHeight();
            }

            public boolean isExpanded(ProjectResource pr) {
                return getResourceTreeTable().isExpanded(pr);
            }
        };
        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 mouseClicked(MouseEvent e) {
                e.consume();
                
                TreePath selPath = table.getTreeTable().getPathForLocation(
                        e.getX(), e.getY());
                if (selPath != null)
                    table.getTreeTable().getTree().setSelectionPath(selPath);

                if (table.getSelectedNodes() == null
                        || table.getSelectedNodes()[0] instanceof ResourceNode) {
                    if (e.isPopupTrigger() || e.getClickCount() == 1
                            && e.getButton() == MouseEvent.BUTTON3) {
                        createPopupMenu(e.getX(), e.getY());
                    } else if (e.getClickCount() == 2
                            && e.getButton() == MouseEvent.BUTTON1) {
                        propertiesHuman(appli);
                    }
                }
            }
        };
        if (!prj.isOnlyViewer) {
            table.addMouseListener(ml);
            table.getTreeTable().getParent().addMouseListener(ml);
        }
    }

    public void setActions()
    {
    	table.setAction(appli.getCopyAction());
        table.setAction(appli.getPasteAction());
        table.setAction(appli.getCutAction());
    }
    
    /* Create the popup menu */
    public void createPopupMenu(int x, int y) {
        JPopupMenu menu = new JPopupMenu();
        AbstractAction[] resourceActions = myResourceActionSet.getActions();
        menu.add(appli.createNewItem(GanttProject.correctLabel(lang
                .getText("propertiesHuman")), "/icons/properties_16.gif"));
        for (int i = 0; i < resourceActions.length; i++) {
            menu.add(new JMenuItem(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.createNewItem(GanttProject.correctLabel(lang.getText("cut")), "/icons/cut_16.gif"));
        menu.add(appli.createNewItem(GanttProject.correctLabel(lang.getText("copy")), "/icons/copy_16.gif"));
        menu.add(appli.createNewItem(GanttProject.correctLabel(lang.getText("paste")), "/icons/paste_16.gif"));
        menu.applyComponentOrientation(lang.getComponentOrientation());
        menu.show(this, x - scrollpane.getHorizontalScrollBar().getValue()
                + (vbar.isVisible() ? vbar.getWidth() : 0), y
                + table.getRowHeight()
                + (new ImageIcon(getClass().getResource("/icons/big.png"))
                        .getIconHeight()));
    }

    /** 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());
    }
    
    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();

        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()));
        }
    }

    /** Edit the setting for this human */
    public void propertiesHuman(GanttProject parent) {
        DefaultMutableTreeNode[] tSelNodes = table.getSelectedNodes();
        if (tSelNodes != null && tSelNodes.length != 0) {
            Object selected = table.getSelectedNodes()[0].getUserObject();
            if (selected instanceof HumanResource) {
                HumanResource people = (HumanResource) selected;
                if (people != null) {
                    final GanttProject gp = parent;
                    final HumanResource hr = people;
                    // parent.getUndoManager().undoableEdit("Resource properties
                    // changed", new Runnable(){
                    // public void run() {
                    appli.getStatusBar().setFirstText(
                            GanttLanguage.getInstance().getText(
                                    "editingParameters"), 2000);
                    GanttDialogPerson dp = new GanttDialogPerson(appli.getUIFacade(), lang, hr);
                    dp.setVisible(true);
                    if (dp.result()) {
                        appli.setAskForSave(true);
                        // The model is updated automatically !
                    }
                    // }});
                }
            }
        }
    }

    /** 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() {
    	DefaultMutableTreeNode[] selectedNodes = table.getSelectedNodes();
    	if(selectedNodes==null)
    		return;
    	DefaultMutableTreeNode selectedNode = selectedNodes[0];
        if (selectedNode instanceof ResourceNode) {
            ResourceNode rn = (ResourceNode) selectedNode;
            int index = rn.getParent().getIndex(rn);
            if (index > 0) {
                HumanResource people = (HumanResource) table.getSelectedNodes()[0]
                        .getUserObject();
                HumanResourceManager resMan = (HumanResourceManager) appli
                        .getHumanResourceManager();
                resMan.up(index);
                model.moveUp(people);
            }
        }
    }

    /** Move down the selected resource */
    private void downResource() {
    	DefaultMutableTreeNode[] selectedNodes = table.getSelectedNodes();
    	if(selectedNodes==null)
    		return;
    	DefaultMutableTreeNode selectedNode = selectedNodes[0];
        if (selectedNode instanceof ResourceNode) {
            ResourceNode rn = (ResourceNode) selectedNode;
            int index = rn.getParent().getIndex(rn);
            if (index < rn.getParent().getChildCount() - 1) {
                HumanResource people = (HumanResource) table.getSelectedNodes()[0]
                        .getUserObject();
                HumanResourceManager resMan = (HumanResourceManager) appli
                        .getHumanResourceManager();
                resMan.down(index);
                model.moveDown(people);
            }
        }
    }

    /** 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();
    }

    public void setPeople(List list) {
        model.changePeople(list);
    }

    /** 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;
    }

}
