#!/usr/bin/perl -w

# This is my first perl program, so if it's not optimal, tell me how to improve it.
# DR 01/02/13

# Filter the 'typedef SField<Bla> SFBla' out of the header files and create a
# dummy file that makes doxygen think that it's actually 
# 'class SFBla: public SField<Bla>'.
#
# Do the same for MField<> and GeoProperty<> and some others.


@simplelist = ( "TransformationMatrix",  "QuaternionBase", "VectorInterface", 
				"PointInterface", "SimpleAttachment", "Color3", "Color4",
              );

while (<>) 
{
	# SField/MField
	if ( /typedef\s+(S)Field<\s*([^>]*)\s*>\s+([^; ]+);/ )
	{
 		$ftype = $1 ;
		$fname = $2 ;
		$cname = $3 ;

		$fname =~ s/\s*//g ;
        
		$line = join( "", 
					  ("class ", $cname, ": public ", $ftype, "Field { };")
					);
        
        if($cname ne "Self")
        {
            push( @sfout, $line );
        }
	}
	elsif ( /typedef\s+(M)Field<\s*([^>]*)\s*>\s+([^; ]+);/ )
	{
		$ftype = $1 ;
		$fname = $2 ;
		$cname = $3 ;

		$fname =~ s/\s*//g ;
		$line = join( "", 
					  ("class ", $cname, ": public ", $ftype, "Field { };")
					);
        if($cname ne "Self")
        {
            push( @mfout, $line );
        }
	}
	# AbstractGeoProperty
	elsif  ( /^typedef\s+AbstractGeoProperty<\s*([^>]*)\s*>\s+([^; ]+);/ )
	{
		$ftype = $1;
		$fname = $2;
		$fname =~ s/\s*//g ;

		$line = join( "", 
					  ("class ", $fname, ": public AbstractGeoProperty, ",
                       " public GeoPropertyInterface, public ",
                       $ftype, " {  };")
					);
		push( @ageoout, $line );
		
	}
	# GeoProperty
	elsif  ( /^typedef\s+GeoProperty<\s*([^>]*)\s*>\s+([^; ]+);/ )
	{
		$tname = $1;
		$fname = $2;
		($cname =  $fname) =~ s/[A-Z]*[0-9].*$// ;

        if ( $fname ne $cname )
		{
			$line = join( "", 
						  ("class ", $fname, ": public GeoProperty, ",
                            "public ", $cname, ", public ", $tname,
						   " {  };")
						);
			push( @cgeoout, $line );
		}		
	}
	# FCPtr
	elsif  ( /^typedef\s+FCPtr<\s*([^,]+),([^>]+)*\s*>\s+([^; ]+);/ )
	{
		$ppname = $1;
		$pname  = $2;
		$cname  = $3;
		$ppname =~ s/\s*//g ;
		$pname  =~ s/\s*//g ;

		$line = join( "", 
					  ("class ", $cname, ": public ", $ppname ," { ", $pname, "* _val; };")
					);
		push( @fout, $line );

	}
	# simple ones 
	elsif  ( /^typedef\s+(\w+)\s*<\s*([^>]*)\s*>\s+([^; ]+);/ )
	{
		$tname = $1 ;
		$tparam = $2 ;
		$cname = $3 ;
		$tparam =~ s/\s*//g ;
		
		for $n ( @simplelist )
		{
			if ( $n eq $tname )
			{
				$line = join( "", 
						("class ", $cname, ": public ",  $tname, "<", $tparam, ">  { ".
						 $tparam, " * _val; };")
							);
				push( @fout, $line );				
			}
		}
	}
	# pretty simple ones: vectors have a <> inside the template parameter 
	# doxygen doesn't like that and stops working there, so remove it
	elsif  ( /^typedef\s+(\w+)\s*<\s*([^<]*)(<[^>]*>)([^>]*)\s*>\s+([^; ]+);/ )
	{
		$tname = $1 ;
		$tparam1 = $2 ;
		$tparam2 = $4 ;
		$cname = $5 ;
		$tparam =~ s/\s*//g ;
		
		for $n ( @simplelist )
		{
			if ( $n eq $tname )
			{
				$line = join( "", 
						("class ", $cname, ": public ",  $tname, "<", $tparam1, 
							$tparam2, ">  {};")
							);
				push( @fout, $line );				
			}
		}
	}
}

@sfout  = sort( @sfout );
@mfout  = sort( @mfout );
@fout   = sort( @fout  );
@ageoout= sort( @ageoout);
@cgeoout= sort( @cgeoout);

# print header

print	"/* This is an automatically created file\n";
print	"   needed to make doxygen interpret traited/typedefed classes\n";
print	"   as real classes. */\n\n";
print	"namespace osg {\n\n";

$last = "";

for $n ( @sfout )
{
	# compress equal entries
	if ( $n ne $last )
	{
        print	"/*!\n";
        print   " \\ingroup GrpBaseFieldSingle\n";
        printCommon();
		print	"*/\n";

		print $n, "\n\n"
	}
	$last = $n
}

for $n ( @mfout )
{
	# compress equal entries
	if ( $n ne $last )
	{
        print	"/*!\n";
        print   " \\ingroup GrpBaseFieldMulti\n";
        printCommon();
		print	"*/\n";

		print $n, "\n\n"
	}
	$last = $n
}

for $n ( @ageoout )
{
	# compress equal entries
	if ( $n ne $last )
	{
        print	"/*!\n";
        printCommon();
        print   " \\ingroup GrpSystemDrawablesGeometryProperties\n\n";
        print   " \\brief An abstract GeometryProperty, see \\ref ";
        print   " PageSystemGeoProperties for a description.\n";
		print	"*/\n";

		print $n, "\n\n"
	}
	$last = $n
}

for $n ( @cgeoout )
{
	# compress equal entries
	if ( $n ne $last )
	{
        print	"/*!\n";
        print   " \\ingroup GrpSystemDrawablesGeometryProperties\n\n";
        print   " \\brief A concrete GeometryProperty, see \\ref ",
                  " PageSystemGeoProperties for a description.\n\n";
        printCommon();
        print   "\nThe actual inheritance is ",
                "nowhere near as complicated as it looks here, see \\ref ",
                "PageSystemGeoProperties for a description.\n\n",
                "The primarily interesting parts of this are: the GenericType in ",
                "the first \b Typedefs section, which describes the generic type for ",
                "this kind of property, the StoredFieldType, which describes the ",
                "FieldType of the data actually stored in this Property, and the ",
                "\b Public \b Methods, which describe the interface of this Property.\n ",
                "Please disregard duplicate types and methods, they are artifacts ",
                "of the hoops we had to jump through to make doxygen generate ",
                "something useful for the GeoProperties.\n",
                "*/\n";

		print $n, "\n\n"
	}
	$last = $n
}

for $n ( @fout )
{
	# compress equal entries
	if ( $n ne $last )
	{
        print	"/*!\n";
        printCommon();
        print	"*/\n";
		print $n, "\n\n"
	}
	$last = $n
}

print	"\n\n}\n\n";


sub printCommon
{
    print	" This is a documentation wrapper. Its only purpose is to fool\n";
    print	" doxygen into thinking of a typedef as a class and to allow\n";
    print	" you to find all the needed info from this page.\n";
    print	" \n";
    print	" \\warning The real inheritance is not what you see here.\n";
    print	" \\warning This is just to give you an idea of the conceptual ";
    print   "relations and to help you understand the available methods of\n";
    print   "this class.\n";
    print	" \n";
}
