// Sample code file: OnlineUsersDlg.java

// Warning: This code has been marked up for HTML

/*
   Copyright (c) 2000 Novell, Inc.  All Rights Reserved.

   THIS WORK IS SUBJECT TO U.S. AND INTERNATIONAL COPYRIGHT LAWS AND TREATIES. 
   USE AND REDISTRIBUTION OF THIS WORK IS SUBJECT TO THE LICENSE AGREEMENT 
   ACCOMPANYING THE SOFTWARE DEVELOPMENT KIT (SDK) THAT CONTAINS THIS WORK. 
   PURSUANT TO THE SDK LICENSE AGREEMENT, NOVELL HEREBY GRANTS TO DEVELOPER A 
   ROYALTY-FREE, NON-EXCLUSIVE LICENSE TO INCLUDE NOVELL'S SAMPLE CODE IN ITS 
   PRODUCT. NOVELL GRANTS DEVELOPER WORLDWIDE DISTRIBUTION RIGHTS TO MARKET, 
   DISTRIBUTE, OR SELL NOVELL'S SAMPLE CODE AS A COMPONENT OF DEVELOPER'S 
   PRODUCTS. NOVELL SHALL HAVE NO OBLIGATIONS TO DEVELOPER OR DEVELOPER'S 
   CUSTOMERS WITH RESPECT TO THIS CODE. 
*/
 


package com.novell.Chat;

//The standard java imports
import java.awt.*;
import java.io.*;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.table.*;
import javax.swing.border.*;
import java.awt.event.*;
import java.util.Enumeration;
import java.util.Vector;
import java.util.Hashtable;
import java.util.ResourceBundle;
import java.text.MessageFormat;
import java.net.URL;

// ConsoleOne imports
import com.novell.application.console.snapin.*;
import com.novell.application.console.widgets.*;
import com.novell.application.console.util.objectentryselector.*;
import com.novell.utility.nmsgbox.*;
import com.novell.utility.localization.Loc;

// NDSNamespace & Common Library Imports
import com.novell.admin.common.exceptions.*;
import com.novell.admin.common.ui.*;

/**
 * Displays a dialog that allows the user to monitor who's online and who's
 * not.  This list of users can then be saved so the user doesn't have
 * to populate the list again the next time he logs in.
 */
public class OnlineUsersDlg extends JFrame implements ActionListener, KeyListener
{
    /**
     * Column indexes to the preferred user table.
     */
    public static final int ONLINE = 0;
    /**
     * Column indexes to the preferred user table.
     */
    public static final int NAME = 1;    
    /**
     * Column indexes to the preferred user table.
     */
    public static final int FULLNAME = 2;
       
    /**
     * The column headers to the table.
     */
    String[] headers = new String[]{Chat.chatRes.getString("On-Line Heading"), 
                                    Chat.chatRes.getString("User Name Heading"), 
                                    Chat.chatRes.getString("Distinguished Name Heading")};
    
    /**
     * The default column sizes.
     */
    int[] columnSizes = new int[]{(new Integer(Chat.chatRes.getString("Table column 1 Width"))).intValue(),
                                  (new Integer(Chat.chatRes.getString("Table column 2 Width"))).intValue(),
                                  (new Integer(Chat.chatRes.getString("Table column 3 Width"))).intValue()};
    
    /**
     * Our custom table model.
     */
    ChatTableModel tableModel = new ChatTableModel(headers, 0);
    
    /**
     * Reference to this user's ObjectEntry.  This is where the list of 
     * preferred users will be stored.
     */
    ObjectEntry userOE = null;
    
    /**
     * Maintains a list of the information known about each preferred user.
     */
    Vector userList = new Vector();
    
    /**
     * GUI Components
     */
    JPanel mainPanel = new JPanel();
        JTable userTable = new JTable(tableModel);
        JScrollPane userScrollPane = new JScrollPane(userTable);
        JPanel buttonPanel = new JPanel();
        JButton chatButton = new JButton();
        JButton addButton = new JButton();
        JButton removeButton = new JButton();
        JButton updateButton = new JButton();
        JButton saveButton = new JButton();
        JButton hideButton = new JButton();
        JPanel prefPanel = new JPanel();
        JLabel updateLabel = new JLabel(Chat.chatRes.getString("Update Frequency Label"));
        JLabel minLabel = new JLabel(Chat.chatRes.getString("mins"));
        NIntTextField timeText = new NIntTextField(2,1,60);
        JButton startButton = new JButton(Chat.chatRes.getString("Start Update Button"));
        Timer updateTimer = new Timer(5000, this);
        JLabel onLineLabel = new JLabel();
        JLabel offLineLabel = new JLabel();
        Checkbox audioBox = new Checkbox(Chat.chatRes.getString("Beep on Change Box"), true);
       
