package kalyptusCxxToObjc;

use File::Path;
use File::Basename;

use Carp;
use Ast;
use kdocAstUtil;
use kdocUtil; 
use Iter;
use kalyptusDataDict;

use strict;
no strict "subs";

use vars qw/ @clist $host $who $now $gentext %functionId $docTop
	$lib $rootnode $outputdir $opt $debug $typeprefix $eventHandlerCount *CLASS *HEADER /;

BEGIN
{
	@clist = ();

	# Page footer

	$who = kdocUtil::userName();
	$host = kdocUtil::hostName();
	$now = localtime;
	$gentext = "$who\@$host on $now, using kalyptus $main::Version.";

	$docTop =<<EOF
                             -------------------
    begin                : $now
    copyright            : (C) 2000-2001 Lost Highway Ltd. All rights reserved.
    email                : Lost_Highway\@tipitina.demon.co.uk
    generated by         : $gentext
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   This library is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU Library General Public License as       *
 *   published by the Free Software Foundation; either version 2 of the    *
 *   License, or (at your option) any later version.                       *
 *                                                                         *
 ***************************************************************************/

EOF

}

sub cplusplusToObjc
{
	my ( $cplusplusType )  = @_;
	
	if ( $cplusplusType =~ /bool/ && kalyptusDataDict::ctypemap($cplusplusType) eq "int" ) {
		return "BOOL";
	} elsif ( $cplusplusType =~ /(DOM::)?DOMString/ || kalyptusDataDict::ctypemap($cplusplusType) =~ /qt_QString\s*\*/ || kalyptusDataDict::ctypemap($cplusplusType) =~ /qt_QCString\s*\*/ || kalyptusDataDict::ctypemap($cplusplusType) =~ /^char\s*\*/ ) {
		return "NSString *";
	} elsif ( kalyptusDataDict::ctypemap($cplusplusType) =~ /qt_QDateTime\s*\*/ || kalyptusDataDict::ctypemap($cplusplusType) =~ /qt_QTime\s*\*/ || kalyptusDataDict::ctypemap($cplusplusType) =~ /qt_QDate\s*\*/ ) {
		return "NSDate *";
	} elsif ( 	kalyptusDataDict::ctypemap($cplusplusType) =~ /qt_QChar\s*(\*)/ ) {
		return "unichar $1";
	} elsif ( 	kalyptusDataDict::ctypemap($cplusplusType) =~ /qt_QStringList\s*\*/
				|| kalyptusDataDict::ctypemap($cplusplusType) =~ /qt_QStrList\s*\*/
				|| kalyptusDataDict::ctypemap($cplusplusType) =~ /kde_QCStringList\s*\*/
				|| kalyptusDataDict::ctypemap($cplusplusType) =~ /qt_QObjectList\s*\*/
				|| kalyptusDataDict::ctypemap($cplusplusType) =~ /qt_QFileInfoList\s*\*/
				|| kalyptusDataDict::ctypemap($cplusplusType) =~ /qt_QDomNodeList\s*\*/
				|| kalyptusDataDict::ctypemap($cplusplusType) =~ /kde_DOMNodeList\s*\*/
				|| kalyptusDataDict::ctypemap($cplusplusType) =~ /kde_KFileItemList\s*\*/
				|| kalyptusDataDict::ctypemap($cplusplusType) =~ /kde_KFileViewItemList\s*\*/
				|| kalyptusDataDict::ctypemap($cplusplusType) =~ /kde_OfferList\s*\*/
				|| kalyptusDataDict::ctypemap($cplusplusType) =~ /kde_MediaList\s*\*/
				|| kalyptusDataDict::ctypemap($cplusplusType) =~ /kde_StyleSheetList\s*\*/
				|| kalyptusDataDict::ctypemap($cplusplusType) =~ /kde_KURLList\s*\*/
				|| kalyptusDataDict::ctypemap($cplusplusType) =~ /qt_QWidgetList\s*\*/ ) {
		return "NSArray *";
	} elsif ( kalyptusDataDict::ctypemap($cplusplusType) =~ /qt_(.*)/ ) {
		return $1;
	} elsif ( kalyptusDataDict::ctypemap($cplusplusType) =~ /kde_(.*)/ ) {
		return $1;
	} else {
		return kalyptusDataDict::ctypemap($cplusplusType);
	}
		
}

sub writeDoc
{
	( $lib, $rootnode, $outputdir, $opt ) = @_;

	$debug = $main::debug;

	mkpath( $outputdir ) unless -f $outputdir;

	
	# Document all compound nodes
	Iter::LocalCompounds( $rootnode, sub { writeClassDoc( shift ); } );
	
}




=head2 writeClassDoc

	Write documentation for one compound node.

=cut

