"
" script downloaded from http://git.openics.org/cgit.cgi/bindzoneedit.vim/plain/bindzoneedit.vim
"

" File: bindzoneedit.vim
" Description: Edit Bind zones safely
" Author: Emmanuel Bouthenot <kolter@openics.org>
" Version: 0.1
" Last Modified: November 21, 2010
" License: WTFPLv2 (see http://sam.zoy.org/wtfpl/)
" Changelog:
"  0.1: Initial Release

if exists("loadedBindZoneEdit") || !executable('named-checkzone')
    finish
endif

let loadedBindZoneEdit = 1

autocmd FileType bindzone execute('call BindZoneApply()')

function BindZoneApply()
    autocmd BufWriteCmd <buffer> execute('call BindZoneChecker()')
endfunction

function BindUpdateSerial()
    let s:bufferLines = getbufline(bufnr("%"), 1, "$")
    let s:lineNumber = 0
    for s:line in s:bufferLines
        let s:lineNumber += 1
        let s:serial = matchlist(s:line, '^\(\s*\)\(2\d\{7\}\)\(\d\{2\}\)\(\s*;\s*Serial.*\)$')
        if s:serial != []
            if (strftime("%Y%m%d") == s:serial[2])
                let s:newserial = s:serial[2] . s:serial[3]+1
            else
                let s:newserial = strftime("%Y%m%d") . '01'
            endif
            call setline(s:lineNumber, s:serial[1] . s:newserial . s:serial[4])
            call cursor(s:lineNumber, strlen(s:serial[1] . s:newserial)+1)
            execute('highlight BindSerial ctermbg=red guibg=red ctermfg=white guifg=white')
            call matchadd("BindSerial", s:newserial)
            break
        endif
    endfor
endfunction

nmap <C-_> :call BindUpdateSerial()<CR>

function BindZoneChecker()
    let s:currentFile = expand("%")
    let s:bufferContents = getbufline(bufnr("%"), 1, "$")
    let s:domain = matchlist(s:bufferContents, '^\$ORIGIN\s\+\(\S\+\)')
    if s:domain != []

        " If the file isn't writable don't do anything (as it could lock it up)
        if filewritable(s:currentFile)
            let s:zoneFile = tempname()
            exe writefile(s:bufferContents, s:zoneFile)

            " Check if the zone file got written (prevent disk space full)
            if filereadable(s:zoneFile)
                let s:output = system('named-checkzone ' . s:domain[1] . ' ' . s:zoneFile)
                let s:output = substitute(s:output, s:zoneFile, s:currentFile, 'g')
                call delete(s:zoneFile)

                " Check if the zone is correct
                let s:okMatch = matchstr(s:output, '\nOK\n')
                if s:okMatch != ''
                    cclose
                    " Avoids the annoying “Press ENTER to …” message
                    if &modified
                        call BindUpdateSerial()
                    endif
                    " Finally, we have to write the file
                    noautocmd w
                    " Avoids the annoying “Press ENTER to …” message
                    redraw
                else
                    let s:outputLines = split(s:output, "\n")
                    let s:errorLines = []
                    for s:line in s:outputLines
                        let s:errorLine = matchlist(s:line, '^\(.\+\):\(\d\+\):\s\+\(.*\)$')
                        if s:errorLine != []
                            call add(s:errorLines, s:currentFile . ':' . s:errorLine[2] . ':' . s:errorLine[3])
                        endif
                    endfor

                    " if it was impossible to detect errors properly, we still
                    " had them to the error console in a “raw” way
                    if s:errorLines == []
                        for s:line in s:outputLines
                            call add(s:errorLines, s:currentFile . ':0:' . s:line)
                        endfor
                    endif

                    let s:cFile = tempname()
                    exe writefile(s:errorLines, s:cFile)
                    let s:errorWindowHeight = len(s:errorLines)+2
                    " Limiting the error window rows
                    if s:errorWindowHeight >= 15
                        let s:errorWindowHeight = 15
                    endif

                    let s:oldCpoptions = &cpoptions
                    let s:oldErrorFormat = &errorformat

                    set cpoptions-=F
                    set errorformat=%f:%l:%m

                    execute('cfile ' . s:cFile)
                    execute('botright cwindow ' . s:errorWindowHeight)
                    call delete(s:cFile)

                    let &cpoptions = s:oldCpoptions
                    let &errorformat = s:oldErrorFormat

                    redraw
                    return
                endif
            endif
        endif
    endif
    if s:currentFile != ''
    endif
endfunction

