/*
 * TimeTablePanel.java
 *
 * Created on 6. prosinec 2000, 10:55
 */

package timetable.gui;

import timetable.data.*;
import timetable.util.*;

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.dnd.*;
import java.awt.datatransfer.*;
import java.io.*;
/**
 *
 * @author  Administrator
 * @version 
 */
public class TimeTablePanel extends javax.swing.JPanel implements ActionListener {
    JPopupMenu menu;
    JCheckBoxMenuItem mPin;
    private OneTimeTablePanel selected=null;
    protected DNDActivityEngine dndEngine = null;
    public Activity selectedActivity;
    public static javax.swing.border.LineBorder BORDER_DEFAULT = new javax.swing.border.LineBorder(java.awt.Color.darkGray,1);
    public static javax.swing.border.LineBorder BORDER_PIN = new javax.swing.border.LineBorder(java.awt.Color.red,2);
    public static javax.swing.border.LineBorder BORDER_PIN_SELECTED = new javax.swing.border.LineBorder(java.awt.Color.blue,2);
    public static javax.swing.border.LineBorder BORDER_SELECTED = new javax.swing.border.LineBorder(java.awt.Color.blue,1);
    
    public static Color COLOR_DEFAULT = new Color(255,255,255);
    public static Color COLOR_HEAD = new Color(120,120,255);
    public static Color COLOR_SELECTED = new Color(130,130,255);
    public static Color COLOR_NULL = new Color(170,170,170);
    public static Color TEXT_NORMAL = new Color(0,0,0);
    public static Color BG_HARD = new Color(210,150,150);
    public static Color BG_SOFT = new Color(200,200,150);
    public static Color BG_SCH_SOFT = new Color(255,255,200);
        
    public Resource resource = null;
    public ResourceGroup resources=null;
    private Config config = null;
    private int slotsPerDay =0;
    private int days=0;
    private int slots=0;
    
    private TableLayout tableLayout;
    
    public void setConfig(Config config) throws TimetableException{
        this.config=config;
        days = config.getInt(Config.NR_DAYS);
        if (days==0) days=5;
        slots = config.getInt(Config.NR_SLOTS);
        slotsPerDay = slots/days;
    }
    
    public void addMenuItem(JMenuItem item) {
        menu.add(item);
    }

    public void setDNDEngine(DNDActivityEngine dndEngine) {
        this.dndEngine=dndEngine;
    }

    public void addMenuSeparator() {
        menu.add(new javax.swing.JPopupMenu.Separator());
    }

    /** Creates new TimeTablePanel */
    public TimeTablePanel(Config config) throws TimetableException{
        this.config = config;
        days = config.getInt(Config.NR_DAYS);
        if (days==0) days=5;
        slots = config.getInt(Config.NR_SLOTS);
        slotsPerDay = slots/days;
       
        menu = new JPopupMenu();
        mPin = new JCheckBoxMenuItem(Loc.get("timetable.gui.pin"));
        mPin.addActionListener(this);
        menu.add(mPin);
        
        tableLayout = new TableLayout();
        
        setLayout(tableLayout);
    }
    
    public TimeTablePanel(Config config,Resource resource) throws TimetableException {
        this(config);
        setResource(resource);
    }
    
    public TimeTablePanel(Config config,ResourceGroup resources) throws TimetableException {
        this(config);
        setResources(resources);
    }
    
    public void setResources(ResourceGroup resources) throws TimetableException {
        this.resources=resources;
        this.resource=null;
        tableLayout.setRows(resources.size()+2);
        tableLayout.setColumns(slots+1);
        int width=1;
        if (resources==null) return;
        for (int col=-1;col<slots;col++) {
            
            OneTimeTablePanel p = new OneTimeTablePanel((col>=0?(config.DAY_OF_WEEK[col/slotsPerDay]+" "+(col%slotsPerDay+1)):null),true);
            this.add(p,new Rectangle(col+1,0,1,1));
        };
        for (int row=0;row<resources.size();row++) {
            OneTimeTablePanel ph = new OneTimeTablePanel(resources.get(row).shortCut,false);
            this.add(ph, new Rectangle(0,row+1,1,1));
            for (int col=0;col<slots;){
                Activity a=resources.get(row).getActivityAt(col);
                if (a==null) width=1; else width=a.length;
                int s=col;
                if (width+col>=slots) {
                    width=slots-col;col=slots;
                } else col+=width;
                OneTimeTablePanel p = new OneTimeTablePanel(config,a,resources.get(row),s,width);
                this.add(p, new Rectangle(s+1,row+1,width,1));
            }
        }
        for (int col=-1;col<slots;col++) {
            OneTimeTablePanel p = new OneTimeTablePanel((col>=0?(config.DAY_OF_WEEK[col/slotsPerDay]+" "+(col%slotsPerDay+1)):null),true);
            this.add(p, new Rectangle(col+1,resources.size()+1,1,1));
        };
    }

