" @Author:      Tom Link (micathom AT gmail com?subject=[vim])
" @Website:     http://www.vim.org/account/profile.php?user_id=4037
" @License:     GPL (see http://www.gnu.org/licenses/gpl.txt)
" @Revision:    168


if !exists('g:tlib#file#drop')
    " If true, use |:drop| to edit loaded buffers (only available with GUI).
    let g:tlib#file#drop = has('gui')   "{{{2
endif


if !exists('g:tlib#file#use_tabs')
    let g:tlib#file#use_tabs = 0   "{{{2
endif


if !exists('g:tlib#file#edit_cmds')
    let g:tlib#file#edit_cmds = g:tlib#file#use_tabs ? {'buffer': 'tab split | buffer', 'edit': 'tabedit'} : {}  "{{{2
endif


if !exists('g:tlib#file#absolute_filename_rx')
    let g:tlib#file#absolute_filename_rx = '^\~\?[\/]'   "{{{2
endif

""" File related {{{1
" For the following functions please see ../../test/tlib.vim for examples.


" EXAMPLES: >
"   tlib#file#Split('foo/bar/filename.txt')
"   => ['foo', 'bar', 'filename.txt']
function! tlib#file#Split(filename) "{{{3
    let prefix = matchstr(a:filename, '^\(\w\+:\)\?/\+')
    " TLogVAR prefix
    if !empty(prefix)
        let filename = a:filename[len(prefix) : -1]
    else
        let filename = a:filename
    endif
    let rv = split(filename, '[\/]')
    " let rv = split(filename, '[\/]', 1)
    if !empty(prefix)
        call insert(rv, prefix[0:-2])
    endif
    return rv
endf


" :display: tlib#file#Join(filename_parts, ?strip_slashes=1, ?maybe_absolute=0)
" EXAMPLES: >
"   tlib#file#Join(['foo', 'bar', 'filename.txt'])
"   => 'foo/bar/filename.txt'
function! tlib#file#Join(filename_parts, ...) "{{{3
    TVarArg ['strip_slashes', 1], 'maybe_absolute'
    " TLogVAR a:filename_parts, strip_slashes
    if maybe_absolute
        let filename_parts = []
        for part in a:filename_parts
            if part =~ g:tlib#file#absolute_filename_rx
                let filename_parts = []
            endif
            call add(filename_parts, part)
        endfor
    else
        let filename_parts = a:filename_parts
    endif
    if strip_slashes
        " let rx    = tlib#rx#Escape(g:tlib#dir#sep) .'$'
        let rx    = '[/\\]\+$'
        let parts = map(copy(filename_parts), 'substitute(v:val, rx, "", "")')
        " TLogVAR parts
        return join(parts, g:tlib#dir#sep)
    else
        return join(filename_parts, g:tlib#dir#sep)
    endif
endf


" EXAMPLES: >
"   tlib#file#Relative('foo/bar/filename.txt', 'foo')
"   => 'bar/filename.txt'
function! tlib#file#Relative(filename, basedir) "{{{3
    " TLogVAR a:filename, a:basedir
    " TLogDBG getcwd()
    " TLogDBG expand('%:p')
    let b0 = tlib#file#Absolute(a:basedir)
    let b  = tlib#file#Split(b0)
    " TLogVAR b
    let f0 = tlib#file#Absolute(a:filename)
    let fn = fnamemodify(f0, ':t')
    let fd = fnamemodify(f0, ':h')
    let f  = tlib#file#Split(fd)
    " TLogVAR f0, fn, fd, f
    if f[0] != b[0]
        let rv = f0
    else
        while !empty(f) && !empty(b)
            if f[0] != b[0]
                break
            endif
            call remove(f, 0)
            call remove(b, 0)
        endwh
        " TLogVAR f, b
        let rv = tlib#file#Join(repeat(['..'], len(b)) + f + [fn])
    endif
    " TLogVAR rv
    return rv
endf


function! tlib#file#Absolute(filename, ...) "{{{3
    if filereadable(a:filename)
        let filename = fnamemodify(a:filename, ':p')
    elseif a:filename =~ '^\(/\|[^\/]\+:\)'
        let filename = a:filename
    else
        let cwd = a:0 >= 1 ? a:1 : getcwd()
        let filename = tlib#file#Join([cwd, a:filename])
    endif
    let filename = substitute(filename, '\(^\|[\/]\)\zs\.[\/]', '', 'g')
    let filename = substitute(filename, '[\/]\zs[^\/]\+[\/]\.\.[\/]', '', 'g')
    return filename
endf


function! tlib#file#Canonic(filename, ...) "{{{3
    TVarArg ['mode', '']
    if a:filename =~ '^\\\\'
        let mode = 'windows'
    elseif a:filename =~ '^\(file\|ftp\|http\)s\?:'
        let mode = 'url'
    elseif (empty(mode) && g:tlib#sys#windows)
        let mode = 'windows'
    endif
    let filename = a:filename
    if mode == 'windows'
        let filename = substitute(filename, '/', '\\', 'g')
    else
        let filename = substitute(filename, '\\', '/', 'g')
    endif
    return filename
endf


function! s:SetScrollBind(world) "{{{3
    let sb = get(a:world, 'scrollbind', &scrollbind)
    if sb != &scrollbind
        let &scrollbind = sb
    endif
endf


" :def: function! tlib#file#With(fcmd, bcmd, files, ?world={})
function! tlib#file#With(fcmd, bcmd, files, ...) "{{{3
    " TLogVAR a:fcmd, a:bcmd, a:files
    exec tlib#arg#Let([['world', {}]])
    call tlib#autocmdgroup#Init()
    augroup TLibFileRead
        autocmd!
    augroup END
    for f in a:files
        let bn = bufnr('^'.f.'$')
        " TLogVAR f, bn
        let bufloaded = bufloaded(bn)
        let ok = 0
        let s:bufread = ""
        if bn != -1 && buflisted(bn)
            if !empty(a:bcmd)
                " TLogDBG a:bcmd .' '. bn
                exec a:bcmd .' '. bn
                let ok = 1
                call s:SetScrollBind(world)
            endif
        else
            if filereadable(f)
                if !empty(a:fcmd)
                    " TLogDBG a:fcmd .' '. tlib#arg#Ex(f)
                    exec 'autocmd TLibFileRead BufRead' escape(f, '\ ') 'let s:bufread=expand("<afile>:p")'
                    try 
                        exec a:fcmd .' '. tlib#arg#Ex(f)
                    finally
                        exec 'autocmd! TLibFileRead BufRead'
                    endtry
                    let ok = 1
                    call s:SetScrollBind(world)
                endif
            else
                echohl error
                echom 'File not readable: '. f
                echohl NONE
            endif
        endif
        " TLogVAR ok, bufloaded, &filetype
        if empty(s:bufread) && ok && !bufloaded && empty(&filetype)
            doautocmd BufRead
        endif
    endfor
    augroup! TLibFileRead
    unlet! s:bufread
    " TLogDBG "done"
endf


" Return 0 if the file isn't readable/doesn't exist.
" Otherwise return 1.
function! tlib#file#Edit(fileid) "{{{3
    if type(a:fileid) == 0
        let bn = a:fileid
        let filename = fnamemodify(bufname(bn), ':p')
    else
        let filename = fnamemodify(a:fileid, ':p')
        let bn = bufnr(filename)
    endif
    if filename == expand('%:p')
        return 1
    else
        " TLogVAR a:fileid, bn, filename, g:tlib#file#drop, filereadable(filename)
        if bn != -1 && buflisted(bn)
            if g:tlib#file#drop
                " echom "DBG" get(g:tlib#file#edit_cmds, 'drop', 'drop') fnameescape(filename)
                exec get(g:tlib#file#edit_cmds, 'drop', 'drop') fnameescape(filename)
            else
                " echom "DBG" get(g:tlib#file#edit_cmds, 'buffer', 'buffer') bn
                exec get(g:tlib#file#edit_cmds, 'buffer', 'buffer') bn
            endif
            return 1
        elseif filereadable(filename)
            try
                " let file = tlib#arg#Ex(filename)
                " " TLogVAR file
                " echom "DBG" get(g:tlib#file#edit_cmds, 'edit', 'edit') fnameescape(filename)
                exec get(g:tlib#file#edit_cmds, 'edit', 'edit') fnameescape(filename)
            catch /E325/
                " swap file exists, let the user handle it
            catch
                echohl error
                echom v:exception
                echohl NONE
            endtry
            return 1
        else
            echom "TLIB: File not readable: " . filename
            if filename != a:fileid
                echom "TLIB: original filename: " . a:fileid
            endif
        endif
    endif
    return 0
endf


if v:version > 704 || (v:version == 704 && has('patch279'))

    function! tlib#file#Glob(pattern) abort "{{{3
        return glob(a:pattern, 0, 1)
    endf

    function! tlib#file#Globpath(path, pattern) abort "{{{3
        return globpath(a:path, a:pattern, 0, 1)
    endf

else

    " :nodoc:
    function! tlib#file#Glob(pattern) abort "{{{3
        return split(glob(a:pattern), '\n')
    endf

    " :nodoc:
    function! tlib#file#Globpath(path, pattern) abort "{{{3
        return split(globpath(a:path, a:pattern), '\n')
    endf

endif

