#!/usr/bin/perl
#
# colorize-0.0.3.pl - Colorize messages, nicks in message text, or both.
#
# Usage: see the POD at the end of this file or type '/colorize ?' in Xchat.
#
# To customize the brackets that surround the sending nick, e.g. <nick>,
# modify any of the three variables in the section called 'BRACKET SETTINGS'
# below.
# 

use strict;
use warnings;

my %color = (
    white        => '00',
    black        => '01',
    blue         => '02',
    green        => '03',
    red          => '04',
    darkgred     => '05',
    purple       => '06',
    darkyellow   => '07',
    yellow       => '08',
    brightgreen  => '09',
    darkgreen    => '10',
    green        => '11',
    blue         => '12',
    brightpurple => '13',
    darkgrey     => '14',
    lightgrey    => '15',
);

#-----------------------------------------------------------------
#  BRACKET SETTINGS
#
# For surrounding the nick, e.g. <nick>
#
# Examples are in the following comments
#   my $BRACKET_COLOR       = $color{white};
#   my $LEFT_BRACKET_STYLE  = '<';
#   my $RIGHT_BRACKET_STYLE = '>';
#
my $BRACKET_COLOR       = "";
my $LEFT_BRACKET_STYLE  = '';
my $RIGHT_BRACKET_STYLE = '';

#-----------------------------------------------------------------

my $script_name    = 'colorize.pl';
my $script_version = '0.0.3';

# Text Event to listen in on
my $print_event = 'Channel Message';

# Xchat command to set colorize option
my $config_command = 'colorize';

# functions for colorizing [ nicks | messages | all ]
my %colorize_with = (
    'message and embedded nicks' => \&colorize_all,
    'message only'               => \&colorize_messages_only,
    'embedded nicks only'        => \&colorize_nicks_only,
);

# Default to colorizing 'enabled' and colorizing all
my $colorize_command = 'message and embedded nicks';
my $colorize_enabled = 1;

# Formatting codes
my $start_coloring_with = "\cC";
my $formatting_off      = "\cO";

# Brackets
my $left_bracket  
    = $start_coloring_with 
    . $BRACKET_COLOR 
    . $LEFT_BRACKET_STYLE 
    . $formatting_off
    ;

my $right_bracket 
    = $start_coloring_with 
    . $BRACKET_COLOR
    . $RIGHT_BRACKET_STYLE
    . $formatting_off
    ;

# Cache for color codes of seen nicks
my %color_code_for = ();

# Register plugin with Xchat
Xchat::register( $script_name , $script_version );

# Print a notice that the plugin was loaded
Xchat::print(
    "\cB$script_name\cB version \cB$script_version\cB " . "loaded\n" 
);

# Intercept events
Xchat::hook_print( $print_event, \&do_colorize );
Xchat::hook_command( $config_command, \&set_colorize_option );

# Get/Set options
sub set_colorize_option {   # {{{
    my ( $switch ) = $_[0][1];

    $switch ||= '';

    my $msg;

    for ( $switch ) {
        # No switch, report state
        /^$/    and do {
                        $msg = report_state();

                        last;
                    };
        # Show usage
        /^\?$|^h/i    and do {
                        $msg = usage(); 

                        last;
                    };

        # Enable/Disable
        
        # disable
        /^d/i  and do {
                        # off
                        $colorize_enabled = 0;

                        $msg = "$script_name: Colorizing disabled\n";
                        last;
                    };
        # enable 
        /^e/i  and do {
                        # on
                        $colorize_enabled = 1;

                        $msg = "$script_name: Colorizing enabled\n";
                        last;
                    };

        # Colorizing scheme
        
        # colorize all
        /^a/i   and do { 
                        $colorize_command = 'message and embedded nicks';

                        $msg 
                            = "$script_name: Setting colorize scheme to "
                            . "'$colorize_command'\n";

                        last;
                    };
        # colorize message only
        /^m/i   and do { 
                        $colorize_command = 'message only';

                        $msg 
                            = "$script_name: Setting colorize scheme to "
                            . "'$colorize_command'\n";

                        last;
                    };
        # colorize nicks only
        /^n/i   and do { 
                        $colorize_command = 'embedded nicks only';

                        $msg 
                            = "$script_name: Setting colorize scheme to "
                            . "'$colorize_command'\n";

                        last;
                    };

        # Unrecognized switch
        $msg 
            = "$script_name: Unrecognized option '$switch', "
            . "keeping current option: $colorize_command\n";
    }

    Xchat::print( $msg );
    return Xchat::EAT_ALL;

} # }}}

