#!/usr/bin/perl

# ------------------------------------------------------------------------------
# ParseCFC
# ------------------------------------------------------------------------------
# Version 0.1
# Copyright (c) 2010 by Klaus Meyer
# http://www.klaus-meyer.net
# ------------------------------------------------------------------------------
# ParseCFC is Mate-ware. If you you like it, think it's
# useful or something other, you can buy me a Mate if
# you want :-)
# ------------------------------------------------------------------------------

use strict;
use warnings;
use Data::Dumper;
use Cwd qw(abs_path);

my @cfcs = ();

#
# Pars-Hauptroutine
# Durchläuft das Verzeichnis und sucht nach *.cfc Dateien
# und ruft für jede Datei die parseCFC Funktion auf
#
sub parseCFCs {
    my $cfcdir = shift;
    my $docdir = shift;
    opendir(DIRECTORY,$cfcdir);
    my @files =readdir(DIRECTORY);
    foreach my $file (@files) {
        if($file =~ m/cfc$/) {
            parseCFC($cfcdir . $file);
        }
    }
    print "Erzeuge HTML Doku\n";
    writeDocu($docdir);
    print "Fertig :-)\n";
    print "\n";
}

#
# ParseCFC Routine
# Parst eine CFC und speichert die Daten in ein globales Array
#
sub parseCFC {
    my $file = shift;
    open(FILE, $file) or die("Kann Datei " . $file . " nicht öffnen");
    my $cfc = {};
    my @functions = ();
    my $function  = {};
    my @arguments = ();
    my $argument  = {};
    foreach my $line (<FILE>) {
        if($line =~ m/<cffunction/) {
            $function  = {};
            @arguments = ();
            # Name der Funktion
            if($line =~ m/name="([^"]+)"/) {
                $function->{'name'} = $1;
            }
            else {
                $function->{'name'} = "kein Name definiert";
            }
            # Sichtbarkeit der Funktion
            if($line =~ m/access="([^"]+)"/) {
                $function->{'access'} = $1;
            }
            else {
                $function->{'access'} = "public";
            }
            # Output
            if($line =~ m/output="([^"]+)"/) {
                $function->{'output'} = $1;
            }
            else {
                $function->{'output'} = "false";
            }
            # Rückgabetyp
            if($line =~ m/returntype="([^"]+)"/) {
                $function->{'returntype'} = $1;
            }
            else {                
                $function->{'returntype'} = "void";
            }
            # Kommentar
            if($line =~ m/hint="([^"]+)"/) {
                $function->{'hint'} = $1;
            }
            else {                
                $function->{'hint'} = "";
            }
        }
        # Arguments
        if($line =~ m/<cfargument/) {
            $argument = {};
            # Name
            if($line =~ m/name="([^"]+)"/) {
                $argument->{'name'} = $1;
            }
            else {
                $argument->{'name'} = "";
            }
            # Type
            if($line =~ m/type="([^"]+)"/) {
                $argument->{'type'} = $1;
            }
            else {
                $argument->{'type'} = "any";
            }
            # Required
            if($line =~ m/required="([^"]+)"/) {
                $argument->{'required'} = $1;
            }
            else {
                $argument->{'required'} = "false";
            }
            # Default
            if($line =~ m/default="([^"]+)"/) {
                $argument->{'default'} = $1;
            }
            else {
                $argument->{'default'} = "";
            }
            push(@arguments, $argument);
            $argument = {};
        }
        if($line =~ m/<\/cffunction>/) {
            @{$function->{'arguments'}} = @arguments;
            @arguments = ();
            push(@functions,$function);
        }
        if($file =~ m/\/([^\/]+).cfc$/) {
            $file = $1
        }
        $cfc->{'functions'} = \@functions;
        $cfc->{'filename'} = $file;
    }
    push(@cfcs, $cfc);
    close(FILE);
}

