/*
 Eteria IRC Client, an RFC 1459 compliant client program written in Java.
 Copyright (C) 2000-2001  Javier Kohen <jkohen at tough.com>
 
 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */
 
 import java.awt.*;
 import java.awt.event.*;
 import java.net.URL;
 import java.net.MalformedURLException;
 import java.io.*;
 import java.util.*;
 import java.text.Collator;
 import java.text.MessageFormat;
 import java.text.ParseException;
 
 import ar.com.jkohen.irc.Channel;
 import ar.com.jkohen.irc.User;
 import ar.com.jkohen.irc.MircMessage;
 import ar.com.jkohen.awt.ChatPanel;
 import ar.com.jkohen.awt.ImageButton;
 import ar.com.jkohen.util.Resources;
 import ar.com.jkohen.util.ConfigurationProperties;
 import com.splendid.awtchat.*;
 
 
 public class ChanListWindow extends ChatPanel implements ActionListener, ItemListener, HyperlinkReceiver, Observer, CopyText
 {
 	private EIRC eirc;
 	private String title;
 	private SmileyTextArea text_canvas;
 	private TextField new_chan, users_nbr;
 	private Checkbox byname, bynumber;	
 	private ImageButton b;
 	private Label label;
 	private int number = 0;
 
 	private Resources res;
 	protected static final String min_str = Resources.getString("channel_list.minima");
 	protected static final String users_str = Resources.getString("channel_list.users");
 	protected static final String newchan_str = Resources.getString("channel_list.new");
 	protected static final String refresh = Resources.getString("channel_list.refresh");
 	
 //	private Vector chans;
 	private ChannelItem chans[];
 	private int count = 0;
 	
 	private Collator collator;
 	
 	private final int SORT_BYNAME = 0;
 	private final int SORT_BYNUM = 1;
 	private final int SORT_BYTOPIC = 2;
 	
 	private int sort_criteria = SORT_BYNAME;
 	
 	private final int MAXCHANS = 40000;
 	
 	/* Configuration properties. */
 	private String list_parameter;
 
 
 	public ChanListWindow(EIRC eirc, String title)
 	{
 		super(title);
 		text_canvas = new SmileyTextArea(this, this);
 
 		this.eirc = eirc;
 		this.title = title;
 		this.collator = Collator.getInstance();
 		this.chans = new ChannelItem[MAXCHANS];
 		
 		text_canvas.setMode(eirc.scrollSpeed());
 		text_canvas.setBufferlen(MAXCHANS);
 		text_canvas.setBreaks(false);
 		int tabs[] = {-1, 160, 190};
 		text_canvas.setTabs(tabs);
 		
 		GridBagLayout gb = new GridBagLayout();
 		GridBagConstraints gbc = new GridBagConstraints();
 		setLayout(gb);
 
 		gbc.insets = new Insets(2, 2, 2, 2);
 		
 		label = new Label(newchan_str + " : ", Label.RIGHT);
 		gbc.gridx = 0;
 		gbc.gridy = 2;
 		gbc.gridwidth = 3;
 		gbc.anchor = GridBagConstraints.WEST;
 		gbc.fill = GridBagConstraints.NONE;
 	  	gbc.weightx = 0;
 		gb.setConstraints(label, gbc);
 		add(label);
 
 		new_chan = new TextField();
 		gbc.gridx = 3;
 		gbc.weightx = 1;
 		gbc.gridwidth = 4;
 		gbc.anchor = GridBagConstraints.WEST;
 		gbc.fill = GridBagConstraints.HORIZONTAL;
 		gb.setConstraints(new_chan, gbc);
 		add(new_chan);
 		
 		Label l = new Label(min_str);
 		gbc.gridx = 0;
 		gbc.gridy = 0;
 		gbc.gridwidth = 1;
 		gbc.weightx = 0;
 		gbc.fill = GridBagConstraints.NONE;
 		gbc.anchor = GridBagConstraints.WEST;
 		gb.setConstraints(l, gbc);
 		add(l);
 		
 		gbc.gridx++;
 		
 		users_nbr = new TextField();
 		users_nbr.setText("1");
 		gbc.weightx = 0.05;
 		gbc.fill = GridBagConstraints.HORIZONTAL;
 		gb.setConstraints(users_nbr, gbc);
 		add(users_nbr);
 		
 		gbc.gridx++;
 		
 		l = new Label(users_str);
 		gbc.weightx = 0;
 		gb.setConstraints(l, gbc);
 		add(l);
 		
 		l = new Label(res.getString("channel_list.sort") + " :");
 		gbc.gridx++;
 		gb.setConstraints(l, gbc);
 		add(l);
 
 		CheckboxGroup cbg = new CheckboxGroup();
 		byname = new Checkbox(res.getString("channel_list.byname"), cbg, (sort_criteria == SORT_BYNAME));
 		gbc.gridx++;
 	   	gb.setConstraints(byname, gbc);
 		add(byname);
 		
 		bynumber = new Checkbox(res.getString("channel_list.bynumber"), cbg, (sort_criteria == SORT_BYNUM));
 		gbc.gridx++;
 		gb.setConstraints(bynumber, gbc);
 		add(bynumber);
 		
 		b = new ImageButton(refresh);
 		b.setWaitType();
 		b.setEnabled(true);
 		b.setActionCommand("list");
 		gbc.gridx++;
 		gbc.weightx = 1;
 		gbc.anchor = GridBagConstraints.WEST;
 		gb.setConstraints(b, gbc);
 		add(b);
 		
 		gbc.gridx = 0;
 		gbc.gridy = 1;
 		gbc.anchor = GridBagConstraints.CENTER;
 		gbc.fill = GridBagConstraints.BOTH;
 		gbc.weighty = 1;
 	  	gbc.weightx = 1;
 	  	gbc.gridwidth = 7;
 		gb.setConstraints(text_canvas, gbc);
 		add(text_canvas);
 
 		bynumber.addItemListener(this);
 		byname.addItemListener(this);
 		new_chan.addActionListener(this);
 		users_nbr.addActionListener(this);
 		b.addActionListener(this);
 
 	}
 	
 	public void clear()
 	{
 		count = 0;
 	}
 	
 	public void setEnabled(boolean enabled)
 	{
 		b.setEnabled(enabled);
 	}
 	
 	public void listChannels()
 	{
 		String l[];
 		int min = 1;
 		try
 		{
 			min = Integer.parseInt(users_nbr.getText());
 		} catch (NumberFormatException e) {}
 		
 		if (--min > 0)
 		{
 			l = new String[1];
 			l[0] = MessageFormat.format(list_parameter, new Object[] { new Integer(min) });
 			eirc.sendMessage("LIST", l);
 		}
 		else
 		{
 			l = new String[0];
 			eirc.sendMessage("LIST", l);
 		}
 	}
 	
 	private void display()
 	{
 		text_canvas.clear();
 		text_canvas.setMode(text_canvas.SAFE);
 		
 		sort();
 
 	  	for (int i = 0; i < count; i++)
 	  	{
 			ChannelItem channel = chans[i];
 			
 			String topic = channel.getTopic();
 			if (topic != null)
 			{
 				// Strip chan modes in topic (Unreal)
 				
 				if (topic.startsWith("[+"))
 				{
 					MessageFormat mf = new MessageFormat("[+{0}] {1}");
 					try
 					{
 						Object o[] = mf.parse(topic);
 						if (o[1] != null)
 							topic = o[1].toString();
 					}
 					catch (ParseException ex) {}
 				}					
 			 }  
 			text_canvas.append(channel.getTag() + " " + MircMessage.COLOR + "3 " + channel.getUsers() + " " + MircMessage.RESET + topic);
 		}
 
 		text_canvas.setMode(eirc.scrollSpeed());
 		text_canvas.home();
 		b.setEnabled(true);
 		
 	}
 	
 	public boolean initialized()
 	{
 		return(count >= 0);
 	}
 		
 	public void add(ChannelItem ch)
 	{
 		if (count < MAXCHANS)
 			chans[count++] = ch;
 		else
 			stop();
 	}
 	
 	public void stop()
 	{
 		display();
 	}
 	
 	public int number()
 	{
 		return(count);
 	}
 	
 	// Sorting algorithm from Denis Ahrens
 	
 	private void sort()
 	{
 	   	sort(0, count - 1);
 		
 		switch (sort_criteria)
 		{
 		case SORT_BYNAME:
 			sortByName();
 			break;
 		case SORT_BYNUM:
 			sortByNum();
 
 		}		
 	}
 	
 	private void sortByName()
 	{
 		int i, j;
 		String v;
 		for (i = 0; i < count; i++)
 		{
 			ChannelItem ch = chans[i];
 			v = ch.getTag();
 					
 			j=i;
 			while ((j > 0) && (collator.compare(chans[j-1].getTag(), v) > 0))
 			{
 				chans[j] = chans[j-1];
 				j--;
 			}
 			chans[j] = ch;
 		}
 	}
 	
 	private void sortByNum()
 	{
 		int i, j, w;
 		for (i = count - 1; i >= 0; i--)
 		{
 			ChannelItem ch = chans[i];
 			w = ch.getUsers();
 					
 			j=i;
 			while ((j < count-1) && (chans[j+1].getUsers() > w))
 			{
 				chans[j] = chans[j+1];
 				j++;
 			}
 			chans[j] = ch;
 		}
 	}
 
    private void sort(int l, int r)
    {
 		int i, j;
 		
 		if ((r-l)>4)
 		{
 			i = (r+l)/2;
 			
 			switch (sort_criteria)
 			{
 			case SORT_BYNAME:
 				String s1 = chans[i].getTag();
 				String s2 = chans[l].getTag();
 				String s3 = chans[r].getTag();
 				if (collator.compare(s2, s1) < 0) swap(l,i);
 				if (collator.compare(s2, s3) < 0) swap(l,r);
 				if (collator.compare(s1, s3) < 0) swap(i,r);
 				break;
 			case SORT_BYNUM:
 				int comp1 = chans[i].getUsers();
 				int comp2 = chans[l].getUsers();
 				int comp3 = chans[r].getUsers();
 				if (comp2 < comp1) swap(l,i);
 				if (comp2 < comp3) swap(l,r);
 				if (comp1 < comp3) swap(i,r);
 			}
 			   
 			j = r-1;
 			swap(i,j);
 			i = l;
 				
 				
 			switch (sort_criteria)
 			{
 			case SORT_BYNAME:
 				String v = chans[j].getTag();
 				for(;;)
 				{
 					while(collator.compare(chans[++i].getTag(), v) > 0);
 					while(collator.compare(chans[--j].getTag(), v) < 0);
 					if (j<i) break;
 					swap (i,j);
 				}
 				break;
 			case SORT_BYNUM:
 				int w = chans[j].getUsers();
 				for(;;)
 				{
 					while(chans[++i].getUsers() > w);
 					while(chans[--j].getUsers() < w);
 					if (j<i) break;
 					swap (i,j);
 				}
 			}
 		
 			swap(i,r-1);
 			sort(l,j);
 			sort(i+1,r);
 		}
 	}
 
 	private void swap(int i, int j)
 	{
 			ChannelItem ch = chans[i];
 			chans[i] = chans[j];
 			chans[j] = ch;
 	}
 
 	
 	public void setBackground(Color c)
 	{
 		super.setBackground(c);
 		b.setBackground(c);
 
 		Component cp[] = getComponents();
 		for (int i = 0; i < cp.length; i++)
 			if (cp[i] instanceof Label || cp[i] instanceof Checkbox)
 				cp[i].setBackground(c);
 	}
 
 	public void setTextBackground(Color c)
 	{
 		new_chan.setBackground(c);
 		users_nbr.setBackground(c);
 		text_canvas.setBackground(c);
 	}
 	
 	public void setSelectedBackground(Color c)
 	{
 		text_canvas.setSelectedBackground(c);
 	}
 
 	public void setForeground(Color c)
 	{
 		super.setForeground(c);
 	}
 
 	public void setTextForeground(Color c)
 	{
 		new_chan.setForeground(c);
 		users_nbr.setForeground(c);
 	}
 
 	public void setFont(Font f)
 	{
 		new_chan.setFont(f);
 		users_nbr.setFont(f);
 		text_canvas.setFont(f);
 		b.setFont(f);
 	}
 
 	protected void visitURL(URL url)
 	{
 		eirc.visitURL(url);
 	}
 
 	protected void joinChannel(String name)
 	{
 		eirc.joinChannel(name);
 	}
 	
 	public void handleHyperlink(String link)
 	{
 		if (Channel.isChannel(link))
 		{
 			joinChannel(link);
  		}
  		else
  		{
 	 	   try
 	 	   {
 				visitURL(new URL(link));
 	 	   }
 	 	   catch (MalformedURLException e) {}
 		}
 	}
 
 	public void handleNick(String nick)
 	{
 	}
 
 	public void addText(String s)
 	{
 		eirc.cutPaste(s);
 	}
 
 	public void update(Observable o, Object arg)
 	{
 		ConfigurationProperties props = (ConfigurationProperties) o;
 
  		if (arg == null || arg.equals("list_parameter"))
 			this.list_parameter = props.getString("list_parameter");
 			
 		if (arg == null || arg.equals("scroll_speed"))
 			text_canvas.setMode(props.getInt("scroll_speed"));
 	}
 
 	public void itemStateChanged(ItemEvent ev) 
 	{
 		Object ob = ev.getSource();
 		if (ob == byname || ob == bynumber)
 		{
 			if (byname.getState())
 				sort_criteria = SORT_BYNAME;
 			if (bynumber.getState())
 				sort_criteria = SORT_BYNUM;
 				
 			display();
 		}
 	}
 	
 	public void actionPerformed(ActionEvent ev)
 	{
 		String ac = ev.getActionCommand();
 		Object ob = ev.getSource();
 
 		if (ob == new_chan)
 		{
 			String chan = new_chan.getText();
 			if (!Channel.isChannel(chan))
 				chan = "#" + chan;
 			
 			if (chan.length() > 1)
 				joinChannel(chan);
 		}
 		
 		if (ac.equals("list") || ob == users_nbr)
 		{
 			b.setEnabled(false);
 			
 			listChannels();
 		}
 	}
 }