/******************************************************************************
    SputnikChat v0.3 - (C) 2005 Heiko Stamer <stamer@gaos.org>
                       
    tiny web based IRC client 
	
    (X-mas gift for Radio Sputnik (aka DT64) - Alles Andere ist Taeuschung!)
    
	http://stinfwww.informatik.uni-leipzig.de/~mai97ixb
	
    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.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*******************************************************************************/
import java.lang.*;
import java.util.*;
import java.applet.*;
import java.io.*;
import java.net.*;
import java.awt.*;
import java.awt.event.*;			// Java 1.1 Event Handling

/** 
SputnikChat
@author Heiko Stamer
@version 0.3

Please ignore the teribble coding style below this line !
**/

public class SputnikChat extends Applet 
	implements MouseListener, MouseMotionListener, ActionListener {
	// ---------------------------------------------------------------
	// help messages
	// ---------------------------------------------------------------
	public static final String MSG_LOGO = "SputnikChat v0.3 - " +
		"(c) 2000, 2001, 2005 Heiko Stamer " +
		"http://gaos.org/~stamer";
	public static final String[][] MSG_INPUT = {
		{"Trage hier Deinen NICKNAME (Spitznamen) ein, welchen Du im Chat " +
		 "verwenden moechtest und druecke ENTER!",
		 ""},
		{"Jetzt musst Du noch Deinen richtigen Namen (Vor- und Nachname) " +
		 "angeben.",
		 ""},
		{"Gib nun bitte auch das dazugehoerige Passwort ein. Zur Sicherheit " +
		 "werden nur * am Bildschirm ausgegeben.",
		 ""},
		{"Hier kannst Du Deine Chatbeitraege eingeben. Mit ENTER " +
		 "werden diese an die anderen Benutzer geschickt.",
		 ""}
	};
	public static final String[][] MSG_BUTTONS_MOVED = {
		{"Zeigt eine aktuelle Liste der Benutzer dieses Raumes.", "Button 1"},
		{"Laesst Euch aus einer Liste von Chatraeumen auswaehlen.", "Button 2"},
		{"Stellt einige Emoticons zur Verfuegung.", "Button 3"}
	};
	public static final String[][] MSG_BUTTONS_CLICKED = {
		{"Zeigt eine aktuelle Liste der Benutzer dieses Raumes.", "Button 1 pressed"},
		{"Laesst Euch aus einer Liste von Chatraeumen auswaehlen.", "Button 2 pressed"},
		{"Stellt einige Emoticons zur Verfuegung.", "Button 3 pressed"}
	};
	public static final String[] MSG_SOCKET = {
		" Verbindungsfehler: ",
		" SOCKET error: "	
	};
	public static final String[] MSG_IO = {
		">>> Ein-/Ausgabefehler: ",
		">>> IO error: "	
	};
	public static final String[] MSG_WAIT = {
		"Verbindung OK. Anmeldung beim IRC Server ... Bitte warten!",
		""	
	};
	public static final String[] MSG_NOREG = {
		"Anmeldung fehlgeschlagen! Ggf. bitte neu anmelden.",
		""	
	};
	public static final String[] MSG_IRC = {
		">>> Syntax: /<IRC KOMMANDO> <IRC PARAMETER>",
		""	
	};
	public static final String[] MSG_PRIV = {
		">>> Syntax: @<NICKNAME> <PRIVATE NACHRICHT>",
		""	
	};
	public static final String[] IRC_ERROR = {
		">>> Die IRC Verbindung wurde getrennt. Bitte ggf. neu verbinden!",
		""	
	};
	public static final String[] IRC_JOIN = {
		" betritt den Raum ",
		""	
	};
	public static final String[] IRC_PART = {
		" verlaesst den Raum ",
		""	
	};
	public static final String[] IRC_ERR_433 = {
		">>> Dieser NICKNAME ist leider schon belegt. Suche Dir bitte einen " +
		"anderen Spitznamen aus!",
		""	
	};
	public static final String[] IRC_ERR_401 = {
		">>> Der angegebene NICKNAME/CHANNEL existiert nicht. Vertippt? ",
		""	
	};
	// ---------------------------------------------------------------
	// WUI components (Wurbo User Interface - needful own widgets)
	// ---------------------------------------------------------------
	public static final Color WuiBackground = new Color(178, 178, 178);
	public static final Color WuiRootColor = new Color(120, 100, 220);
	public static final Color WuiHideColor = new Color(120, 120, 120);
	public static final int WuiButtonWidth = 60;
	public static final Font WuiTitleFont = new Font("Serif", Font.BOLD, 30);
	public static final Font WuiButtonFont = new Font("SansSerif", Font.BOLD, 14);
	public static final Font WuiConsoleFont = new Font("SansSerif", Font.PLAIN, 10);
	protected SputnikChat WuiRootApplet = this;
	protected WuiButton[] actionButtons;
	protected WuiConsole helpConsole, chatConsole;
	
	public class WuiConsole {
		public boolean update = false;
		private String[][] lines = null;
		protected int rw = 4, rh = 2;
		protected int x, y, width, height;
		protected Font font = null;
		protected FontMetrics metric = null;
		protected Color background = null, mycolor = null, myprefixcolor = null;
		
		public WuiConsole(FontMetrics metric, Font font, int lines, Color b, int
		x, int y, int w, Color mc, Color mpc) {
			this.lines = new String[lines][2];
			this.font = font;
			this.metric = metric;
			this.x = x;
			this.y = y;
			this.width = w;
			this.height = (lines * rh) + (lines * this.metric.getHeight());
			this.background = b;
			this.mycolor = mc;
			this.myprefixcolor = mpc;
		}
		
		private boolean space(String[][] array) {
			boolean tmp = false;
			for (int i = 0; i < array.length; i++) {
				if ((array[i][0] == null) && (array[i][1] == null)) {
					tmp = true;
					break;
				}
			}
			return tmp;
		}
		
		public void println(String text) {
			Vector textlines = new Vector();
			Enumeration enum = null;
			String tmp = text.trim();
			
			do {
				while (metric.stringWidth(tmp) > width) {
					if (tmp.indexOf(" ") == -1) break;
					tmp = tmp.substring(0,tmp.lastIndexOf(" "));
				}
				textlines.addElement(tmp);
				text = text.substring(tmp.length());
				text = text.trim();
				tmp = text.trim();
			} while (tmp.length() != 0);
			
			enum = textlines.elements();	
			while (enum.hasMoreElements()) {
				if (!space(lines)) {
					for (int i = 0; i < (lines.length - 1); i++) {
						lines[i][0] = lines[i + 1][0];
						lines[i][1] = lines[i + 1][1];
					}
					lines[lines.length - 1][0] = null;
					lines[lines.length - 1][1] = null;
				}
				for (int i = 0; i < lines.length; i++) {
					if ((lines[i][0] == null) && (lines[i][1] == null)) {
						lines[i][0] = null;
						lines[i][1] = (String)enum.nextElement();
						break;
					}
				}
			}
		}
		
		public void preprintln(String text) {
			Vector textlines = new Vector();
			Enumeration enum = null;
			String tmp = text.trim();
			
			do {
				while (metric.stringWidth(tmp) > width) {
					if (tmp.indexOf(" ") == -1) break;
					tmp = tmp.substring(0,tmp.lastIndexOf(" "));
				}
				textlines.addElement(tmp);
				text = text.substring(tmp.length());
				text = text.trim();
				tmp = text.trim();
			} while (tmp.length() != 0);
			
			enum = textlines.elements();	
			while (enum.hasMoreElements()) {
				if (!space(lines)) {
					for (int i = 0; i < (lines.length - 1); i++) {
						lines[i][0] = lines[i + 1][0];
						lines[i][1] = lines[i + 1][1];
					}
					lines[lines.length - 1][0] = null;
					lines[lines.length - 1][1] = null;
				}
				for (int i = 0; i < lines.length; i++) {
					if ((lines[i][0] == null) && (lines[i][1] == null)) {
						lines[i][1] = null;
						lines[i][0] = (String)enum.nextElement();
						break;
					}
				}
			}
		}
		
		public void println(String prefix, String text) {
			Vector textlines = new Vector();
			Enumeration enum = null;
			String tmp = text.trim();
			boolean prefix_set = false;
			
			do {
				if (textlines.size() == 0) 
				{	
					while (metric.stringWidth(prefix) +
						metric.stringWidth(": ") +
						metric.stringWidth(tmp) > width) {
						if (tmp.indexOf(" ") == -1) break;
							tmp = tmp.substring(0, tmp.lastIndexOf(" "));
					}
				} 
				else
				{
					while (metric.stringWidth(tmp) > width) {
						if (tmp.indexOf(" ") == -1) break;
							tmp = tmp.substring(0,tmp.lastIndexOf(" "));
					}
				}
				textlines.addElement(tmp);
				text = text.substring(tmp.length());
				text = text.trim();
				tmp = text.trim();
			} while (tmp.length() != 0);
			
			enum = textlines.elements();	
			while (enum.hasMoreElements()) {
				if (!space(lines)) {
					for (int i = 0; i < (lines.length - 1); i++) {
						lines[i][0] = lines[i + 1][0];
						lines[i][1] = lines[i + 1][1];
					}
					lines[lines.length - 1][0] = null;
					lines[lines.length - 1][1] = null;
				}
				for (int i = 0; i < lines.length; i++) {
					if ((lines[i][0] == null) && (lines[i][1] == null)) {
						if (!prefix_set) 
						{
							lines[i][0] = prefix + ": ";
							prefix_set = true;
						} else lines[i][0] = null;
						lines[i][1] = (String)enum.nextElement();
						break;
					}
				}
			}
		}
				
		public void clear() {
			for (int i = 0; i < lines.length; i++)
			{
				lines[i][0] = null;
				lines[i][1] = null;
			}
		}
		
		public void paint(Graphics g) {
			int offset;
			g.setColor(background);
			g.fillRect(x, y, width, height + 1);
			g.setFont(this.font);
			g.setColor(mycolor);
			for (int i = 0; i < lines.length; i++) {
				offset = 0;
				if (lines[i][0] != null)
					{
						g.setColor(myprefixcolor);
						g.drawString(lines[i][0],x, y + (i * rh) + ((i + 1) *
						metric.getHeight()));
						offset = metric.stringWidth(lines[i][0]);
						g.setColor(mycolor);
					}
				if (lines[i][1] != null)
					g.drawString(lines[i][1],x + offset,y + (i * rh) + ((i + 1) *
						metric.getHeight()));
			}
		}	
	}
	
	public class WuiButton {
		public boolean update = false;
		public boolean light = false;
		private boolean status = false;
		protected int rw = 4, rh = 4;
		protected Font font = null;
		protected FontMetrics metric = null;
		protected String text = null;
		protected int x, y, width, height, textwidth;
		protected Polygon edge = null;
						
		public WuiButton(FontMetrics metric, Font font, String text, int x, int y) {
			this.font = font;
			this.metric = metric;
			this.text = text;
			this.x = x;
			this.y = y;
			this.width = WuiButtonWidth; 
			this.textwidth = this.metric.stringWidth(this.text);
			this.height = this.metric.getHeight() + (2 * rh);
			this.edge = new Polygon(new int[]{x,x + rw + 2,x + rw + 2,x},
				new int[]{y, y, y + rh + 2,y + rh + 2},4);
		}
		
		public WuiButton(FontMetrics metric, Font font, String text, int x, int	y, int w) {
			this.font = font;
			this.metric = metric;
			this.text = text;
			this.x = x;
			this.y = y;
			this.width = w;
			this.textwidth = this.metric.stringWidth(this.text);
			this.height = this.metric.getHeight() + (2 * rh);
			this.edge = new Polygon(new int[]{x,x + rw + 2,x + rw + 2,x},
				new int[]{y, y, y + rh + 2,y + rh + 2},4);
		}
		
		public void paint(Graphics g) {
			if (status)
			{
				if (light) g.setColor(WuiRootColor.brighter());
					else g.setColor(WuiRootColor);
				g.fillRect(x,y,width,height);
				g.setColor(WuiRootColor.darker());
				g.drawRect(x,y,width,height);
				g.fillPolygon(edge);
				if (light) g.setColor(WuiRootColor.darker());
					else g.setColor(WuiRootColor.darker());
				g.setFont(this.font);
				g.drawString(text,x + (width - textwidth) / 2,
					y + height - rh - rh);
			}
			else
			{
				g.setColor(WuiHideColor);
				g.fillRect(x, y, width, height);
				g.setColor(WuiHideColor.darker());
				g.drawRect(x, y, width, height);
				g.fillPolygon(edge);
				g.setColor(WuiHideColor.darker());
				g.setFont(this.font);
				g.drawString(text, x + (width - textwidth) / 2,
					y + height - rh - rh);
			}
		}
					
		public boolean inside(int mx, int my) 
		{
			return(mx >= x && mx < (x + width) && my >= y && my < (y + height));
		}
		
		public boolean enabled()
		{
			return(status);
		}
		
		public boolean disabled()
		{
			return(!status);
		}
		
		public void enable()
		{
			status = true;
		}
		
		public void disable()
		{
			status = false;
		}
		
		public String getLabel()
		{
			return(text);
		}
	}
	// ---------------------------------------------------------------
	// eAWT components (extended AWT widgets)
	// ---------------------------------------------------------------
	protected eTextField chatInput;
	protected eWindow windowChannels, windowEmoticons;
	protected boolean showChannels, showEmoticons;
	public class eWindow extends Window
		implements MouseListener, MouseMotionListener, WindowListener {
		WuiButton[] myButtons;
		int w, h, action;
		
		public eWindow(Frame parent, WuiButton[] buttons, int w, int h, int a)
		{
			super(parent);
			this.addMouseListener(this);
			this.addMouseMotionListener(this);
			this.addWindowListener(this);
			this.myButtons = buttons;
			this.w = w;
			this.h = h;
			this.action = a;
			this.setSize(w, h);
		}
		
		public void paint (Graphics g)
		{
			g.setColor(WuiBackground);
			g.fillRect(0, 0, w, h);	
			//g.drawImage(logo,dim.width-logo.getWidth(this),0,this);	
			for (int i = 0; i <	myButtons.length; i++) 
				myButtons[i].paint(g);
		}
	
		public void update (Graphics g)
		{
			boolean one_action = false;
			for (int i = 0; i <	myButtons.length; i++)
			{
				if (myButtons[i].update)
				{
					myButtons[i].update = false;
					myButtons[i].paint(g);
					one_action = true;
				}
			}
			if (!one_action) paint(g);
		}
		
		public void mousePressed(MouseEvent e) { }
		public void mouseReleased(MouseEvent e) { }
		public void mouseClicked(MouseEvent e) 
		{ 
			for (int i = 0; i <	myButtons.length; i++)
			{
				if (myButtons[i].inside(e.getX(),e.getY()) &&
					myButtons[i].enabled())
				{
					if (action == 1)
					{
						this.hide();
						showChannels = false;
						myButtons[i].light = false;
						myButtons[i].update = true;
						repaint();
							
						irc.send("PART " + CURRENT_CHANNEL);
						CURRENT_CHANNEL = myButtons[i].getLabel();
						irc.send("JOIN " + CURRENT_CHANNEL);
					}
					else if (action == 2)
					{
						this.hide();
						showEmoticons = false;
						myButtons[i].light = false;
						myButtons[i].update = true;
						repaint();
						
						irc.send("PRIVMSG " + CURRENT_CHANNEL + " :" +
						"\001ACTION " + myButtons[i].getLabel() + "\001");
						chatConsole.preprintln("*** " + NICKNAME + " " + 
						myButtons[i].getLabel());
						chatConsole.update = true;
						WuiRootApplet.repaint();
					}
				}		
			}
			e.consume();
		}
		public void mouseEntered(MouseEvent e) { } 
		public void mouseExited(MouseEvent e) { }
		public void mouseDragged(MouseEvent e) { }
		public void mouseMoved(MouseEvent e) 
		{
			for (int i = 0; i <	myButtons.length; i++)
			{
				if (myButtons[i].inside(e.getX(),e.getY()) &&
					!(myButtons[i].light) && (myButtons[i].enabled()))
				{
					myButtons[i].light = true;
					myButtons[i].update = true;
					repaint();
				} else if (!(myButtons[i].inside(e.getX(),e.getY())) &&
					myButtons[i].light)
				{
					myButtons[i].light = false;
					myButtons[i].update = true;
					repaint();
				}
			}
			e.consume();
		}
		
		public void windowActivated(WindowEvent e) { }
		public void windowClosed(WindowEvent e) { }
		public void windowClosing(WindowEvent e) { }
		public void windowDeactivated(WindowEvent e) { }
		public void windowDeiconified(WindowEvent e) { }
		public void windowIconified(WindowEvent e) { }
		public void windowOpened(WindowEvent e) { }
	}	
	public class eTextField extends TextField 
		implements MouseListener, MouseMotionListener, TextListener {
		
		private int phase = 0;
		
		public eTextField(String text, int columns)
		{
			super(text, columns);
			this.addMouseListener(this);
			this.addMouseMotionListener(this);
			this.addTextListener(this);
		}
		
		public int getPhase() { return(phase); }
		public void changePhase(int what)
		{
			phase = what;
			helpConsole.clear();
			helpConsole.println(MSG_INPUT[phase][language]);
			helpConsole.update = true;
			WuiRootApplet.repaint();
		}
		
		public void mousePressed(MouseEvent e) { }
		public void mouseReleased(MouseEvent e) { }
		public void mouseClicked(MouseEvent e) { }
		public void mouseEntered(MouseEvent e) 
		{
			helpConsole.clear();
			helpConsole.println(MSG_INPUT[phase][language]);
			helpConsole.update = true;
			WuiRootApplet.repaint();			
		}
		public void mouseExited(MouseEvent e) 
		{
			helpConsole.clear();
			helpConsole.update = true;
			WuiRootApplet.repaint();
		}
		public void mouseDragged(MouseEvent e) { }
		public void mouseMoved(MouseEvent e) { }
		
		public void textValueChanged(TextEvent e)
		{
			if (e.getID() == TextEvent.TEXT_VALUE_CHANGED) { }
		}
	}
	// ---------------------------------------------------------------
	// IRC data
	// ---------------------------------------------------------------
	protected IRCConnection irc;
	String NICKNAME, REALNAME, PASSWORD;
	String CURRENT_CHANNEL, DEFAULT_CHANNEL;
	String IRC_SERVER;
	int IRC_PORT;
	
	public class IRCConnection extends Thread 
	{
		public final String CRLF = "\015\n";
		public String PREFIX = null, COMMAND = null, PARAMS = null;
		public Vector PARAMV = null;
		public int PARAMC = 0;
		public boolean registered = false;
		public boolean status = false;
	
        public boolean stop = false;
    	private Socket socket = null;
    	protected DataInputStream in = null;
    	protected DataOutputStream out = null;
		
    	public IRCConnection(String server, int port)
		{
			try
			{
				this.socket = new Socket(server, port);
				this.in = new DataInputStream((new BufferedInputStream(this.socket.getInputStream())));
				this.out = new DataOutputStream((new BufferedOutputStream(this.socket.getOutputStream())));
				status = true;
			}
			catch (SocketException e)
			{
				chatConsole.preprintln(">>> " + server + ":" + port + MSG_SOCKET[language] + e.getMessage());
				chatConsole.update = true;
				WuiRootApplet.repaint();
				status = false;
	    	}
			catch (IOException e)
			{ 
				chatConsole.preprintln(">>> " + server + ":" + port + MSG_SOCKET[language] + e.getMessage());
				chatConsole.update = true;
				WuiRootApplet.repaint();
				status = false;
			}
		}
		
		public void send(String what)
		{
			try
			{
				out.writeBytes(what + CRLF);
				out.flush();
			}
			catch (IOException e) 
			{
				chatConsole.preprintln(MSG_IO[language] + e.getMessage());
				chatConsole.update = true;
				WuiRootApplet.repaint();
				stop = true;
			}
		}
		
		public boolean is(String cmd)
		{
			if (cmd.equals(COMMAND)) return (true);
				else return(false);
		}
	
		public void parsePARAMS(String list)
		{
			PARAMV = new Vector();		
			while ((list != null) && (!(list.equals("")))) {
				if (list.startsWith(":")) {
					if (list.substring(1).length() > 0) {
						PARAMV.addElement(list.substring(1));
					}
					list = null;
				} else {
					if (list.indexOf(" ") == -1) {
						if (list.length() > 0) {
							PARAMV.addElement(list);
						}
						list = null;
					} else {
						PARAMV.addElement(list.substring(0,list.indexOf(" ")));
						list = list.substring(list.indexOf(" "));
						while (list.startsWith(" ")) { list = list.substring(1); }
					}
				}
			}
			PARAMC = PARAMV.size();
		}
	
		public void parse(String msg) {
			if (msg.startsWith(":")) {
				if (msg.indexOf(" ") == -1) {
					PREFIX = null;
				} else {
					PREFIX = msg.substring(1,msg.indexOf(" "));
					msg = msg.substring(msg.indexOf(" ") + 1);
				}
			}
			while (msg.startsWith(" ")) { msg = msg.substring(1); }
			if (msg.indexOf(" ") == -1) {
				COMMAND = msg;
			} else {
				COMMAND = msg.substring(0,msg.indexOf(" "));
				msg = msg.substring(msg.indexOf(" ") + 1);
				while (msg.startsWith(" ")) { msg = msg.substring(1); }
				PARAMS = msg;
			}
System.err.println(PREFIX + "|" + COMMAND + "|" + PARAMS + "|");
			parsePARAMS(PARAMS);
		}
	
		public void run()
		{
			for(;(!stop);)
			{
				try
				{
					if (in.available() != 0)
					{
						String s = in.readLine();
						parse(s);
						
						if (is("PING"))	send("PONG " + PARAMS);
						else if (is("ERROR"))
						{
							registered = false;
							chatInput.changePhase(0);
							chatInput.setText("");
							for (int i = 0; i <	actionButtons.length; i++) 
							{
								actionButtons[i].disable();
								actionButtons[i].update = true;
							}
							chatConsole.preprintln(IRC_ERROR[language]);
							chatConsole.update = true;
							WuiRootApplet.repaint();
							stop = true;
						}
						else if (is("401"))
						{
							chatConsole.preprintln(IRC_ERR_401[language]);
							chatConsole.update = true;
							WuiRootApplet.repaint();
						}
						else if (is("433"))
						{
							chatConsole.preprintln(IRC_ERR_433[language]);
							chatConsole.update = true;
							WuiRootApplet.repaint();
							stop = true;
						}
						else if (is("001"))
						{
							registered = true;
						}
						else if (is("352"))
						{
							if (PARAMC >= 6)
							{
								chatConsole.preprintln("+++ " + (String)PARAMV.elementAt(5));
								chatConsole.update = true;
								WuiRootApplet.repaint();
							}
						}
						else if (is("JOIN"))
						{
							if (PARAMC == 1)
							{
								String FROM = PREFIX;
								if (PREFIX.indexOf("!") != -1)
									FROM = FROM.substring(0, PREFIX.indexOf("!"));
								chatConsole.preprintln(">>> " + FROM + IRC_JOIN[language]
								+ (String)PARAMV.elementAt(0));
								chatConsole.update = true;
								WuiRootApplet.repaint();
							}
						}
						else if (is("PART"))
						{
							if (PARAMC == 1)
							{
								String FROM = PREFIX;
								if (PREFIX.indexOf("!") != -1)
									FROM = FROM.substring(0, PREFIX.indexOf("!"));
								chatConsole.preprintln(">>> " + FROM + IRC_PART[language]
								+ (String)PARAMV.elementAt(0));
								chatConsole.update = true;
								WuiRootApplet.repaint();
							}
						}
						else if (is("PRIVMSG"))
						{
							if (PARAMC == 2)
							{
								if (((String)PARAMV.elementAt(0)).startsWith("#"))
								{
									String FROM = PREFIX;
									if (PREFIX.indexOf("!") != -1)
										FROM = FROM.substring(0, PREFIX.indexOf("!"));
									if (((String)PARAMV.elementAt(1)).startsWith("\001"))
									{
										// CTCP ACTION
										if (((String)PARAMV.elementAt(1)).startsWith("\001ACTION"))
										{
											String TMSG = ((String)PARAMV.elementAt(1)).substring(8);
											TMSG = TMSG.substring(0, TMSG.length() - 1);
											chatConsole.preprintln("*** " + FROM + " " + TMSG);
										}
									}
									else
									{
										chatConsole.println(FROM, (String)PARAMV.elementAt(1));
									}
								}
								else
								{
									String FROM = PREFIX;
									if (PREFIX.indexOf("!") != -1)
										FROM = FROM.substring(0, PREFIX.indexOf("!"));
									chatConsole.println("!!! " + FROM, (String)PARAMV.elementAt(1));
								}								
								chatConsole.update = true;
								WuiRootApplet.repaint();
							}
						}
					}
					
				}	
				catch (IOException e) 
				{
					chatConsole.preprintln(MSG_IO[language] + e.getMessage());
					chatConsole.update = true;
					WuiRootApplet.repaint();
					stop = true;
				}
				
				try { this.sleep(10); } catch (InterruptedException ef) { }
			}
			
			try
			{
				socket.close();
			}
			catch (IOException e) { }
		}
    }
	
	// ---------------------------------------------------------------
	// data
	// ---------------------------------------------------------------
	protected final int WuiButtonHeight = 
		getFontMetrics(WuiButtonFont).getHeight() + 9;	
	protected final	WuiButton[] Channels = {
		new WuiButton(getFontMetrics(WuiButtonFont), WuiButtonFont,
			"#sputnik", 0, 0 * WuiButtonHeight, 199),
		new WuiButton(getFontMetrics(WuiButtonFont), WuiButtonFont,
			"#offen", 0, 1 * WuiButtonHeight, 199),
		new WuiButton(getFontMetrics(WuiButtonFont), WuiButtonFont,
			"#meckerei", 0, 2 * WuiButtonHeight, 199)
	};
	protected final WuiButton[] Emoticons = {
		new WuiButton(getFontMetrics(WuiButtonFont), WuiButtonFont,
		"freut sich und ist gut gelaunt   :-)", 0, 0 * WuiButtonHeight,449),
		new WuiButton(getFontMetrics(WuiButtonFont), WuiButtonFont,
		"zwinkert, meint es nicht ganz ernst   ;-)", 0, 1 * WuiButtonHeight,449),
		new WuiButton(getFontMetrics(WuiButtonFont), WuiButtonFont,
		"ist traurig oder nicht so gut drauf   :-(", 0, 2 * WuiButtonHeight, 449),
		new WuiButton(getFontMetrics(WuiButtonFont), WuiButtonFont,
		"ist sehr erstaunt   :-()", 0, 3 * WuiButtonHeight, 449),
		new WuiButton(getFontMetrics(WuiButtonFont), WuiButtonFont,
		"traegt eine Kappe bzw. hat Geburtstag   <:-)", 0, 4 * WuiButtonHeight, 449),
		new WuiButton(getFontMetrics(WuiButtonFont), WuiButtonFont,
		"hat Brett vor dem Kopf   #-)", 0, 5 * WuiButtonHeight, 449),
		new WuiButton(getFontMetrics(WuiButtonFont), WuiButtonFont,
		"ist betrunken   :*)", 0, 6 * WuiButtonHeight, 449),
		new WuiButton(getFontMetrics(WuiButtonFont), WuiButtonFont,
		"ist verwirrt   %-)", 0, 7 * WuiButtonHeight, 449),
		new WuiButton(getFontMetrics(WuiButtonFont), WuiButtonFont,
		"ist skeptisch   :-/", 0, 8 * WuiButtonHeight, 449),
		new WuiButton(getFontMetrics(WuiButtonFont), WuiButtonFont,
		"weint   :,-(", 0, 9 * WuiButtonHeight, 449),
		new WuiButton(getFontMetrics(WuiButtonFont), WuiButtonFont,
		"ist ein Clown   <:+)", 0, 10 * WuiButtonHeight, 449),
		new WuiButton(getFontMetrics(WuiButtonFont), WuiButtonFont,
		"streckt die Zunge raus   :-P", 0, 11 * WuiButtonHeight, 449),
		new WuiButton(getFontMetrics(WuiButtonFont), WuiButtonFont,
		"ist schockiert   :-O", 0, 12 * WuiButtonHeight, 449)
	};

	protected Image logo;
	protected int logo_width = 0, logo_height = 0, language = 0;
	protected Dimension dim;
	protected boolean logo_text = false;
	// ---------------------------------------------------------------
	// methods
	// ---------------------------------------------------------------
	// Initalisierung
	// ---------------------------------------------------------------
	public void init () {
		dim = getSize();
		logo = this.getImage(this.getDocumentBase(), this.getParameter("logo"));
		logo_width = (new Integer(this.getParameter("logo_width"))).intValue();
		logo_height = (new Integer(this.getParameter("logo_height"))).intValue();
		
		String lang = this.getParameter("language");
		if (lang == null) language = 0;
			else if (lang.equals("de")) language = 0;
				else if (lang.equals("en")) language = 1;
				
		IRC_SERVER = this.getParameter("irc_server");
		IRC_PORT = (new Integer(this.getParameter("irc_port"))).intValue();
		DEFAULT_CHANNEL = this.getParameter("default_channel");
		
		actionButtons = new WuiButton[3];	
		actionButtons[0] = new WuiButton(getFontMetrics(WuiButtonFont),
			WuiButtonFont, "?", 20 + 0 * (dim.width / 8), dim.height - 40);
		actionButtons[1] = new WuiButton(getFontMetrics(WuiButtonFont),
			WuiButtonFont, "@", 20 + 1 * (dim.width / 8), dim.height - 40);
		actionButtons[2] = new WuiButton(getFontMetrics(WuiButtonFont),
			WuiButtonFont, ";-)", 20 + 2 * (dim.width / 8), dim.height - 40);
			
		helpConsole = new WuiConsole(getFontMetrics(WuiConsoleFont),
			WuiConsoleFont, 3, WuiBackground, 20 + 3 * (dim.width / 8), dim.height
			- 40, 360, WuiRootColor.darker(), WuiRootColor);
		
		int chatMaxHeight = 310 - logo_height - 10;
		int chatLines = chatMaxHeight / (2 + getFontMetrics(WuiConsoleFont).getHeight());
				
		chatConsole = new WuiConsole(getFontMetrics(WuiConsoleFont),
			WuiConsoleFont, chatLines, WuiBackground, 10, logo_height + 10, dim.width 
			- 20, WuiHideColor.darker(), WuiRootColor.darker());
		
		this.setLayout(new FlowLayout(FlowLayout.LEFT, 10, 320));
		chatInput = new eTextField("", 70);
		chatInput.setFont(WuiConsoleFont);
		chatInput.addActionListener(this);
		chatInput.changePhase(0);
		
		this.add(chatInput);
		this.addMouseListener(this);
		this.addMouseMotionListener(this);
		
		helpConsole.clear();
//helpConsole.println(MSG_START[language]);
		helpConsole.update = true;
		
		chatConsole.clear();
		chatConsole.update = true;
		repaint();
	}
	// ---------------------------------------------------------------
	// Warten
	// ---------------------------------------------------------------
	public void sleep (long ms) {
		long time = System.currentTimeMillis();
		while (System.currentTimeMillis() < (time + ms))
		{
			try { irc.sleep(1);	} catch (InterruptedException e) { }
		}
	}
	// ---------------------------------------------------------------
	// Beendigung
	// ---------------------------------------------------------------
	public void destroy () {
		logo.flush();
	}
	// ---------------------------------------------------------------
	// Paintfunktion des Applets
	// ---------------------------------------------------------------
	public void paint (Graphics g) {		
		g.setColor(WuiBackground);
		g.fillRect(0,0,dim.width,dim.height);	
		g.drawImage(logo,dim.width-logo.getWidth(this),0,this);	
		for (int i = 0; i <	actionButtons.length; i++) 
			actionButtons[i].paint(g);
		helpConsole.paint(g);
		chatConsole.paint(g);
		chatInput.paint(g);
	}
	// ---------------------------------------------------------------
	// Updatefunktion des Applets
	// ---------------------------------------------------------------
	public void update (Graphics g) {
		boolean one_action = false;
		
		for (int i = 0; i <	actionButtons.length; i++)
		{
			if (actionButtons[i].update)
			{
				actionButtons[i].update = false;
				actionButtons[i].paint(g);
				one_action = true;
			}
		}
		if (helpConsole.update)
		{
			helpConsole.update = false;
			helpConsole.paint(g);
			one_action = true;
		}
		if (chatConsole.update)
		{
			chatConsole.update = false;
			chatConsole.paint(g);
			one_action = true;
		}
		
		if (!one_action) paint(g);
	}
	// ---------------------------------------------------------------
	// Informationsfunktionen des Applets
	// ---------------------------------------------------------------
	public String getAppletInfo () {
		return("Info");
	}
	
	public String[][] getParameterInfo () {
		return(new String[][] {
		{"language","[String] = \"de\", \"en\"","language of help messages"},
		{"logo", "[String]", "filename of an logo image"},
		{"logo_width", "[integer]", "width of the logo image"},
		{"logo_height", "[integer]", "height of the logo image"}
		});
	}
	
	public void mousePressed(MouseEvent e) { }
	public void mouseReleased(MouseEvent e) { }
	public void mouseClicked(MouseEvent e) {
		for (int i = 0; i <	actionButtons.length; i++)
		{
			if (actionButtons[i].inside(e.getX(),e.getY()) &&
				actionButtons[i].enabled())
			{
				if (i == 0) irc.send("WHO " + CURRENT_CHANNEL);
				if (i == 1)
				{
					if (showChannels) 
					{
						windowChannels.hide();
						showChannels = false;
						for (int j = 0; j < Channels.length; j++)
							Channels[j].disable();
					}
					else
					{
						for (int j = 0; j < Channels.length; j++)
							Channels[j].enable();
						windowChannels.show();
						showChannels = true;
					}
				}
				if (i == 2)
				{
					if (showEmoticons) 
					{
						windowEmoticons.hide();
						showEmoticons = false;
						for (int j = 0; j < Emoticons.length; j++)
							Emoticons[j].disable();
					}
					else
					{
						for (int j = 0; j < Emoticons.length; j++)
							Emoticons[j].enable();
						windowEmoticons.show();
						showEmoticons = true;
					}
				}
				
				helpConsole.clear();
				helpConsole.println(MSG_BUTTONS_CLICKED[i][language]);
				helpConsole.update = true;
				// (this.getToolkit()).beep();
				repaint();
			}
		}
		e.consume();
	}
	public void mouseEntered(MouseEvent e) { }
	public void mouseExited(MouseEvent e) { 
		for (int i = 0; i <	actionButtons.length; i++)
		{
			if (actionButtons[i].light)
			{
				actionButtons[i].light = false;
				actionButtons[i].update = true;
				helpConsole.clear();
				helpConsole.update = true;
				repaint();
			}
		}
		e.consume();
	}
	
	public void mouseDragged(MouseEvent e) { }
	public void mouseMoved(MouseEvent e) {
		for (int i = 0; i <	actionButtons.length; i++)
		{
			if (actionButtons[i].inside(e.getX(),e.getY()) &&
				!(actionButtons[i].light) && (actionButtons[i].enabled()))
			{
				actionButtons[i].light = true;
				actionButtons[i].update = true;
				helpConsole.clear();
				helpConsole.println(MSG_BUTTONS_MOVED[i][language]);
				helpConsole.update = true;
				repaint();
			} else if (!(actionButtons[i].inside(e.getX(),e.getY())) &&
				actionButtons[i].light)
			{
				actionButtons[i].light = false;
				actionButtons[i].update = true;
				helpConsole.clear();
				helpConsole.update = true;
				repaint();
			}
		}			
		if ((e.getY() <= logo_height) && 
			(e.getX() >= dim.width-logo.getWidth(this)) && !(logo_text)) 
		{
			logo_text = true;
			helpConsole.clear();
			helpConsole.println(MSG_LOGO);
			helpConsole.update = true;
			repaint();
		}
		else if (((e.getY() > logo_height) && (logo_text)))
		{
			logo_text = false;
			helpConsole.clear();
			helpConsole.update = true;
			repaint();
		}
		e.consume();
	}
	
	public void actionPerformed(ActionEvent e) 
	{
		String command = e.getActionCommand();
		
		if (chatInput.getPhase() == 0)
		{
			NICKNAME = command;
			chatInput.changePhase(1);
			chatInput.setText("");
		}
		else if (chatInput.getPhase() == 1)
		{
			REALNAME = command;
			chatInput.changePhase(2);
			chatInput.setText("");
			chatInput.setEchoChar('*');
		}
		else if (chatInput.getPhase() == 2)
		{
			PASSWORD = command;
			chatInput.setText("");
			this.remove(chatInput);
			
			// IRC Anmeldung
			irc = new IRCConnection(IRC_SERVER, IRC_PORT);
			if (irc.status)
			{
				irc.start();
				chatConsole.preprintln(MSG_WAIT[language]);
				chatConsole.update = true;
				repaint();
				
				irc.send("PASS " + PASSWORD);
				irc.send("NICK " + NICKNAME);
				irc.send("USER " + NICKNAME + " 0 0 :" + REALNAME);
				
				int t = 0;
				while (!irc.registered && (t < 500))
				{
					t++;
					this.sleep(10);
				}
System.out.println("t: " + t);
				if (t >= 500)
				{
					chatConsole.preprintln(MSG_NOREG[language]);
					chatConsole.update = true;
					repaint();
					chatInput = new eTextField("", 70);
					chatInput.setFont(WuiConsoleFont);
					chatInput.addActionListener(this);
					chatInput.changePhase(0);
				}
				else
				{
// from http://java.sun.com/j2se/1.4.2/docs/guide/deployment/deployment-guide/upgrade-guide/article-08.html
// Navigate component tree
Container c = this.getParent();
while (c != null && (c instanceof Frame) == false)
	c = c.getParent();
// Cast Container to Frame
if (c instanceof Frame)
{
					windowChannels = new eWindow((Frame)c,
						Channels, 200, (Channels.length + 1) * WuiButtonHeight, 1);
					if (windowChannels.getWarningString() == null) 
						windowChannels.setSize(200, Channels.length * WuiButtonHeight);
					windowChannels.hide();
					showChannels = false;
					
					windowEmoticons = new eWindow((Frame)c,
						Emoticons, 450, (Emoticons.length + 1) * WuiButtonHeight, 2);
					if (windowEmoticons.getWarningString() == null) 
						windowEmoticons.setSize(450, Emoticons.length * WuiButtonHeight);
					windowEmoticons.hide();
					showEmoticons = false;
}
else
	System.out.println("cast to Frame failed!");
					
					for (int i = 0; i <	actionButtons.length; i++) 
					{
						actionButtons[i].enable();
						actionButtons[i].update = true;
					}
				
					CURRENT_CHANNEL = DEFAULT_CHANNEL;
					irc.send("JOIN " + CURRENT_CHANNEL);
					
					chatInput = new eTextField("", 70);
					chatInput.setFont(WuiConsoleFont);
					chatInput.addActionListener(this);
					chatInput.changePhase(3);
				}
			}
			else 
			{
				chatInput = new eTextField("", 70);
				chatInput.setFont(WuiConsoleFont);
				chatInput.addActionListener(this);
				chatInput.changePhase(0);
			}
			// Applet neu aufbauen
			this.add(chatInput);
			this.doLayout();
			repaint();
			chatInput.requestFocus();
		}	
		else
		{
			if (irc.stop == true)
			{
				for (int i = 0; i <	actionButtons.length; i++) 
				{
					actionButtons[i].disable();
					actionButtons[i].update = true;
				}
				chatInput.changePhase(0);
				repaint();
			}
		
			if (command.startsWith("/"))
			{
				if (command.equals("/"))
				{
					chatConsole.preprintln(MSG_IRC[language]);
					chatConsole.update = true;
					chatInput.setText("");
					repaint();
				}
				else
				{
					// Kommando und Parameter direkt senden
					irc.send(command.substring(1));
					chatInput.setText("");
					repaint();
				}
			}
			else if (command.startsWith("@"))
			{
				if (command.indexOf(" ") != -1)
				{
					// private Nachricht senden
					String TO = command.substring(1, command.indexOf(" "));
					String MSG = command.substring(command.indexOf(" ") + 1);
					irc.send("PRIVMSG " + TO + " :" + MSG);
					chatConsole.println("!!! [" + TO + "] " + NICKNAME, MSG);
					chatConsole.update = true;
					chatInput.setText("");
					repaint();
				}
				else
				{
					chatConsole.preprintln(MSG_PRIV[language]);
					chatConsole.update = true;
					chatInput.setText("");
					repaint();
				}
			}
			else
			{
				// PRIVMSG senden
				irc.send("PRIVMSG " + CURRENT_CHANNEL + " :" + command);				
				chatConsole.println(NICKNAME, command);
				chatConsole.update = true;
				chatInput.setText("");
				repaint();
			}
		}
	}
}

