www.pudn.com > java_chat.rar > ChatApplet.java


package at.ac.uni_linz.tk.vchat; 
 
import java.applet.*; 
import java.awt.*; 
import java.awt.image.*; 
import java.awt.event.*; 
import java.util.*; 
import java.io.*; 
import java.net.*; 
import symantec.itools.awt.*; 
 
 
/** 
 * Provides the Chat's main client functionality, it administrates users and takes 
 * control over UserEvents. The user interface shown in the applet area is the 
 * LoginPanel only, the ChatPanel is part of an own Frame (ChatFrame). 
 * 
 * @author      Arno Huetter 
 * (C)opyright by the Institute for Computer Science, Telecooperation Department, University of Linz 
 */ 
 
public class ChatApplet extends Applet implements ChatRepository, Runnable { 
 
  private LoginPanel loginPanel; 
  private ChatFrame chatFrame; 
  private ChatClient chatClient; 
 
  private Image[] moodIcon, defaultAvatar; 
  private Image emptyIcon, unknownIcon, defaultBackAvatar, imgSlider; 
 
  private IntegerHashtable userTable, roomTable, userRoomTable; 
  private int currentUserId; 
 
  private Date histDate, chatStartDate; 
  private boolean historyMode, chatRunning; 
  private String status; 
  private Simulator simulator; 
 
  private HistoryPanel pnlHistory; 
  private Hashtable hashHistory; 
  private Thread thrMoodTimeout; 
 
  private ImageCanvas logoCanvas; 
  private MediaTracker tracker; 
 
  public static String SERVER_POTRAIT_FILENAME[][] = { { "smiley6.gif", "smiley0.gif", "smiley1.gif", "smiley2.gif", "smiley3.gif", "smiley4.gif", "smiley5.gif" }, 
                                                             { "man1.gif", "man1.gif", "man1.gif", "man1.gif", "man1.gif", "man1.gif", "man1.gif" }, 
                                                             { "man2.gif", "man2.gif", "man2.gif", "man2.gif", "man2.gif", "man2.gif", "man2.gif" }, 
                                                             { "woman1.gif", "woman1.gif", "woman1.gif", "woman1.gif", "woman1.gif", "woman1.gif", "woman1.gif" }, 
                                                             { "woman2.gif", "woman2.gif", "woman2.gif", "woman2.gif", "woman2.gif", "woman2.gif", "woman2.gif" }, 
                                                             { "baghead.gif", "baghead.gif", "baghead.gif", "baghead.gif", "baghead.gif", "baghead.gif", "baghead.gif" }, 
                                                             { "teddy.gif", "teddy.gif", "teddy.gif", "teddy.gif", "teddy.gif", "teddy.gif", "teddy.gif" }, 
                                                             { "moonmask.gif", "moonmask.gif", "moonmask.gif", "moonmask.gif", "moonmask.gif", "moonmask.gif", "moonmask.gif" }, 
                                                             { "devilmask.gif", "devilmask.gif", "devilmask.gif", "devilmask.gif", "devilmask.gif", "devilmask.gif", "devilmask.gif" }, 
                                                             { "darkmask.gif", "darkmask.gif", "darkmask.gif", "darkmask.gif", "darkmask.gif", "darkmask.gif", "darkmask.gif" } 
                                                             }; 
  public static String SERVER_POTRAIT_NAME[] = { "Smiley", "Man 1", "Man 2", "Woman 1", "Woman 2", "Baghead", "Teddy", "Moon Mask", "Devil Mask", "Dark Mask" }; 
 
 
  private class AvatarParam { 
    public String name; 
    public String[] image = new String[ChatRepository.PREDEFINED_NR_OF_MOODS + 1]; 
  } 
 
 
  protected boolean getBooleanParam(String name, boolean defaultVal) { 
    return getParameter(name) == null ? defaultVal : new Boolean(getParameter(name)).booleanValue(); 
  } 
 
/** 
 * Initializes the ChatApplet. 
 */ 
 
 
 
  public void init() { 
    String param; 
    Vector avatars = new Vector(); 
    for (int i = 0; (param = getParameter("PredefinedAvatar[" + i + "]")) != null; i++) { 
        StringTokenizer tok = new StringTokenizer(param, ":"); 
        if (tok.countTokens() == 2) { 
            AvatarParam avatar = new AvatarParam(); 
            avatar.name = tok.nextToken(); 
            StringTokenizer tokAv = new StringTokenizer(tok.nextToken(), ","); 
            for (int j = 0; j <= ChatRepository.PREDEFINED_NR_OF_MOODS; j++) { 
                avatar.image[j] = tokAv.hasMoreTokens() ? tokAv.nextToken() : ( j > 1 ? avatar.image[1] : new String("")); 
            } 
            avatars.addElement(avatar); 
        } 
    } 
 
    if (avatars.size() > 0) { 
        SERVER_POTRAIT_NAME = new String[avatars.size()]; 
        SERVER_POTRAIT_FILENAME = new String[avatars.size()][ChatRepository.PREDEFINED_NR_OF_MOODS + 1]; 
        for (int i = 0; i < avatars.size(); i++) { 
            SERVER_POTRAIT_NAME[i] = ((AvatarParam)avatars.elementAt(i)).name; 
            for (int j = 0; j <= ChatRepository.PREDEFINED_NR_OF_MOODS; j++) { 
                SERVER_POTRAIT_FILENAME[i][j] = ((AvatarParam)avatars.elementAt(i)).image[j]; 
            } 
        } 
    } 
 
    logoCanvas = new ImageCanvas(getImage(LOGO_FILENAME, true), LOGO_DIMENSION); 
    logoCanvas.showDocumentOnClick(this, LOGO_URL); 
 
    moodIcon = new Image[PREDEFINED_NR_OF_MOODS]; 
    defaultAvatar = new Image[PREDEFINED_NR_OF_MOODS]; 
 
    defaultBackAvatar = getImage(SERVER_POTRAIT_FILENAME[0][0]); 
 
    for (int i = 0; i < PREDEFINED_NR_OF_MOODS; i++) { 
      moodIcon[i] = getImage(MOOD_ICON_NAME[i]); 
      defaultAvatar[i] = getImage(SERVER_POTRAIT_FILENAME[0][i + 1]); 
    } 
 
    emptyIcon = getImage(EMPTY_ICON_NAME); 
    unknownIcon = getImage(UNKNOWN_ICON_NAME); 
    setBackground(CONTAINER_BACKGROUND); 
 
    imgSlider = getImage(IMAGE_SLIDER, true); 
 
    setLayout(new GridLayout()); 
    loginPanel = new LoginPanel(this, getParameter("LoginMode") == null ? LoginPanel.MODE_DEFAULT : ChatUtil.getInt(getParameter("LoginMode"))); 
    add(loginPanel); 
 
    chatClient = new ChatClient(getHost(), this); 
 
    startChat(getBooleanParam("DemoMode", true)); 
 
  } 
 
 
/** 
 * Called by the browser or applet viewer to inform this applet that it is 
 * being reclaimed. 
 */ 
 
