package YATT::Translator::Perl::macro_dbfetch;
use strict;
use warnings FATAL => qw(all);
require YATT::Translator::Perl;

YATT::Translator::Perl::make_arg_spec
  (\ my %arg_dict, \ my @arg_order, qw(row sth table schema));

sub macro {
  my ($trans, $scope, $args) = @_;
  my $orig_node = $args->clone;
  my @hash_spec
    = $trans->feed_arg_or_make_hash_of(text => $scope, $args
				       , \%arg_dict, \@arg_order
				       , my ($rowVarName
					     , $sth, $table, $schema));

  unless ($table) {
    die $trans->node_error($orig_node->parent, "table= is missing");
  }

  my %local;
  my $sthVar = $sth ? node_body($sth) : 'sth';
  $local{$sthVar} = $trans->create_var('scalar' => $args
				       , varname => $sthVar);
  my ($loop, $else);
  my $found = my $header = $args->variant_builder;
  for (; $args->readable; $args->next) {
    unless ($args->is_attribute) {
      $found->add_node($args->current);
      next;
    }
    if ($args->node_name eq 'row') { # XXX: body でも良いのでは？
      $loop = $args->open;
      $found = $args->variant_builder;
    } elsif ($args->node_name eq 'else') {
      $else = $args->open;
      last;
    } else {
    }
  }
  my @columns;
  my %inner;
  if ($loop) {
    for (; $loop->readable && $loop->is_primary_attribute; $loop->next) {
      my ($name, $typename) = $trans->arg_name_types($loop);
      $inner{$name} = $trans->create_var
	($typename || 'text', $loop, varname => $name);
      my $expr = $loop->node_body;
      # [varName => columnExpr]
      push @columns, [$name => defined $expr ? "$expr as $name" : $name];
    }
  } else {
  }

  my ($fetchMode, $rowVarExpr) = do {
    if (@columns) {
      (array => '('.join(", ", map {'$'.$_->[0]} @columns).')')
    } else {
      my $name = $rowVarName ? node_body($rowVarName) : 'row';
      $local{$name} = $trans->create_var('list' => $args
					 , varname => $name);
      (hashref => '$'.$name);
    }
  };

  my $loopBody = do {
    if ($loop) {
      $trans->as_block
	($trans->as_statement_list
	 ($trans->generate_body([\%inner, [\%local, $scope]], $loop)));
    } else {
      die "NIMPL";
    }
  };

  # XXX: Static check! (But, to check, quoted expression is too much!)
  my $schemaExpr = $trans->default_gentype
    (DBSchema => text => $scope, $args, $schema);

  my $tableExpr = $trans->faked_gentype
    (text => $scope, $args, $table);

  my $prepare = sprintf(q|my $%s = $this->%s->to_fetch(%s, %s, %s)|
			, $sthVar
			, $schemaExpr
			, $tableExpr
			, (@columns ?
			   ('['.join(", ", map {
			     YATT::Translator::Perl::qparen($_->[1])
			     } @columns).']')
			   : 'undef')
			, join(", ", map {"$_->[0] => $_->[1]"}
			       @hash_spec));

  my $if = sprintf(q|if (my %1$s) {%2$s; do %3$s while (%1$s); %4$s}|
		   , sprintf(q|%s = $%s->fetchrow_%s|
			     , $rowVarExpr, $sthVar, $fetchMode)
		   , $trans->as_statement_list
		   ($trans->generate_body([\%local, $scope], $header))
		   , $loopBody
		   , $trans->as_statement_list
		   ($trans->generate_body([\%local, $scope], $found))
		  );
  $if .= " else ".$trans->as_block
    ($trans->as_statement_list
     ($trans->generate_body([\%local, $scope], $else))) if $else;

  \ "{$prepare; $if}";
}

1;