    /**
     * Constructor
     *
     * @param userOE The user's ObjectEntry where this list of users where be stored.
     */
        public OnlineUsersDlg(ObjectEntry userOE)
        {
            this.userOE = userOE;
            
                //Get the icon for the corner of the frame.             
                URL url = getClass().getResource("/com/novell/application/console/shell/resources/images/ConsoleOneIcon.gif");
                if(url != null)
        {
                    Image image = Toolkit.getDefaultToolkit().getImage(url);
                    if(image != null)
                        setIconImage(image);
                }
                
                //Construct the GUI
                setTitle(MessageFormat.format(Chat.chatRes.getString("Online Dialog Title"), new Object[]{userOE.getName()}));
                getContentPane().setLayout(new GridBagLayout());
                
                onLineLabel.setName("OnLine");
                onLineLabel.setIcon(Chat.getInstance().getIcon("OnLine"));
                onLineLabel.setHorizontalAlignment(JLabel.CENTER);
                offLineLabel.setName("OffLine");
                offLineLabel.setIcon(Chat.getInstance().getIcon("OffLine"));
                offLineLabel.setHorizontalAlignment(JLabel.CENTER);
                
                mainPanel.setBorder(new BevelBorder(BevelBorder.RAISED));
                mainPanel.setLayout(new GridBagLayout());
                getContentPane().add(mainPanel, new SimpleGridBagConstraints(0,0,2,1,1.0,1.0,java.awt.GridBagConstraints.CENTER,java.awt.GridBagConstraints.BOTH,new Insets(0,0,0,0),0,0));
                mainPanel.add(userScrollPane, new SimpleGridBagConstraints(0,0,1,1,1.0,1.0,java.awt.GridBagConstraints.CENTER,java.awt.GridBagConstraints.BOTH,new Insets(6,6,6,6),0,0));
                buttonPanel.setLayout(new GridLayout(6,1,0,6));
                mainPanel.add(buttonPanel, new SimpleGridBagConstraints(1,0,1,1,0.0,0.0,java.awt.GridBagConstraints.NORTH,java.awt.GridBagConstraints.NONE,new Insets(6,0,0,6),0,0));           
                Loc.setText(chatButton, Chat.chatRes.getString("Chat Button"));
                buttonPanel.add(chatButton);
                Loc.setText(addButton, Chat.chatRes.getString("Add User Button"));
                buttonPanel.add(addButton);
                Loc.setText(removeButton, Chat.chatRes.getString("Remove User Button"));
                buttonPanel.add(removeButton);
                Loc.setText(updateButton, Chat.chatRes.getString("Update Button"));
                buttonPanel.add(updateButton);
                Loc.setText(saveButton, Chat.chatRes.getString("Save List Button"));
                buttonPanel.add(saveButton);
                Loc.setText(hideButton, Chat.chatRes.getString("Hide Window Button"));
                buttonPanel.add(hideButton);            
                getContentPane().add(prefPanel, new SimpleGridBagConstraints(0,1,1,1,1.0,0.0,java.awt.GridBagConstraints.CENTER,java.awt.GridBagConstraints.HORIZONTAL,new Insets(0,0,6,0),0,0));
                prefPanel.setLayout(new GridBagLayout());       
                prefPanel.add(audioBox, new SimpleGridBagConstraints(0,0,1,1,0.0,0.0,java.awt.GridBagConstraints.WEST,java.awt.GridBagConstraints.NONE,new Insets(6,10,0,8),0,0));
                prefPanel.add(updateLabel, new SimpleGridBagConstraints(1,0,1,1,0.0,0.0,java.awt.GridBagConstraints.WEST,java.awt.GridBagConstraints.NONE,new Insets(6,10,0,8),0,0));
                timeText.setText("5");
                prefPanel.add(timeText, new SimpleGridBagConstraints(2,0,1,1,0.0,0.0,java.awt.GridBagConstraints.WEST,java.awt.GridBagConstraints.NONE,new Insets(6,0,0,3),0,0));
                prefPanel.add(minLabel, new SimpleGridBagConstraints(3,0,1,1,0.0,0.0,java.awt.GridBagConstraints.WEST,java.awt.GridBagConstraints.NONE,new Insets(6,0,0,10),0,0));
        getContentPane().add(startButton, new SimpleGridBagConstraints(1,1,1,1,0.0,0.0,java.awt.GridBagConstraints.EAST,java.awt.GridBagConstraints.NONE,new Insets(6,6,6,8),0,0));

                // Table prefs
                userTable.setAutoResizeMode(JTable.AUTO_RESIZE_LAST_COLUMN);
        userTable.setCellSelectionEnabled(false);
        userTable.setColumnSelectionAllowed(false);        
        
        TableColumnModel columnModel = userTable.getColumnModel();
        
        TableColumn column = columnModel.getColumn(ONLINE);
        column.setWidth(columnSizes[ONLINE]);
        column.setMaxWidth(columnSizes[ONLINE]);    
        column.setMinWidth(columnSizes[ONLINE]);    
        column.setResizable(false);
        column.setCellRenderer(new ChatTableCellRenderer());
                
        column = columnModel.getColumn(NAME);
        column.setWidth(columnSizes[NAME]);
        column.setMaxWidth(columnSizes[NAME]);
        column.setMinWidth(columnSizes[NAME]);
        column.setResizable(false);
        
        column = columnModel.getColumn(FULLNAME);
        column.setResizable(true);
        column.sizeWidthToFit();
        
        //Listeners
        startButton.addActionListener(this);
        timeText.addKeyListener(this);
        hideButton.addActionListener(this);
        addButton.addActionListener(this);              
                removeButton.addActionListener(this);   
                chatButton.addActionListener(this);             
                updateButton.addActionListener(this);
                saveButton.addActionListener(this);
                
                //Get the width and height of the pane from the resource bundle.
                int width = (new Integer(Chat.chatRes.getString("userScrollPane Width"))).intValue();
                int height = (new Integer(Chat.chatRes.getString("userScrollPane Height"))).intValue();
                userScrollPane.setMinimumSize(new Dimension(width,height));    
        userScrollPane.setPreferredSize(new Dimension(width,height));    
        userScrollPane.setSize(new Dimension(width,height));                    
                        
        pack();     
        
        startButton.setMinimumSize(chatButton.getSize());
        startButton.setPreferredSize(chatButton.getSize());
        startButton.setSize(chatButton.getSize());        
                
                this.setResizable(false);
                
                saveButton.setEnabled(false);
                
        
        //Get this user's list of preferred chat users
                String[] list = Chat.getInstance().getMultiValuedAttribute(userOE, Chat.ATTRIBUTE_USER_PREFS);
                
                if(list != null)
                {
                    for(int i = 0; i < list.length; i++)
                    {
                        try
                        {
                            //Add the user to the table
                            addUserToList(Chat.getInstance().getNDSNamespace().getObjectEntry(list[i]));
                        }
                catch(SPIException e)
                {
                    NSPIExceptionMsgBox msg = new NSPIExceptionMsgBox(Chat.getInstance().getShell(), e, MessageFormat.format(Chat.chatRes.getString("User Info Error"), new Object[]{list[i]}));
                    msg.show();  
                }
            }
                }                               
        }
        