  public void destroy() { 
 
    /* 
     * Stop the chat on Netscape browsers 
     */ 
    if (System.getProperty("java.vendor").indexOf("Netscape") != -1) 
      stopChat(); 
  } 
 
 
/** 
 * Called by the browser or applet viewer to inform this applet that it should 
 * stop its execution. 
 */ 
 
  public void stop() { 
    /* 
     * Netscape is buggy on the stop-method() - it might also be called when 
     * resizing the browser window 
     */ 
    if (System.getProperty("java.vendor").indexOf("Netscape") == -1) 
      stopChat(); 
 
  } 
 
  public void setFrameVisibility(boolean visible) { 
    chatFrame.setVisible(visible); 
  } 
 
/** 
 * Starts the chat. Initializes variables, opens the ChatFrame and  runs the 
 * simulator. 
 */ 
 
  public void startChat(boolean demoMode) { 
    User robot[]; 
    Random random; 
    Room room; 
 
    userTable = new IntegerHashtable(); 
    roomTable = new IntegerHashtable(); 
    hashHistory = new Hashtable(); 
    chatStartDate = new Date(); 
 
    for (int i = 0; i < STANDARD_ROOM_NAME.length; i++) { 
        room = new Room(i, STANDARD_ROOM_NAME[i], ChatRepository.ROOM_DIMENSION); 
        room.setPrivate(STANDARD_ROOM_PRIVATE[i]); 
        room.setDemo(i != 0); 
        if (STANDARD_ROOM_INVITED[i]) { 
            room.inviteUser("Guest"); 
        } 
        addRoom(room); 
    } 
 
    /* 
    * Init the demo-version's Users 
    */ 
    User user = new User(UNKNOWN_USER_ID, "Guest", "", Color.red, new Point (ROOM_DIMENSION.width / 2, ROOM_DIMENSION.height / 2), 0, 0, User.HUMAN_RACE); 
 
    user.setBackAvatar(defaultBackAvatar); 
    for (int i = 0; i < PREDEFINED_NR_OF_MOODS; i++) 
        user.setAvatar(i, defaultAvatar[i]); 
 
    setCurrentUser(user); 
 
 
    if (demoMode) { 
 
        /* 
        * Start the simulator and add the Users 
        */ 
        simulator = new Simulator(this); 
        simulator.start(); 
 
        random = new Random(); 
        robot = new User[ROBOT_NAME.length]; 
        for (int i = 0; i < ROBOT_NAME.length; i++) { 
        addUser(robot[i] = new User(ROBOT_USER_ID + i, ROBOT_NAME[i], "", new Color((int)(random.nextDouble() * MAX_COLOR_VALUE), (int)(random.nextDouble() * MAX_COLOR_VALUE), (int)(random.nextDouble() * MAX_COLOR_VALUE)), new Point ((int)(random.nextDouble() * 150), (int)(random.nextDouble() * 150)), (int)(random.nextDouble() * 360), 0, User.ROBOT_RACE)); 
        robot[i].setAvatar(0, getImage(ROBOT_PORTRAIT_FILENAME[i])); 
        robot[i].setCommercialBanner(ROBOT_COMMERCIAL_BANNER[i]); 
        simulator.addUser(robot[i]); 
        } 
    } 
 
    chatFrame = new ChatFrame(this); 
    chatFrame.setSize(800, 620); 
    chatFrame.setVisible(demoMode); 
 
    historyMode = false; 
    setStatus("", true); 
 
    chatRunning = true; 
  } 
 
 
/** 
 * Closes a possible server-connection, stops the simulator and closes the 
 * ChatFrame. 
 */ 
 
  public void stopChat() { 
    chatRunning = false; 
    chatClient.disconnect(); 
 
    if (simulator != null && simulator.isAlive()) 
      simulator.stop(); 
 
    if (chatFrame != null) { 
      chatFrame.setVisible(false); 
      // chatFrame = null; 
    } 
  } 
 
 
/** 
 * Returns true in case the ChatClient is running. 
 */ 
 
  public boolean chatRunning() { 
    return chatRunning; 
  } 
 
 
/** 
 * Fills up the RoomListPanel's XList with the Rooms' data. 
 */ 
 
  public void fillRoomList() { 
    if (chatFrame != null) 
      chatFrame.fillRoomList(); 
  } 
 
 
/** 
 * Repaints the whole ChatFrame. 
 */ 
 
  public void repaintAll() { 
    if (chatFrame != null) 
      chatFrame.repaintAll(); 
  } 
 
 
/** 
 * Repaints the ChatFrame's ViewCanvas. 
 */ 
 
  public void repaintView() { 
    if (chatFrame != null) 
      chatFrame.repaintView(); 
  } 
 
 
/** 
 * Updates RoomListPanel's XList with the Rooms' data. 
 */ 
 
  public void updateRoomList() { 
    if (chatFrame != null) 
      chatFrame.updateRoomList(); 
  } 
 
 
/** 
 * Repaints the ChatFrame's RoomPanel. 
 */ 
 
  public void repaintRoom() { 
    if (chatFrame != null) 
      chatFrame.repaintRoom(); 
  } 
 
 
/** 
 * Repaints the ChatFrame's MoodCanvas. 
 */ 
 
  public void repaintMood() { 
    if (chatFrame != null) 
      chatFrame.repaintMood(); 
  } 
 
 
/** 
 * Repaints the current User. 
 */ 
 
