package grafikm;

use template;
use GD;

@ISA = qw ( template );

# Datasets:
##########
# In den Datasets steht ein Zeiger auf ein Array mit Zeigern auf die HASHES der Datasets.
# Jedes Datasethash besteht aus folgenden Teilen:
#	N		die N's nach dem die Prozente für diesen Dataset berechnet werden
#			in der Regel fuer alle Datasets dasselbe, aber halt nicht immer....
#	num		die Menge
#	txt		der Text dieses Sets
#	lfd		eine laufende Nummer der natürlichen Abfolge


# Textformatierung mit textformatv und textformath:
###################################################
# Diese Formatierungstexte dienen zur individuellen Beschriftung
# der Grafiken, wobei der textformatv (wie vorne) VOR der Grafik steht
# und der textformath (wie hinten) HINTER der Grafik steht
# Folgende ersetzungen werden vorgenommen:
#	&N wird durch die gesamt Ns ersetzt
#	&P durch die Prozentzahl (ohne %)
#	&Z durch die eigentliche Zahl (num)
#	&T durch den Text
#	&L durch die laufende Nummer (lfd)
#
# bei N=200, num=70, text="Hallo" und der lfd=1 wird aus:
# "&Z - &T (&N)" -> "70 - Hallo (200)"  bzw. aus
# "Frage[&L] - &P%" -> "Frage[1] - 35%"


# Daten die bei setdata uebergeben werden:
########################################
#	filename  der Dateiname
#	size      die Groesse der Grafik (normal ist 25)
#   maxdata   Maximale Anzahl der Datensaetze, alle darueber werden zum 
#			  letzten zusammengefasst
#	sumtext	  Text des letzten summendatensatzes s.o.
#	fontcolor   Farbe des Schriftentextes
#	transcolor  Farbe der Durchsichtigkeit
#	shadowcolor Farbe des Schattens
#	col		  Zeiger auf Array mit Farben
#	GRA		  Grafiktyp
#	textformatv/h	Formatierungsanweisung für die Grafikbeschriftung
#	nachkomma	Anzahl der Nachkommastellen
#	printN		Ob die "Gesamt n=..." ausgegeben wird
#	N			ein gemeinsames N bei Mehrfachantworten z.B.
#	sorttype	wie soll sortiert werden "txt" "lfd" "num"
#	schmuck		wie die Grafik "geschmueck" werden soll "3D" oder "schatten" oder ""
#






####################################################################
####         Konstuktor der Grafikklasse
####         Argumente  : Parentzeiger
####         Returnwert : Referenz auf das neue Grafikobjekt
####################################################################
sub init {
	my $that = shift;
	my $class = ref($that) || $that;
	my $self = template->init(@_);
	bless $self, $class;	
	$self->imgreset;
}


####################################################################
####         Setzt alle Eigenschaften auf Defaultwerte
####         Argumente  : Parentzeiger
####         Returnwert : Referenz auf das neue Grafikobjekt
####################################################################
sub imgreset {	
	my $self=shift;
	$self->{size}=25;				# Groesse der Grafik
	$self->{printN}=1;				# Ob die "Gesamt n=..." ausgegeben wird
	$self->{fontcolor}="000000";	# Schriftfarbe
	$self->{transcolor}="010001";	# Transparentfarbe
	$self->{shadowcolor}="#999999";	# Farbe des Schattens
	$self->{sumtext}="Sonstiges";	# Text fuer die Sammlung der Datensaetze > {maxdata}
	$self->{maxdata}=120;			# Maximale Anzahl der Datensaetze
	$self->{N}=0;					# Der gemeinsame N, wird in der Regel aus der summe der num gebildet
	$self->{schmuck}= 1;			# Verzierung.....  (3D)
	$self->rmdata;				# Zeiger auf Datensaetze
	$self->{textformatv}="Nr.&L (&Z)";	# Text Vorne
	$self->{textformath}="&T - &P%";		# Text hinten
	$self->{sorttype}="lfd";				# Art der Sortierung
	$self->{nachkomma}=0;
	$self->{filename}="";
	$self->{GRA}="BA";						#Im Zweifelsfall ein Balken 
	#$self->{col}=["0099cc","ff9900"];
	$self->{col}=["0099cc","ff9900","ffff99","00cc66","3333cc","ff6666","aaddaa","66ccff","ff99ff","999999"]; # Array der Standardfarben
	return $self;
}

####################################################################
####         Erstellt das Image
####         Argumente  : -
####         Returnwert : -
####################################################################
sub createimg {
	my $self=shift;
	my $GRA=$self->{GRA};
	$self->maxdata;
	$self->formnum;
	$self->datasort;
	$self->textcreate;
	$self->$GRA();
	$self->save;
	return;
}

####################################################################
####         nimmt einen Dateinamen fuer das Bild entgegen
####         Argumente  : Dateiname
####         Returnwert : -
####################################################################
sub setfilename {
	my $self = shift;
	$_=shift;
	unless (/\.gif$/) {$self->log(2,"Datei endet nicht mit '.gif' ($_)");}
	$self->{filename}=$_;
}

####################################################################
####         Loescht die Datensaetze
####         Argumente  : -
####         Returnwert : -
####################################################################
sub rmdata {
	my $self=shift;
	if (defined $self->{img}) {
		foreach $index (@{$self->{datasets}}) {			#Alle Farben "deallocaten"
			$self->{img}->colorDeallocate($data->{colorn});
			$self->{img}->colorDeallocate($data->{colord});
			$self->{img}->colorDeallocate($data->{colorh});
			$self->log(4,"Colors Allocated after deleting: ".$self->{img}->colorsTotal);
		}
	}
	$self->{datasets}=[];	# und Datensätze löschen
	$self->{datadirty}=0;
}

