p_node_filename
  }
  return undef;
}

sub initialize_output_units_files($)
{
  my $self = shift;

  $self->{'out_filepaths'} = {};
  $self->{'file_counters'} = {};
  $self->{'filenames'} = {};
}

# If CASE_INSENSITIVE_FILENAMES is set, reuse the first
# filename with the same name insensitive to the case.
sub register_normalize_case_filename($$)
{
  my $self = shift;
  my $filename = shift;

  if ($self->get_conf('CASE_INSENSITIVE_FILENAMES')) {
    if (exists($self->{'filenames'}->{lc($filename)})) {
      if ($self->get_conf('DEBUG')) {
        print STDERR "Reusing case-insensitive ".
                   $self->{'filenames'}->{lc($filename)}." for $filename\n";
      }
      $filename = $self->{'filenames'}->{lc($filename)};
    } else {
      $self->{'filenames'}->{lc($filename)} = $filename;
    }
  } else {
    if (exists($self->{'filenames'}->{$filename})) {
      if ($self->get_conf('DEBUG')) {
        print STDERR "Reusing ".$self->{'filenames'}->{$filename}
                     ." for $filename\n";
      }
    } else {
      $self->{'filenames'}->{$filename} = $filename;
    }
  }
  return $filename;
}

# return the registered filename if there is one, else return undef.
# Note that it only tells that a file name has been its name considered,
# not that the corresponding file is created.
# currently unused.
sub registered_filename($$)
{
  my $self = shift;
  my $filename = shift;

  if ($self->get_conf('CASE_INSENSITIVE_FILENAMES')) {
    if (exists($self->{'filenames'}->{lc($filename)})) {
      return $self->{'filenames'}->{lc($filename)};
    }
  } elsif (exists($self->{'filenames'}->{$filename})) {
    return $self->{'filenames'}->{$filename};
  }
  return undef;
}

# Sets $output_unit->{'unit_filename'}.
sub set_output_unit_file($$$)
{
  my $self = shift;
  my $output_unit = shift;
  my $filename = shift;

  if (!defined($filename)) {
    cluck("set_output_unit_file: filename not defined\n");
  }
  if (!defined($output_unit)) {
    cluck("set_output_unit_file: output_unit not defined\n");
  }

  $filename = $self->register_normalize_case_filename($filename);

  # This should never happen, set_output_unit_file is called once per
  # tree unit.
  if (exists($output_unit->{'unit_filename'})) {
    if ($output_unit->{'unit_filename'} eq $filename) {
      print STDERR "set_output_unit_file: already set: $filename\n"
         if ($self->get_conf('DEBUG'));
    } else {
      print STDERR  "set_output_unit_file: unit_filename reset: "
        .$output_unit->{'unit_filename'}.", $filename\n"
           if ($self->get_conf('DEBUG'));
    }
  }
  $output_unit->{'unit_filename'} = $filename;
}

# sets out_filepaths converter state, associating a file name
# to a file path.
# $FILEPATH can be given explicitly, otherwise it is based on $FILENAME
# and $DESTINATION_DIRECTORY
sub set_file_path($$$;$)
{
  my $self = shift;
  my $filename = shift;
  my $destination_directory = shift;
  my $filepath = shift;

  if (!defined($filename)) {
    cluck("set_file_path: filename not defined\n");
  }

  $filename = $self->register_normalize_case_filename($filename);

  if (not defined($filepath)) {
    if (defined($destination_directory) and $destination_directory ne '') {
      $filepath = join('/', ($destination_directory, $filename));
    } else {
      $filepath = $filename;
    }
  }
  # the file path should be set only once per file name.  With
  # CASE_INSENSITIVE_FILENAMES the same file path can appear more
  # than once when files differ in case.
  if (defined($self->{'out_filepaths'}->{$filename})) {
    if ($self->{'out_filepaths'}->{$filename} eq $filepath) {
      print STDERR "set_file_path: filepath set: $filepath\n"
         if ($self->get_conf('DEBUG'));
    } else {
      print STDERR  "set_file_path: filepath reset: "
        .$self->{'out_filepaths'}->{$filename}.", $filepath\n"
         if ($self->get_conf('DEBUG'));
    }
  }
  $self->{'out_filepaths'}->{$filename} = $filepath;
}

sub _get_root_element($$)
{
  my $self = shift;
  my $command = shift;

  my $current = $command;

  while (1) {
    if ($current->{'associated_unit'}) {
      return $current->{'associated_unit'};
    }
    if ($current->{'parent'}) {
      $current = $current->{'parent'};
    } else {
      return undef;
    }
  }
}

