# Graph for tla
# Copyright (C) 2005 Thomas Gerigk
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
# or look under http://www.gnu.org/licenses/licenses.html#GPL

use strict;

package ArchWay::Util::RenderNodes_AA;
use base qw(ArchWay::Util::RenderNodes);


#center text in field of defined width
# filling left and right with given character
sub center {
	### no self here. 
	my $breite = shift;
	my $text = shift;
	my $lchar = shift;
	my $rchar = shift;
	my $laenge = 0;
	$laenge = (length $text) if (defined $text);
	my $links = int ( ($breite - $laenge) / 2 );
	my $rechts = $breite - $laenge - $links;
	my $lfill = $lchar x $links;
	my $rfill = $rchar x $rechts;
	return ( $lfill . $text . $rfill);
}

sub set_graph_char_set ($;$) {
	my $self = shift;
	my $use_drawing_chars = shift || 0;

	if ($use_drawing_chars) {
		$self->{graph_char_set} = {
			senk  => "\x{2502}",  # light vertical
			senk2 => "\x{2502}",  # light vertical
			waag  => "\x{2500}",  # light horizontal
			rnu   => "\x{250c}",  # l. right + down
			lnu   => "\x{2510}",  # l. left + down
			onr   => "\x{2514}",  # l. up + right
			onl   => "\x{2518}",  # l. up + left
			sur   => "\x{251c}",  # l. vert. + right
			sul   => "\x{2524}",  # l. vert. + left
			wuu   => "\x{252c}",  # l. hor. + down
			wuo   => "\x{2534}",  # l. hor. + up
			wus   => "\x{2502}",  # l. vertical
			surp  => "\x{251c}",  # l. vert. + right
			sulp  => "\x{2524}",  # l. vert. + left
		};
	} else {
		$self->{graph_char_set} = {
			senk  => "|",
			senk2 => ":",
			waag  => "-",
			rnu   => "/",
			lnu   => "\\",
			onr   => "\\",
			onl   => "/",
			sur   => ">",
			sul   => "<",
			wuu   => "v",
			wuo   => "^",
			wus   => "-",
			surp  => "+",
			sulp  => "+",
		};
	}
}