####################################################################
####         Speichert alle Datensätze in der DB
####         Argumente  : -
####         Returnwert : -
####################################################################
sub store {
	my $self=shift;
	$self->sqldo("lock tables bar write");
	$self->{id} = $self->sqlselect("select max(id) from bar") +1;
	my $alias="T".$self->{id};
	foreach (@{$self->{datasets}}) {
		$_->{wher}=~s/ (\w)/ $alias\.$1/g;
		$_->{wher}=~s/"/\"/g;
		my $sql="insert into bar (id,pid,plfd,lfd,num,N,tabl,wher,x1,x2,x3,x4,y1,y2,y3,y4,descr) values ".
		"('".$self->{id}."','".$self->{pid}."','".$self->{plfd}."','".$_->{lfd}."','".$_->{num}."','".$_->{N}."','".
		$_->{tabl}." $alias',\"".$alias.".".$_->{wher}."\",'" .
		join ("','", @{$_->{X}} ) ."','". join ("','", @{$_->{Y}} ) ."','".$_->{descr}."')"; 
		$self->sqldo($sql);
	}
	$self->sqldo("unlock tables");
	return;
}

####################################################################
####         laedt alle Datensätze aus der DB oder einen bestimmten
####         Argumente  : -
####         Returnwert : -
####################################################################
sub load {
	my ($self, $id, $plfd) = @_;
	my $sql="select id,lfd,pid,plfd,num,N,tabl,wher,x1,x2,x3,x4,y1,y2,y3,y4,descr from bar where id='$id'";
	my (@data, $target);
	my $sth=$self->sqlprepare($sql);
	while (my $set = $sth->fetchrow_hashref) {
		push @data, $set;
		for (1...4) {
			$set->{X}[$_-1] = $set->{"x$_"};
			$set->{Y}[$_-1] = $set->{"y$_"};
			$self->log(4,"--".$_."------".$set->{"x$_"});
		}
		if ($plfd==$set->{lfd} && defined $plfd) {return $set;}   # wenn nur einer geladen werden soll
	}
	$self->{datasets}=\@data;
	return; 
}

####################################################################
####         Loescht den Datensatz mit der lfd
####         Argumente  : lfd
####         Returnwert : -
####################################################################
sub rmdatalfd {
	my ($self, $lfd) = @_;
	my @new=();
	foreach $data ( @{$self->{datasets}} )  {
		if ($data->{lfd} != $lfd) {push @new, $data;}
	}
	$self->{datasets}=\@new;
	$self->{datadirty}=1;
}

####################################################################
####         Datenuebernahme
####         Argumente  : Parentzeiger
####         Returnwert : Referenz auf das neue Grafikobjekt
####################################################################
sub setdata {
	my ($self,$hp) = @_;
	my %hash=%$hp;
	$self->log(4,"Entering grafik: setdata");
	if (defined $hash{GRA}) {$self->setgrafiktyp($hash{GRA});}
	if (defined $hash{filename}) {$self->setfilename($hash{filename});}
	if (defined $hash{size}) {$self->{size}=$hash{size};}
	if (defined $hash{fontcolor}) {$self->{fontcolor}=$hash{fontcolor};}
	if (defined $hash{shadowcolor}) {$self->{shadowcolor}=$hash{shadowcolor};}
	if (defined $hash{transcolor}) {$self->{transcolor}=$hash{transcolor};}
	if (defined $hash{sumtext}) {$self->{sumtext}=$hash{sumtext};}
	if (defined $hash{maxdata}) {$self->{maxdata}=$hash{maxdata}; $self->{datadirty}=1;}
	if (defined $hash{textformatv}) {$self->{textformatv}=$hash{textformatv};$self->log(4,"textformatv=$self->{textformatv}");}
	if (defined $hash{textformath}) {$self->{textformath}=$hash{textformath};$self->log(4,"textformath=$self->{textformath}");}
	if (defined $hash{nachkomma}) {$self->{nachkomma}=$hash{nachkomma};$self->log(4,"nachkomma=$self->{nachkomma}");}
	if (defined $hash{printN}) {$self->{printN}=$hash{printN};$self->log(4,"printN=$self->{printN}");}
	if (defined $hash{col}) {$self->{col}=$hash{col};}
	if (defined $hash{N}) {$self->{N}=$hash{N}; $self->{datadirty}=1;}
	if (defined $hash{sorttype}) {$self->{sorttype}=$hash{sorttype};}
	if (defined $hash{pid}) {$self->{pid}=$hash{pid}+0;}
	if (defined $hash{plfd}) {$self->{plfd}=$hash{plfd}+0;}
	if (defined $hash{schmuck}) {$self->{schmuck}=$hash{schmuck};}
	return;

}

####################################################################
####         Datenuebernahme eines neuen Datensets
####         Argumente  : Zeiger auf datasethash
####         Returnwert : -
####################################################################
sub setgrafiktyp {
	my ($self, $GRA)=@_;
	my @GR=qw/BA PI VL SK/;
	my $G; my $OK=0;
	$self->{GRA}=$GRA;
	$self->log(4,"GRA=".$self->{GRA});
	foreach (@GR) {$OK=1 if /$self->{GRA}/ ;}
	unless ($OK) {$self->{GRA}=$GR[0];}
}