sub writeClassDoc
{
	my( $node ) = @_;

	print "Enter: $node->{astNodeName}\n" if $debug;

	my $typeName = $node->{astNodeName}."*";

	if ( kalyptusDataDict::ctypemap($typeName) eq () ) {
		$typeprefix = ($typeName =~ /^Q/ ? "qt_" : "kde_");
		kalyptusDataDict::setctypemap($typeName, $typeprefix.$node->{astNodeName}."*");
		print "'$typeName' => '$typeprefix$typeName',\n";
	} elsif ( kalyptusDataDict::ctypemap($typeName) =~ /^qt_/ ) {
		$typeprefix = "qt_";
	} elsif ( kalyptusDataDict::ctypemap($typeName) =~ /^kde_/ ) {
		$typeprefix = "kde_";
	}
	
	my $file = "$outputdir/".join("__", kdocAstUtil::heritage($node)).".h";
	my $docnode = $node->{DocNode};
	my @list = ();
	my $version = undef;
	my $author = undef;

	
	if( $#{$node->{Kids}} < 0 || $node->{Access} eq "private" || exists $node->{Tmpl} ) {
		return;
	}
	
	open( HEADER, ">$file" ) || die "Couldn't create $file\n";
	$file =~ s/\.h/.m/;
	open( CLASS, ">$file" ) || die "Couldn't create $file\n";

	# Header
	 
	my $short = "";
	my $extra = "";

	print HEADER "/***************************************************************************\n";
	print HEADER "                            ", $node->{astNodeName}, ".h -  description\n";
	print HEADER $docTop;
		
	print CLASS "/***************************************************************************\n";
	print CLASS "                            ", $node->{astNodeName}, ".m -  description\n";
	print CLASS $docTop;
		
	print HEADER "#ifndef ", uc($node->{astNodeName}), "_H\n";
	print HEADER "#define ", uc($node->{astNodeName}), "_H\n\n";
	
	print CLASS "#include <qtc/qt_QString.h>\n";
	print CLASS "#include <qtc/qt_QCString.h>\n";
	
	if ( $typeprefix eq "qt_" ) {
		print CLASS "#include <qtc/qt_", $node->{astNodeName}, ".h>\n";
		print CLASS "#include <qtobjc/", $node->{astNodeName}, ".h>\n";
	} else {
		print CLASS "#include <kdec/kde_", $node->{astNodeName}, ".h>\n";
		print CLASS "#include <kdeobjc/KDESupport.h>\n";
		print CLASS "#include <kdeobjc/", $node->{astNodeName}, ".h>\n";
	}
	
	print HEADER "#include <Foundation/NSObject.h>\n";
	print HEADER "#include <Foundation/NSString.h>\n";
	
		# ancestors
	my @ancestors = ();
	Iter::Ancestors( $node, $rootnode, undef, undef,
		sub { # print
			my ( $ances, $name, $type, $template ) = @_;
			push @ancestors, $name;
			},
			undef
		);
	
	if ( $#ancestors < 0 ) {
		print HEADER "#include <qtobjc/QtSupport.h>\n";
	} else {
		foreach my $ancestor ( @ancestors ) {
			my $ancestortype = $ancestor."*";
			if ( kalyptusDataDict::ctypemap($ancestor."*") =~ /^qt_/ ) {
				print HEADER "#include <qtobjc/", $ancestor, ".h>\n";
			} else {
				print HEADER "#include <kdeobjc/", $ancestor, ".h>\n";
			}
		}
	}
	
	print HEADER "\n";	

	if ( defined $docnode ) {
		print HEADER "/**\n";
		if ( defined $docnode->{Text} ) {
			my $node;
			my $line;
			foreach $node ( @{$docnode->{Text}} ) {
			next if $node->{NodeType} ne "DocText";
			$line = $node->{astNodeName};
			$line =~ s/(\w+)#(\w+)/-\[$1 $2\]/g;
			$line =~ s/(->)?#(\w+)/ #-$2/g;
			$line =~ s/(\w+)\s*((::)|(->))\s*(\w+)\s*(\(\w*\))?/-\[$1 $5\]/g;
			$line =~ s/(\w+)\(\)/-$1/g;
			print HEADER $line, "\n";
			}
		}
			
		exists $docnode->{Author} && print HEADER " \@author ", $docnode->{Author}, "\n";
		exists $docnode->{Version} && print HEADER " \@version ", $docnode->{Version}, "\n";
		exists $docnode->{ClassShort} && print HEADER " \@short ", $docnode->{ClassShort}, "\n";
		print HEADER "*/\n";
	}

	print CLASS "\n\@implementation  ", $node->{astNodeName}, "\n\n";

	if ( kalyptusDataDict::interfacemap($node->{astNodeName}) ne "" ) {
		print HEADER "\@protocol ", kalyptusDataDict::interfacemap($node->{astNodeName}), "\n";
	} elsif ( $#ancestors < 0 ) {
		print HEADER "\@interface  ", $node->{astNodeName}, " : NSObject <QtSupport>\n";
		print HEADER "{\n\@private\n\tvoid * _qt;\n";
		print HEADER "\tBOOL  _allocatedInObjcWorld;\n}\n";
		print CLASS "- (void *) qt\n{\n\treturn _qt;\n}\n\n";
		print CLASS "- setQt: (void *) qt\n{\n\t_qt = qt;\n\treturn self;\n}\n\n";
		print CLASS "- (BOOL) allocatedInObjcWorld\n{\n\treturn _allocatedInObjcWorld;\n}\n\n";
		print CLASS "- setAllocatedInObjcWorld: (BOOL) yn\n{\n\t_allocatedInObjcWorld = yn;\n\treturn self;\n}\n\n";
	} else {
		print HEADER "\@interface ", $node->{astNodeName}, " : ";
		my $ancestor;
		foreach $ancestor ( @ancestors ) {
			if ( kalyptusDataDict::interfacemap($ancestor) eq () ) {
				print HEADER "$ancestor ";
				last;
           	} elsif ($ancestor eq @ancestors[$#ancestors] ) {
				print HEADER @ancestors[$#ancestors], " ";
			}
		}

		print HEADER "\n";
	}

	%functionId = ();
	$eventHandlerCount = 0;
	countEventHandlers($node);

	# Add any enums found to the %ctypemap
	Iter::MembersByType ( $node,
		sub { print HEADER "", $_[0], ""; print CLASS "", $_[0], "";  },
		sub {	my ($node, $kid ) = @_;
                 parseEnum( $node, $kid );
               },
		sub { print HEADER ""; print CLASS ""; }
	);
	
	Iter::MembersByType ( $node,
		sub { print HEADER "", $_[0], ""; print CLASS "", $_[0], "";  },
		sub {	my ($node, $kid ) = @_;
                 parseMember( $node, $kid );
               },
		sub { print HEADER ""; print CLASS ""; }
	);

	if ( kalyptusDataDict::interfacemap($node->{astNodeName}) ne () ) {
		print HEADER "\@end\n";
		
		if ( $#ancestors < 0 ) {
			print HEADER "\n\@interface ", $node->{astNodeName}, " : NSObject <QtSupport,", kalyptusDataDict::interfacemap($node->{astNodeName}), ">\n";
			print HEADER "{\n\@private\n\tvoid * _qt;\n";
			print HEADER "\tBOOL  _allocatedInObjcWorld;\n}\n";
			print CLASS "- (void *) qt\n{\n\treturn _qt;\n}\n\n";
			print CLASS "- setQt: (void *) qt\n{\n\t_qt = qt;\n\treturn self;\n}\n\n";
			print CLASS "- (BOOL) allocatedInObjcWorld\n{\n\treturn _allocatedInObjcWorld;\n}\n\n";
			print CLASS "- setAllocatedInObjcWorld: (BOOL) yn\n{\n\t_allocatedInObjcWorld = yn;\n\treturn self;\n}\n\n";
        } else {
			print HEADER "\@interface ", $node->{astNodeName}, " : ";
			my $ancestor;
			foreach $ancestor ( @ancestors ) {
				if ( kalyptusDataDict::interfacemap($ancestor) eq () ) {
					print HEADER "$ancestor ";
					last;
           		} elsif ($ancestor eq @ancestors[$#ancestors] ) {
					print HEADER @ancestors[$#ancestors], " ";
				}
			}

			print HEADER "<", kalyptusDataDict::interfacemap($node->{astNodeName}), ">\n";
		}
	}

	Iter::MembersByType ( $node,
		sub { print HEADER "", $_[0], ""; print CLASS "", $_[0], "";  },
		sub {	my ($node, $kid ) = @_;
                 generateClassMethodForEnum( $node, $kid );
               },
		sub { print HEADER ""; print CLASS ""; }
	);
	
	print HEADER "\@end\n";
	print CLASS "\n\@end\n";

	if ( $#ancestors >= 1 ) {
		foreach my $ancestor ( @ancestors ) {
			if ( kalyptusDataDict::interfacemap($ancestor) ne () ) {
				print HEADER "\n\@interface ", $node->{astNodeName}, " ($ancestor", "Implementation) <", kalyptusDataDict::interfacemap($ancestor), ">\n\@end\n";
				print CLASS "\n\@implementation ", $node->{astNodeName}, " ($ancestor", "Implementation)\n\@end\n";
            }
		}
	}

	if ( $eventHandlerCount > 0 ) {
		print HEADER "\n/\*\* Override these methods in subclasses of ",
			$node->{astNodeName}, " to customise event handling behaviour \*/\n";
		print HEADER "\@protocol ", $node->{astNodeName}, "EventHandling\n";
		generateEventHandlers($node);
		print HEADER "\@end\n\n";
	}

	print HEADER "\n#endif\n";
	
	close HEADER;
	close CLASS;

}

sub countEventHandlers
{
	my( $node ) = @_;
	my %allmem = ();
	my $key;

	my $m;
	my $name;

	kdocAstUtil::allMembers( \%allmem, $node );

	foreach $key (keys (%allmem)) {
		$m = $allmem{$key};
		$name = $m->{astNodeName} ;
		my $type = $m->{NodeType};
		my $docnode = $m->{DocNode};

	if( $type eq "method" && $m->{Access} eq "protected"  && $name =~ /.*Event$/
		&& $name !~ /qwsEvent/ && $name !~ /x11Event/ && $name !~ /winEvent/ && $name !~ /macEvent/  && $name !~ /movableDropEvent/ )
	{
		$eventHandlerCount++;
	}
	}
}

sub generateEventHandlers
{
	my( $node ) = @_;
	my %allmem = ();
	my $key;

	my $m;
	my $name;

	kdocAstUtil::allMembers( \%allmem, $node );

	foreach $key (keys (%allmem)) {
		$m = $allmem{$key};
		$name = $m->{astNodeName} ;
		my $type = $m->{NodeType};
		my $docnode = $m->{DocNode};

	if( $type eq "method" && $m->{Access} eq "protected"  && $name =~ /.*Event$/
		&& $name !~ /qwsEvent/ && $name !~ /x11Event/ && $name !~ /winEvent/ && $name !~ /macEvent/  && $name !~ /movableDropEvent/ ) {
		my $cparams = $m->{Params};
		my $objcparams;
		if ( $cparams =~ /\s*\)\s*:\s*/ ) {
#			print "found a constructor list: '$cparams'\n";
			$cparams =~ s/(.*)\s*\)\s*:\s*.*$/$1/;
		}

		$cparams =~ s/=\s*(("[^"]*")|(\'.\')|(([-\w:.]*)\s*(\|\s*[-\w]*)*(\(\w*\))?))//g;
		$cparams =~ s/\s+/ /g;
		$cparams =~ s/\s*([,\*\&])\s*/$1 /g;
		$cparams =~ s/^\s*void\s*$//;
		$cparams =~ s/^\s*$//;
		my $argId = 0;
		my @cargs = split(",", $cparams);
		$cparams = "";
		foreach my $arg ( @cargs ) {
			my $argType;
			my $cargType;
			$arg =~ s/\s*([^\s].*[^\s])\s*/$1/;
			if ( $arg =~ /(.*)\s+(\w+)$/ ) {
				$argType = $1;
				$arg = $2;
			} else {
				$argType = $arg;
				$argId++;
				$arg = "arg".$argId;
			}
			$objcparams .= "\(".$argType."\) ".$arg.", ";
			$cparams .= $arg.", ";
		}
		$cparams =~ s/, $//;
		$objcparams =~ s/, $//;

		if ( defined $docnode ) {
			if ( defined $docnode->{Text} ) {
				print HEADER "\n/** ";
				my $node;
				my $line;
				foreach $node ( @{$docnode->{Text}} ) {
					next if $node->{NodeType} ne "DocText";
					$line = $node->{astNodeName};
					$line =~ s/(\w+)#(\w+)/-\[$1 $2\]/g;
					$line =~ s/(->)?#(\w+)/ #-$2/g;
					$line =~ s/(\w+)\s*((::)|(->))\s*(\w+)\s*(\(\w*\))?/-\[$1 $5\]/g;
					$line =~ s/(\w+)\(\)/-$1/g;
					print HEADER $line, "\n";
				}
				print HEADER "*/\n";
			}
		}

		print HEADER "- $name:$objcparams;\n";
	}
	}
}

sub parseEnum
{
	my( $class, $m ) = @_;
	
	if( $m->{NodeType} eq "enum" ) {
		my $enum = $m->{astNodeName};
		# Add a C++ to C type mapping for this enum - an int in C
		$enum =~ s/\s//g;
		kalyptusDataDict::setctypemap($enum, 'int');
		$enum = $class->{astNodeName}."::".$enum;
		kalyptusDataDict::setctypemap($enum, 'int');
	}
}

sub parseMember
{
	my( $class, $m ) = @_;
	my $name;
    my $function;
    my $stringargs;
    my $defaultstringargs;
	my $defaultcparams;
	my $defaultobjcparams;

	$name = $m->{astNodeName} ;
	my $type = $m->{NodeType};

	my $docnode = $m->{DocNode};

	if ( $m->{ReturnType} =~ /~/ ) {
		$name = "~".$name;
	}

	if ( $functionId{$name} eq "" ) {
		$functionId{$name} = 0;
		$function = $name;
	} else {
		$functionId{$name}++;
		$function = $name.$functionId{$name};
	}

	$function =~ s/~//;

	if( $type eq "method" && $m->{Access} ne "private" && $m->{Access} ne "private_slots" && $m->{Access} ne "signals" ) {
		if ( $m->{ReturnType} =~ /[<>]/ || $m->{Params} =~ /[<>]/  || $m->{Params} =~ /\.\.\./  || $m->{Params} =~ /Impl/
				|| $m->{ReturnType} =~ /QAuBucket/ || $m->{Params} =~ /QAuBucket/
				|| $m->{ReturnType} =~ /QMember/ || $m->{Params} =~ /QMember/   ) {
			return;
		}

		my $returnType = $m->{ReturnType};

		$returnType =~ s/friend\s*//;
		$returnType =~ s/const\s*//;
		$returnType =~ s/inline\s*//;
		$returnType =~ s/Q_EXPORT\s*//;
		$returnType =~ s/\s*([,\*\&])\s*/$1/;
		$returnType =~ s/^\s*//;
		$returnType =~ s/\s*$//;
		if ( $returnType ne "" && cplusplusToObjc($returnType) eq "" ) {
			$returnType =~ s/^.*::.*$/int/;
		} else {
			$returnType = cplusplusToObjc($returnType);
			$returnType =~ s/\s*([,\*\&])\s*/$1/;
		}

		my $cparams = $m->{Params};
		my $objcparams;
		if ( $cparams =~ /\s*\)\s*:\s*/ ) {
#			print "found a constructor list: '$cparams'\n";
			$cparams =~ s/(.*)\s*\)\s*:\s*.*$/$1/;
		}

		$cparams =~ s/\s+/ /g;
		$cparams =~ s/\s*([,\*\&])\s*/$1 /g;
		$cparams =~ s/^\s*void\s*$//;
		my $argId = 0;
		my @cargs = split(",", $cparams);
		$cparams = "";
		foreach my $arg ( @cargs ) {
			my $argType;
			my $cargType;
			my $objcargType;
   $arg =~ s/\s*([^\s].*[^\s])\s*/$1/;
			$arg =~ s/(\w+)\[\]/\* $1/;

			if ( $arg =~ /^\s*$/ ) {
				next;
			}

			# A '<arg> = <value>' default parameter
			if ( $arg =~ s/=\s*(("[^"]*")|(\'.\')|(([-\w:.]*)\s*(\|\s*[-\w]*)*(\(\w*\))?))// ) {
				my $param = $1;
				if ( $defaultcparams eq "" ) {
					$defaultcparams = $cparams;
					$defaultobjcparams = $objcparams;
					$defaultstringargs = $stringargs;
				}

				if ( $param =~ /(.*)::(.*)/ && kalyptusDataDict::ctypemap($param) eq ()) {
					$defaultcparams .= "[$1 $2], "
				} else {
					if ( kalyptusDataDict::ctypemap($param) eq () ) {
						if ( $param =~ /^[A-Z]/ ) {
							$defaultcparams .= "[".$class->{astNodeName}." ".$param."], ";
						} else {
							$defaultcparams .= $param.", ";
                    	}
					} else {
						$defaultcparams .= kalyptusDataDict::ctypemap($param).", ";
					}
				}
			}

			if ( $arg =~ /^(.*)\s+(\w+)\s*$/ ) {
				$argType = $1;
				$arg = $2;
			} else {
				$argType = $arg;
				$argId++;
				$arg = "arg".$argId;
			}
			$arg =~ s/^id$/identifier/;
			$argType =~ s/\s*([^\s].*[^\s])\s*/$1/;
			$argType =~ s/\s*const//g;
			$argType =~ s/^\s*//;
			$argType =~ s/([\*\&])\s*([\*\&])/$1$2/;
			$cargType = kalyptusDataDict::ctypemap($argType);
			$objcargType = cplusplusToObjc( $argType );
			if ( $objcargType eq "" ) {
				$objcargType = $argType;
				$objcargType =~ s/\&/\*/;
				$objcargType =~ s/^.*::.*$/int/;
			}

			if ( $arg =~ /^arg[0-9]/ ) {
				$objcargType =~ /^[QK]?(\w)(\w*).*/;
				my $temp = lc($1).lc($2);
				$temp =~ s/^ns//;
				$objcparams .= $temp.": (".$objcargType.")";
			} else {
				$objcparams .= $arg.": (".$objcargType.")";
			}
			$objcparams .= $arg." ";

			if ( $cargType eq "" ) {
				print "'$argType' => '$typeprefix$argType',\n";
				if ( kalyptusDataDict::ctypemap($argType) =~ /^qt_/ || kalyptusDataDict::ctypemap($argType) =~ /^kde_/ ) {
					$argType =~ s/\&//;
					$cparams .= "(".$argType.") [".$arg." qt], ";
				} else {
					$argType =~ s/\&//;
					$cparams .= "(".$argType.") ".$arg.", ";
				}
			} else {
				if ( $objcargType =~ /NSString/ ) {
					if ( kalyptusDataDict::ctypemap($argType) =~ /qt_QString\s*\*/ ) {
						$stringargs = "\nstatic qt_QString * _qstring_$arg = 0L;".$stringargs;
						$cparams .= "(".kalyptusDataDict::ctypemap($argType).") [$arg toQString: &_qstring_$arg], ";
					} elsif ( kalyptusDataDict::ctypemap($argType) =~ /qt_QCString\s*\*/ ) {
						$stringargs = "\nstatic qt_QCString * _qcstring_$arg = 0L;".$stringargs;
						$cparams .= "(".kalyptusDataDict::ctypemap($argType).") [$arg toQCString: &_qcstring_$arg], ";
					} elsif ( kalyptusDataDict::ctypemap($argType) =~ /kde_DOMString\s*(\*)/ ) {
						$stringargs = "\nstatic kde_DOMString * _domstring_$arg = 0L;".$stringargs;
						$cparams .= "(".kalyptusDataDict::ctypemap($argType).") [$arg toDOMString: &_domstring_$arg], ";
					} else {
						$cparams .= "(".kalyptusDataDict::ctypemap($argType).") [".$arg." cString], ";
					}
				} elsif ( $objcargType =~ /NSDate/ ) {
					if ( kalyptusDataDict::ctypemap($argType) =~ /qt_QDateTime\s*\*/ ) {
						$stringargs = "\nstatic qt_QDateTime * _qdate_$arg = 0L;".$stringargs;
						$cparams .= "(".kalyptusDataDict::ctypemap($argType).") [$arg toQDateTime: (qt_QDateTime **)&_qdate_$arg], ";
					} elsif ( kalyptusDataDict::ctypemap($argType) =~ /qt_QTime\s*\*/ ) {
						$stringargs = "\nstatic qt_QTime * _qdate_$arg = 0L;".$stringargs;
						$cparams .= "(".kalyptusDataDict::ctypemap($argType).") [$arg toQTime: (qt_QTime **)&_qdate_$arg], ";
					} elsif ( kalyptusDataDict::ctypemap($argType) =~ /qt_QDate\s*\*/ ) {
						$stringargs = "\nstatic qt_QDate * _qdate_$arg = 0L;".$stringargs;
						$cparams .= "(".kalyptusDataDict::ctypemap($argType).") [$arg toQDate: (qt_QDate **)&_qdate_$arg], ";
					}
				} elsif ( $objcargType =~ /NSArray/ && kalyptusDataDict::ctypemap($argType) =~ /qt_(QStrList|QStringList)\s*\*/ ) {
						$stringargs = "\nstatic qt_$1 * _qlist_$arg = 0L;".$stringargs;
						$cparams .= "(".kalyptusDataDict::ctypemap($argType).") [$arg to$1: (void *)&_qlist_$arg], ";
				} elsif ( $objcargType =~ /NSArray/ && kalyptusDataDict::ctypemap($argType) =~ /kde_(QCStringList|KURLList|KFileItemList|KFileViewItemList)\s*\*/ ) {
						$stringargs = "\nstatic kde_$1 * _qlist_$arg = 0L;".$stringargs;
						$cparams .= "(".kalyptusDataDict::ctypemap($argType).") [$arg to$1: (void *)&_qlist_$arg], ";
				} elsif ( $objcargType =~ /unichar/ ) {
					$cparams .= "(".kalyptusDataDict::ctypemap($argType).")".$arg.", ";
				} elsif ( kalyptusDataDict::ctypemap($argType) =~ /^qt_/ || kalyptusDataDict::ctypemap($argType) =~ /^kde_/ ) {
					$cparams .= "(".kalyptusDataDict::ctypemap($argType).") [".$arg." qt], ";
				} else {
					$cparams .= "(".kalyptusDataDict::ctypemap($argType).")".$arg.", ";
				}
			}

		}
		$cparams =~ s/\s*,\s*$//;
		$objcparams =~ s/\s*$//;
		$objcparams =~ s/^[^:]*(.*)/$1/;
 		$objcparams =~ s/\smember:/ slot:/;

		$defaultcparams =~ s/\s*,\s*$//;
		$defaultobjcparams =~ s/^[^:]*(.*)/$1/;
		$defaultobjcparams =~ s/\s*,\s*$//;
		$defaultobjcparams =~ s/\smember:/ slot:/;

		$objcparams =~ /^[^:]*:\s*\(([^\)\*\s]*).*/;
		my $initialargtype = $1;
		$initialargtype =~ s/^[QK]//;
		$initialargtype =~ s/^NSString/Text/;
		$initialargtype =~ s/^NS//;
		$initialargtype =~ /(.)(.*)/;
		$initialargtype = uc($1).$2;
		if ($name =~ /^(change|insert|replace|update|remove|add)Item$/) {
			$name = $1.$initialargtype."Item";
			$name =~ s/ItemItem/Item/;
        }

		if ( $m->{ReturnType} =~ /QString/ && $returnType =~ /NSString/ ) {
			$stringargs = "\nstatic qt_QString * _qstring = 0L;".$stringargs;
		}

		if ( $m->{ReturnType} =~ /QCString/ && $returnType =~ /NSString/ ) {
			$stringargs = "\nstatic qt_QCString * _qcstring = 0L;".$stringargs;
		}

		if ( $m->{ReturnType} =~ /(DOM::)?DOMString/ && $returnType =~ /NSString/ ) {
			$stringargs = "\nstatic kde_DOMString * _domstring = 0L;".$stringargs;
		}

		if (  $returnType =~ /NSDate/ && $m->{ReturnType} =~ /(QDateTime|QTime|QDate)/ ) {
			$stringargs = "\nstatic qt_$1 * _qdate = 0L;".$stringargs;
		}

		if (  $returnType =~ /NSArray/ && $m->{ReturnType} =~ /(QStrList|QStringList|QDomNodeList|QWidgetList|QObjectList|QFileInfoList)/ ) {
			$stringargs = "\nstatic qt_$1 * _qlist = 0L;".$stringargs;
		} elsif (  $returnType =~ /NSArray/ && $m->{ReturnType} =~ /(QCStringList|DOM::NodeList|NodeList|DOM::StyleSheetList|StyleSheetList|DOM::MediaList|MediaList|KFileItemList|KFileViewItemList|KURL::List|OfferList)/ ) {
			$stringargs = "\nstatic kde_$1 * _qlist = 0L;".$stringargs;
		}

		my $flags = $m->{Flags};

		if ( !defined $flags ) {
			warn "Method ".$m->{astNodeName}.  " has no flags\n";
		}


		my $extra = "";
		$extra .= "static " if $flags =~ "s";
		$returnType =~ s/void\s*$//;
		if ( $name =~ /operator/ ) {
			return;
		}

		if ( $m->{Access} =~ /protected/ && $name ne $class->{astNodeName}  ) {
			if ( $class->{Pure} ) {
				return;
			}
		}

		if ( $name eq $class->{astNodeName} && $class->{Pure} ) {
			return;
		}

		if( $m->{Access} eq "protected"  && $name =~ /.*Event$/ ) {
			$eventHandlerCount++;
			return;
		}

		if ( defined $docnode ) {
			if ( defined $docnode->{Text} ) {
				print HEADER "\n/** ";
				my $node;
				my $line;
				foreach $node ( @{$docnode->{Text}} ) {
					next if $node->{NodeType} ne "DocText";
					$line = $node->{astNodeName};
					$line =~ s/(\w+)#(\w+)/-\[$1 $2\]/g;
					$line =~ s/(->)?#(\w+)/ #-$2/g;
					$line =~ s/(\w+)\s*((::)|(->))\s*(\w+)\s*(\(\w*\))?/-\[$1 $5\]/g;
					$line =~ s/(\w+)\(\)/-$1/g;
					print HEADER $line, "\n";
				}
				print HEADER "*/\n";
			}
		}

		if ( $name eq $class->{astNodeName} ) {
			# Constructor
			if ( $objcparams =~ /^:\s*\($name\s*[\*\&]\)\w*\s*$/ ) {
				print HEADER "- copyWithZone: (NSZone *) zone;\n";
				print CLASS "\n- copyWithZone: (NSZone *) zone\n{\n\t", $class->{astNodeName}, " * aCopy;\n";
				print CLASS "\taCopy = [[(",$class->{astNodeName}, " *)[[self class] allocWithZone: zone]";
				print CLASS " setQt: $typeprefix", "new_", $function, "([self qt])] init];\n";
				print CLASS "\t[aCopy setAllocatedInObjcWorld: YES];\n";
				print CLASS "\t[QtSupport setObject: aCopy forQtKey: [aCopy qt]];\n\treturn aCopy;\n}\n";
            } else {
				if ( $objcparams eq "" ) {
					$name = "- init";
				} else {
					$name = "- initWith$initialargtype";
				}
				print HEADER $name, $objcparams, ";\n";
				print CLASS "\n", $name, $objcparams, "\n{$stringargs\n",
					"\tif ([self qt] == 0L) {\n\t\t[self setQt: $typeprefix", "new_", $function, "(", $cparams, ")];\n",
					"\t\t[self setAllocatedInObjcWorld: YES];\n",
					"\t\t[QtSupport setObject: self forQtKey: [self qt]];\n\t}\n\t[super init];\n\treturn self;\n}\n";
                if ( $defaultcparams ne "" ) {
					if ( $defaultobjcparams eq "" ) {
						$name = "- init";
					}

					print HEADER $name, $defaultobjcparams, ";\n";
					print CLASS "\n", $name, $defaultobjcparams, "\n{$defaultstringargs\n",
					"\tif ([self qt] == 0L) {\n\t\t[self setQt: $typeprefix", "new_", $function, "(", $defaultcparams, ")];\n",
					"\t\t[self setAllocatedInObjcWorld: YES];\n",
					"\t\t[QtSupport setObject: self forQtKey: [self qt]];\n\t}\n\t[super init];\n\treturn self;\n}\n";
 				}
           }
		}
		elsif ( $returnType =~ /~/ ) {
			# Destructor
			print HEADER $extra,
				"- (void) dealloc;\n";
			print CLASS "\n- (void) dealloc\n{\n";

			print CLASS "\tif ([self qt] != 0L) {\n";

			if ( $class->{astNodeName} =~ /^QWidget$/  || defined kdocAstUtil::findOverride( $rootnode, $class, "parentWidget" ) ) {
				print CLASS "\t\tif ([self allocatedInObjcWorld] && [self parentWidget: YES] == nil) {\n";
			} elsif ( $class->{astNodeName} =~ /^QObject$/  || defined kdocAstUtil::findOverride( $rootnode, $class, "parent" ) ) {
				print CLASS "\t\tif ([self allocatedInObjcWorld] && [self parent] == nil) {\n";
			} else {
				print CLASS "\t\tif ([self allocatedInObjcWorld]) {\n";
			}
			
			print CLASS "\t\t\t$typeprefix", "del_", $class->{astNodeName}, "\(\($typeprefix", $class->{astNodeName}, " *\)[self qt]);\n\t\t}\n";

			print CLASS "\t\t[QtSupport removeQtKey: [self qt]];\n",
				"\t\t[self setQt: 0L];\n\t}\n",
				"\t[super dealloc];\n}\n";
		} else {
			# Class or instance method
			my $selfstring;
			if ( $extra =~ /static/ ) {
				print HEADER "+ ";
				print CLASS "\n+ ";
			} else {
				print HEADER "- ";
				print CLASS "\n- ";
				$selfstring = "\($typeprefix".$class->{astNodeName}." *\)[self qt]";
				if ($cparams ne "" ) {
					$selfstring .= ", ";
				}
			}

			if ( $returnType eq "" ) {
				print HEADER "$name$objcparams;\n";
				print CLASS "$name$objcparams\n{$stringargs\n";
				print CLASS "\t$typeprefix", $class->{astNodeName}, "_", $function, "\($selfstring$cparams\);\n\treturn self;\n}\n" ;
				if ( $defaultcparams ne "" ) {
					if ( $extra =~ /static/ ) {
						print HEADER "+ ";
						print CLASS "\n+ ";
					} else {
						print HEADER "- ";
						print CLASS "\n- ";
                    }
					print HEADER "$name$defaultobjcparams;\n";
					print CLASS "$name$defaultobjcparams\n{$defaultstringargs\n";
					print CLASS "\t$typeprefix", $class->{astNodeName}, "_", $function, "\($selfstring$defaultcparams\);\n\treturn self;\n}\n" ;
				}
			} elsif ( $returnType =~ /NSString/ ) {
				print HEADER "\(NSString *\) $name$objcparams;\n";
				print CLASS "\(NSString *\) $name$objcparams\n{$stringargs\n";

				if ( $m->{ReturnType} =~ /QString\s*[\*\&]?\s*$/ ) {
					print CLASS "\t_qstring = ", "$typeprefix", $class->{astNodeName}, "_$function\($selfstring$cparams\);\n";
					print CLASS "\treturn [NSString fromQString: _qstring];\n}\n";
				} elsif ( $m->{ReturnType} =~ /QCString\s*[\*\&]?\s*$/ ) {
					print CLASS "\t_qcstring = ", "$typeprefix", $class->{astNodeName}, "_$function\($selfstring$cparams\);\n";
					print CLASS "\treturn [NSString fromQCString: _qcstring];\n}\n";
				} elsif ( $m->{ReturnType} =~ /(DOM::)?DOMString\s*[\*\&]?\s*$/ ) {
					print CLASS "\t_domstring = ", "$typeprefix", $class->{astNodeName}, "_$function\($selfstring$cparams\);\n";
					print CLASS "\treturn [NSString fromDOMString: _domstring];\n}\n";
				} else {
					print CLASS "\treturn \(NSString *\) [NSString stringWithCString:";
					print CLASS " $typeprefix", $class->{astNodeName}, "_$function\($selfstring$cparams\)];\n}\n" ;
				}
			} elsif ( $returnType =~ /NSDate/ ) {
				print HEADER "\(NSDate *\) $name$objcparams;\n";
				print CLASS "\(NSDate *\) $name$objcparams\n{$stringargs\n";

				if ( $m->{ReturnType} =~ /(QDateTime|QTime|QDate)\s*[\*\&]?\s*$/ ) {
					print CLASS "\t_qdate = ", "$typeprefix", $class->{astNodeName}, "_$function\($selfstring$cparams\);\n";
					print CLASS "\treturn (NSDate *\) [[NSDate alloc] initWith$1: _qdate];\n}\n";
				}
			} elsif ( $returnType =~ /NSArray/ ) {
				print HEADER "\(NSArray *\) $name$objcparams;\n";
				print CLASS "\(NSArray *\) $name$objcparams\n{$stringargs\n";

				if ( $m->{ReturnType} =~ /(QStrList|QStringList|QCStringList|QWidgetList|QFileInfoList|QObjectList|QDomNodeList|DOM::NodeList|NodeList|DOM::StyleSheetList|StyleSheetList|DOM::MediaList|MediaList|KFileItemList|KFileViewItemList|KURL::List|OfferList)\s*[\*\&]?\s*$/ ) {
					print CLASS "\t_qlist = ", "$typeprefix", $class->{astNodeName}, "_$function\($selfstring$cparams\);\n";
					print CLASS "\treturn (NSArray *\) [NSMutableArray arrayWith$1: _qlist];\n}\n";
				}
			} elsif ( kalyptusDataDict::ctypemap($returnType) =~ /^qt_/ ||  kalyptusDataDict::ctypemap($returnType) =~ /^kde_/ ) {
				print HEADER "\($returnType\) $name$objcparams;\n";
				print CLASS "\($returnType\) $name$objcparams\n{$stringargs\n";
				print CLASS "\treturn \($returnType\) [QtSupport objectForQtKey:";
				print CLASS " $typeprefix", $class->{astNodeName}, "_$function\($selfstring$cparams\)";
				$returnType =~ /^(.*)\*$/;
				print CLASS " withClass: [$1 class] allocatedInObjcWorld: YES];\n}\n";
				if ( $defaultcparams ne "" ) {
					if ( $extra =~ /static/ ) {
						print HEADER "+ ";
						print CLASS "\n+ ";
					} else {
						print HEADER "- ";
						print CLASS "\n- ";
                    }
					print HEADER "\($returnType\) $name$defaultobjcparams;\n";
					print CLASS "\($returnType\) $name$defaultobjcparams\n{$defaultstringargs\n";
					print CLASS "\treturn \($returnType\) [QtSupport objectForQtKey:";
					print CLASS " $typeprefix", $class->{astNodeName}, "_$function\($selfstring$defaultcparams\)";
					$returnType =~ /^(.*)\*$/;
					print CLASS " withClass: [$1 class] allocatedInObjcWorld: YES];\n}\n";
				}
			} else {
				print HEADER "\($returnType\) $name$objcparams;\n";
				print CLASS "\($returnType\) $name$objcparams\n{$stringargs\n";
				print CLASS "\treturn \(", $returnType, "\) $typeprefix", $class->{astNodeName}, "_", $function, "\($selfstring$cparams\);\n}\n" ;
				if ( $defaultcparams ne "" ) {
					if ( $extra =~ /static/ ) {
						print HEADER "+ ";
						print CLASS "\n+ ";
					} else {
						print HEADER "- ";
						print CLASS "\n- ";
                    }
					print HEADER "\($returnType\) $name$defaultobjcparams;\n";
					print CLASS "\($returnType\) $name$defaultobjcparams\n{$defaultstringargs\n";
					print CLASS "\treturn \(", $returnType, "\) $typeprefix", $class->{astNodeName}, "_", $function, "\($selfstring$defaultcparams\);\n}\n" ;
				}
			}
		}
	}

}

sub generateClassMethodForEnum
{
	my( $class, $m ) = @_;
	
	if( $m->{NodeType} eq "enum" ) {
		my $enum = $m->{astNodeName};
		my @enums = split(",", $m->{Params});
		foreach my $enum ( @enums ) {
			$enum =~ s/\s//g;
			if ( $enum =~ /(.*)=(.*)/ ) {
				print HEADER "+ (int) ", $1, ";\n",;
				print CLASS "\n+ (int) ", $1, "\n{\n\treturn (int) ", uc $class->{astNodeName}, "_", $1, ";\n}\n",;
			} else {
				print HEADER "+ (int) ", $enum, ";\n",;
				print CLASS "\n+ (int) ", $enum, "\n{\n\treturn (int) ", uc $class->{astNodeName}, "_", $enum, ";\n}\n",;
			}
		}
	}
}

=head2 printIndexEntry

	Parameters: member node

	Prints an index entry for a single node.

	TODO: stub

=cut

sub printIndexEntry
{
	my ( @node ) = @_;
}




sub writeSrcHTML
{
	my ( $outfile, $infile ) = @_;

	open ( OUT, ">$outfile" ) || die "Couldn't open $outfile for".
			"writing.\n";


	close OUT;
}

1;

