#!/usr/local/bin/perl5 -w
#
# FuzzyColor - Turns RGB values into a textual decription
#              of the color via a fuzzifying algorithm
#
# REFERENCES:
#
#    color conversion:
#
#        http://www.cs.rit.edu/~ncs/color/t_convert.html
#        http://www.robo.mein.nagoya-u.ac.jp/~niimi/color-space/COL_25.htm
#
#
#    fuzzifier algorithm adapted from:
#
#        C++ Neural Networks & Fuzzy Logic, 2nd Edition
#        by Dr. Valluru Rao and Hayagriva Rao
#        (c) 1995 MIS Press
#
###################################################################
use strict;
use AI::Fuzzy::Set;
use AI::Fuzzy::Label;
use Color::Convert;

my $hue = new AI::Fuzzy::Label;
my $sat = new AI::Fuzzy::Label;
my $val = new AI::Fuzzy::Label;

## first set up some labels ###

$val->addlabel( "black", -1, 0, 15 );
$val->addlabel( "blackish", 10, 20, 30 );
$val->addlabel( "dark", 15, 30, 50 );
$val->addlabel( "normal", 40, 80, 95 );
$val->addlabel( "bright", 90, 100, 101 );  # very rare to say this

$sat->addlabel( "gray", -1, 0, 20 );
$sat->addlabel( "pale", 15, 30, 72 );
$sat->addlabel( "normal", 60, 80, 101 );

$hue->addlabel( "gray",     -2,   -1,  0  );
$hue->addlabel( "red",      -1,    0,  15 );
$hue->addlabel( "orange",   10,   30,  50 );
$hue->addlabel( "yellow",   45,   60,  75 );
$hue->addlabel( "green",    65,  120, 172 );
$hue->addlabel( "cyan",    165,  180, 190 );
$hue->addlabel( "blue",    180,  240, 260 );
$hue->addlabel( "indigo",  255,  260, 280 );
$hue->addlabel( "magenta",  270,  290, 310 );
$hue->addlabel( "violet",  300,  320, 340 );
$hue->addlabel( "red2",    330,  360, 361);


### get the color value from the command line ##
### possibly convert to hsv ##

my ($h, $s, $v);

@_ = @ARGV;

 SWITCH: for ($_[0]) {

     /rgb/i && do { shift @_; ($h, $s, $v) = rgb2hsv(@_); };
     /\d+/  && do { ($h,$s,$v) = rgb2hsv(@_); };
     /hsv/i && do { ($h, $s, $v) = @_; };
 }


###### cfuzzify the color value #########


## first, the hue ##

my $hueset = new AI::Fuzzy::Set( $hue->label($h) );

my @colors = $hueset->members();
my $color = pop @colors;

# if the color has more than one label, 
# pick one, or just merge them:

if (@colors) { 
    
    my $othercolor = pop (@colors);
    
    my $m_c = $hueset->membership($color);
    my $m_o = $hueset->membership($othercolor);
    
    # first, pick a "primary" label ..
    if ( rand( $m_o + $m_c ) > $m_c )  {
	($color, $othercolor) = ($othercolor, $color);
    }

    # and if they're really close, pick both..
    # (the 3 just gives othercolor a fighting chance)
    if ( rand() < (3 * $hueset->membership($othercolor))) {
	$color = $othercolor . "ish-" . $color;
    }
}

$color =~ s/red2/red/;
$color =~ s/redish/reddish/;

## now the saturation ###

for (my $saturation = $sat->label($s)) {
    m/gray/ && do {
	$color .= "ish gray"
	    unless $color =~ /gray/;
    };
    m/pale/ && do {
	$color = "pale $color";
    };
}

## and the value... ##

for (my $value = $val->label($v)) {
    m/black$/ && do { 
	$color = "black";
    };
    m/blackish/ && do {
	$color .= "ish black"
	    unless $color =~ s/.*ish gray/dark gray/;
    };
    m/bright/ && do {
	$color = "bright $color"
	    unless $color =~ s/gray$/white/;
    };
}

## now print it out ###

print "$color\n";


__END__