####################################################################
####         Datenuebernahme eines neuen Datensets
####         Argumente  : Zeiger auf datasethash
####         Returnwert : -
####################################################################
sub newdataset {
	my ($self, $data) = @_;
	my %mydata=%{$data};			# Lokale Kopie der Daten
	$mydata{lfd}+=0;
	$mydata{N}+=0;
	$mydata{num}+=0;
	for (0..3) {$mydata{X}[$_]=0; $mydata{Y}[$_]=0; }
	push (@{$self->{datasets}},\%mydata);	# Hinzufuegen
	$self->{datadirty}=1;			# Datensaetze als "dreckig" markieren
}

####################################################################
####         Schreibt ins Logfile
####         Argumente  : Emergency-NR und Logtext
####         Returnwert : -
####################################################################
sub log {
	my ($self, $emer, $TEXT) = @_;
	$self->printlog($emer, "[GRAFIK:$self->{GRA}] $TEXT");
	return;
}

####################################################################
####         Sortiert die Datasets
####         Argumente  : -
####         Returnwert : -
####################################################################
sub datasort {
	my $self=shift;
	my $way=$self->{sorttype};
	my $c;
	$self->log(4,"Entering grafik: datasort, Sorttype=$way");
	my @lw = qw/num txt lfd proz N/;
	foreach(@lw) {  $c++ if /$way/;} 
	unless ($c) {return 0;}
	$self->log(4,"Inlistcounter=$c");
	########## Die Einzelnen Sortierungen
	sub num {$b->{num} <=> $a->{num};}
	sub txt {lc($a->{txt}) cmp lc($b->{txt});}
	sub lfd {$a->{lfd} <=> $b->{lfd};}
	sub proz {$b->{proz} <=> $a->{proz};}
	sub N   {$a->{N}   <=> $b->{N};}
	##############
	my @L = sort $way @{$self->{datasets}};
	$self->{datasets}=\@L;
	return 1;
}

####################################################################
####         Formatiert die Beschreibungstexte und 
####         speichert den laengsten unter $self->{laengstes}
####         Argumente  : -
####         Returnwert : -
####################################################################
sub textcreate {
	my $self=shift;
	$self->log(4,"Entering grafik: textcreate");
	my ($laengstes, $laengstesv, $laengstesh, $data, $tring, $V, $H);
	foreach $data ( @{$self->{datasets}} )  {
      $V=$self->_textform($self->{textformatv},$data);
      $H=$self->_textform($self->{textformath},$data);
	  if ($laengstes < length($V.$H)) { $laengstes = length($V.$H);  }
  	  if ($laengstesv < length($V)) { $laengstesv = length($V);  }
  	  if ($laengstesh < length($H)) { $laengstesh = length($H);  }
	  $data->{textv}=$V;
	  $data->{texth}=$H;
	  $self->log(4,$data->{textv}." - ".$data->{texth});	
	} 
	$self->{laengstes}=$laengstes*6;   # Zeichenbreite multiplizieren
	$self->{laengstesv}=$laengstesv*6;  
	$self->{laengstesh}=$laengstesh*6;  
}

####################################################################
####         Formatiert den übergebenen Formatstring 
####         Argumente  : -
####         Returnwert : -
####################################################################
sub _textform {
	my ($self,$tring,$data) = @_;
	my $txt= $data->{txt};
	$txt=~ s/<[^>]*>//g; # den Text von HTML befreien
	$self->log(4,"Entering grafik: _textform");
	$tring=~s/&N/$data->{pN}/g;    # Die Ns ersetzen
	$tring=~s/&T/$txt/g;	       # Den Text einsetzen
	$tring=~s/&P/$data->{proz}/g;  # Die Prozente einsetzen (ohne %-Zeichen)
	$tring=~s/&Z/$data->{pnum}/g;  # Die Anzahl einsetzen    
	$tring=~s/&L/$data->{plfd}/g;  # Die laufende Nummer einsetzen    
	return $tring;
}      

####################################################################
####         Fasst alles > maxdata zusammen
####         Argumente  : -
####         Returnwert : -
####################################################################
sub maxdata {
  my $self=shift;
  $self->log(4,"Entering grafik: maxdata" );
  $self->datasort("num");
  my $anz = @{$self->{datasets}}; # Anzahl der Datensaetze 
  my $max=$self->{maxdata}-1;
  $self->log(4,"Anzahl=$anz, Max=$max" );
  if ( ($max+1) < $anz) {
    for ($x=$max+1 ; $x<$anz ; $x++) {
       $self->{datasets}->[$max]->{num}+=$self->{datasets}->[$x]->{num};
       $self->{datasets}->[$max]->{N}+=$self->{datasets}->[$x]->{N};
    }
    $self->{datasets}->[$max]->{txt}=$self->{sumtext};
    $self->{datasets}->[$max]->{N}/=($anz-$max);
	splice @{$self->{datasets}}, $self->{maxdata};
  }
}

####################################################################
####         Initialisiert das Bild
####         Argumente  : -
####         Returnwert : -
####################################################################
sub _init_img {
	my ($self,$width,$height) = @_;
	$self->log(4,"Entering grafik: init_img");
	$self->{img} = GD::Image->new($width, $height);
	$self->{fontcol} = $self->{img}->colorAllocate($self->_hex2dec($self->{fontcolor})); #schwarz normalerweise
	$self->{transcol} = $self->{img}->colorAllocate($self->_hex2dec($self->{transcolor}));  #transparent
	$self->{shadowcol} = $self->{img}->colorAllocate($self->_hex2dec($self->{shadowcolor})); #Schattenfarbe
	$self->{img}->transparent($self->{transcol});
	$self->{img}->fill(2,2,$self->{transcol});
	return $self->{img};
}