    public void setResource(Resource resource) throws TimetableException {
        this.resource=resource;
        this.resources=null;
        this.removeAll();
        tableLayout.setRows(days+1);
        tableLayout.setColumns(slotsPerDay+1);
        int width=1;
        if (resource==null) return;
        for (int col=-1;col<slotsPerDay;col++) {
            OneTimeTablePanel p = new OneTimeTablePanel((col>=0?(" "+(col+1)):null),true);
            this.add(p, new Rectangle(col+1,0,1,1));
        };
        for (int row=0;row<days;row++) {
            OneTimeTablePanel ph = new OneTimeTablePanel(config.DAY_OF_WEEK[row],false);
            this.add(ph, new Rectangle(0,row+1,1,1));
            for (int col=0;col<slotsPerDay;){
                int c=col;
                int s=slotsPerDay*row+col;
                Activity a=resource.getActivityAt(s);
                if (a==null) width=1; else width=a.length;
                if (width+col>=slotsPerDay) {
                    width=slotsPerDay-col;
                    col=slotsPerDay;
                } else col+=width;
                OneTimeTablePanel p = new OneTimeTablePanel(config,a,resource,s,width);
                this.add(p, new Rectangle(c+1,row+1,width,1));
            }
        }
    }
    
    public void updateUI() {
//        System.out.println(">> UPDATE <<");
/*        try {
            updateResources();
            updateResource();
        } catch (Exception e) {
            System.err.println("Error: "+e);
        };*/
        super.updateUI();
    }

    public void actionPerformed(final java.awt.event.ActionEvent e) {
        if (e.getSource()==mPin) {
            ((OneTimeTablePanel)(menu.getInvoker())).changePin();
        };
    }
    
    public class OneTimeTablePanel extends JTextArea implements DropTargetListener,DragSourceListener, DragGestureListener    {
        private Config config;
        private Activity activity;
        private int slot;
        private boolean pin;
        private boolean pinIsChangable=false;
        protected Cursor cursor;
        protected DropTarget dropTarget = null;
        protected DragSource dragSource = null;
        
        public Activity getActivity() {
            return activity;
        }
        
        public OneTimeTablePanel(String text, boolean header) {
            setEditable(false);
//          setBackground(COLOR_DEFAULT);
            setAlignmentX(Component.CENTER_ALIGNMENT);
            setAlignmentY(Component.CENTER_ALIGNMENT);
            setBorder(BORDER_DEFAULT);
            int width=55;
            int height=55;
            if (text!=null) setText(" "+text); else width=30;
            if (header) height=20; else width=30;
            setPreferredSize(new java.awt.Dimension(width,height));
            setBackground(COLOR_HEAD);
            slot=-1;
        }