  public void repaintUser() { 
  } 
 
 
/** 
 * Adds a new User. 
 * 
 * @param userParam      the User to be added 
 */ 
 
  public synchronized void addUser(User userParam) { 
    userTable.put(userParam.getId(), userParam); 
    moveUserToRoom(userParam.getId(), userParam.getRoom(), false); 
    if (userParam.getRoom() == getCurrentRoomId()) { 
      repaintRoom(); 
      if (userParam.getId() == getCurrentUserId() || inVisualRange(getCurrentUserId(), userParam.getId())) 
        repaintView(); 
    } 
  } 
 
 
/** 
 * Adds a new Room. 
 * 
 * @param roomParam      the Room to be added 
 */ 
 
  public synchronized void addRoom(Room roomParam) { 
    roomTable.put(roomParam.getId(), roomParam); 
    repaintAll(); 
    fillRoomList(); 
  } 
 
 
/** 
 * Removes a User. 
 * 
 * @param idParam      the id of the User to be removed 
 */ 
 
  public synchronized void removeUser(int idParam) { 
    int roomId; 
 
    if (idParam != getCurrentUserId() && userTable.containsKey(idParam)) { 
      roomId = getUser(idParam).getRoom(); 
      getRoom(roomId).removeUser(getUser(idParam).getName()); 
      userTable.remove(idParam); 
      updateRoomList(); 
      if (roomId == getCurrentRoomId()) { 
        repaintRoom(); 
        repaintView(); 
      } 
    } 
  } 
 
 
/** 
 * Removes a Room. 
 * 
 * @param idParam      the Id of the Room to be removed 
 */ 
 
  public synchronized void removeRoom(int roomIdParam) { 
    if (getRoom(roomIdParam) != null && getRoom(roomIdParam).getNrOfUsers() == 0) { 
      roomTable.remove(roomIdParam); 
      repaintAll(); 
      fillRoomList(); 
    } 
  } 
 
 
/** 
 * Removes all but the current User from the chat system. Needed when connecting/ 
 * disconnecting to/from the chat server. 
 */ 
 
  public synchronized void removeAllExceptCurrentUser() { 
    User user; 
    Enumeration roomIds; 
 
    user = getCurrentUser(); 
 
    userTable = new IntegerHashtable(); 
    roomIds = getRoomIds(); 
    while (roomIds.hasMoreElements()) 
      getRoom(((Integer)roomIds.nextElement()).intValue()).removeAllUsers(); 
 
    addUser(user); 
    repaintRoom(); 
    repaintView(); 
  } 
 
 
/** 
 * Removes User with "unknown" id (demo User). 
 */ 
 
  public synchronized void removeUnknownUser() { 
    if (getCurrentUserId() != UNKNOWN_USER_ID) 
      removeUser(UNKNOWN_USER_ID); 
  } 
 
 
/** 
 * Stops the simulator. Called when connecting to the chat server. 
 */ 
 
  public void stopSimulator() { 
    for (int i = 0; i < ROBOT_NAME.length; i++) { 
      if (getUser(ROBOT_USER_ID + i) != null) 
        removeUser(ROBOT_USER_ID + i); 
    } 
  } 
 
 
/** 
 * Removes all ROoms except the default Room. 
 */ 
 
  public synchronized void removeAllExceptDefaultRoom() { 
    Enumeration roomEnum; 
    Room room; 
    roomEnum = roomTable.elements(); 
    while (roomEnum.hasMoreElements()) { 
      room = (Room)roomEnum.nextElement(); 
      if (room.getId() != 0) 
        forceRoomRemoval(room.getId(), false); 
    } 
  } 
 
 
/** 
 * Returns the User with a certain id. 
 * 
 * @param idParam      the User's id 
 */ 
 
  public synchronized User getUser(int idParam) { 
    Object object; 
    object = userTable.get(idParam); 
    if (object != null) 
      return (User)object; 
    else 
      return null; 
  } 
 
 
/** 
 * Sets the current User by his id. This User has to exist already. 
 * 
 * @param idParam      the User's id 
 */ 
 
  public synchronized void setCurrentUserId(int idParam) { 
    if (userTable.containsKey(idParam)) { 
      currentUserId = idParam; 
      moveUserToRoom(idParam, getUser(idParam).getRoom(), false); 
      repaintView(); 
      repaintRoom(); 
      repaintMood(); 
      repaintCurrentUser(); 
    } 
  } 
 
 
/** 
 * Returns the current User's id. 
 */ 
 
  public synchronized int getCurrentUserId() { 
    return currentUserId; 
  } 
 
 
/** 
 * Returns the current User. 
 */ 
 
  public synchronized User getCurrentUser() { 
    return getUser(currentUserId); 
  } 
 
 
/** 
 * Sets the current User. 
 * 
 * @param userParam      the User to be the new current User. 
 */ 
 
  public synchronized void setCurrentUser(User userParam) { 
    addUser(userParam); 
    setCurrentUserId(userParam.getId()); 
  } 
 
 
/** 
 * Returns all Users as an IntegerHashtable. 
 */ 
 
  public synchronized IntegerHashtable getAllUsers() { 
    return userTable; 
  } 
 
 
/** 
 * Sets the position of a certain User. 
 * 
 * @param idParam       the User's id 
 * @param position      the new position (refer's to the room's dimension) 
 * @param send          determines wheter the new position should be broadcasted 
 */ 
 