####################################################################
####         Wandelt einen Hexstring "#ffee33" oder "ff88aa" in ein 
####		 Array von 3 Dezimalwerten
####         Argumente  : Hexstring
####         Returnwert : Dezimalarray
####################################################################
sub _hex2dec {
	my ($self,$hex) = @_;
	$hex=~/^\#?(\w\w)(\w\w)(\w\w)/; # Aufteilen 
	@ret= ( hex($1),hex($2),hex($3) ); # und in Hex umwandeln
	$self->log(4,"Hex2Dec: ".$hex."=".join (",",@ret));
	return @ret; 
}

####################################################################
####         Bearbeitet die Zahlen
####         Argumente  : Hexstring
####         Returnwert : Dezimalarray
####################################################################
sub formnum {
	my $self=shift;
	$self->log(4,"Entering grafik: formnum");
	if ($self->{datadirty}==0) {$self->log(4,"Formnum: Nothing to do :-)");return;}
	my ($gnum, $gN, $data, $mnum,$mN,$mlfd, $llfd, $lN, $lnum, $nach);
	foreach $data ( @{$self->{datasets}} )  {
		if ($mnum < $data->{num}) {$mnum=$data->{num};}    # Die Maximas der einzelnen Zahlen num
		if ($mN < $data->{N}) {$mN=$data->{N};}				# N
		if ($mlfd < $data->{lfd}) {$mlfd=$data->{lfd};}		# und lfd ermitteln
		$gnum+=$data->{num};	# Die Summe ueber num
		$gN+=$data->{N};		# Die Summe ueber N
		if ($data->{num}=~/\./) {$knum=3;}
		if ($data->{lfd}=~/\./) {$klfd=3;}
		if ($data->{N}=~/\./) {$kN=3;}
	
	}
	if ($self->{N} == 0) {$self->{N}=$gnum;}    # wurde ein gemeinsames N vorgegeben ?
	if ($gN ==0) {	 # Alle bekommen ein gemeinsames N wenn die Summe der N=0
		foreach $data ( @{$self->{datasets}} )  {$data->{N}=$self->{N};}
		$mN=$self->{N};
	}
	if ($self->{nachkomma}>0) {$nach=$self->{nachkomma}+1;}   # Wenn Nachkomma, dann mit .
	$lnum=length(int($mnum))+$nach;
	$lN=length(int($mlfd))+$nach;
	$llfd=length(int($mlfd));
	if ($nach>0) {$nach--;}
	foreach $data ( @{$self->{datasets}} )  {
		if ($data->{num} > $data->{N}) {$data->{num} = $data->{N}*1.11;	}   # WENN alles viel zu groß ist !
		if ($data->{N} != 0) { $data->{proz} = sprintf ("%5.1f",100*$data->{num}/$data->{N}); }
		else { $data->{proz}="-----"; }          # Division by zero
		$data->{pnum}=sprintf "%$lnum.${nach}f",$data->{num};
		$data->{pN}=sprintf "%$lN.${nach}f",$data->{N};
		$data->{plfd}=sprintf "%${llfd}.0f",$data->{lfd};
		$self->log(4,"num='".$data->{pnum}."' N='".$data->{pN}."' lfd='".$data->{plfd}."' Prozent='".$data->{proz}."'" );
	}
	$self->{datadirty}=1;
}


####################################################################
####         Setzt die Farben entsprechend den Vorgaben
####         Argumente  : -
####         Returnwert : -
####################################################################
sub _setcolors {
	my $self=shift;
	my ($data, @Cols);
	$self->log(4,"Entering grafik: setcolors");
	my @Cols = @{$self->{col}};
	$colors=@Cols;
	$self->log(4,"Available Colors: @Cols");
	foreach $data (@{$self->{datasets}}) {
		$col=$data->{color};						# Entweder eigene Farbe
		if ($col eq "") {$col=shift @Cols; push @Cols, $col;$self->log(4,"Rotate Colortable");} # oder aus rotierter Farbenliste
		( $data->{colorn}, $data->{colord}, $data->{colorh} )=
		$self->_colorblend($col);
	}
}	
sub _colorblend {
	my ($self,$col)=@_;
	my $x=64; my @ret=();
	my ($r,$g,$b,$rh,$gh,$bh,$rd,$gd,$bd);
	($r,$g,$b)=$self->_hex2dec($col);
	$rd=$r-$x;$gd=$g-$x;$bd=$b-$x;
	$rh=$r+$x;$gh=$g+$x;$bh=$b+$x;
	if ($rd<0) {$rd=0;}
	if ($gd<0) {$gd=0;}
	if ($bd<0) {$bd=0;}
	if ($rh>255) {$rh=255;}
	if ($gh>255) {$gh=255;}
	if ($bh>255) {$bh=255;}
	my $in=$self->{img}->colorExact($r,$g,$b);
	my $id=$self->{img}->colorExact($rd,$gd,$bd);
	my $ih=$self->{img}->colorExact($rh,$gh,$bh);
	if ($in==-1) {$in=$self->{img}->colorAllocate($r,$g,$b);}
	if ($id==-1) {$id=$self->{img}->colorAllocate($rd,$gd,$bd);}
	if ($ih==-1) {$ih=$self->{img}->colorAllocate($rh,$gh,$bh);}
	$self->log(4,"Colors Allocated: ".$self->{img}->colorsTotal);
	return ($in,$id,$ih);	
}

