#!/usr/bin/perl -w
# -*- cperl -*-

binmode STDOUT;

while (<>) {
  last if (m#BEGINING OF FUNCTION DEFINITION#);
}

$line = "";

while (<>) {
  last if (m#END OF FUNCTION DEFINITION#);
  chomp;
  $line .= $_ unless (m{^\s*//});
}

$line =~ s/\s+/ /g;

print <<"__EOM__";
// DO NOT EDIT
// this file is automatically generated by makefunc
// see dependency information in mayu-common.mak

#ifdef FUNCTION_DATA
__EOM__
foreach $functionDefinition ( split(/;/, $line) ) {
  # void funcPrefix(FunctionParam *i_param, const Keymap *i_keymap,
  #                 bool i_doesIgnoreModifiers = true);
  next unless ( $functionDefinition =~ m{^
	\s*	\w+		# void
	\s+	func(\w+)	# funcPrefix
	\s*	\(		# (
	\s*	FunctionParam	# FunctionParam
	\s*	\*		# *
	\s*	\w+		# i_param
	\s*	,?		# ,
	\s*	(.*?)		# const Keymap *i_keymap,
				# bool i_doesIgnoreModifiers = true
	\s*	\)		# )
	\s*$}x );
  my($name) = $1;
  push(@names, $name);
  print <<"__EOM__";
class FunctionData_$name : public FunctionData
{
public:
__EOM__
  my(@args) = split(/\s*,\s*/, $2);
  
  my $argc = 0;
  my @argIsReference = ();
  my @argTypes = ();
  my @argNames = ();
  my @argDefaultValues = ();
  
  foreach $arg ( @args ) {
    my $isReference = 0;
    my $type = "";
    my $argName = "";
    my $defaultValue = "";
    # bool i_doesIgnoreModifiers = true
    if ( $arg =~ m{^
		(.*\S)		# bool i_doesIgnoreModifiers
	\s*	=		# =
	\s*	(\S.*)		# true
	$}x ) {
      $arg = $1;
      $defaultValue = $2;
    }
    # const Keymap *i_keymap
    if ( $arg =~ m{^
		(.*\S		# const Keymap
	\s*	\*)		# *
	\s*	i_(\w+)		# i_keymap
	$}x ) {
      # const Hoge *i_hoge
      $type = $1;
      $argName = $2;
    } elsif ( $arg =~ m{^
		const		# const
	\s*	(.*\S)		# ...
	\s*	&		# &
	\s*	i_(\w+)		# i_...
	$}x ) {
      # const Hoge &i_hoge
      $type = $1;
      $argName = $2;
      $isReference = 1;
    } elsif ( $arg =~ m{^
		(.*\S)		# ...
	\s*	i_(\w+)		# i_...
	$}x ) {
      # Hoge i_hoge
      $type = $1;
      $argName = $2;
    } else {
      die;
    }
    
    push(@argIsReference, $isReference);
    push(@argTypes, $type);
    push(@argNames, $argName);
    push(@argDefaultValues, $defaultValue);
    $argc ++;
  }
  
  for ($i = 0; $i < $argc; $i ++) {
    print <<"__EOM__";
  $argTypes[$i] m_$argNames[$i];
__EOM__
  }
  print <<"__EOM__";

public:
  static FunctionData *create()
  {
    FunctionData_$name *fd
      = new FunctionData_$name;
__EOM__
  for ($i = 0; $i < $argc; $i ++) {
    if ($argDefaultValues[$i]) {
      print "    fd->m_$argNames[$i] = $argDefaultValues[$i];\n";
    }
  }
  print <<"__EOM__";
    return fd;
  }
  
  virtual void load(SettingLoader *i_sl)
  {
__EOM__
  if ($argc == 0 || $argDefaultValues[0]) {
    print <<"__EOM__";
    if (!i_sl->getOpenParen(false, FunctionData_${name}::getName()))
      return;
__EOM__
  } else {
    print <<"__EOM__";
    i_sl->getOpenParen(true, FunctionData_${name}::getName()); // throw ...
__EOM__
  }
  for ($i = 0; $i < $argc; $i ++) {
    if ($argDefaultValues[$i]) {
      print <<"__EOM__";
    if (i_sl->getCloseParen(false, FunctionData_${name}::getName()))
      return;
__EOM__
    }
    if (0 < $i) {
      print <<"__EOM__";
    i_sl->getComma(false, FunctionData_${name}::getName()); // throw ...
__EOM__
    }
    print "    i_sl->load_ARGUMENT(&m_$argNames[$i]);\n";
  }
  print <<"__EOM__";
    i_sl->getCloseParen(true, FunctionData_${name}::getName()); // throw ...
  }

  virtual void exec(Engine *i_engine, FunctionParam *i_param) const
  {
__EOM__
  print "    i_engine->func$name(i_param";
  for ($i = 0; $i < $argc; $i ++) {
    print ", m_$argNames[$i]";
  }
  print ");\n";
  
  print <<"__EOM__";
  }

  inline virtual const _TCHAR *getName() const
  {
    return _T("$name");
  }

  virtual tostream &output(tostream &i_ost) const
  {
    i_ost << _T("&") << getName();
__EOM__
  if ( 0 < $argc ) {
    print <<"__EOM__";
    i_ost << _T("(");
__EOM__
  }
  for ($i = 0; $i < $argc; $i ++) {
    if ($i == $argc - 1) {
    print <<"__EOM__";
    i_ost << m_$argNames[$i];
__EOM__
    } else {
    print <<"__EOM__";
    i_ost << m_$argNames[$i] << _T(", ");
__EOM__
    }
  }
  if ( 0 < $argc ) {
    print <<"__EOM__";
    i_ost << _T(") ");
__EOM__
  }
  print <<"__EOM__";
    return i_ost;
  }

  virtual FunctionData *clone() const
  {
    return new FunctionData_${name}(*this);
  }
};

__EOM__
}

print <<"__EOM__";
#endif // FUNCTION_DATA

#ifdef FUNCTION_FRIEND
__EOM__
foreach $name ( @names ) {
  print <<"__EOM__";
friend class FunctionData_$name;
__EOM__
}
print <<"__EOM__";
#endif // FUNCTION_FRIEND

#ifdef FUNCTION_CREATOR
FunctionCreator functionCreators[] = {
__EOM__
foreach $name ( @names ) {
  print <<"__EOM__";
  { _T("$name"), FunctionData_${name}::create },
__EOM__
}
print <<"__EOM__";
};
#endif // FUNCTION_CREATOR
__EOM__