  public synchronized void setUserPosition(int idParam, Point positionParam, boolean send) { 
    Enumeration userIdEnum; 
    User userParam, user; 
    Room currentRoom; 
    boolean collides, wasInSight; 
 
    if ((currentRoom = getCurrentRoom()) != null) { 
      positionParam = new Point(Math.max(Math.min(positionParam.x, currentRoom.getSize().width - 2), 1), Math.max(Math.min(positionParam.y, currentRoom.getSize().height - 2), 1)); 
      userParam = getUser(idParam); 
      collides = false; 
 
      if (userParam != null) { 
        /* 
        * Check if the new position collides with any other User. Should be done by the ChatServer, 
        * this is just for double security in case of inconsistant states. 
        */ 
        userIdEnum = getRoomUserIdVector(getCurrentRoomId()).elements(); 
        while (userIdEnum.hasMoreElements() && !collides) { 
          user = getUser(((Integer)userIdEnum.nextElement()).intValue()); 
          if (user != null) 
            collides = new Rectangle(user.getPosition().x - USER_SIZE / 2 - MINIMUM_DISTANCE, user.getPosition().y - USER_SIZE / 2 - MINIMUM_DISTANCE, USER_SIZE + MINIMUM_DISTANCE * 2, USER_SIZE + MINIMUM_DISTANCE * 2).contains(positionParam) && user != userParam; 
        } 
 
        if (!collides) { 
          wasInSight = inVisualRange(getCurrentUser().getId(), userParam.getId()); 
          userParam.setPosition(positionParam); 
 
          if (wasInSight || inVisualRange(getCurrentUser().getId(), userParam.getId()) || userParam == getCurrentUser()) 
            repaintView(); 
 
          repaintRoom(); 
 
          if (idParam != getCurrentUserId() && userParam.getRoom() == getCurrentRoomId()) 
          generateHistoryEntry(); 
 
        } 
 
        /* 
        * Send the position, if the User collides send the last valid position 
        */ 
        if (userParam == getCurrentUser() && send && isConnected()) { 
          chatClient.send(new UserPositionEvent(userParam.getId(), userParam.getPosition())); 
        } 
      } 
    } 
  } 
 
 
/** 
 * Sets the heading of a certain User. 
 * 
 * @param idParam      the User's id 
 * @param heading      the new heading 
 * @param send         determines wheter the new heading should be broadcasted 
 */ 
 
  public synchronized void setUserHeading(int idParam, int headingParam, boolean send) { 
    User userParam; 
 
    if ((userParam = getUser(idParam)) != null) { 
      userParam.setHeading(headingParam); 
 
      if (userParam == getCurrentUser() || inVisualRange(getCurrentUser().getId(), userParam.getId())) 
        repaintView(); 
      repaintRoom(); 
 
      if (idParam != getCurrentUserId() && userParam.getRoom() == getCurrentRoomId()) 
        generateHistoryEntry(); 
 
      if (userParam == getCurrentUser() && send && isConnected()) 
        chatClient.send(new UserHeadingEvent(userParam.getId(), userParam.getHeading())); 
    } 
  } 
 
 
/** 
 * Returns the distance between a User's position and a certain point. 
 * 
 * @param idParam       the User 
 * @param position      the position to calculate the distance to 
 */ 
 
  public int getDistance(int idParam, Point position) { 
    return getDistance(getUser(idParam).getPosition(), position); 
  } 
 
 /** 
 * Returns the distance between a User's position and a certain point. 
 * 
 * @param idParam       the User 
 * @param position      the position to calculate the distance to 
 */ 
 
  public int getDistance(Point position1, Point position2) { 
    return (int)Math.sqrt(Math.pow(position1.x - position2.x, 2) + Math.pow(position1.y - position2.y, 2)); 
  } 
 
 
/** 
 * Returns true if a position can be seen by a User. 
 * 
 * @param idParam       the id of the User watching 
 * @param position      position to be seen 
 */ 
 
  public boolean inVisualRange(int idParam, Point position) { 
    try { 
      return inVisualRange(getUser(idParam).getPosition(), getUser(idParam).getHeading(), position); 
    } 
    catch (Exception excpt) { 
      return false; 
    } 
  } 
 
  public boolean inVisualRange(Point position1, int headingParam, Point position2) { 
    int distance, angle; 
    distance = getDistance(position1, position2); 
    angle = getAngle(position1, position2); 
    return (distance <= VISUAL_RANGE && ChatUtil.inAngleRange(angle, ChatUtil.subAngle(headingParam, VISUAL_ANGLE / 2), ChatUtil.addAngle(headingParam, VISUAL_ANGLE / 2))); 
  } 
 
 
/** 
 * Returns true if one User can be seen by another User. 
 * 
 * @param idParam1      the id of the User watching 
 * @param idParam2      the id of the User to be seen 
 */ 
 
  public boolean inVisualRange(int idParam1, int idParam2) { 
    User user1, user2; 
    try { 
      user1 = getUser(idParam1); 
      user2 = getUser(idParam2); 
 
      if ((user1 != user2) && (user1.getRoom() == user2.getRoom())) { 
        return inVisualRange(user1.getPosition(), user1.getHeading(), user2.getPosition()); 
      } 
    } 
    catch (Exception excpt) { 
    } 
    return false; 
  } 
 
 
/** 
 * Returns true one User can listen to another User (means his avatar's balloon 
 * is visible for the other User). 
 * 
 * @param idParam1      the User who listens 
 * @param idParam2      position User to be listened to 
 */ 
 
  public boolean inPhonicalRange(int idParam1, int idParam2) { 
    User user1, user2; 
    user1 = getUser(idParam1); 
    user2 = getUser(idParam2); 
 
    if ((user1 != user2) && (user1.getRoom() == user2.getRoom())) 
      return inPhonicalRange(idParam1, user2.getPosition()); 
    else 
      return false; 
  } 
 
 
/** 
 * Returns true one User can listen to another User (means his avatar's balloon 
 * is visible for the other User). 
 * 
 * @param idParam1      the User who listens 
 * @param idParam2      position User to be listened to 
 */ 
 
  public boolean inPhonicalRange(int idParam, Point pointParam) { 
    User user; 
    int distance, angle; 
    user = getUser(idParam); 
 
    distance = getDistance(idParam, pointParam); 
    angle = getAngle(idParam, pointParam); 
    return (distance <= PHONICAL_RANGE && ChatUtil.inAngleRange(angle, ChatUtil.subAngle(user.getHeading(), PHONICAL_ANGLE / 2), ChatUtil.addAngle(user.getHeading(),PHONICAL_ANGLE / 2))); 
  } 
 
 
/** 
 * Determines the angle between a User and a point (< 180 degrees). 
 * 
 * @param idParam       the id of the  User 
 * @param position      the point to calculate the angle within 
 */ 
 
  public int getAngle(int idParam, Point position) { 
    return ChatUtil.getAngle(getUser(idParam).getPosition(), position); 
  } 
 
