
:- lib( os_slashify/2 ).
:- lib( os_name/2 ).

/** os_path( +Dir, +File, -Path ). 
    os_path( -Dir, -File, +Path ). 
    os_path( -Parts, +Path ).
    os_path( +Parts, -Path ).

  Mostly a polymorphic directory_file_path/3 nickname.
Also '' is the default rather than '/' when dealing with absolute paths.
The predicate understands all the input types known to os_name/2. 
Path takes its type from Dir and vice versa- when mode is reversed. 
If you require Path to be of specific type regardless of what Dir is
decorate -Path as explained is os_name/2.

==
?- os_path( D, F,  '/abc/def/' ).
D = '/abc',
F = def.

?- os_path( D, F,  "/abc/def/" ).
D = "/abc",
F = "def".

?- os_path( D, F,  /abc/def/ ).
ERROR: Syntax error: Unbalanced operator
ERROR: os_path( D, F,  /abc/def/
ERROR: ** here **
ERROR:  ) . 

?- os_path( D, F,  /abc/def ).
D = /abc,
F = def.

?- os_path( abc/def, ghi.txt, Path ).
Path = abc/def/ghi.txt.

?- os_path( /abc/def, ghi.txt, Path ).
Path = /abc/def/ghi.txt.

?- os_path( '', abc, Abc ).
Abc = abc.

?- directory_file_path( '', abc, Abc ).
   Abc = '/abc'.

?- os_path( Dir, Base, '/abc' ).
Dir = '',
Base = abc.

?- directory_file_path( Dir, Base, '/abc' ).
Dir =  (/),
Base = abc.


?- os_path( hmrn(library(what)), abc, Abc ).
ERROR: pack(os): Nested aliases are not supported yet.
Found: hmrn(library(what)) at position: 1 for predicate: os_path/3

?- file_search_path( hmrn, Hmrn ).
Hmrn = '/home/nicos/ac/14mg/cohorts/hmrn'.

?- os_path( hmrn(what), if, Abc ).
Abc = hmrn('what/if').

?- os_path( hmrn(what/if), not, Abc ).
Abc = hmrn(what/if/not).

?- os_path( hmrn(what/if), not, +Abc ).
Abc = '/home/nicos/ac/14mg/cohorts/hmrn/what/if/not'.

?- os_path( hmrn(what/if), not, \Abc ).
Abc = /home/nicos/ac/'14mg'/hmrn/what/if/not.

?- os_path( hmrn(what/if), not, @Abc ).
Abc = hmrn(what/if/not).

?- os_path( "what/if", foo.txt, Abc ).
Abc = "what/if/foo.txt".

?- os_path( Parts, 'a/b/c.txt' ), os_path( Parts, Rel ).
Parts = [a, b, c.txt],
Rel = 'a/b/c.txt'.

?- os_path( Parts, '/a/b/c.txt' ), os_path( Parts, Rel ).
Parts = ['', a, b, c.txt],
Rel = '/a/b/c.txt'.

==

@author nicos angelopoulos
@version  0.4 2020/9/14
*/
os_path( Parts, Path ) :-
    ground( Path ),
    !,
    os_path_decon( Path, Parts ).
os_path( Parts, Path ) :-
    % do not use at_con/3, see example above...
    atomic_list_concat( Parts, '/', Prov ),
    os_cast( Prov, Path ).
os_path( Dir, File, Path ) :-
    File == '.', 
    !,
    Path = Dir.
os_path( Dir, File, Path ) :-
	ground( Path ),
	% var( Dir ), 
	% var( File ),
	!,
	os_name( Path, Type ),
	os_path_type_de( Type, Path, Dir, File ).

os_path( Dir, File, PathOut ) :-
	ground( Dir ),
	ground( File ),
	os_path_ground( Dir, File, Type, Path ),
	os_cast( Type, Path, PathOut ).

os_path_ground( '', File, Type, Os ) :- 
	!, 
	os_name( File, Type ), 
	os_cast( Type, File, Os ).
os_path_ground( Dire, '', Type, Os ) :- 
	!,
	os_name( Dire, Type ),
	os_cast( Type, Dire, Os ).
os_path_ground( Dir, File, Type, Path ) :-
	os_name( Dir, Type ),
	os_cast( Type, File, Tile ),
	os_path_type( Type, Dir, Tile, Path ).

os_path_type( atom, Dir, File, Path ) :-
	directory_file_path( Dir, File, Path ).
os_path_type( slash, Dir, File, Path ) :-
	Path = Dir/File.
os_path_type( alias, Dir, File, Path ) :-
	Dir =.. [Alias,AArg],
	os_name( AArg, AAtype ),
	os_path_alias_arg( AAtype, Dir, AArg, File, PArg ),
	Path =.. [Alias,PArg].
os_path_type( string, Dir, File, Path ) :-
	atom_string( '/', Slash ),
	string_concat( Slash, File, Sile ),
	string_concat( Dir, Sile, Path ).

os_path_alias_arg( alias, Dir, _AArg, _File, _PArg ) :-  
	!,
	throw( pack_error(os,nested_alias(1,os_path/3,Dir)) ).
os_path_alias_arg( NonAlias, _Dir, AArg, File, PArg ) :-
	os_path_type( NonAlias, AArg, File, PArg ).

/*
os_path_unalias( Dir, Unaliased ) :-
	compound( Dir ),
	Dir =.. [Alias|_],
	user:file_search_path( Alias, _ ),
	absolute_file_name( Dir, Unaliased ),
	!.
os_path_unalias( Dir, Dir ).
*/


os_path_type_de( atom, Path, Dir, RelF ) :-
	os_slashify( PathNoSlash, Path ),
    ( ground(Dir) ->
	    directory_file_path( Dir, RelF, PathNoSlash )
        ;
	    directory_file_path( DirPrv, RelF, PathNoSlash ),
	    os_path_type_de_dir( DirPrv, Dir )
    ).
os_path_type_de( slash, DirFile, Dir, File ) :-
	( Dir/File = DirFile -> true; /(File) = DirFile, Dir = (/) ).
os_path_type_de( alias, Aliased, Dir, File ) :-
	% currently nested aliases are not handled by absolute_file_name/2
	% but we might introduce a version that does
	absolute_file_name( Aliased, DirFile ),
	os_path_type_de( atom, DirFile, Dir, File ).
os_path_type_de( string, String, Dir, File ) :-
	atom_string( Atom, String ),
	os_path_type_de( atom, Atom, DirAtom, FileAtom ),
    maplist( os_cast(string), [DirAtom,FileAtom], [Dir,File] ).

os_path_type_de_dir( '/', '' ) :- !.
os_path_type_de_dir( Dir, Dir ).

os_path_decon( Path, Parts ) :-
    os_path( '.', File, Path ),
    Path == File,
    !,
    Parts = [Path].
os_path_decon( Path, Parts ) :-
    os_path( Dir, Base, Path ),
    os_path_decon( Dir, Darts ),
    append( Darts, [Base], Parts ),
    !.