####################################################################
####         Speichert das image als .gif 
####         Argumente  : Dateiname
####         Returnwert : -
####################################################################
sub save {
	my ($self,$filename)=@_;
	$self->log(4,"Entering grafik: save");
	if ($filename eq "") {$filename=$self->{filename};}
	if ($filename eq "") {$self->log(2,"No Filename !"); return}
	open FILE, ">$filename" || $self->log(2, "Konnte Datei: '$filename' nicht oeffnen");
	binmode FILE;
	print FILE $self->{img}->gif;
	close FILE;
	$self->store;
}



####################################################################
####         Ueberprueft, in welchem Polygon der Punkt liegt
####         Argumente  : Dateiname
####         Returnwert : das dataset, wenn Treffer
####################################################################
sub polygonhit {
	my ($self,$x,$y)=@_;
	my $target;
	$self->log(4,"Entering grafik: polygonhit x=$x y=$y");
	foreach $data (@{$self->{datasets}}) {
		$target=$self->_isinpoly($x,$y,$data);
		if (defined $target) {$self->log(4,"Dataset lfd:".$target->{lfd}." TREFFER"); last;}
	}
	return $target;
}


####################################################################
####         Ueberprueft, ob ein Punkt im Polygon liegt, oder nicht
####         Argumente  : x/y und \dataset
####         Returnwert : das dataset, wenn Treffer
####################################################################
sub _isinpoly {
	my ($self,$x,$y,$data)=@_;
	my ($er,$erg)=(0,0);
	$self->log(4,"Entering grafik: isinpoly");
	$data->{X}[4] = $data->{X}[0]; # Linie 3 -0 auf 3 -4
	$data->{Y}[4] = $data->{Y}[0];

	for ($z=0; $z<4; $z++) {
		$x1=$data->{X}[$z];   $y1=$data->{Y}[$z];	# Alle Linien
		$x2=$data->{X}[$z+1]; $y2=$data->{Y}[$z+1]; # auf Kreuzung mit 
		$er=_crossing($x,$y,$x1,$y1,$x2,$y2);		# Strahl von Punkt pruefen
		$self->log(4,"Datalfd:".$data->{lfd}." x1=$x1 y1=$y1 x2=$x2 y2=$y2 erg=$er");
		$erg+=$er;
	}
	if ($erg==1 || $erg==3) {return $data;}
	else {return;}	

	sub _crossing {						# ob linie x1/y1 - x2/y2 sich schneidet 
		my ($x,$y,$x1,$y1,$x2,$y2)=@_;  # mit linie 0/y - x/y
		if ( ($x1>$x) && ($x2>$x) ) {return 0;}  # Linie zu weit rechts
		if ( ($y1>$y) && ($y2>$y) ) {return 0;}  # Linie zu weit unten
		if ( ($y1<$y) && ($y2<$y) ) {return 0;}  # Linie zu weit oben 
		if ( ($x1<$x) && ($x2<$x) ) {return 1;}  # Linie  kreuzt sich !
		if ( $y1==$y2) {return 1;}				 # Liegen aufeinander	
		$steig=($x2-$x1)/($y2-$y1);				 # Steigung berechnen	
		$self->log(4,"Steigung=$steig x=".($x1+($y-$y1)*$steig));
		if ( ($x1+($y-$y1)*$steig)<=$x )  {return 1;}			 # Kreuzung !
		else {return 0;}
	}

}


####################################################################
####         gibt die sachen zurück Tabelle und where
####         Argumente  : x/y und \dataset
####         Returnwert : das dataset, wenn Treffer
####################################################################
sub tablwher {
	my ($self, $target)=@_;
	my (@table, @where, @descr);
    while (defined $target) {
		$self->log(4,++$x." Table='".$target->{tabl}."'");
		$self->log(4,$x." Where='".$target->{wher}."'");
		push @table, $target->{tabl};
		push @where, split / / , $target->{wher};
		unshift @descr, $target->{descr};
		if ($target->{pid}) {
			$target=$self->load($target->{pid}, $target->{plfd});
		}
		else {$target= undef;}
	};
	return (\@table, \@where, \@descr);
}


####################################################################
####         Zeichnet den Kuchen
####         Argumente  : -
####         Returnwert : -
####################################################################
sub PI {
	my $self=shift;
	$self->log(4,"Entering grafik: PI");
	my $rad=$self->{size} * 4.1;      # Radius des Kreises	
	my $scha=$rad*0.15;				# Radius des Schattens
	my $Zx=1.05*$rad+$self->{laengstes}+24; # KreisZentrum x 
	my $Zy=1.05*$rad+20;		# und y
	if ($self->{N} == 0) {return;}  # DIV by zero praevention
	my $winkel=0;					# Startwinkel
	
	my $img=$self->_init_img($Zx*2,$Zy*2+16);
	$self->_setcolors($img);
		
	# Schatten......
	$self->log(4,"Z(x)=$Zx, Z(y)=$Zy, Radius=$rad, Faktor=$Faktor");
	if ($self->{schmuck} == 2) { # Schatten
		$img->arc($Zx+$scha,$Zy+$scha,2*$rad,2*$rad,0,360,$self->{shadowcol} );
		$img->fill($Zx,$Zy,$self->{shadowcol});
		$img->arc($Zx,$Zy,2*$rad,2*$rad,0,360,$self->{transcol});
		$img->fill($Zx,$Zy,$self->{transcol});
		$img->fill($Zx-$rad+1,$Zy,$self->{transcol});
	}
	foreach $data ( @{$self->{datasets}} ) {
		$winkel=$self->_pie($img, $data, $winkel, $rad, $Zx, $Zy);
		#$self->save;
		#read STDIN, $aaa, 1
	}

	if ($self->{printN} > 0) {
		$img->string(gdSmallFont,1,2*$Zy,"Gesamt: n=".$self->{N},$self->{fontcol});
	}
return;
}