# TODO document
# set file_counters converter state
sub set_output_units_files($$$$$$)
{
  my $self = shift;
  my $output_units = shift;
  my $output_file = shift;
  my $destination_directory = shift;
  my $output_filename = shift;
  my $document_name = shift;

  # Ensure that the document has pages
  return undef if (!defined($output_units) or !@$output_units);

  $self->initialize_output_units_files();

  my $extension = '';
  $extension = '.'.$self->get_conf('EXTENSION')
            if (defined($self->get_conf('EXTENSION'))
                and $self->get_conf('EXTENSION') ne '');

  if (!$self->get_conf('SPLIT')) {
    $self->set_file_path($output_filename, undef, $output_file);
    foreach my $output_unit (@$output_units) {
      $self->set_output_unit_file($output_unit, $output_filename);
    }
  } else {
    my $node_top;

    my $identifiers_target;
    if ($self->{'document'}) {
      $identifiers_target = $self->{'document'}->labels_information();
    }

    $node_top = $identifiers_target->{'Top'}
                            if ($identifiers_target);

    my $top_node_filename = $self->top_node_filename($document_name);
    # first determine the top node file name.
    if ($node_top and defined($top_node_filename)) {
      my ($node_top_unit) = $self->_get_root_element($node_top);
      if (!defined($node_top_unit)) {
        print STDERR "No element for top node (".scalar(@$output_units)." units)\n"
         if ($self->get_conf('DEBUG'));
      } else {
        $self->set_file_path($top_node_filename, $destination_directory);
        $self->set_output_unit_file($node_top_unit, $top_node_filename);
      }
    }
    my $file_nr = 0;
    my $previous_page;
    foreach my $output_unit (@$output_units) {
      # For Top node.
      next if (defined($output_unit->{'unit_filename'}));
      my $file_output_unit = $output_unit->{'first_in_page'};
      if (!$file_output_unit) {
        cluck ("No first_in_page for $output_unit\n");
      }
      if (!defined($file_output_unit->{'unit_filename'})) {
        foreach my $root_command (@{$file_output_unit->{'unit_contents'}}) {
          if ($root_command->{'cmdname'}
              and $root_command->{'cmdname'} eq 'node') {
            my $node_filename;
            # double node are not normalized, they are handled here
            if (!defined($root_command->{'extra'}->{'normalized'})
                or !defined($identifiers_target->{
                               $root_command->{'extra'}->{'normalized'}})) {
              $node_filename = 'unknown_node';
            } else {
              $node_filename
               = $self->node_information_filename(
                               $root_command->{'extra'}->{'normalized'},
                               $root_command->{'args'}->[0]);
            }
            $node_filename .= $extension;
            $self->set_file_path($node_filename,$destination_directory);
            $self->set_output_unit_file($file_output_unit, $node_filename);
            last;
          }
        }
        if (!defined($file_output_unit->{'unit_filename'})) {
          # use section to do the file name if there is no node
          my $command = $file_output_unit->{'unit_command'};
          if ($command) {
            if ($command->{'cmdname'} eq 'top' and !$node_top
                and defined($top_node_filename)) {
              $self->set_file_path($top_node_filename, $destination_directory);
              $self->set_output_unit_file($file_output_unit, $top_node_filename);
            } else {
              my ($normalized_name, $filename)
                 = $self->normalized_sectioning_command_filename($command);
              $self->set_file_path($filename, $destination_directory);
              $self->set_output_unit_file($file_output_unit, $filename);
            }
          } else {
            # when everything else has failed
            if ($file_nr == 0 and !$node_top and defined($top_node_filename)) {
              $self->set_file_path($top_node_filename, $destination_directory);
              $self->set_output_unit_file($file_output_unit, $top_node_filename);
            } else {
              my $filename = $document_name . "_$file_nr";
              $filename .= $extension;
              $self->set_file_path($filename, $destination_directory);
              $self->set_output_unit_file($output_unit, $filename);
            }
            $file_nr++;
          }
        }
      }
      $self->set_output_unit_file($output_unit,
                    $file_output_unit->{'unit_filename'});
    }
  }

  foreach my $output_unit (@$output_units) {
    my $output_unit_filename = $output_unit->{'unit_filename'};
    $self->{'file_counters'}->{$output_unit_filename} = 0
       if (!exists($self->{'file_counters'}->{$output_unit_filename}));
    $self->{'file_counters'}->{$output_unit_filename}++;
    print STDERR 'Page '
     # uncomment for Perl object name
     #."$output_unit "
     .Texinfo::OutputUnits::output_unit_texi($output_unit)
     .": $output_unit_filename($self->{'file_counters'}->{$output_unit_filename})\n"
              if ($self->get_conf('DEBUG'));
  }
}