# One big function
#
#
sub _render {
	my $self = shift;
	
	my $maxpos = $self->{"maxpos"};
	my $revnodes = $self->{"RevCol"}->{"nodes"};
	my $level = $self->{"y"};
	my $nodes = $self->{"nodes"};
	my $kon = $self->{"kon"};
	my $letter = $self->{"letter"};
	my $buffer = "";
	
	my $t1v;
	my $t1r;
	my $t2v;
	my $t2r;
	my $tag;
	my $temp;
	
	my $curlevel;
	my $curcol;
	my $curpos;
	my %nextlevel;
	my @showrevision;
	my $temptext;
	my @col;
	my $maxcol;
	my @pos2col;
	my $rechts;
	my $links;
	my $lspc;
	my $rspc;
	my $fspc;
	my $maxrevlaenge;

	my $count;
	my $pos1;
	my $pos2;
	my $coldir;
	my @colrange;
	my $colins;
	
	my $laenge;
	my $opre;
	my $opost;
	my $out;
	
	my $distance_required;
	my $tagl;
	my $tagr;
	my $targetcol;
	my $outline;

	my %graphchar = %{$self->{graph_char_set}};

	# what is the longest FullRevision-Name using $letter
	foreach $t1v ( keys %{$nodes} ) {
		foreach $t1r ( keys %{$nodes->{$t1v}} ) {
			$temp = length ($letter->{$t1v} . "--" . $t1r);
			if ( $maxrevlaenge < $temp ) {
				$maxrevlaenge = $temp;
			}
		}
	}
	$maxrevlaenge = $maxrevlaenge + 4;
	
# # First pass: dry-run to collect some data
	
###	   print "Render Pass 1\n";
	
	# init $col-array
	$count = 0;
	foreach $curpos ( 0..$maxpos ) {
		$col[$count]->[0] = -1;
		$col[$count]->[1] = 1;
		$count++;
		$col[$count]->[0] = $curpos;
		$col[$count]->[1] = $maxrevlaenge;
		$pos2col[$curpos] = $count;
###	print "$curcol $count \n";
		$count++;
		$col[$count]->[0] = -1;
		$col[$count]->[1] = 1;
		$count++;
	}
	$maxcol = $count - 1;
	
# section 0 end
	$curlevel = 0;

	# init $nextlevel-hash
	foreach $t1v (keys %{$nodes}) {
		$t1r = ( sort keys %{$nodes->{$t1v}} )[0];
		$nextlevel{$t1v} = $t1r;
###	print "nextlevel $t1v - $t1r\n";
	}
	
	do {
		
###		foreach (0..$maxcol) {
###			print $col[$_]->[0] . " ";
###		}
###		print "\n";

###		print "curlevel $curlevel\n";
		# which revision are at the current $curlevel / which come next
		foreach $t1v ( keys %nextlevel ) {
			if ( $level->{$t1v}->{ $nextlevel{$t1v} } == $curlevel ) {
				$t1r = $nextlevel{$t1v};
###				print "nextlevel $t1v - $t1r\n";
# section 2 begin
				$col[ $pos2col[ $kon->{$t1v}->{"pos"} ] ]->[3]->[0] = $t1v;
				$col[ $pos2col[ $kon->{$t1v}->{"pos"} ] ]->[3]->[1] = $t1r;
# section 2 end
				if ( defined $nodes->{$t1v}->{$t1r}->{"next"} ) {
					($t2v, $t2r) = $self->_zerlege_vers_rev($nodes->{$t1v}->{$t1r}->{"next"});
###					print " $t2v - $t2r\n";
					$nextlevel{$t1v} = $t2r;
###					print "new next	 $t1v - $t2r\n";
				} else {
					# reduce search-space for next iterations.
					delete $nextlevel{$t1v};
				}
			}
		}
		
# section 3 begin
		# first run: resolve ending merge-lines
		foreach $curcol (0..$maxcol) {
			if ( $col[$curcol]->[0] == (-1) 
				 && defined $col[$curcol]->[3]->[0] ) {
				$t1v = $col[$curcol]->[3]->[0];
				$t1r = $col[$curcol]->[3]->[1];
###				print "search end for line to $t1v - $t1r $curcol\n";
				foreach $curpos ( 0..$maxpos ) {
					if ( !defined $col[$pos2col[$curpos]]->[3]
						 || !defined $col[$pos2col[$curpos]]->[3]->[0] ) {
						next; 
					}
					if ( $col[ $pos2col[$curpos] ]->[3]->[0] eq $t1v
						 && $col[ $pos2col[$curpos] ]->[3]->[1] eq $t1r ) {
###						print " found end for line " . $pos2col[$curpos] . "\n";
						undef $col[ $curcol ]->[2];
						undef $col[ $curcol ]->[3];
						last;
					}
				}
			}
		}
		
		# last run: add beginning merge-lines
		$curcol = 0 - 1;
		while ($curcol < $maxcol) {
			$curcol++;
			if ( $col[$curcol]->[0] < 0 ) {
				next;
			}
			if ( $col[$curcol]->[0] >= 0
				 && !defined $col[$curcol]->[3]->[0] ) {
				next;
			}
			$t1v = $col[$curcol]->[3]->[0];
			$t1r = $col[$curcol]->[3]->[1];
			if ( !defined $revnodes->{$t1v}
				 || !defined $revnodes->{$t1v}->{$t1r}
				 || !defined $revnodes->{$t1v}->{$t1r}->{"to"} ) {
				next;
			}
			
###			print "starting line from $t1v - $t1r $curcol\n";
			foreach $t2v ( keys %{$revnodes->{$t1v}->{$t1r}->{"to"}} ) {
				foreach $t2r ( keys %{$revnodes->{$t1v}->{$t1r}->{"to"}->{$t2v}} ) {
###					print "  to $t2v - $t2r\n";
					# status: $v/$r is current (not yet) rendering revision
					#		  $v2/$r2 is revision to which $v/$r merges-to
					$pos1 = $kon->{$t1v}->{"pos"};
					$pos2 = $kon->{$t2v}->{"pos"};
					$coldir = 0;
					@colrange = undef;
					if ( $pos1 < $pos2 ) {
						@colrange = (( $pos2col[$pos1]+1 )..( $pos2col[$pos1+1]-1 ));
						$coldir = 1;
					} elsif ( $pos1 > $pos2 ) {
						@colrange = reverse (( $pos2col[$pos1-1]+1 )..( $pos2col[$pos1]-1 ));
						$coldir = (-1);
					} elsif ( $pos1 == $pos2 ) {
						if ( $pos1 == 0 ) {
							@colrange = reverse (0..( $pos2col[$pos1]-1 ));
						} else {
							@colrange = reverse (( $pos2col[$pos1-1]+1 )..( $pos2col[$pos1]-1 ));
						}
						$coldir = (-1);
					}
					# find a place for merge-line
					$tag = 0;
					$colins = undef;
					foreach (@colrange) {
						if ( $col[$_]->[0] >= 0 ) {
							next;
						}
						if ( defined $col[$_]->[3]->[0] ) {
							# found allocated merge-line-column
							if ( $col[$_]->[2]->[0] eq $t1v
								 && $col[$_]->[3]->[0] eq $t2v
								 && $col[$_]->[3]->[1] eq $t2r ) {
								# column is for merge-line i want
								$tag = 1;
								undef $colins;
###								print " found allocated line to $t2v - $t2r $_\n";
								last;
							} else {
								# column is used by other merge-line
								next;
							}
						}
						# found free column
						if ( !defined $colins ) {
							$colins = $_;
###							print " found free line to $t2v - $t2r $_\n";
						}
						$tag = 1;
					}
					if ( $tag == 1 ) {
						if ( defined $colins ) {
							$col[$colins]->[2]->[0]=$t1v;
							$col[$colins]->[3]->[0]=$t2v;
							$col[$colins]->[3]->[1]=$t2r;
						}
						next;
					}
					# no usable column available; add one
					$colins = $colrange[0];
					if ($coldir == -1) {
						$colins = $colins + 1;
					}
					foreach ( reverse $colins..$maxcol ) {
						$col[$_+1] = $col[$_];
						if ( $col[$_+1]->[0] >= 0 ) {
							$pos2col[ $col[$_+1]->[0] ] = $_+1;
						}
					}
					undef $col[$colins];
					$col[$colins]->[0]=-1;
					$col[$colins]->[1]=1;
					$col[$colins]->[2]->[0]=$t1v;
					$col[$colins]->[3]->[0]=$t2v;
					$col[$colins]->[3]->[1]=$t2r;
					$maxcol++;
					$curcol++;
###					print " allocated new line to $t2v - $t2r $colins\n";
				}
			}
		}
		
		# if there are /current/-data move them now to /old/-data
		foreach $curcol ( 0..$maxcol ) {
			if ( $col[$curcol]->[0] >= 0 ) {
				if ( defined $col[$curcol]->[3]->[0] ) {
					$col[$curcol]->[2] = $col[$curcol]->[3];
					undef $col[$curcol]->[3];
				}
			}
		}
# section 3 end
		
		$curlevel++;
	} until ( ((keys %nextlevel) + 0) == 0 );
	
	
	
	
	
# # second pass: rendering
	
###	   print "Render Pass 2\n";
	
	# half-init $col-array
	$curpos = 0;
	foreach $curcol ( 0..$maxcol ) {
		undef $col[$curcol]->[2];
		undef $col[$curcol]->[3];
		if ( $col[$curcol]->[0] >= 0 ) {
			$pos2col[$curpos] = $curcol;
			$curpos++;
		}
	}
	
# section 0 end
	
	$curlevel = 0;
	
	# init $nextlevel-hash
	foreach $t1v (keys %{$nodes}) {
		$t1r = ( sort keys %{$nodes->{$t1v}} )[0];
		$nextlevel{$t1v} = $t1r;
	}
	
	
	do {
		foreach $t1v ( keys %nextlevel ) {
			if ( $level->{$t1v}->{ $nextlevel{$t1v} } == $curlevel ) {
				$t1r = $nextlevel{$t1v};
				
# section 2 begin
				$col[ $pos2col[ $kon->{$t1v}->{"pos"} ] ]->[3]->[0] = $t1v;
				$col[ $pos2col[ $kon->{$t1v}->{"pos"} ] ]->[3]->[1] = $t1r;
# section 2 end
				if ( defined $nodes->{$t1v}->{$t1r}->{"next"} ) {
					($t2v, $t2r) = $self->_zerlege_vers_rev($nodes->{$t1v}->{$t1r}->{"next"});
					$nextlevel{$t1v} = $t2r;
				} else {
					delete $nextlevel{$t1v};
				}
			}
		}
		
# section 3 begin
		# zero run: cache data
		foreach $curcol ( 0..$maxcol ) {
			$col[$curcol]->[4]="";
			$col[$curcol]->[5]="";
			undef $col[$curcol]->[6];
			if ( $col[$curcol]->[0] >= 0 ) {
				# version-columns
				$t1v = undef;
				$t1r = undef;
				$t2v = undef;
				$t2r = undef;
				$tag = 0;
				if ( defined $col[$curcol]->[3]->[0] ) {
					$t2v = $col[$curcol]->[3]->[0];
					$t2r = $col[$curcol]->[3]->[1];
					$col[$curcol]->[5] = $kon->{$t2v}->{"letter"} . "--" . $t2r ;
					$tag = 1;
				}
				if ( defined $col[$curcol]->[2]->[0] ) {
					# pre-revision defined
					$t1v = $col[$curcol]->[2]->[0];
					$t1r = $col[$curcol]->[2]->[1];
					# cur-rev defined ?
					if ( $tag == 0
						 && defined $nextlevel{$t1v} ) {
						# else look for next-level
						$t2v = $t1v;
						$t2r = $nextlevel{$t1v};
						$tag = 2;
					}
					# if there is next-link prepare vert line
###			print "$t2v\n";
					if ( defined $t2v
						 && defined $revnodes->{$t1v}->{$t1r}
						 && defined $revnodes->{$t1v}->{$t1r}->{"next"}
						 && $revnodes->{$t1v}->{$t1r}->{"next"} eq "$t2v--$t2r") {
						$col[$curcol]->[4] = $graphchar{senk};
						if ( $tag == 2 ) {
							$col[$curcol]->[5] = $graphchar{senk};
						}
					} 
				}
			} elsif ( $col[$curcol]->[0] == -1 ) {
				# merge-line-columns
				if ( defined $col[$curcol]->[3]->[0] ) {
					$col[$curcol]->[4] = $graphchar{senk};
					$col[$curcol]->[5] = $graphchar{senk};
				} 
			} else {
				# anything else is empty
			}
		}
		
		# first run: continue vertical lines
		foreach $curcol ( 0..$maxcol ) {
			
			$laenge = $col[$curcol]->[1];
			$opre = " ";
			$opost = " ";
			
			$out = $col[$curcol]->[4];
			if ( $out eq $graphchar{senk}
				 && (  $curcol % 2 ) ) {
				$out = $graphchar{senk2};
			}
			$buffer = $buffer . center($laenge, $out, $opre, $opost);
		}
		
		$buffer = $buffer . "\n";
		
		# second run: resolve merge-lines
		$distance_required = 0;
		
		do {
			$tag = 0;
			
			# left-to-right run
			$tagl = 0;
			$targetcol = undef;
			$outline = "";
			$curcol = 0-1;
			while ( $curcol < $maxcol ) {
				$curcol++;
				$laenge = $col[$curcol]->[1];
				$opre  = " ";
				$opost = " ";
				if ( defined $targetcol ) {
					$out = $graphchar{waag};
					$opre = $graphchar{waag};
					if ( $targetcol > $curcol ) {
						$opost = $graphchar{waag};
					}
				} else {
					$out = $col[$curcol]->[4];
				}
				if ($col[$curcol]->[0] >= 0) {
					# rev-column
					if ( defined $targetcol
						 && $targetcol == $curcol ) {
						if ($col[$curcol]->[4] eq $graphchar{senk}) {
							$out = $graphchar{sulp};
						} else {
							$out = $graphchar{lnu};
						}
						$col[$curcol]->[4] = $graphchar{senk};
						undef $targetcol;
					} 
					
				} elsif ($col[$curcol]->[0] == -1) {
					# merge-line-column
					if ( defined $col[$curcol]->[3]->[0] ) {
						if ( !defined $targetcol ) {
							$t1v = $col[$curcol]->[3]->[0];
							$t1r = $col[$curcol]->[3]->[1];
							foreach my $curcol2 ( ($curcol+1)..$maxcol ) {
								if ( $col[$curcol2]->[0] < 0 ) {
									next;
								}
								if ( !defined $col[$curcol2]->[3]->[0] ) {
									next;
								}
								if ( $col[$curcol2]->[3]->[0] ne $t1v
									 || $col[$curcol2]->[3]->[1] ne $t1r ) {
									next;
								}
								$targetcol = $curcol2;
								last;
							}
							if ( defined $targetcol ) {
								$out = $graphchar{onr};
								$opost = $graphchar{waag};
								undef $col[$curcol]->[2];
								undef $col[$curcol]->[3];
								$col[$curcol]->[4] = "";
								$col[$curcol]->[5] = "";
								$tagl = 1;
							}
						}
					}
				} else {
					# unknown col
					#use defaults
				}
				if ( $out eq $graphchar{senk}
					 && (  $curcol % 2 ) ) {
					$out = $graphchar{senk2};
				}
				$outline = $outline . center($laenge, $out, $opre, $opost);
			}
			if ($tagl == 1) {
				$buffer = $buffer . $outline . "\n";
				$tag = 1;
			}
			
			# right-to-left run
			$tagr = 0;
			undef $targetcol;
			$outline = "";
			$curcol = $maxcol+1;
			while ( $curcol > 0 ) {
				$curcol--;
				$laenge = $col[$curcol]->[1];
				$opre  = " ";
				$opost = " ";
				if ( defined $targetcol ) {
					$out = $graphchar{waag};
					$opost = $graphchar{waag};
					if ( $targetcol < $curcol ) {
						$opre = $graphchar{waag};
					}
				} else {
					$out = $col[$curcol]->[4];
				}
				
				if ($col[$curcol]->[0] >= 0) {
					# rev-column
					if ( defined $targetcol
						 && $targetcol == $curcol ) {
						if ($col[$curcol]->[4] eq $graphchar{senk}) {
							$out = $graphchar{surp};
						} else {
							$out = $graphchar{rnu};
						}
						$col[$curcol]->[4] = $graphchar{senk};
						undef $targetcol;
					} 
					
				} elsif ($col[$curcol]->[0] == -1) {
					# merge-line-column
					if ( defined $col[$curcol]->[3]->[0] ) {
						if ( !defined $targetcol ) {
							$t1v = $col[$curcol]->[3]->[0];
							$t1r = $col[$curcol]->[3]->[1];
							foreach ( reverse (0..($curcol-1)) ) {
								if ( $col[$_]->[0] < 0 ) {
									next;
								}
								if ( !defined $col[$_]->[3]->[0] ) {
									next;
								}
								if ( $col[$_]->[3]->[0] ne $t1v
									 || $col[$_]->[3]->[1] ne $t1r ) {
									next;
								}
								$targetcol = $_;
								last;
							}
							if ( defined $targetcol ) {
								$out = $graphchar{onl};
								$opre = $graphchar{waag};
								undef $col[$curcol]->[2];
								undef $col[$curcol]->[3];
								$col[$curcol]->[4] = "";
								$col[$curcol]->[5] = "";
								$tagr = 1;
							}
						}
					}
				} else {
					# unknown col
					#use defaults
				}
				if ( $out eq $graphchar{senk}
					 && (  $curcol % 2 ) ) {
					$out = $graphchar{senk2};
				}
				$outline = center($laenge, $out, $opre, $opost) . $outline;
			}
			if ($tagr == 1) {
				$buffer = $buffer . $outline . "\n";
				$tag = 1;
			}
			if ($tag == 1) {
				$distance_required = 1;
			}
		} until ( $tag == 0 );

		# third run: output distance line
		if ($distance_required == 1) {
			foreach $curcol ( 0..$maxcol ) {
				
				$laenge = $col[$curcol]->[1];
				$opre = " ";
				$opost = " ";
				
				$out = $col[$curcol]->[4];
				if ( $out eq $graphchar{senk}
					 && (  $curcol % 2 ) ) {
					$out = $graphchar{senk2};
				}
				$buffer = $buffer . center($laenge, $out, $opre, $opost);
			}
			$buffer = $buffer . "\n";
		}
		
		# fourth run: prepare beginning merge-lines (no output, deferred to last run)
		$curcol = 0 - 1;
		while ($curcol < $maxcol) {
			$curcol++;
			if ( $col[$curcol]->[0] < 0 ) {
				# no processing starts with merge-lines
				next;
			}
			if ( $col[$curcol]->[0] >= 0
				 && !defined $col[$curcol]->[3]->[0] ) {
				# no processing with rev-lines without current rev
				next;
			}
			$t1v = $col[$curcol]->[3]->[0];
			$t1r = $col[$curcol]->[3]->[1];
			if ( !defined $revnodes->{$t1v}
				 || !defined $revnodes->{$t1v}->{$t1r}
				 || !defined $revnodes->{$t1v}->{$t1r}->{"to"} ) {
				next;
			}
			
			foreach $t2v ( keys %{$revnodes->{$t1v}->{$t1r}->{"to"}} ) {
				foreach $t2r ( keys %{$revnodes->{$t1v}->{$t1r}->{"to"}->{$t2v}} ) {
					# status: $v/$r is current (not yet) rendering revision
					#		  $v2/$r2 is revision to which $v/$r merges-to
					$pos1 = $kon->{$t1v}->{"pos"};
					$pos2 = $kon->{$t2v}->{"pos"};
					@colrange;
					if ( $pos1 < $pos2 ) {
						@colrange = (( $pos2col[$pos1]+1 )..( $pos2col[$pos1+1]-1 ));
					} elsif ( $pos1 > $pos2 ) {
						@colrange = reverse (( $pos2col[$pos1-1]+1 )..( $pos2col[$pos1]-1 ));
					} elsif ( $pos1 == $pos2 ) {
						if ( $pos1 == 0 ) {
							@colrange = reverse (0..( $pos2col[$pos1]-1 ));
						} else {
							@colrange = reverse (( $pos2col[$pos1-1]+1 )..( $pos2col[$pos1]-1 ));
						}
					}
					# find a place for merge-line
					$colins = undef;
					$tag = 0;
					foreach my $curcol2 (@colrange) {
						if ( $col[$curcol2]->[0] >= 0 ) {
							# schud näwer kamm along hier
							next;
						}
						if ( defined $col[$curcol2]->[3]->[0] ) {
							# found allocated merge-line-column
							if ( $col[$curcol2]->[2]->[0] eq $t1v
								 && $col[$curcol2]->[3]->[0] eq $t2v
								 && $col[$curcol2]->[3]->[1] eq $t2r ) {
								# column is for merge-line i want
								$colins = $curcol2;
								$tag = 1;
								last;
							} else {
								# column is used by other merge-line
								next;
							}
						}
						# found free column
						if ( !defined $colins ) {
							$colins = $curcol2;
						}
					}
					if ( defined $colins ) {
						if ($tag == 0) {
							$col[$colins]->[2]->[0]=$t1v;
							$col[$colins]->[3]->[0]=$t2v;
							$col[$colins]->[3]->[1]=$t2r;
						}
						if ( $colins > $curcol ) {
							if ($col[$colins]->[5] eq $graphchar{senk} ) {
								$col[$colins]->[5] = $graphchar{sul};
							} else {
								$col[$colins]->[5] = $graphchar{lnu};
							}
							if ( !defined $col[$curcol]->[6]
								 || $col[$curcol]->[6] < $colins ) {
								$col[$curcol]->[6] = $colins;
							}
						} else {
							if ($col[$colins]->[5] eq $graphchar{senk} ) {
								$col[$colins]->[5] = $graphchar{sur};
							} else {
								$col[$colins]->[5] = $graphchar{rnu};
							}
							if ( !defined $col[$colins]->[6]
								 || $col[$colins]->[6] < $curcol ) {
								$col[$colins]->[6] = $curcol;
							}
						}
					}
				}
			}
		}
		
		# last run: write out revisions and continue vert lines of merges
		undef $targetcol;
		foreach ( 0..$maxcol) {
			
			$laenge = $col[$_]->[1];
			$opre = " ";
			$opost = " ";
			$out = $col[$_]->[5];
			
			if ( defined $targetcol ) {
				$opre = $graphchar{waag};
			}
			
			if ( defined $targetcol
				 && $targetcol > $_ ) {
				if ( $out eq $graphchar{lnu}
					 || $out eq $graphchar{rnu} ) {
					if ( $col[$_]->[4] ne $graphchar{senk} ) {
						$out = $graphchar{wuu};
					} else {
						$out = "#";
					}
				} elsif ( $out eq $graphchar{senk} ) {
					$out = $graphchar{wus};
				} elsif ( $out eq ""
						   || $out eq " " ) {
					$out = $graphchar{waag};
				}
			}
			if ( defined $targetcol
				 && $targetcol == $_ ) {
				undef $targetcol;
			}
			
			if ( !defined $targetcol
				 && defined $col[$_]->[6] ) {
				$targetcol = $col[$_]->[6];
			}
			
			if ( defined $targetcol
				 && $targetcol > $_ ) {
				$opost = $graphchar{waag};
			}
			
			if ( $out eq $graphchar{senk}
				 && (  $_ % 2 ) ) {
				$out = $graphchar{senk2};
			}
			$buffer = $buffer . center($laenge, $out, $opre, $opost);
		}
		
		$buffer = $buffer . "\n";
		
		# if there are /current/-data move them now to /old/-data
		foreach ( 0..$maxcol ) {
			if ( $col[$_]->[0] >= 0 ) {
				if ( defined $col[$_]->[3]->[0] ) {
					$col[$_]->[2] = $col[$_]->[3];
					undef $col[$_]->[3];
				}
			}
		}
# section 3 end
		
		$curlevel++;
	} until ( ((keys %nextlevel) + 0) == 0 );
	
	$buffer = $buffer . "\n";
	
	return $buffer;
}