# Ein Kuchenstück malen !
sub _pie {
  my $PI = 3.1415927;	# Wurzel aus 2
  my ($self, $img, $data, $start, $rad, $Zx, $Zy) = @_;
  my $scha=$rad*0.15;
  $end=$start+360*$data->{num}/$self->{N};		#  Endwinkel
  $ret=$end; my $S=1;
  if ($self->{schmuck} == 1) {$S=0.4;} #3D
  if ($end == $start) {return $end; }	# In diesem Fall müssen wir nix zeichnen
  my ($p1x, $p1y, $p2x,$p2y,$p3x,$p3y,$p4x,$p4y,$bo1,$bo2,$bo3, $pfx,$pfy);	
  $self->log(4,"Text=$text, A=$start, B=$end");
  $img->arc($Zx,$Zy,2*$rad,2*$rad*$S,$start,$end+1,$self->{fontcol});   #Teil-Kreis malen
  $bo1=((90-$start)*2*$PI)/360 ;						 #Radius1 im Bogenmass
  $bo2=((90-$end)*2*$PI)/360 ;							 #Radius2 im Bogenmaß
  $bo3=($bo1+$bo2)/2;									 #Halber Radius , fuer Punkt mitten im Pie
  if ($bo2 > $bo1) {$bo3+=$PI;}
  $p1x=$rad*sin($bo1)+$Zx;
  $p1y=$rad*cos($bo1)*$S+$Zy;
  $p2x=$rad*sin($bo2)+$Zx;
  $p2y=$rad*cos($bo2)*$S+$Zy;
  $p3x=$rad*sin($bo3)/2+$Zx;					# Mitten im Pie fuer Fuellen
  $p3y=$rad*cos($bo3)/2*$S+$Zy;
  $p4x=$rad*sin($bo3)*1.05+$Zx;					# Textkoordinaten
  $p4y=$rad*cos($bo3)*1.05*$S+$Zy;
  $self->log(4,"p1x=$p1x, p1y=$p1y, p2x=$p2x, p2y=$p2y, bo1=$bo1, bo2=$bo2");
  $img->line($Zx,$Zy,$p1x,$p1y,$self->{fontcol});
  $img->line($Zx,$Zy,$p2x,$p2y,$self->{fontcol});
  $img->fill($p3x,$p3y,$data->{colorn});
  $data->{X}[0]=$p1x; $data->{Y}[0]=$p1y; $data->{X}[1]=$p4x; $data->{Y}[1]=$p4y;	# Umspannendes Polygon
  $data->{X}[2]=$p2x; $data->{Y}[2]=$p2y; $data->{X}[3]=$Zx; $data->{Y}[3]=$Zy;
  if ( ($self->{schmuck} == 1) && ($start<180) ) { #3D
   	if ($end>180) {
	  $end=180;
	  $bo2=((90-$end)*2*$PI)/360 ;						 #Radius2 im Bogenmaß
          $p2x=$rad*sin($bo2)+$Zx;
          $p2y=$rad*cos($bo2)*$S+$Zy;
  	}
	$self->log(4,"3D:p1x=$p1x, p1y=$p1y, p2x=$p2x, p2y=$p2y, bo1=$bo1, bo2=$bo2");
      if ($p1x-3>$p2x){  					# Nur zeichnen, wenns was zu fuellen gibt	
	$img->line($p1x,$p1y,$p1x,$p1y+$scha,$self->{fontcol});   #Die Verbindungslinien
	$img->line($p2x,$p2y,$p2x,$p2y+$scha,$self->{fontcol});		
	$img->arc($Zx,$Zy+$scha,2*$rad,2*$rad*$S,$start,$end+1,$self->{fontcol});   #Teil-schatten Kreis malen
	$img->fill($p1x-1,$p1y+$scha/2,$data->{colord});  # "Tiefe" Fuellen
      }
	$self->log(4,$p1x." - ".$p2x);
   	if ($p4y>$Zy){$p4y+=$scha;}	# Schrift nach unten setzen
  }	
  if ($p4x < $Zx) {$p4x-=length($data->{textv}.$data->{texth})*6;}
  $img->string(gdSmallFont,$p4x,$p4y-6,$data->{textv}.$data->{texth},$self->{fontcol});
  return $ret;
}