# Calls appropriate colorizing function
sub do_colorize {   # {{{
    my ( $nick, $text ) = @{ $_[0] };

    return Xchat::EAT_NONE unless $colorize_enabled;

    # Get: message sender's nick color for future reference
    #      sender's nick without color coding for use as key in cache
    my ( $nick_color, $nick_name_only ) = $nick =~ /^\x03(\d{2})(.*)$/;

    # Stop processing if nicks aren't colored
    return Xchat::EAT_NONE unless defined $nick_color;

    my $channel = Xchat::get_info("channel");
    my $server  = Xchat::get_info("server");

    # Cache the color code for the sender's nick
    $color_code_for{$server}{$channel}{$nick_name_only} = $nick_color;

    # Use appropriate colorize scheme 
    my $colorized = $colorize_with{$colorize_command}->(
        channel        => $channel,
        server         => $server,
        nick           => $nick,
        text           => $text,
        nick_color     => $nick_color,
    );

    # Print newly colorized [ nick | message | both ]
    Xchat::print(
        $colorized,
        $channel,
        $server
    );

    # Let other plugins/scripts still see this event
    return Xchat::EAT_XCHAT;

} # }}}

sub colorize_messages_only {    # {{{
    my %arg = @_;

    my $nick           = $arg{nick};
    my $text           = $arg{text};
    my $nick_color     = $arg{nick_color};

    # Colorize the message text
    my $colorized_text 
        = $start_coloring_with 
        . $arg{nick_color} 
        . $arg{text};

    # Join nick and colorized text 
    my $colorized_message 
        = $left_bracket . $arg{nick} . $right_bracket 
        . "\t" 
        . $colorized_text
        . "\n"
        ;

    return $colorized_message;

} # }}}

sub colorize_nicks_only {   # {{{
    my %arg = @_;

    my $channel    = $arg{channel};
    my $server     = $arg{server};
    my $nick       = $arg{nick};
    my $text       = $arg{text};
    my $nick_color = $arg{nick_color};

    # Colorize the mention of any cached nicks in the message text
    for my $cached_nick ( keys %{ $color_code_for{$server}{$channel} } ) {
        # cached nick found in message
        if ( $text =~ /(\b\Q$cached_nick\E\b)/ ) {
            my $cached_nick_color 
                = $color_code_for{$server}{$channel}{$cached_nick};

            my $colorized_cached_nick 
                = $start_coloring_with
                . $cached_nick_color 
                . $cached_nick 
                . $formatting_off;

            $text =~ s/(\b)\Q$cached_nick\E(\b)/$1$colorized_cached_nick$2/g;
        }
    }

    # Join sender's nick and colorized text 
    my $message_with_colored_nicks_only 
        = $left_bracket . $nick . $right_bracket 
        . "\t" 
        . $text 
        . "\n"
        ;

    return $message_with_colored_nicks_only;

} # }}}

sub colorize_all {  # {{{
    my %arg = @_;

    my $channel    = $arg{channel};
    my $server     = $arg{server};
    my $nick       = $arg{nick};
    my $text       = $arg{text};
    my $nick_color = $arg{nick_color};

    # Colorize the mention of any cached nicks in the message text
    for my $cached_nick ( keys %{ $color_code_for{$server}{$channel} } ) {
        if ( $text =~ /(\b\Q$cached_nick\E\b)/ ) {
            my $cached_nick_color 
                = $color_code_for{$server}{$channel}{$cached_nick};

            my $colorized_cached_nick 
                = $start_coloring_with
                . $cached_nick_color 
                . $cached_nick 
                . $start_coloring_with
                . $nick_color
                ;

            $text =~ s/(\b)\Q$cached_nick\E(\b)/$1$colorized_cached_nick$2/g;
        }
    }

    # Colorize the message 
    $text 
        = $start_coloring_with
        . $nick_color 
        . $text;

    # Join sender's nick and colorized text 
    my $colorized_message 
        = $left_bracket . $nick . $right_bracket 
        . "\t" 
        . $text 
        . "\n"
        ;

    return $colorized_message;

} # }}}