        /**
         * Pulls the needed information from the user's object entry and
         * then puts it in the table.
         *
         * @param oe The user to add to the list.
         */
        void addUserToList(ObjectEntry oe)
        {
            if(oe != null)
            {
                ChatUser newUser = new ChatUser();              
                newUser.setObjectEntry(oe);             
                newUser.setFullName(Chat.getInstance().getNDSNamespace().getFullName(oe));
                newUser.setName(oe.getName());
                //newUser.setIPAddress(Chat.getInstance().getIPAddress(oe));                                
                String port = Chat.getInstance().getAttributeValueAsString(oe, Chat.ATTRIBUTE_USER_PORT);
                
                //If the ObjectEntry contains no port value, then a value of -1 will be set to the port.
                if(port != null)
                    newUser.setPort((new Integer(port).intValue()));
                else
                    newUser.setPort(-1);
                     
                //This list keeps a reference to the need information about this user.        
                userList.addElement(newUser);
                
                Object[] newRow = new Object[3];
                
                //A -1 means that the user isn't online.                    
                if(newUser.getPort() != -1)
                    newRow[ONLINE] = onLineLabel;
                else
                    newRow[ONLINE] = offLineLabel;
                                
                newRow[NAME] = newUser.getName();
                newRow[FULLNAME] = newUser.getFullName();
                                                        
                //The data will now be placed on the table.        
                tableModel.addRow(newRow);            
        }           
        }
        
        /**
         * Updates the information on the table about the users.
         */
        void updateList()
        {
            int row = -1;           
            Enumeration enum = userList.elements();
            
        while(enum.hasMoreElements())
        {
            row++;
                ChatUser user = (ChatUser)enum.nextElement();
                
                //Checks the port value to see if the user is online or not.
                String port = Chat.getInstance().getAttributeValueAsString(user.getObjectEntry(), Chat.ATTRIBUTE_USER_PORT);
                if(port != null)
                {
                    user.setPort((new Integer(port).intValue()));
                    
                    //Notify the user by a beep that someone has come on-line.
                    JLabel oldValue = (JLabel)tableModel.getValueAt(row, ONLINE);
                    if(oldValue != onLineLabel && audioBox.getState())                      
                        this.getToolkit().beep();
                    
                    tableModel.setValueAt(onLineLabel, row, ONLINE);
                }
                else
                {
                    user.setPort(-1);                                                   
                    tableModel.setValueAt(offLineLabel, row, ONLINE);
                }
        }                           
        }
        