####################################################################
####         Zeichnet die Balken
####         Argumente  : -
####         Returnwert : -
####################################################################
sub BA {
	my $self=shift;
	my $bar=$self->{size} * 9.23;      # Breite des Balkens krumme Werte provozieren
	my $barhi=$bar/16;			  # Balkenhoehe;
	my $anzahl=@{$self->{datasets}};
	my ($Y, $X) = ($barhi*2,1);
	my $img = $self->_init_img($bar+$X+$self->{laengstes}+6, 2*$barhi*($anzahl+1)+$barhi/2+16);
	$self->_setcolors;
	$self->log(4,"X=".($bar+$X+$self->{laengstes}+6)."  Y=".(2*$barhi*($anzahl+1)+$barhi/2+16) );
	foreach $data ( @{$self->{datasets}} ) {
		if ($data->{N} == 0) {next;}  # Division by Zero praevention
		($X,$Y)=$self->_bar($img, $data, $X, $Y, $bar, $barhi );
	}
	if ($self->{printN} > 0) {
		$img->string(gdSmallFont,$X,$Y,"Gesamt: n=".$self->{N},$self->{fontcol});
	}

}


sub _bar {
  my ($self,$img, $data, $x, $y, $size, $height) = @_;
  if ($data->{N} == 0) {return ($x,$y);	}  # Division by Zero praevention
  my $lang=$size*$data->{num}/$data->{N};	# Effektive Laenge des Balkens abhaengig von den Daten
  my $half=$height/2;						# Halbe Hoehe fuer die 3D ansicht
  my $Dx=$x+$self->{laengstesv}+4;			# Abstand des Balkens von Links
  my $p1x=$Dx; my $p1y=$y; my $p2x=$Dx+$lang; my $p2y=$y;
  my $p3x=$p2x+$half; my $p3y=$p2y-$half;
  my $p4x=$Dx; my $p4y=$y-$height; my $p5x=$Dx+$lang; my $p5y=$y-$height;
  my $p6x=$p4x+$half; my $p6y=$p4y-$half; my $p7x=$p5x+$half; my $p7y=$p5y-$half;
  my $ptx=$p3x+4; my $pty=$p2y-12; my $ptyv=$p1y-12; # Textkoord.
  my $pf1x=$p1x+1; my $pf1y=$p1y-1; my $pf2x=$p6x; my $pf2y=$p6y+1; my $pf3x=$p3x-1; my $pf3y=$p3y;  # Fuellkoordinaten
  my $ps1x=$p1x+$half; my $ps1y=$p1y+$half; my $ps2x=$p5x+$half; my $ps2y=$p5y+$half;
  if ($self->{schmuck} == 2) { # Schatten
	  $img->rectangle($ps1x,$ps1y,$ps2x,$ps2y,$self->{shadowcol});		    # Rechteck
	  if ($ps1x+2<$ps2x) {$img->fill($ps2x-1,$ps2y+1,$self->{shadowcol});}
  
  }
  $self->log(4, "P1X : $p1x $p1y $p2x $p2y $p3x $p3y");
  $img->rectangle($p1x,$p1y,$p5x,$p5y,$self->{fontcol});		    # Rechteck
  if ($p5x-2>$pf1x) {  $img->fillToBorder($pf1x,$pf1y,$self->{fontcol},$data->{colorn});	}
  
  $data->{X}[0]=$p1x; $data->{Y}[0]=$p1y; $data->{X}[1]=$p2x; $data->{Y}[1]=$p2y;  # Umspannendes Polygon
  $data->{X}[2]=$p5x; $data->{Y}[2]=$p5y; $data->{X}[3]=$p4x; $data->{Y}[3]=$p4y;
  if ($self->{schmuck} == 1) { #3D
    $img->line($p4x,$p4y,$p6x,$p6y,$self->{fontcol});           # Schräg ob. li.
    $img->line($p5x,$p5y,$p7x,$p7y,$self->{fontcol});           # Schräg ob. re.
    $img->line($p2x,$p2y,$p3x,$p3y,$self->{fontcol});           # Schräg un. re.
    $img->line($p6x,$p6y,$p7x,$p7y,$self->{fontcol});           # grade ob.
    $img->line($p7x,$p7y,$p3x,$p3y,$self->{fontcol});           # senkr. re.
    if ($p7x-2>$pf2x) { $img->fill($pf2x,$pf2y,$data->{colorh});}
    $img->fill($pf3x,$pf3y,$data->{colord});
	$pty=$p3y-12;												# Texth etwas hoeher bei 3D
	$data->{X}[2]=$p7x; $data->{Y}[2]=$p7y; $data->{X}[3]=$p6x; $data->{Y}[3]=$p6y;  # Polygon aendern
  }
  $img->string(gdSmallFont,$ptx,$pty,$data->{texth},$self->{fontcol});
  $img->string(gdSmallFont,$x,$ptyv,$data->{textv},$self->{fontcol});
  return ($x,$y+$height*2);					
}


####################################################################
####         Zeichnet die Skala
####         Argumente  : -
####         Returnwert : -
####################################################################
sub SK {
	my $self=shift;
	$self->{N}=int($self->{N});
	my $xsize=$self->{size}*0.95;       # Breite der Teilskala
	my $ysize=$xsize;			   # Hoehe der Teilskala
	my $anzahl=@{$self->{datasets}};
	my ($Y, $X) = ($ysize+4, 1);
	if ($self->{schmuck} == 1) {   # 3D
		$ysize/=2;
		$X=$xsize*$anzahl+1;
	}
	
	my $img = $self->_init_img($X+$self->{N}*$xsize+$self->{laengstes}+6, ($anzahl+1)*$ysize+16);
	$self->_setcolors;
	foreach $data ( @{$self->{datasets}} ) {
		#$self->save;
		#read STDIN, $aaa,1;
		($X,$Y)=$self->_skala($img, $data, $X, $Y, $xsize, $ysize );
	}
	if ($self->{printN} > 0) {
		$img->string(gdSmallFont,$X,$Y,"Gesamt: n=".$self->{N},$self->{fontcol});
	}

}
  