#
# writeDocu
# Schreibt das globale Array als HTML in eine Datei
#
sub writeDocu {
    my $docdir = shift;
    open(FILE,">", $docdir . "doku.html");
    print FILE "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n";
    print FILE "<html>\n";
    print FILE " <head>\n";
    print FILE "    <title>CFC Referenz</title>\n";
    print FILE "    <style type='text/css'>\n";
    print FILE "    body {\n";
    print FILE "        font-family: Arial;\n";
    print FILE "        font-size: 12px;\n";
    print FILE "        line-height: 15px;\n";
    print FILE "    }\n";
    print FILE "\n";
    print FILE "    a {\n";
    print FILE "        color: blue;\n";
    print FILE "        text-decoration: none;\n";
    print FILE "    }\n";
    print FILE "\n";    
    print FILE "    a:hover {\n";
    print FILE "        text-decoration: underline;\n";
    print FILE "    }\n";
    print FILE "\n";    
    print FILE "    ul {\n";
    print FILE "        padding-left: 20px;\n";
    print FILE "        list-style-type: square;\n";
    print FILE "    }\n";
    print FILE "\n";    
    print FILE "    h2 {\n";
    print FILE "        padding: 5px;\n";
    print FILE "        background-color: #f7f7f7;\n";
    print FILE "        border-bottom: 1px solid #c0c0c0;\n";
    print FILE "    }\n";
    print FILE "\n";    
    print FILE "    table {\n";
    print FILE "        width: 100%;\n";
    print FILE "        border-spacing: 1px;\n";
    print FILE "        background-color: black;\n";
    print FILE "        margin-bottom: 10px;\n";
    print FILE "    }\n";
    print FILE "\n";    
    print FILE "    table tr td {\n";
    print FILE "        padding: 5px;\n";
    print FILE "        background-color: white;\n";
    print FILE "        vertical-align: top;\n";
    print FILE "    }\n";
    print FILE "\n";    
    print FILE "    table tr td.th {\n";
    print FILE "        font-weight: bold;\n";
    print FILE "        background-color: #f7f7f7;\n";
    print FILE "    }\n";
    print FILE "    </style>";
    print FILE " </head>\n";
    print FILE " <body>\n";
    print FILE "    <h1>CFC Referenz</h1>\n";
    
    foreach my $cfc (@cfcs) {
        print FILE "<h2>Component " . $cfc->{'filename'} . "</h2>\n";
        print FILE "<h3>Funktionen</h3>\n";
        print FILE "<ul>\n";
        foreach my $function (@{$cfc->{'functions'}}) {
            print FILE "<li><a href='#" . $cfc->{'filename'} . "." . $function->{'name'} . "'>" . $function->{'name'} . "</a></li>";
        }
        print FILE "</ul>\n";
        foreach my $function (@{$cfc->{'functions'}}) {
            print FILE "<a id='" . $cfc->{'filename'} . "." . $function->{'name'} . "'></a>\n";
            print FILE "<table>\n";
            print FILE "    <colgroup>\n";
            print FILE "        <col width='120' />\n";
            print FILE "        <col />\n";
            print FILE "    </colgroup>\n";
            print FILE "    <tr>\n";
            print FILE "        <td class='th'>Funktionsname</td>\n";
            print FILE "        <td>" . $function->{'name'} . "</td>\n";
            print FILE "    </tr>\n";
            print FILE "    <tr>\n";
            print FILE "        <td class='th'>Access</td>\n";
            print FILE "        <td>" . $function->{'access'} . "</td>\n";
            print FILE "    </tr>\n";
            print FILE "    <tr>\n";
            print FILE "        <td class='th'>Output</td>\n";
            print FILE "        <td>" . $function->{'output'} . "</td>\n";
            print FILE "    </tr>\n";
            print FILE "    <tr>\n";
            print FILE "        <td class='th'>R&uuml;ckgabewert</td>\n";
            print FILE "        <td>" . $function->{'returntype'} . "</td>\n";
            print FILE "    </tr>\n";
            print FILE "    <tr>\n";
            print FILE "        <td class='th'>Beschreibung</td>\n";
            print FILE "        <td>" . $function->{'hint'} . "</td>\n";
            print FILE "    </tr>\n";
            if(@{$function->{'arguments'}} > 0) {
                print FILE "    <tr>\n";
                print FILE "        <td class='th'>Argumente</td>\n";
                print FILE "        <td>\n";
                print FILE "            <table>\n";
                print FILE "            <tr>\n";
                print FILE "                <td class='th'>Name</td>\n";
                print FILE "                <td class='th'>Typ</td>\n";
                print FILE "                <td class='th'>Required</td>\n";
                print FILE "                <td class='th'>Default</td>\n";
                print FILE "            </tr>\n";
                foreach my $argument (@{$function->{'arguments'}}) {
                    print FILE "            <tr>\n";
                    print FILE "                <td>" . $argument->{'name'} . "</td>\n";
                    print FILE "                <td>" . $argument->{'type'} . "</td>\n";
                    print FILE "                <td>" . $argument->{'required'} . "</td>\n";
                    print FILE "                <td>" . $argument->{'default'} . "</td>\n";
                    print FILE "            </tr>\n";
                }
                print FILE "            </table>\n";
                print FILE "        </td>\n";
                print FILE "    </tr>\n";
            }
            print FILE "</table>\n";
        }
    }
    
    print FILE " </body>\n";
    print FILE "</html>\n";
    close(FILE);
}

#
# Hauptroutine
#
sub main {
    my $cfcdir = "";
    my $docdir = "";
    print "\n";
    print "ParseCFC (c) 2010 by Klaus Meyer\n";
    print "--------------------------------\n";
    print "\n";
    if($#ARGV+1 == 2) {
        $cfcdir = abs_path($ARGV[0]) . "/";
        $docdir = abs_path($ARGV[1]) . "/";
    }
    if($cfcdir =~ m/^$/ or $docdir =~ m/^$/) {
        print "FEHLER: Bitte geben Sie 2 Argumente an:\n";
        print "\t1. Der Pfad zu den CFC Dateien\n";
        print "\t2. Den Pfad in dem die HTML Doku erstellt werden soll.\n";
        print "\n";
        return;
    }
    print "CFCDir: " . $cfcdir . "\n";
    print "DocDir: " . $docdir . "\n";
    print "\n";
    parseCFCs($cfcdir, $docdir);
}

main();