#!/usr/bin/perl6-m

# die with printing a backtrace
my class X::P6doc is Exception {
    has $.message;
    multi method gist(X::P6doc:D:) {
        self.message;
    }
}

constant DEBUG = %*ENV<P6DOC_DEBUG>;

sub findbin() returns Str {
    $*PROGRAM_NAME.subst(rx{<-[/\\]>+$}, '');
}

constant INDEX = findbin() ~ 'index.data';

sub tempfile() {
    my $tempfile = %*ENV<TEMP> // %*ENV<TMP> // '/tmp';
    $tempfile ~= '/';
    $tempfile ~= join '', ('a'..'z', 0..9).roll(5);
    $tempfile ~= '.tmp';
    nextsame if $tempfile.IO.e;
    return $tempfile;
}

sub search-paths() {
    (findbin()  X~ <../doc/perl6/lib/ ../lib/> X~ '',<Type/ Language/ Routine/>),
    @*INC>>.Str.map({ /\/$/ ?? $_ !! $_ ~ '/' });
}

sub module-names(Str $modulename) {
    $modulename.split('::').join('/')
        X~ '.pm', '.pm6', '.pod';
}

sub locate-module(Str $modulename) {
    my $m = (search-paths() X~ module-names($modulename)).first: *.IO.f;
    unless $m.defined {
        my $message = join "\n",
            "Cannot locate $modulename in any of the following paths:",
            search-paths.map({"  $_"});
        X::P6doc.new(:$message).throw;
    }
    return $m;
}

sub show-docs(Str $path, :$section) {
   my $pager = %*ENV<PAGER> // ($*OS eq 'mswin32' ?? 'more' !! 'less');
   if not open($path).lines.grep( /^'=' | '#|' | '#='/ )  {
      say "No Pod found in $path";
      return;
   }
   if $section.defined {
       %*ENV<PERL6_POD_HEADING> = $section;
      my $i = findbin() ~ '../lib';
       say "launching '$*EXECUTABLE_NAME -I$i --doc=SectionFilter $path | $pager'" if DEBUG;
       shell "$*EXECUTABLE_NAME -I$i --doc=SectionFilter $path | $pager";
   }
   else {
       shell "$*EXECUTABLE_NAME --doc $path | $pager";
   }

}

multi sub MAIN() {
    say 'What documentation do you want to read?';
    say "Examples: $*PROGRAM_NAME Type::Str";
    say "          $*PROGRAM_NAME Type::Str.split";
}

multi sub MAIN($docee) {
    return MAIN($docee, :f) if defined $docee.index('.') ;
    if INDEX.IO ~~ :e {
        my %data = EVAL slurp INDEX;
        if %data{$docee} {
            my $newdoc = %data{$docee}[0][0];
            return MAIN($newdoc);
        }
    }
    show-docs(locate-module($docee));
}

multi sub MAIN($docee, Bool :$f!) {
    my ($package, $method) = $docee.split('.');
    unless $method {
      if INDEX.IO ~~ :e {
        my %data = EVAL slurp INDEX;
        for <routine method> -> $pref {
            my $ndocee = $pref ~ " " ~ $docee;
            if %data{$ndocee} {
                my $newdoc = %data{$ndocee}[0][0] ~ "." ~ $docee;
                return MAIN($newdoc, :f);
            }
        }
        show-docs(locate-module($docee));
      }
        say 'In order to use unqualified sub and method names like "p6doc -f say" you will need to run "p6doc-index build" to build index.data';
        say 'otherwise use "p6doc -f Str.split" instead of "p6doc -f split" for now';
        exit 2;
    }
    my $m = locate-module($package);
    show-docs($m, :section($method));
}


# vim: ft=perl6