sub _skala {
	  my ($self, $img, $data, $x, $y, $xsize, $ysize) = @_;
	  my $Dx=$self->{laengstesv}+4+$x;
	  my $yo=$y-$ysize/2; my $yu=$yo+$ysize;
	  my $xo=$Dx; my $xu=$Dx;
	  my $ry=$y+$ysize; my $rx=$x;			# Returnwerte
	  if ($self->{schmuck} == 1) {$xo+=$xsize/2; $xu=$xo-$xsize; $rx=$x-$xsize}  #3D
	  $img->line($Dx-2,$y,$Dx+($data->{N}-1)*$xsize+2,$y,$data->{fontcol});           # Waagerechte Linie...
	  if ($self->{schmuck} == 2) { # Schatten
		$img->line($Dx-2+9,$y+9,$Dx+($data->{N}-1)*$xsize+2+9,$y+5,$data->{shadowcol});           # Waagerechter Schatten
	  }
	  for ($n=0; $n<$data->{N}; $n++) {											  # Senkrechte Linien		
		$img->line($xo+$xsize*$n,$yo,$xu+$xsize*$n,$yu,$self->{fontcol});	  
	    if ($self->{schmuck} == 2) {# Schatten
			$img->line($xo+$xsize*$n+9,$yo+9,$xu+$xsize*$n+9,$yu+9,$self->{shadowcol});	  
		}
	  }
	  $img->arc($Dx+($data->{num}-1)*$xsize,$y,$xsize/2,$ysize/2,0,360,$data->{colorn});   #Zielkreis malen	
	  $img->fillToBorder($Dx+($data->{num}-1)*$xsize,$y,$data->{colorn},$data->{colorn});  # und ausfüllen	
	  $img->string(gdSmallFont,$x,$y-6,$data->{textv},$self->{fontcol});
	  $img->string(gdSmallFont,$Dx+($data->{N}-1)*$xsize+4,$y-6,$data->{texth},$self->{fontcol});
	  $data->{X}[0]=$xo; $data->{Y}[0]=$yo; $data->{X}[1]=$xo+$xsize*($data->{N}-1); $data->{Y}[1]=$yo;  # Umspannendes Polygon
	  $data->{X}[2]=$xu+$xsize*($data->{N}-1); $data->{Y}[2]=$yu; $data->{X}[3]=$xu; $data->{Y}[3]=$yu;

	  #$img->line($x,$y,$rx,$ry,$self->{fontcol});	   	
	  return ($rx, $ry);
	  
}	


####################################################################
####         Zeichnet den Verlauf
####         Argumente  : -
####         Returnwert : -
####################################################################
sub VL {
	my $self=shift;
	my $ysize=$self->{size}*1.02;     # Breite der Teilskala
	my $xsize=$ysize;   # Hoehe der Teilskala
	my $anzahl=@{$self->{datasets}};
	my ($Y, $X) = ($ysize+4, 1);
	$ysize/=2;
	#if ($self->{schmuck} eq "3D") {
	#	$ysize/=2;
	#	$X=$xsize*$anzahl+1;
	#}
	my ($ox,$oy)=(0,0);
	my $img = $self->_init_img($X+10*$xsize+$self->{laengstes}+6, ($anzahl+1)*$ysize+16);
	$self->_setcolors;
	foreach $data ( @{$self->{datasets}} ) {
		($X,$Y,$ox,$oy)= $self->_verlauf($img,$data,$X,$Y,$ox,$oy,$xsize,$ysize);	
	}
	if ($self->{printN} > 0) {
		$img->string(gdSmallFont,$X,$Y,"Gesamt: n=".$self->{N},$self->{fontcol});
	}
}

sub _verlauf{
	  my ($self, $img, $data, $x, $y, $oldx, $oldy, $xsize, $ysize) = @_;
	  my $Dx=$self->{laengstesv}+4+$x;
	  my $xh=$xsize*$data->{proz}/10+$Dx;
	  $img->line($Dx, $y, $xh, $y, $data->{colord});
	  if ($oldx!=0 && $oldy!=0) {  $img->line($xh,$y,$oldx,$oldy,$self->{fontcol}); }
      $img->arc($xh, $y, $xsize/3,$xsize/3,0,360,$data->{colorn});	# Kringel
  	  $img->fillToBorder($xh, $y, $data->{colorn},$data->{colorn});  # und ausfüllen	
	  $img->string(gdSmallFont,$x,$y-6,$data->{textv},$self->{fontcol});
	  $img->string(gdSmallFont,$xh+$xsize/5+3,$y-6,$data->{texth},$self->{fontcol});
	  $self->log(4,"X=$x, Y=$y, OldX=$oldx, OldY=$oldy, Dx=$Dx, xh=$xh");
	  $data->{X}[0]=$Dx; $data->{Y}[0]=$y-$ysize/2; $data->{X}[1]=$xh; $data->{Y}[1]=$y-$ysize/2;  # Umspannendes Polygon
	  $data->{X}[2]=$xh; $data->{Y}[2]=$y+$ysize/2; $data->{X}[3]=$Dx; $data->{Y}[3]=$y+$ysize/2;
	  $oldx=$xh;
      $oldy=$y;
	  $y+=$ysize;
	  return $x,$y,$oldx,$oldy;	
 }