sub report_state {  # {{{

    my $msg;

    if ( $colorize_enabled ) {
        $msg 
            = "$script_name: Status - Colorizing is enabled. "
            . "Colorization scheme set to '$colorize_command'\n";
    }
    else {
        $msg 
            = "$script_name: Status - Colorizing is disabled. "
            . "Colorization scheme last set to '$colorize_command'\n";
    }

    return $msg;
} # }}}

sub usage { # {{{
    return my $usage = <<END_USAGE;
-------------------------------
Usage: /$config_command [OPTION]
If no option is given, the default action is to show the current settings. 

  ?, help - Display this help message

Enable/Disabling Colorization

  enable - Enable colorizing 
  disable - Disable colorizing

Colorizing Schemes

  all - Colorize message and embedded nicks in message 
  message - Colorize message only
  nicks - Colorize embedded nicks only 

Example. To set colorization scheme to only colorize embedded nicks:

/colorize nicks

Note that you only need to type the first letter of the option. So the
following command will also set the scheme to colorize just nicks:

/colorize n
-------------------------------
END_USAGE
} # }}}

__END__

=head1 NAME

colorize.pl - Colorize messages and/or embedded nicks with corresponding
colors.

=head1 VERSION

This documentation refers to colorize.pl version 0.0.3.

=head1 INSTALLATION 

Short answer: 

Put this file in your Xchat data directory (e.g. ~/.xchat2 on 
linux). Make sure you've turned on colored nick names in your preferences. 

Long answer:

The following is from http://www.xchat.org/faq/#q218 

18. How do I auto-load scripts at startup?

You just have to place the scripts into XChat's data directory. XChat will
auto-load scripts if they have the right extension .e.g If a filename ends in
.pl, it will be loaded as a Perl script. This data directory is different on
each platform:

Windows

It depends on your version of Windows and where it stores the Application Data
folder. On Windows XP it is usually:

C:\Documents and Settings\username\Application Data\X-Chat 2\


UNIX

~/.xchat2/ Where "~" represents your home directory i.e.: $HOME/.xchat2/

=head1 USAGE

/colorize [OPTION]

If no option is given, the default action is to show the current settings. 

  ?, help - Display this help message

Enable/Disabling Colorization

  enable - Enable colorizing 
  disable - Disable colorizing

Colorizing Schemes

  all - Colorize message and embedded nicks in message 
  message - Colorize message only
  nicks - Colorize embedded nicks only 

Example. To set colorization scheme to only colorize embedded nicks:

/colorize nicks

Note that you only need to type the first letter of the option. So the
following command will also set the scheme to colorize just nicks:

/colorize n

=head1 CONFIGURATION

You can customize the type and color of the brackets that surround the 
nick names. The default is to not have any surrounding brackets.

To change the bracket type and color, go to the section labeled
"BRACKET SETTINGS" towards the top of the script and edit the three
variables:

 my $BRACKET_COLOR       = "";
 my $LEFT_BRACKET_STYLE  = '';
 my $RIGHT_BRACKET_STYLE = '';

You can use the %color hash defined at the top of the script for defining 
$BRACKET_COLOR. For example, to set the bracket color to green, set 
the following:

 my $BRACKET_COLOR = $color{green};

The brackets can be any characters you want, you are not limited to 
the usual '<' and '>'. For example, to set the bracket type to use
parentheses, set the following:

 my $LEFT_BRACKET_STYLE  = '(';
 my $RIGHT_BRACKET_STYLE = ')';

=head1 INCOMPATIBILITIES

Xchat 2.0.8 or above is required to load this plugin.

=head1 BUGS AND LIMITATIONS

Please report any bugs you find to the author.

This version only colorizes messages sent by other users. It does not
colorize messages sent by you or for you.

Patches welcome. :-)

=head1 SEE ALSO

http://ant.home.comcast.net/colorize is where this plugin is hosted.

http://www.xchat.org/docs/xchat2-perl.html has good documentation on
writing perl plugins.

=head1 AUTHOR

jf3 at swift.fastmail.fm

=head1 LICENSE AND COPYRIGHT

This plugin is made available under the same license as XChat, which 
is the GPL. You can read it at http://www.gnu.org/licenses/gpl.txt.