        public OneTimeTablePanel(Config config,Activity activity,Resource resource,int slot,int width) throws TimetableException {
            this.config=config;
            this.activity=activity;
            this.slot=slot;
            setEditable(false);
//          setBackground(COLOR_DEFAULT);
            setAlignmentX(Component.CENTER_ALIGNMENT);
            setAlignmentY(Component.CENTER_ALIGNMENT);
            setBorder(BORDER_DEFAULT);
                setPreferredSize(new java.awt.Dimension(55*width,55));
                if (activity==null) {
                    setText("");
                    if (resource==null) setBackground(COLOR_NULL);
                    else {
                        if (resource.getPreference().isHARD(slot)) setBackground(BG_HARD); else 
                            if (resource.getPreference().isSOFT(slot)) setBackground(BG_SOFT); else 
                                setBackground(COLOR_NULL);          
                    };
                } else {
                    java.lang.StringBuffer r=new java.lang.StringBuffer(" ");
                    if (!activity.canReschedule) setBorder(BORDER_PIN);
                    r.append(activity.shortCut);
                    for (int i=0;i<activity.selectedResources.size();i++)
                        if (activity.selectedResources.isGroup(i)) {
                            boolean isInGroup=false;
                            for (int k=0;k<activity.selectedResources.getResources(i).size();k++)
                                if (activity.selectedResources.getResources(i).get(k)==resource) isInGroup=true;
                            if (!isInGroup) {r.append("\n ");r.append(activity.selectedResources.getResources(i).shortCut);};
                        } else 
                            if (activity.selectedResources.getResource(i)!=resource) {r.append("\n ");r.append(activity.selectedResources.getResource(i).shortCut);};
                    setText(r.toString());
                    
                    int soft=0;
                    for (int i=0;i<activity.length;i++) {
                        int s=activity.start+i;
                        if (activity.getPreference().isSOFT(s)) soft++;
                        for (int j=0;j<activity.selectedResources.size();j++)
                            if (activity.selectedResources.isGroup(j)) 
                                for (int k=0;k<activity.selectedResources.getResources(j).size();k++) {
                                    if (activity.selectedResources.getResources(j).get(k)!=null && activity.selectedResources.getResources(j).get(k).getPreference().isSOFT(s)) soft++;
                                }
                            else
                                if (activity.selectedResources.getResource(j)!=null && activity.selectedResources.getResource(j).getPreference().isSOFT(s)) soft++;
                    };
                    if (soft>0)  setBackground(new Color(255,255,max2(0,255-30*soft))); else 
                        setBackground(COLOR_DEFAULT);
                    pin=!activity.canReschedule;
                    pinIsChangable=true;
                addMouseListener(new java.awt.event.MouseAdapter() {
                    public void mouseClicked(MouseEvent e) {
                        if ((e.getModifiers()&e.BUTTON3_MASK)>0 && pinIsChangable) {
                            mPin.setSelected(pin);
                            selectedActivity=((OneTimeTablePanel)e.getSource()).activity;
                            menu.show(OneTimeTablePanel.this,e.getX(),e.getY());
                        };
                        if ((e.getModifiers()&e.BUTTON1_MASK)>0) {
                            if (selected!=null) selected.setSelected(false);
                            selected=OneTimeTablePanel.this;
                            setSelected(true);
                        };
                    }
                });
                setBorder();
            }
            initDND();            
        }
        
        public void changePin() {
            pin=activity.canReschedule;
            activity.canReschedule=!activity.canReschedule;
            setBorder();
        }
        
        public void setSelected(boolean selected) {
            if (selected) {
                selectedActivity=activity;
                setBackground(COLOR_SELECTED);
/*                if (pin) setBorder(BORDER_PIN_SELECTED); else 
                    setBorder(BORDER_SELECTED);*/
            } else {
                if (activity==selectedActivity) selectedActivity=null;
/*                if (pin) setBorder(BORDER_PIN); else 
                    setBorder(BORDER_DEFAULT);*/
                    int soft=0;
                    for (int i=0;i<activity.length;i++) {
                        int s=activity.start+i;
                        if (activity.getPreference().isSOFT(s)) soft++;
                        for (int j=0;j<activity.selectedResources.size();j++)
                            if (activity.selectedResources.isGroup(j)) 
                                for (int k=0;k<activity.selectedResources.getResources(j).size();k++) {
                                    if (activity.selectedResources.getResources(j).get(k)!=null && activity.selectedResources.getResources(j).get(k).getPreference().isSOFT(s)) soft++;
                                }
                            else
                                if (activity.selectedResources.getResource(j)!=null && activity.selectedResources.getResource(j).getPreference().isSOFT(s)) soft++;
                    };
                    if (soft>0)  setBackground(new Color(255,255,max2(0,255-30*soft))); else 
                        setBackground(COLOR_DEFAULT);
            }
        }
        
        public void setBorder() {
            if (pin) setBorder(BORDER_PIN); else 
                setBorder(BORDER_DEFAULT);
            //setSelected(selected==this||getBorder()==BORDER_SELECTED||getBorder()==BORDER_PIN_SELECTED);
        }
        

        public void initDND() {
          cursor=this.getCursor();
          dropTarget = new DropTarget (this, this);
          dragSource = new DragSource();
          dragSource.createDefaultDragGestureRecognizer( this, DnDConstants.ACTION_MOVE, this);
        }

        public void dragOver(final java.awt.dnd.DropTargetDragEvent event) {
              if (slot>=0 && dndEngine.canDrop(slot+(((int)event.getLocation().getX()) / 55),activity,resource)) {
                  event.acceptDrag(DnDConstants.ACTION_MOVE);
                  this.setCursor(DragSource.DefaultMoveDrop);
              } else {
                  event.rejectDrag(); 
                  this.setCursor(DragSource.DefaultMoveNoDrop);
              }
        }
        
        public void dropActionChanged(final java.awt.dnd.DropTargetDragEvent p1) {
        }
        
