# -*-perl-*-
# Keitairc::IrcBuffer
# $Id: IrcBuffer.pm,v 1.10 2008-02-25 16:52:20 morimoto Exp $
# $Source: /home/ishikawa/work/keitairc/tmp/keitairc/lib/Keitairc/IrcBuffer.pm,v $
#
# Copyright (c) 2008 Jun Morimoto <morimoto@mrmt.net>
# This program is covered by the GNU General Public License 2

package Keitairc::IrcBuffer;
use strict;
use Encode;
use Data::Dumper;

################################################################
sub new{
	my $proto = shift;
	my $arg = shift;
	my $me = {};

	$me->{history} = $arg->{history};

	# join しているchannelの名称を記録するハッシュ (jis)
	$me->{cid2name} = {};
	$me->{name2cid} = {};

	# join しているtopicの名称を記録するハッシュ (jis)
	$me->{topic} = {};

	$me->{nicks} = {};

	# チャネルの会話内容を記録するハッシュ (euc-jp)
	$me->{buffer} = {};
	$me->{unread} = {};

	# 各チャネルの最終発言時刻
	$me->{mtime} = {};
	# 各チャネルの未読行数
	$me->{unread_lines} = {};

	# chk
	$me->{message_added} = 0;

        bless $me;
}

################################################################
sub add_nick{
	my($me, $cid, $nick, $chop, $realname) = @_;
	$me->{nicks}->{$cid}->{$nick}->{realname} = $realname;
	$me->{nicks}->{$cid}->{$nick}->{chop} = $chop;
}

################################################################
sub list_nick{
	my($me, $cid, $nick, $chop, $realname) = @_;
	keys %{$me->{nicks}->{$cid}};
}

################################################################
sub remove_nick{
	my($me, $cid, $nick) = @_;
	delete $me->{nicks}->{$cid}->{$nick};
}

################################################################
sub get_nick_realname{
	my($me, $cid, $nick) = @_;
	$me->{nicks}->{$cid}->{$nick}->{realname};
}

################################################################
sub op_nick{
	my($me, $cid, $nick) = @_;
	if(defined $me->{nicks}->{$cid}){
		if(defined $me->{nicks}->{$cid}->{$nick}){
			$me->{nicks}->{$cid}->{$nick}->{chop} = 1;
		}
	}
}

################################################################
sub deop_nick{
	my($me, $cid, $nick) = @_;
	if(defined $me->{nicks}->{$cid}){
		if(defined $me->{nicks}->{$cid}->{$nick}){
			$me->{nicks}->{$cid}->{$nick}->{chop} = 0;
		}
	}
}

################################################################
sub get_nick_op{
	my($me, $cid, $nick) = @_;
	if(defined $me->{nicks}->{$cid}){
		if(defined $me->{nicks}->{$cid}->{$nick}){
			return $me->{nicks}->{$cid}->{$nick}->{chop};
		}
	}
}

################################################################
sub channels{
	my $me = shift;
	map {
		$_
	}(sort
	  {
		  $me->mtime($b) <=> $me->mtime($a)
	  } keys %{$me->{cid2name}});
}

################################################################
sub now{
	my ($sec, $min, $hour) = localtime(time);
	sprintf('%02d:%02d', $hour, $min);
}

################################################################
# 生のiso-2022-jpのまま扱うこと。こういう仕様なのでしょうがない。
sub name2cid{
	my($me, $name) = @_;
	$name =~ tr/A-Z[\\]^/a-z{|}~/;

	unless(defined $me->{name2cid}->{$name}){
		my @sort = sort { $a - $b } (keys %{$me->{cid2name}});
		my $cid = 1 + pop @sort;
		$me->{cid2name}->{$cid} = $name;
		$me->{name2cid}->{$name} = $cid;
	}

	$me->{name2cid}->{$name};
}

################################################################
sub cid2name{
	my($me, $cid) = @_;
	$me->{cid2name}->{$cid};
}

################################################################
sub part{
	my($me, $cid) = @_;
	delete $me->{cid2name}->{$cid};
}

################################################################
sub join{
	my ($me, $name) = @_;
	my $cid = $me->name2cid($name);
	$me->{cid2name}->{$cid} = $name;
}

