use Data::Dumper;
use vars qw(%FILES %ALIASES %LINKS $ASP $DOCINIT $DUMP $Site $LINKS_MATCH $VAR1);
use Time::HiRes;
use Data::Dumper;
use Digest::MD5 qw( md5_hex );
use SiteTags;
use strict;

$DUMP = "/tmp/aspbuilddumpdata";
%FILES = ('index' => 'INTRO',
	  'install' => 'INSTALL',
	  'changes' => 'CHANGES',
	  'config' => 'CONFIG',
	  'sessions' => 'SESSIONS',
	  'syntax' => 'SYNTAX',
          'style' => 'STYLE GUIDE',
	  'events' => 'EVENTS',
	  'objects' => 'OBJECTS',
	  'resources' => 'RESOURCES',
	  'ssi' => 'SSI',
	  'cgi' => 'CGI',
	  'perlscript' => 'PERLSCRIPT',
	  'faq' => 'FAQ',
	  'tuning' => 'TUNING',
	  'kudos' => 'CREDITS',
	  'support' => 'SUPPORT',
	  'sites' => 'SITES USING',
	  'todo' => 'TODO',
	  'xml' => 'XML/XSLT',
	  'license' => 'LICENSE',
	  'testimonials' => 'TESTIMONIALS',
	 );

%ALIASES = (
	    'DESCRIPTION' => 'INTRO',
#	    'INSTALL' => 'DOWNLOAD',
	    'NOTES' => 'CREDITS',
	   );

# auto link these key words, includes %FILES inverted
%LINKS = (
	  'Apache Web Server' => 'http://www.apache.org',
	  'mod_perl' => 'http://perl.apache.org',
	  'CGI.pm' => 'http://stein.cshl.org/WWW/software/CGI/cgi_docs.html',
	  'PerlScript' => 'http://www.activestate.com/ActivePerl/',
	  'NT/IIS' => 'http://www.microsoft.com/iis/',
	  'XML::XSLT' => 'http://xmlxslt.sourceforge.net/',
	  'LRN' => 'http://www.lrn.com',
	 );

# purify files and add as links
for(keys %FILES) {
    delete($FILES{$_}) unless -e "$_.html";
    $LINKS{$FILES{$_}} = "$_.html";
}

$LINKS_MATCH = join('|', keys %LINKS);

#exit;

sub Script_OnStart {
    unless ($DOCINIT++) {
	doc_init();
    }
    if($Request->QueryString('site')) {
	$Site = 1;
    }
}

sub Script_OnEnd {
    $Response->Write("\n");
}

sub dmp {
    Data::Dumper->Dump([@_]);
}

sub dbg {
    $Response->Debug(@_);
}

sub doc_init {
    local $/ = undef;
    open(DUMP, $DUMP);
    my $dump = <DUMP>;
    close DUMP;
    my $dump_data;
    if ($dump) {
	$Response->Debug("evaling compiled ASP data");
	$dump_data = eval $dump;
    }
    $dump_data ||= {};
    $Response->Debug("past eval");
    
    open(ASP, "../ASP.pm") || die("can't open ASP.pm: $!");
    my $data = <ASP>;
    close ASP;
    
    my $self_data;
    open(ASP, $0);
    $self_data = <ASP>;
    close ASP;

    $data =~ s/^.*\n__END__//s;
    my $new_checksum = md5_hex($data.$self_data.(join('', %ALIASES)));
    if ($new_checksum eq $dump_data->{checksum}) {
	$Response->Debug("matched old compiled ASP doc $dump_data->{checksum}");
	$ASP = $dump_data->{ASP};
	return;
    }
    
    $ASP = { name => 'ASP', stack => [], level => 0};
    my @levels;
    unshift(@levels, $ASP);
    
    my $count = 0;
    my $level = 0;
    my $time = Time::HiRes::time;
    $data =~ s/\n=(over|back|begin|end)[^\n]*\n/\n/sg;
    while($data =~ s/^.*?\n=(head\d|item) ([^\n]*)\n(.*?)(\n\=|$)/$4/is) {
	my($type, $name, $body) = ($1,$2,$3);
	$body =~ s/\s+$//s;

	$name = $ALIASES{$name} || $name;
	# warn time." ----------- $type :: $name :: $body ----------- \n\n";
	#    warn substr($data, 0, 200)."\n";
	#    $body =~ s/\n=over\s*$//s;
	my $item = { 
		    name => $name,
		    unique => substr($name, 0, 12).(length($name) > 12 ? substr(md5_hex($name.$body),0,8) : ''),
		    body => $body,
		    stack => [],
		    level => ($level + 1),
		   };
	
	if($type =~ /^head(\d)/) {
	    my $current = $1;		
	    $item->{level} = $current;
#	    dbg("$current current level $name");
	    while($current <= $levels[0]->{level}) {
#		dbg("shifting $levels[0]->{name}");
		shift(@levels);
	    }
	    push(@{$levels[0]->{stack}}, $item);
#	    dbg("$level unshifting $item->{name}");
	    unshift(@levels, $item);
	    $level = $item->{level};
	} else {
	    push(@{$levels[0]->{stack}}, $item);	
	}

#	last if $count++ > 20;
    }

#    warn(Time::HiRes::time - $time);
    open(DUMP, ">$DUMP");
    print DUMP Data::Dumper->Dump([{ checksum => $new_checksum, ASP => $ASP}]);
    close DUMP;
    
    dbg(dmp($ASP));
}