        public void dragEnter(final java.awt.dnd.DropTargetDragEvent p1) {
        }
        
        public void drop(final java.awt.dnd.DropTargetDropEvent event) {
            if (slot>=0 && dndEngine.canDrop(slot+(((int)event.getLocation().getX()) / 55),activity,resource)) {
                dndEngine.drop(slot+(((int)event.getLocation().getX()) / 55),resource,this);
                //updateUI();
            } else {
                event.rejectDrop();
            }
        }
        
        public void dragExit(final java.awt.dnd.DropTargetEvent p1) {
            this.setCursor(cursor);
        }
        
        public void dragExit(final java.awt.dnd.DragSourceEvent p1) {
        }
        
        public void dragDropEnd(final java.awt.dnd.DragSourceDropEvent p1) {
            this.setCursor(cursor);
            dndEngine.done();            
        }
        
        public void dropActionChanged(final java.awt.dnd.DragSourceDragEvent p1) {
        }
        
        public void dragOver(final java.awt.dnd.DragSourceDragEvent p1) {
        }
        
        public void dragEnter(final java.awt.dnd.DragSourceDragEvent p1) {
        }
        
        public void dragGestureRecognized(final java.awt.dnd.DragGestureEvent event) {
            if (slot>=0 && dndEngine.canDrag(slot, activity,resource)) {
                StringSelection text = new StringSelection("DNDTable Drag & Drop Feature"); 
                cursor = this.getCursor();
                dragSource.startDrag (event, null, text, this);
                dndEngine.drag(slot,activity,this);
            }
        }
        
    }

    public static int max2(int a,int b) {return (a<b?b:a);}
    
}
/*
     public void setResources(ResourceGroup resources) throws TimetableException {
        this.resources=resources;
        this.resource=null;
        this.removeAll();
        tableLayout.setRows(resources.size()+2);
        tableLayout.setColumns(slots+1);
        int width=1;
        if (resources==null) return;
        for (int col=-1;col<slots;col++) {
            OneTimeTablePanel p = new OneTimeTablePanel((col>=0?(config.DAY_OF_WEEK[col/slotsPerDay]+" "+(col%slotsPerDay+1)):null),true);
            this.add(p,new Rectangle(col+1,0,1,1));
        };
        for (int row=0;row<resources.size();row++) {
            OneTimeTablePanel ph = new OneTimeTablePanel(resources.get(row).shortCut,false);
            this.add(ph, new Rectangle(0,row+1,1,1));
            for (int col=0;col<slots;){
                Activity a=resources.get(row).getActivityAt(col);
                if (a==null) width=1; else width=a.length;
                int s=col;
                if (width+col>=slots) {
                    width=slots-col;col=slots;
                } else col+=width;
                OneTimeTablePanel p = new OneTimeTablePanel(config,a,resources.get(row),s,width);
                this.add(p, new Rectangle(s+1,row+1,width,1));
            }
        }
        for (int col=-1;col<slots;col++) {
            OneTimeTablePanel p = new OneTimeTablePanel((col>=0?(config.DAY_OF_WEEK[col/slotsPerDay]+" "+(col%slotsPerDay+1)):null),true);
            this.add(p, new Rectangle(col+1,resources.size()+1,1,1));
        };
    }

    public void setResource(Resource resource) throws TimetableException {
        this.resource=resource;
        this.resources=null;
        this.removeAll();
        tableLayout.setRows(days+1);
        tableLayout.setColumns(slotsPerDay+1);
        int width=1;
        if (resource==null) return;
        for (int col=-1;col<slotsPerDay;col++) {
            OneTimeTablePanel p = new OneTimeTablePanel((col>=0?(" "+(col+1)):null),true);
            this.add(p, new Rectangle(col+1,0,1,1));
        };
        for (int row=0;row<days;row++) {
            OneTimeTablePanel ph = new OneTimeTablePanel(config.DAY_OF_WEEK[row],false);
            this.add(ph, new Rectangle(0,row+1,1,1));
            for (int col=0;col<slotsPerDay;){
                int c=col;
                int s=slotsPerDay*row+col;
                Activity a=resource.getActivityAt(s);
                if (a==null) width=1; else width=a.length;
                if (width+col>=slotsPerDay) {
                    width=slotsPerDay-col;
                    col=slotsPerDay;
                } else col+=width;
                OneTimeTablePanel p = new OneTimeTablePanel(config,a,resource,s,width);
                this.add(p, new Rectangle(c+1,row+1,width,1));
            }
        }
    }
*/