#!/usr/bin/perl
use Mooix::Thing;
use Text::Wrap;

my @helpfields;

sub gethelp {
	my $this=shift;
	my $field=shift;
	
	my @matches = grep { lc($_) eq lc($field) } @helpfields;
	if (@matches == 1) {
		$field=$matches[0].".hlp";
		return $this->$field;
	}
	else {
		@matches = grep /^\Q$field\E/i, @helpfields;
		if (@matches == 1) {
			$field="$matches[0].hlp";
			return $this->$field;
		}
		elsif (@matches) {
			return "Do you mean =".join("= or =", sort @matches)."=?";
		}
		return;
	}
}

sub links {
	return map { m/=([-_a-zA-Z0-9]+)=/g } @_;
}

sub get_avatar_help {
	my $this=shift;
	my $avatar=shift;
	# It's possible that the user meant not to get help
	# on this object, but on a help topic with a name
	# that happens to match this object's name or
	# aliases.
	if ($_{avatar}) {
		foreach my $topic ($this->name, $this->alias) {
			my @help=$_{avatar}->help(topic => $topic);
			# If the help text is just one line
			# long, it might be a "do you
			# mean...?" question message, or an
			# error, so ignore those.
			if (@help > 1) {
				return @help;
			}
		}
	}
	return;
}

run sub {
	my $this=shift;
	%_=@_;
	my $field = $_{topic};
	@helpfields = map { s/\.hlp$//; $_ } grep { /\.hlp$/ } $this->fields;
	
	if (! length $field) {
		if (! $_{do_preposition}) {
			my @help=get_avatar_help($this, $_{avatar}) if $_{avatar};
			return @help if @help;
		}
		
		$field = 'basics';
	}
	
	if ($field eq 'index') {
		my @index;
		my $maxlen=0;
		foreach my $field (sort @helpfields) {
			my $title=(gethelp($this, $field))[0];
			push @index, "=$field=", $title;
			$maxlen = length $field if length $field > $maxlen;
		}
		if (@index) {
			# Turn put fields and titles on the same lines.
			my @form;
			while (@index) {
				my $topic = shift @index;
				my $title = shift @index;
				push @form, $topic.
					(' ' x (4 + $maxlen - length($topic))).
					$title;
			}
			return "Help index.", "", @form;
		}
		else {
			return "No help is available.";
		}
	}
	elsif ($field eq 'missing') {
		my %links;
		foreach my $field (sort @helpfields) {
			map { $links{$_} = 1 } links(gethelp($this, $field));
		}
		my @missing = grep { $_ ne 'index' && $_ ne 'missing' && 
			             ! gethelp($this, $_) } keys %links;
		if (@missing) {
			return "Missing help topics: =".
			       join("=, =", sort @missing)."=";
		}
		else {
			return "There are no missing help topics!";
		}
	}
	else {
		# Help on a given topic.
		# Try first preserving case, then without case.
		my @help=gethelp($this, $field);
		@help=gethelp($this, lc $field) if ! @help;
		if (! @help) {
			return "Sorry, there is no help available on \"$field\".\nTry \"help index\" for an index of help topics.";
		}
		my %links = map { $_ => 1 } links(@help);
		# Find related help topics and add links to them.
		my @related;
		foreach my $ofield (@helpfields) {
			next if $ofield eq $field;
			next if $links{$ofield};
			my $of=$ofield.".hlp";
			if (gethelp($this, $ofield) =~ /=\Q$field\E=/) {
				push @related, $ofield;
			}
		}
		if (@related) {
			push @help, "",
				wrap("","", "Other related topics: =".
					    join("=, =", sort @related)."=");
		}
		return @help;
	}
}
