#!/usr/bin/perl
# Converts a CWiki markup to MarkDown syntax
use strict;
use warnings;
use Data::Dumper;

use Text::Wrap qw/wrap $huge/;
$huge = "overflow";

my $atchurl = "https://cwiki.apache.org/confluence/download/attachments";

my $pageid = shift;

my $pageName = shift;
my $compressedPageName = $pageName;
$compressedPageName =~ s/\s//g;

my $source = shift;
unless($source && -f $source) {
   print "Use:\n";
   print "  $0 <page id> <page name> <cwiki template> [export.html]\n";
   exit 1;
}
my $dest = shift;
unless($dest) {
   $dest = $source;
   $dest .= ".html";
}

sub convertURL {
   my $url = shift;
   if($url =~ /^http/) {
      return $url;
   }
   $url =~ s/\s/-/g;
   $url = lc($url).".html";
   return $url;
}

sub title2filename {
	my ($title) = @_;
	$title =~ s/\s/-/g;
	$title =~ s/"//g;
	$title =~ s/'//g;
	$title = lc($title) . ".cwiki.html";
	$title =~ s/\(//g;
	$title =~ s/\)//g;
	$title =~ s/&//g;
	return $title;
}

open(INP, "<$source");
open(OUT, ">$dest");

print OUT "<html>\n";
print OUT "<head> \n";
print OUT "<link type=\"text/css\" rel=\"stylesheet\" href=\"code.css\">\n";
print OUT "<link type=\"text/css\" rel=\"stylesheet\" href=\"vcl.css\">\n";
print OUT "<title>$pageName</title>\n";
print OUT "</head>\n";
print OUT "<body>\n";
print OUT "<h1>$pageName</h1>\n";

# Load the file into a temporary array, and do some line wrapping on
#  the paragraphs
my @contents;
my $all = "";
while(my $line = <INP>) {
   $line =~ s/\r//;
=cut
   unless($line =~ /^\s*$/) {
      my @parts = split(/( \[)/, $line);
      $line = "";
      foreach my $p (@parts) {
         if($p =~ /^(.*?\])(.*)$/) {
            $p = $1."\n".wrap("","",$2);
         } else {
            $p = wrap("","",$p);
         }
         $line .= $p;
      }
      unless($line =~ /\n$/s) { $line .= "\n"; }
   }
=cut
	$line =~ s/<\/p>/<\/p>\n/g;
	$line =~ s/<\/ac:image>/<\/ac:image>\n/g;
	$line =~ s/<\/ac:plain-text-link-body>/<\/ac:plain-text-link-body>\n/g;
	$line =~ s/<\/ac:link>/<\/ac:link>\n/g;
	$line =~ s/<\/ac:macro>/<\/ac:macro>\n/g;
	$all .= $line;
}

@contents = split(/\n/, $all);