################################################################
sub mtime{
	my($me, $cid) = @_;
	$me->{mtime}->{$cid};
}

################################################################
sub message_added{
	my($me, $v) = @_;
	if(defined $v){
		$me->{message_added} = $v;
	}
	$me->{message_added};
}

################################################################
sub unread_lines{
	my($me, $cid) = @_;
	$me->{unread_lines}->{$cid};
}

################################################################
sub unread{
	my($me, $cid) = @_;
	$me->{unread}->{$cid};
}

################################################################
sub clear_unread{
	my($me, $cid) = @_;
	$me->{unread}->{$cid} = '';
	$me->{unread_lines}->{$cid} = 0;
}

################################################################
sub topic{
	my($me, $cid, $topic) = @_;
	if(defined $topic){
		$me->{topic}->{$cid} = $topic;
	}
	$me->{topic}->{$cid};
}

################################################################
sub buffer{
	my($me, $cid) = @_;
	$me->{buffer}->{$cid};
}

################################################################
# 引数の $msg は euc-jp, $channel は jis
sub add_message{
	my($me, $cid, $message, $who) = @_;

	if(length $who){
		$message = sprintf('%s %s> %s', now(), $who, $message);
	}else{
		$message = sprintf('%s %s', now(), $message);
	}

	{
		my @tmp = split("\n", $me->{buffer}->{$cid});
		push @tmp, $message;

		if(@tmp > $me->{history}){
			$me->{buffer}->{$cid} =
				CORE::join("\n", splice(@tmp, -$me->{history}));
		}else{
			$me->{buffer}->{$cid} = CORE::join("\n", @tmp);
		}
	}

	{
		my @tmp = split("\n", $me->{unread}->{$cid});
		push @tmp, $message;

		if(@tmp > $me->{history}){
			$me->{unread}->{$cid} =
				CORE::join("\n", @tmp[1 .. $me->{history}]);
		}else{
			$me->{unread}->{$cid} = CORE::join("\n", @tmp);
		}

		$me->{unread_lines}->{$cid} = scalar(@tmp);
	}

	if($me->{unread_lines}->{$cid} > $me->{history}){
		$me->{unread_lines}->{$cid} = $me->{history};
	}

	$me->{mtime}->{$cid} = time;
}

################################################################
# チャネル名称を短かくする
sub compact_channel_name{
	my $me = shift;
	my $cid = shift;
	my $name = $me->cid2name($cid);

	$name = decode('jis', $name);

	# #name:*.jp を %name に
	if($name =~ s/:\*\.jp$//){
		$name =~ s/^#/%/;
	}

	# 末尾の単独の @ は取る (plumプラグインのmulticast.plm対策)
	$name =~ s/\@$//;

	encode('shiftjis', $name);
}

################################################################
sub simple_escape{
	my $me = shift;
        local($_) = shift;
        s/&/&amp;/g;
        s/>/&gt;/g;
        s/</&lt;/g;
        $_;
}

################################################################
sub colorize{
	my $me = shift;
        local($_) = shift;

	my %ct = (
		1 => 'Black',
		2 => '#000080', # Navy Blue
		3 => 'Green',
		4 => 'Red',
		5 => 'Maroon',
		6 => 'Purple',
		7 => 'Olive',
		8 => 'Yellow',
		9 => '#32cd32', # Lime Green
		10 => 'Teal',
		11 => 'Aqua',
		12 => '#4169e1', # Royal Blue
		13 => '#ff69b4', # Hot Pink
		14 => '#a9a9a9', # Dark Gray
		15 => '#d3d3d3', # Light Gray
		16 => 'White');
	my $colored = 0;

	do{
		if($colored){
			s|\x03(\d{1,2})|sprintf('</font><font color="%s">', $ct{0+$1})|e;
			if(s|\x03|</font>|){
				$colored = 0;
			}
		}else{
			if(s|\x03(\d{1,2})|sprintf('<font color="%s">', $ct{0+$1})|e){
				$colored = 1;
			}
		}
	}while(m|\x03\d{1,2}|);

	if($colored){
		$_ .= '</font>';
	}

	$_;
}

1;