 /** 
 * Determines the angle between a User and a point (< 180 degrees). 
 * 
 * @param idParam       the id of the  User 
 * @param position      the point to calculate the angle within 
 */ 
 
  public int getAngle(Point position1, Point position2) { 
    return ChatUtil.getAngle(position1, position2); 
  } 
 
 
/** 
 * Determines the angle between two Users (< 180 degrees). 
 * 
 * @param idParam1      the id of one User 
 * @param idParam2      the id of another User to calculate the angle within 
 */ 
 
  public int getAngle(int idParam1, int idParam2) { 
    return ChatUtil.getAngle(getUser(idParam1).getPosition(), getUser(idParam2).getPosition()); 
  } 
 
 
/** 
 * Sets the message text of a certain User. 
 * 
 * @param idParam      the User's id 
 * @param message      the new message text 
 * @param send         determines wheter the new message should be broadcasted. 
 */ 
 
  public synchronized void setUserMessage(int idParam, String messageParam, boolean send) { 
    User user; 
    user = getUser(idParam); 
    if (user != null) { 
      user.setMessage(messageParam); 
      // Repaint in case it's the current User or the User can be seen 
      if (user == getCurrentUser()) { 
        if (send && isConnected()) { 
          chatClient.send(new UserMessageEvent(user.getId(), messageParam)); 
        } 
        setUserMood(user.getId(), user.getMood(messageParam), send); 
        repaintView(); 
      } 
      else if (inVisualRange(getCurrentUser().getId(), user.getId())) { 
        repaintView(); 
      } 
      if (user.getRoom() == getCurrentRoomId()) { 
		if (pnlHistory != null) { 
          pnlHistory.addMessageEntry(new Date(), messageParam, user.getColor()); 
          generateHistoryEntry(); 
	    } 
		if (chatFrame != null) { 
		  chatFrame.addMessage(user.getName(), messageParam); 
	    } 
      } 
    } 
  } 
 
 
/** 
 * Sets the mood of a certain User. 
 * 
 * @param idParam      the User's id 
 * @param mood         the mood 
 * @param send         determines wheter the new mood should be broadcasted. 
 */ 
 
  public synchronized void setUserMood(int idParam, int moodParam, boolean send) { 
    User user; 
    user = getUser(idParam); 
 
    if (user != null) { 
      user.setMood(moodParam); 
 
      // Repaint in case it's the current User or the User can be seen 
      if (user == getCurrentUser()) { 
        chatFrame.repaintMood(); 
        if (send && isConnected()) 
          chatClient.send(new UserMoodEvent(user.getId(), moodParam)); 
        if (user.getMoodTimeout() > 0) { 
          if (thrMoodTimeout != null && thrMoodTimeout.isAlive()) 
            thrMoodTimeout.stop(); 
          thrMoodTimeout = new Thread(this); 
          thrMoodTimeout.start(); 
        } 
      } 
      else if (inVisualRange(getCurrentUser().getId(), user.getId())) 
        repaintView(); 
 
      if (user.getRoom() == getCurrentRoomId()) 
        generateHistoryEntry(); 
    } 
 
   } 
 
 
/** 
 * Update's a User's data. 
 * 
 * @param user      the User to be updated 
 * @param send      determines wheter the new User's data should be broadcasted 
 */ 
 
  public synchronized void updateUser(User user, boolean send) { 
    if (send) { 
      chatClient.send(new UserUpdateEvent(user)); 
    } 
    else { 
      if (!isConnected()) { 
        if (!user.getBackAvatarURL().equals("")) 
          user.setBackAvatar(getImage(user.getBackAvatarURL())); 
        else 
          user.setBackAvatar(null); 
        for (int i = 0; i < user.getNrOfMoods(); i++) { 
          if (!user.getAvatarURL(i).equals("")) 
            user.setAvatar(i, getImage(user.getAvatarURL(i))); 
          else 
            user.setAvatar(i, null); 
        } 
      } 
      addUser(user); 
      repaintAll(); 
      if (user.getId() == getCurrentUser().getId() && chatFrame != null) { 
        chatFrame.repaintCurrentUser(); 
      } 
    } 
  } 
 
 
 
/** 
 * Update's a Room's data. 
 * 
 * @param room      the Room to be updated 
 * @param send      determines wheter the new Room's data should be broadcasted 
 */ 
 
  public synchronized void updateRoom(Room room, boolean send) { 
    if (send) { 
      if (room.getId() == NEW_ROOM_ID) 
        chatClient.send(new RoomCreateEvent(room)); 
      else 
        chatClient.send(new RoomUpdateEvent(room)); 
    } 
    else { 
      addRoom(room); 
      if (room.isAdministrator(getCurrentUser().getName())) { 
        if (chatFrame.editableRoomPanel.getRoomId() == room.getId()) 
          chatFrame.editableRoomPanel.showRoom(room); 
        if (getCurrentRoomId() == NEW_ROOM_ID) { 
          moveUserToRoom(getCurrentUserId(), room.getId(), isConnected()); 
          removeRoom(NEW_ROOM_ID); 
          chatFrame.editableRoomPanel.showRoom(room); 
        } 
      } 
      repaintAll(); 
    } 
  } 
 
 
 
/** 
 * Removes a Room. 
 * 
 * @param roomId      the Id of the Room to be removed 
 */ 
 
  public synchronized void forceRoomRemoval(int roomId, boolean send) { 
    Enumeration userEnum; 
    Room room; 
 
    if ((room = getRoom(roomId)) != null) { 
      userEnum = getRoomUserIdVector(roomId).elements(); 
      while (userEnum.hasMoreElements()) { 
        moveUserToRoom(((Integer)userEnum.nextElement()).intValue(), 0, send); 
      } 
      removeRoom(roomId); 
      if (send) 
        chatClient.send(new RoomRemoveEvent(roomId)); 
    } 
  } 
 
 
/** 
 * Enters the history mode. In history mode, the messages and moods of a certain 
 * period of time will be displayed. 
 * 
 * @param histDateParam      the start date of the history mode 
 */ 
 