sub pod2html {
    my($body, $title, $depth) = @_;

    if($title) {
	$depth ||= 1;
	my $size = 2 - $depth;
	$size = ($size > -1) ? "+$size" : $size;
	
	$title = "<font class=title size=$size color=#555555><b>$title</b></font>\n";
    }

    if (($body =~ /^(.*?)(<(a|table)[^\<\>]*>.*?<\/(\3)>)(.*)$/is)) {
	my($pre,$html,$post) = ($1, $2, $5);
#	$html =~ s/\s+/ /isg;
	$body = $Server->HTMLEncode($pre).$html.$Server->HTMLEncode($post);
    } else {
	$body = $Server->HTMLEncode($body);
    }
    $body =~ s/(\<\%|\%\>)/$Server->HTMLEncode($1);/esg;

    my @lines = split(/\n/, $body);
    my $pre = 0;
    my @newlines;
    for(@lines) {
	my $pre_tag = '';
	if(/^\s+[^\s]/ || /^\s*$/) {
	    if(! $pre) {
		#			$_ = "<pre>$_";
		$pre_tag = "<font face=\"courier new\" size=3><pre>";
		$pre = 1;
	    }
	} else {
	    if($pre) {
		#			$_ = "</pre>$_";	
		$pre_tag = "</pre></font>";
		$pre = 0;
	    }
	}
#	if($pre) {
#	$_ =~ s/\s*$//;
#	    $_ = $Server->HTMLEncode($_);	    
#	}

#	} 

	$_ = $pre_tag . $_;
	push(@newlines, $_);
    }
    $body = join("\n", @newlines);
    $pre and $body .= "\n</pre>";

    $body =~ s,\n\s+(([^:\n\s]{5}|[A-Z])[^\n]*?)\s*\n\s+(http://[^\n\s]+)\s*?\n,\n  <a href="$3">$1</a>\n,sg;
#print STDERR $body;

    #$body =~ s/\n\s*\n+/<p>/isg;
    $body =~ s/([^\=\"])((http|ftp):\/\/[\w\.\/\-]+\.[\w\.\/\-\#\,\%]+[^\.\s\)])/$1<a href=$2>$2<\/a>/sg;
#    $1 && warn "link: $1\n";
    $body =~ s|(http://localhost[\S]*[^\.\s\,]?)|<tt>$1</tt>|sg;
    $body =~ s|([\w\-]+\@[\w\.\,\@\-]+)(\?[\w\=\:]+)?|'<b>'.&html_encode_hide($1).'</b>'|esg;
    $body =~ s|(\./site/)(eg/[\w\.]+[^\.\s])|<a href=$2>$1$2</a>|sg;

    $body =~ s|\n\n</pre>|\n</pre>|isg;
#    my $match_links = join('|', keys %LINKS);

    my %matched;
    $body =~ s:([^\n]*?)\b($LINKS_MATCH)(?=[^<])\b:
    {
	my($head, $match) = ($1, $2);

#print STDERR "***** $head $match\n";
	if(! $matched{$match}++ and $head !~ /\>$/ and $head !~ /^\s+/ and $LINKS{$match}) {
	    "$head<a href=$LINKS{$match}><font size=-1 face=verdana><b>$match<\/b><\/font><\/a>";
	} else	 {
	    $head.$match;
	}
    }
    :sgex;

    '<font face=verdana>'.$title.$body.'</font>';
}

# we use this to mask email addresses in the documentation
sub html_encode_hide {
    my $word = shift;
    join('',
	 map{
	     sprintf(qq(&#%03d;),ord($_))
	 } split(//, $word)
	);
}