###########################################################################
#                                                                          
#                              GD::Gauge 
#==========================================================================
#              Copyright (c) 2002-2003 Christian Cloutier
#--------------------------------------------------------------------------
#
#	Name:
#		GD::Gauge.pm
#
#	Description:
#       Module to create gauges drawing on a GD::Image
#       object
#
#==========================================================================

package GD::Gauge;
require Exporter;
require 5.000;

use GD;
use Math::Trig;

our @ISA = qw(Exporter);
our @EXPORT = qw(new gd imageAsPng imageAsJpeg);
$GD::Gauge::VERSION = '0.1';
our $im;

sub new {
	
    my $invocant = shift;
    my $class = ref($invocant) || $invocant;
    my $self = { @_ };
    bless($self,$class);

    my ($brush,$arrow, %args);
    my ($white,$black,$red,$green,$blue,$yellow);
    my ($radius,$qtrrad,$value,$size,$percentred,$percentyellow,$clockwise,$tickvalue,$val);
    my ($pvalue,$pyellow,$pred,$pgreen, $side);
    my @big_ticks   = qw(18 36 54 72 90 108 126 144 162);
    my @small_ticks = qw(9 27 45 63 81 99 117 135 153 171);
    
    %args = %$self;

    ($args{'size'}    >= 100 && $args{'size'}    <= 1000) ? ($size = $args{'size'})             : ($size = 150);
    ($args{'value'}   <= 100 && $args{'value'}   >= 0)    ? ($value = $args{'value'})           : ($value = 0);
    ($args{'pyellow'} <= 100 && $args{'pyellow'} >  0)    ? ($percentyellow = $args{'pyellow'}) : ($percentyellow = 10);
    ($args{'pred'}    <= 100 && $args{'pred'}    >  0)    ? ($percentred = $args{'pred'})       : ($percentred = 5);
    ($args{'side'}    == 0   || $args{'side'}    == 1)    ? ($side = $args{'side'})             : ($side = 0);
    if(($args{'pyellow'} + $args{'pred'}) > 100)
    {
	    $args{'pred'} = 100 - $args{'pyellow'};
    }
	
    $radius = $size / 2;
    $qtrrad = $radius * 0.74;
    $pyellow = ($percentyellow / 100) * 180;
    $pred = ($percentred / 100) * 180;
    $pgreen = (180 + $pred + $pyellow) / 2;
    $pvalue = ($value / 100) * 180;

    # Create the new image
    $im = new GD::Image($size,$size / 2 + 30);

    # Create arrow brush (2 x 2 pixels box)
    $brush = new GD::Image(2,2);
    $white = $brush->colorAllocate(255,255,255);
    $blue  = $brush->colorAllocate(0,0,128);
    $brush->transparent($white);
    $brush->filledRectangle(0,0,2,2,$blue);
    $im->setBrush($brush);

    # Allocate some colors
    $white  = $im->colorAllocate(255,255,255);
    $black  = $im->colorAllocate(0,0,0);       
    $red    = $im->colorAllocate(255,30,30);
    $green  = $im->colorAllocate(192,220,162);
    $blue   = $im->colorAllocate(0,0,128);
    $yellow = $im->colorAllocate(255,255,120);

    # Make the background transparent and interlaced
    $im->transparent($white);
    $im->interlaced('true');

    # Draw the gauge
    $im->line(0,$radius,$size - 1,$radius,$black);
    $im->arc($radius,$radius,$size,$size,180,360,$black);
    $im->arc($radius,$radius,$size - ($size * 0.25),$size - ($size * 0.25),180,360,$black);

    # Center circle
    $im->arc($radius,$radius,15,15,180,360,$black);
    $im->fillToBorder($radius, $radius - 3, $black, $black);

    if($side == 0)
    {
    	# Red slice
    	$im->line($radius - (cos(deg2rad($pred)) * $qtrrad),$radius - (sin(deg2rad($pred)) * $qtrrad), $radius - (cos(deg2rad($pred)) * $radius), $radius - (sin(deg2rad($pred)) * $radius), $black);
    	$im->fill($radius - (cos(deg2rad($pred/2)) * ($radius * 0.8)), $radius - (sin(deg2rad($pred/2)) * ($radius * 0.8)), $red);
    	# Yellow slice
    	$im->line($radius - (cos(deg2rad($pred + $pyellow)) * $qtrrad),$radius - (sin(deg2rad($pred + $pyellow)) * $qtrrad), $radius - (cos(deg2rad($pred + $pyellow)) * $radius), $radius - (sin(deg2rad($pred + $pyellow)) * $radius), $black);
    	$im->fill($radius - (cos(deg2rad($pred + $pyellow/2)) * ($radius * 0.8)), $radius - (sin(deg2rad($pred + $pyellow/2)) * ($radius * 0.8)), $yellow);
    	# Green slice
    	$im->fill($radius - (cos(deg2rad($pgreen)) * ($radius * 0.8)), $radius - (sin(deg2rad($pgreen)) * ($radius * 0.8)), $green);
    }
    else
    {
    	# Red slice
    	$im->line(cos(deg2rad($pred)) * $qtrrad + $radius,$radius - (sin(deg2rad($pred)) * $qtrrad), cos(deg2rad($pred)) * $radius + $radius, $radius - (sin(deg2rad($pred)) * $radius), $black);
    	$im->fill(cos(deg2rad($pred/2)) * ($radius * 0.8) + $radius, $radius - (sin(deg2rad($pred/2)) * ($radius * 0.8)), $red);
    	# Yellow slice
    	$im->line(cos(deg2rad($pred + $pyellow)) * $qtrrad + $radius,$radius - (sin(deg2rad($pred + $pyellow)) * $qtrrad), cos(deg2rad($pred + $pyellow)) * $radius + $radius, $radius - (sin(deg2rad($pred + $pyellow)) * $radius), $black);
    	$im->fill(cos(deg2rad($pred + $pyellow/2)) * ($radius * 0.8) + $radius, $radius - (sin(deg2rad($pred + $pyellow/2)) * ($radius * 0.8)), $yellow);
    	# Green slice
    	$im->fill(cos(deg2rad($pgreen)) * ($radius * 0.8) + $radius, $radius - (sin(deg2rad($pgreen)) * ($radius * 0.8)), $green);
    }
    
    # Draw tick marks
    $tickvalue = $radius - 8;
    foreach $val (@big_ticks)
    {
       $im->line($radius - (cos(deg2rad($val)) * $tickvalue), $radius - (sin(deg2rad($val)) * $tickvalue),$radius - (cos(deg2rad($val)) * $radius),$radius - (sin(deg2rad($val)) * $radius),$black);
    }
    $tickvalue = $radius - 5;
    foreach $val (@small_ticks)
    {
       $im->line($radius - (cos(deg2rad($val)) * $tickvalue), $radius - (sin(deg2rad($val)) * $tickvalue),$radius - (cos(deg2rad($val)) * $radius),$radius - (sin(deg2rad($val)) * $radius),$black);
    }

    # Value arrow
    $im->line($radius,$radius, $radius - (cos(deg2rad($pvalue)) * $radius), $radius - (sin(deg2rad($pvalue)) * $radius), gdBrushed);
    $arrow = new GD::Polygon;
    $arrow->addPt($radius - (cos(deg2rad($pvalue - 2)) * ($radius-10)), $radius - (sin(deg2rad($pvalue - 2)) * ($radius-10)));
    $arrow->addPt($radius - (cos(deg2rad($pvalue + 2)) * ($radius-10)), $radius - (sin(deg2rad($pvalue + 2)) * ($radius-10)));
    $arrow->addPt($radius - (cos(deg2rad($pvalue)) * $radius), $radius - (sin(deg2rad($pvalue)) * $radius));
    $im->filledPolygon($arrow,$blue);

    # Title and other text
    $im->string(gdMediumBoldFont, $radius - 5, 0, "50", $black);
    $im->string(gdMediumBoldFont, 0, $radius, "0", $black);
    $im->string(gdMediumBoldFont, $size - 20, $radius, "100", $black);
    $im->string(gdGiantFont, $radius - 8, $radius - 30, $value, $blue);
    
    return $self,$class;
}


sub imageAsJpeg {
    return $im->jpeg if defined($im);
}


sub imageAsPng {
    return $im->png if defined($im);
}


sub gd {
    return $im if defined($im);
}


1;