  public synchronized void enterHistoryMode(Date histDateParam) { 
    historyMode = true; 
    histDate = histDateParam; 
    repaintView(); 
    repaintRoom(); 
  } 
 
 
/** 
 * Exists the history mode. User messages and moods will be displayed as flooding 
 * in. 
 */ 
 
  public synchronized void exitHistoryMode() { 
    historyMode = false; 
    histDate = null; 
    repaintView(); 
    repaintRoom(); 
  } 
 
 
/** 
 * Returns true if the chat is running in history mode. 
 */ 
 
  public boolean historyMode() { 
    return historyMode; 
  } 
 
 
/** 
 * Returns the start date of the history mode (in case history mode is activated). 
 */ 
 
  public Date getHistoryDate() { 
    return histDate; 
  } 
 
 
/** 
 * Returns the start date of the chat, that is when the chat client started up. 
 */ 
 
  public Date getChatStartDate() { 
    return chatStartDate; 
  } 
 
 
/** 
 * Shows a message in the status bar. 
 * 
 * @param statusString      the message to be shown 
 */ 
 
  public void setStatus(String statusString) { 
    setStatus(statusString, false); 
  } 
 
 
/** 
 * Shows a message in the status bar and if - intended - in the login panel as 
 * well. 
 * 
 * @param statusString      the message to be shown 
 * @param login             true if the message should be shown in the login panel 
 */ 
 
  public synchronized void setStatus(String statusString, boolean login) { 
    status = statusString; 
    if (chatFrame != null) 
      chatFrame.setStatus(statusString); 
    if (loginPanel != null && login) 
      loginPanel.setStatus(statusString); 
  } 
 
 
/** 
 * Returns the message that is currently shown in the status bar. 
 */ 
 
 public String getStatus() { 
   return status; 
 } 
 
 
/** 
 * Returns a User's avatar. 
 * 
 * @param userIdParam      the User's id 
 */ 
 
  public Image getUserAvatar(int userIdParam) { 
    return getUserAvatar(userIdParam, getUser(userIdParam).getMood()); 
  }; 
 
 
/** 
 * Returns a User's avatar for a certain mood. 
 * 
 * @param userIdParam      the User's id 
 * @param moodParam        the User's mood 
 */ 
 
  public Image getUserAvatar(int userIdParam, int moodParam) { 
    Image portrait; 
 
    portrait = getUser(userIdParam).getAvatar(moodParam); 
    if (portrait == null) { 
      portrait = moodParam < PREDEFINED_NR_OF_MOODS ? defaultAvatar[moodParam] : defaultAvatar[0]; 
    } 
    return portrait; 
  } 
 
 
/** 
 * Returns a User's back image. 
 * 
 * @param userIdParam      the User's id 
 */ 
 
  public Image getUserBackAvatar(int userIdParam) { 
    return getUser(userIdParam).getBackAvatar(); 
  } 
 
 
/** 
 * Returns the icon for a certain mood. 
 * 
 * @param moodParam      the mood 
 */ 
 
  public Image getMoodIcon(int moodParam) { 
    if (moodParam < PREDEFINED_NR_OF_MOODS) { 
      return moodIcon[moodParam]; 
    } 
    else { 
      return unknownIcon; 
    } 
  } 
 
 
/** 
 * Returns the icon for user-defined moods. 
 */ 
 
  public Image getUnknownIcon() { 
    return unknownIcon; 
  } 
 
 
/** 
 * Returns the icon for back-avatar. 
 */ 
 
  public Image getEmptyIcon() { 
    return emptyIcon; 
  } 
 
 
 
/** 
 * Returns the host where the ChatApplet descends from. 
 */ 
 
  public String getHost() { 
    return getCodeBase().getHost(); 
  } 
 
 
/** 
 * Returns the default port where the ChatServer is listening. 
 */ 
 
  public int getDefaultPort() { 
    try { 
      return getParameter("Port") != null && new Integer(getParameter("Port")).intValue() > 2048 ? new Integer(getParameter("Port")).intValue() : DEFAULT_PORT; 
    } 
    catch (NumberFormatException excpt) { 
      return DEFAULT_PORT; 
    } 
  } 
 
 
/** 
 * Returns the ChatClient. 
 */ 
 
  public ChatClient getClient() { 
    return chatClient; 
  } 
 
 
/** 
 * Requests that the browser or applet viewer show the Web page indicated by the 
 * url argument. 
 * 
 * @param url         an absolute URL giving the location of the document 
 * @param target      a String indicating where to display the page 
 */ 
 
  public void showDocument(URL url, String target) { 
    getAppletContext().showDocument(url, target); 
  } 
 
 
/** 
 * Returns the Id of the current Room. 
 */ 
 
  public synchronized int getCurrentRoomId() { 
    try { 
      return getCurrentUser().getRoom(); 
    } 
    catch (Exception excpt) { 
      return 0; 
    } 
  } 
 
 
/** 
 * Returns the current Room. 
 */ 
 
  public synchronized Room getCurrentRoom() { 
    return getRoom(getCurrentUser().getRoom()); 
  } 
 
 
/** 
 * Sets the Id of the current Room. 
 * 
 * @param roomIdParam      the Id of the current Room 
 */ 
 
  public synchronized void setCurrentRoomId(int roomIdParam) { 
    moveUserToRoom(getCurrentUserId(), roomIdParam, isConnected()); 
  } 
 
 
 
/** 
 * Returns the Room with a certain id. 
 * 
 * @param idParam      the Room's id 
 */ 
 
  public synchronized Room getRoom(int idParam) { 
    Object object; 
    object = roomTable.get(idParam); 
    if (object != null) 
      return (Room)object; 
    else 
      return null; 
  } 
 
 
/** 
 * Returns an Enumeration of the Rooms' Ids. 
 */ 
 
  public synchronized Enumeration getRoomIds() { 
    return roomTable.keys(); 
  } 
 
 
/** 
 * Returns a Rooms' Users' Ids as a Vector. 
 * 
 * @param roomId      the Room's id 
 */ 
 