        /**
         * Implementation of the ActionListener Interface.
         *
         * @param e The ActionEvent.
         */
        public void actionPerformed(ActionEvent e)
        {
            Object src = e.getSource();
            
            //Closes the window     
            if(src == hideButton)
            {
                this.dispose();   
            }       
            //Either starts or stops the update timer.
            else if(src == startButton)
            {
                if(startButton.getText().equals(Chat.chatRes.getString("Start Update Button")))
                {
                    updateTimer.setDelay(60000 * (new Integer(timeText.getText())).intValue()); 
                    updateTimer.start();
                    startButton.setText(Chat.chatRes.getString("Stop Update Button"));
                }
                else
                {
                    updateTimer.stop();
                    startButton.setText(Chat.chatRes.getString("Start Update Button"));  
                    if(timeText.getText().length() <= 0 && startButton.getText().equals(Chat.chatRes.getString("Start Update Button")))
                        startButton.setEnabled(false);
                    else
                        startButton.setEnabled(true);
                }                   
            }
            //Request to chat with the selected user.
            else if(src == chatButton)
            {
                int row = userTable.getSelectedRow();
                if(row >= 0)
                {
                ChatUser user = (ChatUser)userList.elementAt(row);
                if(user != null)            
                        Chat.getInstance().requestChat(user.getObjectEntry());   
                
                    this.requestFocus();
                }                               
            }
            //Called by both the update button and the update timer.
            else if(src == updateButton || src == updateTimer)
            {
                System.out.println("Updating");
                updateList();
            }
            //Adds a user to the list to monitor
            else if(src == addButton)
        {               
            ObjectEntry containerOE = userOE;                          
              
            // Must hand the OES a container ObjectEntry
            if(!containerOE.getObjectType().isContainer())
            {
                containerOE = containerOE.getParent();
            }
            // Setup filter to only allow selection of objects of type "User"
            String[] filter = new String[]{"User"};
              
            // Construct and launch the OES
            ObjectEntrySelector browser = new ObjectEntrySelector(this, containerOE, "", filter);
            browser.setRootSelectable(false);
                browser.show();
              
            // Fix JDK focus bug. 
            requestFocus();
            addButton.requestFocus();
           
                ObjectEntry[] items = browser.getSelectedObjectEntries();
                if (items != null)
                {              
                    addUserToList(items[0]);
                    this.requestFocus();
                    
                    saveButton.setEnabled(true);
                }
        }                    
        //Removes the selected user from the list.
        else if(src == removeButton)
        {
            saveButton.setEnabled(true);
            
            int row = userTable.getSelectedRow();
            userList.removeElementAt(row);
            
            tableModel.removeRow(row);
            this.requestFocus();
        }
        //Saves the users on the table to NDS
        else if(src == saveButton)
        {
            Hashtable tempTable = new Hashtable();
            
            Chat.getInstance().setAttributeValue(userOE, Chat.ATTRIBUTE_USER_PREFS, null, false);
    
            Enumeration enum = userList.elements();
            while(enum.hasMoreElements())
            {
                ChatUser user = (ChatUser)enum.nextElement();
                String name = user.getFullName();
                
                //This table helps to avoid saving duplicate users.
                if(!tempTable.contains(name))
                {
                    tempTable.put(name, "Temp");
                    Chat.getInstance().setAttributeValue(userOE, Chat.ATTRIBUTE_USER_PREFS, name, true);            
                }
            }    
            this.requestFocus();
            
            saveButton.setEnabled(false);
        }
        }
        
        /**
         * Implementation of the KeyListener interface.
         *
         * @param e The KeyEvent
         */
        public void keyReleased(KeyEvent e)     
        {
            if(timeText.getText().length() <= 0 && startButton.getText().equals(Chat.chatRes.getString("Start Update Button")))
                startButton.setEnabled(false);
            else
                startButton.setEnabled(true);       
        }
        public void keyTyped(KeyEvent e){}
        public void keyPressed(KeyEvent e){}
        
        /**
         * This is our custom TableModel.  It's purpose is to disallow editing.
         */
        class ChatTableModel extends DefaultTableModel
    {
        /**
         * Constructor
         *
         * @param columnNames The column headers.
         * @param numRows The number of row to start with.
         */
        public ChatTableModel(Object[] columnNames, int numRows)
        {
            super(columnNames, numRows);   
        }
        
        public boolean isCellEditable(int row, int column)
        {
            return false;
        }                
    }    
    
    /**
     * Provides the cell renderer that allows Labels to be displayed in the
     * table.
     */
    class ChatTableCellRenderer implements TableCellRenderer
    {
        public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column)
        {
            if(value instanceof JLabel)
                return (JLabel)value;
                
            return null;
        }
    }
}