# Convert it
my $in = "";
my @macrolist = ();
my @items;
foreach my $line (@contents) {
=cut
   if($in eq "noformat") {
      if($line =~ /^\s*^{noformat}/) {
         print OUT "\n";
         $in = "";
      } else {
         print OUT "    ".$line;
      }
      next;
   } elsif($in eq "code:xml" || $in eq "code:text") {
      if($line =~ /^\s*^{code}/) {
         print OUT "\n";
         $in = "";
      } else {
         print OUT "    ".$line;
      }
      next;
   } elsif($in eq "table") {
      if($line =~ /^\s*$/) {
         print OUT "</table>\n";
         $in = "";
      }
   } elsif($in) {
      warn("Unexpected block '$in' for $line");
      $in = "";
   }

   # Numbered lists
   if($line =~ /^\s*#/) {
      $line =~ s/^\s*#\s*/1. /;
   }

   # Headings
   if($line =~ /^h(\d)\.\s?(.*)$/) {
      # Build the heading entry
      $line = ("#"x$1)." ".$2."\n";
      # Now replicate the a name
      my $name = $2;
      $name =~ s/\s//g;
      $line = "<a name=\"$compressedPageName-$name\"></a>\n".$line;
   }

   # Links
   if($line =~ /(\[(.*?)\])/) {
      my ($all,$text,$link) = ($1,$2,"");
      if($text =~ /^(.*?)\|(.*)/) {
         ($text,$link) = ($1,$2);
      }

      my $newlink;
      if($link) {
         $newlink = "[$text](".convertURL($link).")";
      } else {
         $newlink = "[$text](".convertURL($text).")";
      }
      $line =~ s/\Q$all\E/$newlink/;
   }

   # Old-style bold / italic
   $line =~ s/\{\{(.*?)\}\}/*$1*/g;
   $line =~ s/\{\{\{(.*?)\}\}\}/**$1**/g;

   # No-Format
   if($line =~ /^\s*^{noformat}/) {
      $in = "noformat";
      $line = "\n";
   }

   # Code blocks
   if($line =~ /^\s*^{code:xml}/) {
      $in = "code:xml";
      $line = "\n";
   }
   if($line =~ /^\s*^{code:title=(.*?)}/) {
      $in = "code:text";
      $line = '<DIV class="code panel" style="border-style: solid;border-width: 1px;"><DIV class="codeHeader panelHeader" style="border-bottom-width: 1px;border-bottom-style: solid;"><B>'.$1.'</B></DIV><DIV class="codeContent panelContent">'."\n";
   }
   if($line =~ /^\s*^{code}/) {
      $in = "code:text";
      $line = "\n";
   }

   # Forced breaks
   if($line =~ /\\\\/) {
      $line = "  \n  \n";
   }

   # Tables
   if($line =~ /^\|/) {
      unless($in eq "table") {
         print OUT "<table>\n";
         $in = "table";
      }
      $line =~ s/\|\|/<\/th><th>/g;
      $line =~ s/\|/<\/td><td>/g;
      $line =~ s/<t[dh]>\s*$//gs;
      $line =~ s/^\s*<\/t[dh]>//gs;
      $line = "<tr>".$line."</tr>\n";
   }
=cut

	# anchor macros
	if(@items = $line =~ /<ac:macro ac:name="anchor"><ac:default-parameter>([^<]+)<\/ac:default-parameter><\/ac:macro>/) {
		$line =~ s/<ac:macro ac:name="anchor"><ac:default-parameter>[^<]+<\/ac:default-parameter><\/ac:macro>/<span id="anchor-$items[0]" \/>/;
	}

	# excerpt macros
	# TODO - do we need to do something with excerpts?
	if($line =~ /<ac:macro ac:name="excerpt">(<ac:parameter.*<\/ac:parameter>)?<ac:rich-text-body>/) {
		$line =~ s/<ac:macro ac:name="excerpt">(<ac:parameter.*<\/ac:parameter>)?<ac:rich-text-body>//;
	}

	# iframe macros
	if($line =~ /<ac:macro ac:name="iframe">/) {
		@items = $line =~ /<ac:parameter ac:name="([^"]+)">([^<]+)<\/ac:parameter>/g;
		my %hash = ();
		for(my $i = 0; $i < scalar(@items); $i+=2) {
			$hash{$items[$i]} = $items[$i + 1];
		}
		my $params = "";
		foreach my $key (keys %hash) {
			$params .= " $key=\"$hash{$key}\"";
		}
		my $replace = "<iframe$params>";
		$line =~ s/<ac:macro ac:name="iframe">.*<\/ac:parameter><ac:rich-text-body>/$replace/;
		push @macrolist, "iframe";
	}

	# include macros - TODO just drop them for now
	if($line =~ /<ac:macro ac:name="include">(<ac:default-parameter>([^<]+)<\/ac:default-parameter>)*<\/ac:macro>/) {
		$line =~ s/<ac:macro ac:name="include">(<ac:default-parameter>([^<]+)<\/ac:default-parameter>)*<\/ac:macro>//;
	}

	# multimedia macros - TODO print that they are not supported
	if($line =~ /<ac:macro ac:name="multimedia">(<ac:parameter ac:name="([^"]+)">([^<]+)<\/ac:parameter>)*<\/ac:macro>/) {
		$line =~ s/<ac:macro ac:name="multimedia">(<ac:parameter ac:name="([^"]+)">([^<]+)<\/ac:parameter>)*<\/ac:macro>/(exporting multimedia macros not supported)/;
	}

	# children macros - TODO print that they are not supported
	if($line =~ /<ac:macro ac:name="(children|pagetree)">(<ac:parameter ac:name="([^"]+)">([^<]+)<\/ac:parameter>)*<\/ac:macro>/) {
		$line =~ s/<ac:macro ac:name="(children|pagetree)">(<ac:parameter ac:name="([^"]+)">([^<]+)<\/ac:parameter>)*<\/ac:macro>/(exporting content from child pages not supported)/;
	}

	# gliffy macros
	if($line =~ /<ac:macro ac:name="gliffy">(<ac:parameter ac:name="([^"]+)">([^<]+)<\/ac:parameter>)*<\/ac:macro>/) {
		@items = $line =~ /<ac:parameter ac:name="name">([^<]+)<\/ac:parameter>/;
		my $name = $items[0] . ".png";
		$name =~ s/ /%20/g;
		$line =~ s/<ac:macro ac:name="gliffy">(<ac:parameter ac:name="([^"]+)">([^<]+)<\/ac:parameter>)*<\/ac:macro>/<img src="$atchurl\/$pageid\/$name" \/>/;
	}

	# toc macro - TODO skip for now, could parse content and generate our own
	if($line =~ /<ac:macro ac:name="toc">(<ac:parameter ac:name="([^"]+)">([^<]+)<\/ac:parameter>)*<\/ac:macro>/) {
		$line =~ s/<ac:macro ac:name="toc">(<ac:parameter ac:name="([^"]+)">([^<]+)<\/ac:parameter>)*<\/ac:macro>//;
	}

	# close macros
	if($line =~ /<\/ac:macro>/ && $line !~ /<ac:macro.*<\/ac:macro>/) {
		if(scalar(@macrolist)) {
			if($macrolist[-1] eq "code" ||
			   $macrolist[-1] eq "noformat") {
				$line =~ s/<\/ac:macro>/<\/pre><\/div>/;
			}
			elsif($macrolist[-1] eq "iframe") {
				$line =~ s/<\/ac:macro>/<\/iframe>/;
			}
			else {
				$line =~ s/<\/ac:macro>/<\/div>/;
			}
			pop @macrolist;
		}
		else {
			$line =~ s/<\/ac:macro>//;
		}
	}

	# other macros
	if(@items = $line =~ /<ac:macro ac:name="([a-zA-Z0-9]+)">/) {
		push @macrolist, $items[0];
		if($macrolist[-1] eq "code" ||
		   $macrolist[-1] eq "noformat") {
			$line =~ s/<ac:macro ac:name="$items[0]">/<div class="codehilite"><pre>/;
		}
		else {
			$line =~ s/<ac:macro ac:name="$items[0]">(<ac:parameter ac:name="[^"]+">[^<]+<\/ac:parameter>)*/<div class="hilite">/;
		}
		# TODO might want to set a different class for name=note and/or name=tip
		# TODO handle icons for notes, tips, etc

		# if line also has a close macro, zap it here
		if($line =~ /<\/ac:macro>$/) {
			if($macrolist[-1] eq "code" ||
			   $macrolist[-1] eq "noformat") {
				$line =~ s/<\/ac:macro>/<\/pre><\/div>/;
			}
			else {
				$line =~ s/<\/ac:macro>/<\/div>/;
			}
			pop @macrolist;
		}
	}

	if($line =~ /<ac:plain-text-body>/) {
		$line =~ s/<ac:plain-text-body>//;
	}
	if($line =~ /<\/ac:plain-text-body>/) {
		$line =~ s/<\/ac:plain-text-body>//;
	}
	if($line =~ /<ac:rich-text-body>/) {
		$line =~ s/<ac:rich-text-body>//;
	}
	if($line =~ /<\/ac:rich-text-body>/) {
		$line =~ s/<\/ac:rich-text-body>//;
	}
	if($line =~ /<!\[CDATA\[/) {
		$line =~ s/<!\[CDATA\[//;
	}
	if($line =~ /\]\]>/) {
		$line =~ s/\]\]>//;
	}

	# images
	if($line =~ /<ac:image[^>]*><ri:attachment ri:filename="[^"]+" \/>/) {
		@items = $line =~ /(border|width|height)="([^"]+)"/g;
		my %hash = ();
		my $match = q{<ac:image[^>]*><ri:attachment ri:filename="([^"]+)" />};
		for(my $i = 0; $i < scalar(@items); $i+=2) {
			$hash{$items[$i]} = $items[$i + 1];
		}
		my $style = "";
		foreach my $key (keys %hash) {
			if($key =~ /(width|height)/) {
				$style .= "$key: $hash{$key}px; ";
			}
			elsif($key eq "border" && $hash{$key} eq "true") {
				$style .= "border: 1px solid; ";
			}
		}
		my $thumb = "";
		($thumb) = $line =~ /thumbnail="([^"]+)"/;
		if($thumb && $thumb ne "" && $thumb eq "true" && $style !~ /width/ && $style !~ /height/) {
			$style .= "width: 50%; ";
		}
		if($style ne "") {
			$style = "style=\"$style\" ";
		}
		@items = $line =~ /filename="([^"]+)"/;
		my $replace = "<a href=\"$atchurl/$pageid/$items[0]\"><img $style src=\"$atchurl/$pageid/$items[0]\" /></a>";

		$line =~ s/$match/$replace/;
	}
	if($line =~ /<\/ac:image>/) {
		$line =~ s/<\/ac:image>//;
	}

	# links
	if(@items = $line =~ /<ac:link><ri:page ri:content-title="([^"]+)" \/><ac:plain-text-link-body>([^<]+)<\/ac:plain-text-link-body>/) {
		my $link = $items[0];
		my $title = $items[1];
		$link = title2filename($link);

		$line =~ s/<ac:link><ri:page ri:content-title="([^"]+)" \/><ac:plain-text-link-body>[^<]+<\/ac:plain-text-link-body>/<a href="$link">$title<\/a>/;
	}
	if(@items = $line =~ /<ac:link><ri:page ri:content-title="([^"]+)" \/><ac:link-body>([^<]+)<\/ac:link-body>/) {
		my $link = $items[0];
		my $title = $items[1];
		$link = title2filename($link);

		$line =~ s/<ac:link><ri:page ri:content-title="([^"]+)" \/><ac:link-body>[^<]+<\/ac:link-body>/<a href="$link">$title<\/a>/;
	}
	if(@items = $line =~ /<ac:link><ri:page ri:content-title="([^"]+)" \/>/) {
		my $link = $items[0];
		my $title = $link;
		$link = title2filename($link);

		$line =~ s/<ac:link><ri:page ri:content-title="([^"]+)" \/>/<a href="$link">$title<\/a>/;
	}
	if($line =~ /<\/ac:link>/) {
		$line =~ s/<\/ac:link>//;
	}
	if(@items = $line =~ /<ac:link ac:anchor="([^"]+)"><ri:page ri:content-title="([^"]+)" \/><ac:plain-text-link-body>([^<]+)<\/ac:plain-text-link-body>/) {
		my $anchor = $items[0];
		my $link = $items[1];
		my $title = $items[2];
		$link = title2filename($link);
		$line =~ s/<ac:link[^>]+><ri:page[^>]+><ac:plain[^>]+>[^<]+<\/ac:plain-text-link-body>/<a href="$link#anchor-$anchor">$title<\/a>/;
	}
	if(@items = $line =~ /<ac:link ac:anchor="([^"]+)"><ac:plain-text-link-body>([^<]+)<\/ac:plain-text-link-body>/) {
		my $anchor = $items[0];
		my $title = $items[1];
		my $link = $dest;
		$line =~ s/<ac:link[^>]+><ac:plain[^>]+>[^<]+<\/ac:plain-text-link-body>/<a href="$link#anchor-$anchor">$title<\/a>/;
	}

   # Table of contents
   if($line =~ /\s*^{toc}/) {
      my @headings = grep(/^h/, @contents);
      $line = "";
      foreach my $h (@headings) { 
         $h =~ /^\s*h(\d).\s+(.*?)\s*$/s;
         my $hnum = $1;
         my $text = $2;
         my $name = $2;
         $name =~ s/\s//g;

         my $l = "   "x($hnum-1);
         $l .= "* [$text](#$compressedPageName-$name)\n";
         $line .= $l;
      }
   }

	# TODO might need to check for <?php as part of content, look at "Web Code Overview" for an example

   print OUT "$line\n";
}
print OUT "</body>\n";
print OUT "</html>\n";

close INP;
close OUT;

=head1 LICENSE

           Licensed to the Apache Software Foundation (ASF) under one
           or more contributor license agreements.  See the NOTICE file
           distributed with this work for additional information
           regarding copyright ownership.  The ASF licenses this file
           to you under the Apache License, Version 2.0 (the
           "License"); you may not use this file except in compliance
           with the License.  You may obtain a copy of the License at

             http://www.apache.org/licenses/LICENSE-2.0

           Unless required by applicable law or agreed to in writing,
           software distributed under the License is distributed on an
           "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
           KIND, either express or implied.  See the License for the
           specific language governing permissions and limitations
           under the License.