  public synchronized Vector getRoomUserIdVector(int roomId) { 
    Room room; 
    Vector roomUserIdVector; 
    Enumeration userNameEnum; 
 
    roomUserIdVector = new Vector(); 
 
    if ((room = getRoom(roomId)) != null) { 
      userNameEnum = room.getUserNameVector().elements(); 
 
      while (userNameEnum.hasMoreElements()) { 
        roomUserIdVector.addElement(new Integer(getUserId((String)userNameEnum.nextElement()))); 
      } 
    } 
    return roomUserIdVector; 
  } 
 
 
  public synchronized int getUserId(String userNameParam) { 
    Enumeration userIdEnum; 
    int id; 
 
    userIdEnum = userTable.keys(); 
 
    while (userIdEnum.hasMoreElements()) { 
      if (((User)userTable.get(id = ((Integer)userIdEnum.nextElement()).intValue())).getName().equals(userNameParam)) 
        return id; 
    } 
 
    return -1; 
  } 
 
 
 
/** 
 * Moves a User to a Room. 
 * 
 * @param userIdParam      the Id of the User to be moved 
 * @param roomIdParam      the Id of the Room to move the User to 
 */ 
 
  public synchronized void moveUserToRoom(int userIdParam, int roomIdParam, boolean send) { 
    Room room; 
    User user; 
    boolean bGenerateHistoryEntry, bRestartHistory; 
 
    if (userTable.containsKey(userIdParam) && roomTable.containsKey(roomIdParam)) { 
      room = getRoom(roomIdParam); 
      user = getUser(userIdParam); 
      if (room.hasAccess(user.getName())) { 
 
        bRestartHistory = (user.getRoom() == getCurrentRoomId() && roomIdParam != getCurrentRoomId()); 
        bGenerateHistoryEntry = (user.getRoom() == getCurrentRoomId() || roomIdParam == getCurrentRoomId()); 
 
        if (getRoom(getUser(userIdParam).getRoom()) != null) { 
          getRoom(user.getRoom()).removeUser(user.getName()); 
        } 
 
        user.setRoom(roomIdParam); 
        room.addUser(user.getName()); 
 
        if (userIdParam == getCurrentUserId()) { 
          setStatus("Joined room \"" + room.getName() +"\""); 
          if (bRestartHistory) { 
            restartHistory(); 
          } 
          if (send) 
            chatClient.send(new UserRoomEvent(userIdParam, roomIdParam, new Point())); 
        } 
 
        repaintView(); 
        repaintRoom(); 
        updateRoomList(); 
 
        if (bGenerateHistoryEntry) 
          generateHistoryEntry(); 
 
      } 
      else if (userIdParam == getCurrentUserId()) { 
        setStatus("You do not have access to room \"" + room.getName() +"\""); 
      } 
    } 
  } 
 
 
/** 
 * Returns the number of Rooms. 
 */ 
 
  public synchronized int getNrOfRooms() { 
    return roomTable.size(); 
  } 
 
 
/** 
 * Returns the Id of a Room of a given name. 
 */ 
 
  public synchronized int getRoomId(String roomNameParam) { 
    Enumeration roomIds; 
    int roomId; 
 
    roomIds = getRoomIds(); 
    while (roomIds.hasMoreElements()) { 
      roomId = ((Integer)roomIds.nextElement()).intValue(); 
      if (getRoom(roomId).getName().equals(roomNameParam)) 
        return roomId; 
    } 
    return -1; 
  } 
 
  public byte[] getResourceFromArchive(String strResource) { 
    InputStream inStr; 
    byte[] buffer; 
 
    try { 
      inStr = getClass().getResourceAsStream(strResource); 
      if (inStr == null) { 
        return null; 
      } 
      buffer = new byte [inStr.available()]; 
      inStr.read(buffer); 
      return buffer; 
    } 
    catch (IOException excpt) { 
      excpt.printStackTrace(); 
    } 
    return null; 
  } 
/** 
 * Retrieves an image from the webserver. 
 * 
 * @param name      the file name 
 */ 
 
  public Image getImage(String name, boolean wait) { 
    Image img; 
    byte buffer[] = getResourceFromArchive("/" + IMAGE_FOLDER + name); 
    if (buffer != null) { 
      img =  Toolkit.getDefaultToolkit().createImage(buffer); 
    } 
    else { 
      img = getImage(getCodeBase(), IMAGE_FOLDER + name); 
    } 
    if (wait) { 
      if (tracker == null) { 
        tracker = new MediaTracker(this); 
      } 
      tracker.addImage(img, 0); 
      try { 
        tracker.waitForID(0, 5000); 
      } 
      catch (InterruptedException excpt) { 
        excpt.printStackTrace(); 
      } 
    } 
    return img; 
  } 
 
  public Image getImage(String name) { 
    return getImage(name, false); 
  } 
 
/** 
 * Displays another User's data in a new Frame. 
 * 
 * @param userId      the Id of the User to be shown 
 */ 
 
  public void showUser(int userIdParam) { 
    if (chatFrame != null) 
      chatFrame.showUser(userIdParam); 
  } 
 
 
/** 
 * Updates User data in the User TabPanel, which can be edited. 
 * 
 * @param userId      the Id of the User to be edited 
 */ 
 
  public void editUser(int userIdParam) { 
    if (chatFrame != null) 
      chatFrame.editUser(userIdParam); 
  } 
 
 
/** 
 * Displays a Room's data in a new Frame. 
 * 
 * @param roomId      the Id of the Room to be shown 
 */ 
 
  public void showRoom(int roomIdParam) { 
    if (chatFrame != null) 
      chatFrame.showRoom(roomIdParam); 
  } 
 
 
/** 
 * Updates Room data in the Room TabPanel, which can be edited by the Room's 
 * Administrator. 
 * 
 * @param userId      the Id of the Room to be edited 
 */ 
 
  public void editRoom(int roomIdParam) { 
    if (chatFrame != null) 
      chatFrame.editRoom(roomIdParam); 
  } 
 
 
/** 
 * Creates a new Room and lets the User edit its data. 
 */ 
 