sub print_letters {
	my $self = shift;
	
	my $letter = $self->{"letter"};

	print "\n";
	foreach (sort keys %{$letter}) {
		print "" . $_ . "\t-\t" . $letter->{$_} . "\n";
	}
}

sub render {
	my $self = shift;
	my $buffer = $self->{"buffer"};
	
	if (!defined $buffer) {
		$buffer = $self->_render();
	}
	
	return $buffer;
}

#
# dump for test purposes
#
sub _dump  {
	my $self = shift;
	
	my $nodes = $self ->{"nodes"};
	foreach my $t1v ( sort keys %{$nodes} ) {
		foreach my $t1r ( sort keys %{$nodes->{$t1v}} ) {
			print "${t1v}--${t1r}\n";
			
			if (defined $nodes->{$t1v}->{$t1r}->{"pre"}) {
				print "	 previous\n";
				print "		" . $nodes->{$t1v}->{$t1r}->{"pre"} . "\n";
			}
			
			foreach my $t2v ( sort keys %{$nodes->{$t1v}->{$t1r}->{"from"}} ) {
				foreach my $t2r ( sort keys %{$nodes->{$t1v}->{$t1r}->{"from"}->{$t2v}} ) {
					my $temp = $t2v . "--" . $t2r;
#			if ( defined $nodes->{$t1v}->{$t1r}->{"tagged-of"}
#			 && $nodes->{$t1v}->{$t1r}->{"tagged-of"} == $temp ) {
#			print "	 tag-of\n  ";
#			}
					print "	  ${t2v}--${t2r}\n";
				}
			}
			print "\n";
		}
	}
}





1;

__END__