  public synchronized void createRoom() { 
    Room room; 
    int roomId; 
 
    roomId = isConnected() ? NEW_ROOM_ID : getNrOfRooms(); 
    room = new Room(roomId, "New Room", ROOM_DIMENSION); 
    if (roomExists(room.getName())) { 
      int i; 
      for (i = 1; roomExists(room.getName() + i); i++); 
      room.setName(room.getName() + i); 
    } 
    room.setAdministrator(getCurrentUser().getName()); 
    room.setDemo(!isConnected()); 
    addRoom(room); 
    moveUserToRoom(getCurrentUserId(), roomId, false); 
    if (chatFrame != null) 
      chatFrame.editRoom(roomId); 
  } 
 
 
/** 
 * Repaint the current User. Should be called after his data has been updated. 
 * Administrator. 
 */ 
 
  public void repaintCurrentUser() { 
    if (chatFrame != null) 
      chatFrame.repaintCurrentUser(); 
  } 
 
 
/** 
 * Returns the Room with a certain name. 
 * 
 * @param roomNameParam      the Rooms's name 
 */ 
 
  public Room getRoom(String roomNameParam) { 
    return getRoom(getRoomId(roomNameParam)); 
  } 
 
 
/** 
 * Returns true if a Room of a certain name exists. 
 * 
 * @param roomNameParam      the Name of the Room 
 */ 
 
  public boolean roomExists(String roomNameParam) { 
    return getRoom(roomNameParam) != null; 
  } 
 
 
/** 
 * Returns true if the ChatClient is currently connected to a ChatServer. 
 */ 
 
  public boolean isConnected() { 
    return chatClient != null && chatClient.connected(); 
  } 
 
 
/** 
 * Defines the ChatApplet's HistoryPanel. This Panel will receive 
 * MessageEntries. 
 * 
 * @param pnlHistoryParam      the ChatApplet's HistoryPanel 
 */ 
 
  public void setHistoryPanel(HistoryPanel pnlHistoryParam) { 
    pnlHistory = pnlHistoryParam; 
  } 
 
 
/** 
 * Returns an Image being used as the slider in the HistoryPanel's scrollbar. 
 * MessageEntries. 
 */ 
 
  public Image getSliderImage() { 
    return imgSlider; 
  } 
 
 
/** 
 * Brings the Chat TabPanel back to the foreground. 
 */ 
 
  public void showChat() { 
    if (chatFrame != null) 
      chatFrame.showChat(); 
  } 
 
 
/** 
 * Stores the Chat's current situation into the history. 
 */ 
 
  private synchronized void generateHistoryEntry() { 
    hashHistory.put(new Date(), getCurrentSituationVector()); 
  } 
 
 
/** 
 * Returns a Vector which reflects the Chat's current situation. 
 */ 
 
  public synchronized Vector getCurrentSituationVector() { 
    Vector vecHistoryEntry, vecCurrentRoomUserIds; 
    Date dateNow; 
    User user; 
 
    dateNow = new Date(); 
    vecHistoryEntry = new Vector(); 
    vecCurrentRoomUserIds = getRoomUserIdVector(getCurrentRoomId()); 
    for (int i = 0; i < vecCurrentRoomUserIds.size(); i++) { 
      user = getUser(((Integer)vecCurrentRoomUserIds.elementAt(i)).intValue()); 
      if (user != null) 
        vecHistoryEntry.addElement(new HistoryEntry(dateNow, getCurrentRoomId(), user.getId(), user.getPosition(), user.getHeading(), user.getColor(), user.getMessage(), user.getMood())); 
    } 
    return (Vector)vecHistoryEntry.clone(); 
  } 
 
 
/** 
 * Returns a Vector which reflects the Chat's situation at a certain point in time. 
 * 
 * @param dateParam      the Date to return the Vector for 
 */ 
 
  public synchronized Vector getHistoryEntryVector(Date dateParam) { 
    Object objHistory; 
    HistoryEntry histEntry; 
    Date date, dateEntry; 
    Enumeration enumDate; 
 
    date = new Date(0l); 
    enumDate = hashHistory.keys(); 
 
    while (enumDate.hasMoreElements()) { 
      dateEntry = (Date)enumDate.nextElement(); 
      if (dateEntry.getTime() < dateParam.getTime() && dateEntry.getTime() > date.getTime()) 
        date = dateEntry; 
    } 
 
    return ((objHistory = hashHistory.get(date)) != null) ? (Vector)(((Vector)objHistory)).clone() : new Vector(); 
  } 
 
 
/** 
 * Restarts the Chat's history. 
 */ 
 
  public synchronized void restartHistory() { 
    hashHistory = new Hashtable(); 
    if (pnlHistory != null) 
      pnlHistory.clear(); 
  } 
 
 
/** 
 * Runs a Thread being used to timeout User moods. 
 */ 
 
  public void run() { 
    try { 
      Thread.sleep(getCurrentUser().getMoodTimeout() * 1000); 
    } 
    catch (InterruptedException excpt) { 
    } 
    finally { 
      setUserMood(getCurrentUserId(), 0, isConnected()); 
    } 
  } 
 
 
/** 
 * Returns an incidently chosen User. 
 */ 
 
  public User getRandomUser() { 
    Vector roomUserIdVector; 
    roomUserIdVector = getRoomUserIdVector(getCurrentRoomId()); 
    return getUser(((Integer)roomUserIdVector.elementAt((int)(roomUserIdVector.size() * new Random().nextFloat()))).intValue()); 
  } 
 
 
/** 
 * Returns the TK-Logo. 
 */ 
 
  public ImageCanvas getLogo() { 
    return (ImageCanvas)logoCanvas.clone(); 
  } 
 
 
/** 
 * Returns the default avatar for a certain mood. 
 * 
 * @param moodParam        the User's mood 
 */ 
 
  public Image getDefaultAvatar(int moodParam) { 
    return (moodParam >= 0 && moodParam < PREDEFINED_NR_OF_MOODS) ? defaultAvatar[moodParam] : null; 
  } 
 
 
/** 
 * Returns the default back-side avatar. 
 */ 
 
  public Image getDefaultBackAvatar() { 
    return defaultBackAvatar; 
  } 
 
  public synchronized void setRoomTable(IntegerHashtable roomTableParam) { 
    Room room; 
    room = (Room)roomTable.get(0); 
    roomTable = roomTableParam; 
    roomTable.put(0, room); 
    moveUserToRoom(getCurrentUserId(), 0, false); 
    fillRoomList(); 
    repaintAll(); 
  } 
 
}