command -nargs=1 -complete=dir DlcPro call s:ProjectSet('dlcpro-new', '<args>')
command -nargs=1 -complete=dir DlcProOld call s:ProjectSet('dlcpro', '<args>')
command -nargs=1 -complete=dir DlcProShg call s:ProjectSet('shg', '<args>')
command -nargs=1 -complete=dir DlcProGui call s:ProjectSet('dlcpro-gui', '<args>')
command -nargs=1 -complete=dir DlcProTui call s:ProjectSet('dlcpro-tui', '<args>')
command -nargs=1 -complete=dir DlcProTuiSimulator call s:ProjectSet('dlcpro-tui-simulator', '<args>')
command -nargs=1 -complete=dir DlcProCan call s:ProjectSet('dlcpro-can', '<args>')
command -nargs=1 -complete=dir DlcProSpecalyser call s:ProjectSet('dlcpro-specalyser', '<args>')
command -nargs=1 -complete=dir Topmode call s:ProjectSet('topmode', '<args>')
command -nargs=1 -complete=dir TopmodeGui call s:ProjectSet('topmode-gui', '<args>')
command -nargs=1 -complete=dir DigiFalc call s:ProjectSet('digifalc', '<args>')
command -nargs=1 -complete=dir ServoBoard call s:ProjectSet('servoboard', '<args>')
command -nargs=1 -complete=dir DlMotor call s:ProjectSet('dl-motor', '<args>')
command -nargs=1 -complete=dir Pfd call s:ProjectSet('pfd', '<args>')
command -nargs=1 -complete=dir Tiny call s:ProjectSet('tiny', '<args>')
command -nargs=1 -complete=dir OperationPanelF1 call s:ProjectSet('operation-panel-f1', '<args>')
command -nargs=1 -complete=dir OperationPanelF4 call s:ProjectSet('operation-panel-f4', '<args>')
command -nargs=1 -complete=dir DeCoF call s:ProjectSet('decof', '<args>')
command DeviceFirmwareUpdate call s:DeviceFirmwareUpdate()
command -nargs=? -complete=file JenkinsLinter call s:Jenkins_linter('<args>')

let s:path_orig = $PATH
set titlestring=

function! s:ProjectSet(project_type, project_base_dir)
    execute "DirenvExport"
    let g:project_type = a:project_type
    let g:jenkins_url = 'http://jenkins.toptica.com'

    " directories
    if a:project_base_dir != ''
        if (isdirectory(fnamemodify(a:project_base_dir, ':p:h:h').'/src'))
            let s:ProjectBaseDir = fnamemodify(a:project_base_dir, ':p:h:h')
        elseif (isdirectory(fnamemodify(a:project_base_dir, ':p:h').'/src'))
            let s:ProjectBaseDir = fnamemodify(a:project_base_dir, ':p:h')
        else
            let s:ProjectBaseDir = fnamemodify(a:project_base_dir, ':p')
        endif
    else
        " defaults
        if (g:project_type == 'dlcpro-new')
            let s:ProjectBaseDir = '/home/stefan/dlcpro/firmware'
        elseif (g:project_type == 'dlcpro')
            let s:ProjectBaseDir = '/home/stefan/dlcpro/firmware'
        elseif (g:project_type == 'dlcpro-tui')
            let s:ProjectBaseDir = '/home/stefan/dlcpro/firmware'
        elseif (g:project_type == 'dlcpro-tui-simulator')
            let s:ProjectBaseDir = '/home/stefan/dlcpro/firmware.tui-simulator'
        elseif (g:project_type == 'dlcpro-can')
            let s:ProjectBaseDir = '/home/stefan/dlcpro/firmware'
        elseif (g:project_type == 'dlcpro-specalyser')
            let s:ProjectBaseDir = '/home/stefan/dlcpro/firmware'
        elseif (g:project_type == 'shg')
            let s:ProjectBaseDir = '/home/stefan/dlcpro/shg-firmware'
        elseif (g:project_type == 'dlcpro-gui')
            let s:ProjectBaseDir = '/home/stefan/dlcpro/pc-gui'
        elseif (g:project_type == 'topmode')
            let s:ProjectBaseDir = '/home/stefan/topmode/firmware'
        elseif (g:project_type == 'topmode-gui')
            let s:ProjectBaseDir = '/home/stefan/topmode/pc-gui'
        elseif (g:project_type == 'digifalc')
            let s:ProjectBaseDir = '/home/stefan/dlcpro/falc/firmware'
        elseif (g:project_type == 'servoboard')
            let s:ProjectBaseDir = '/home/stefan/dlcpro/mta/firmware'
        elseif (g:project_type == 'dl-motor')
            let s:ProjectBaseDir = '/home/stefan/dlcpro/dl-motor'
        elseif (g:project_type == 'pfd')
            let s:ProjectBaseDir = '/home/stefan/dlcpro/pfd/firmware'
        else
            echo "no project"
        endif
    endif

    let g:ProjectSrcDirRel = 'src'
    let s:ProjectSrcDir = s:ProjectBaseDir.'/'.g:ProjectSrcDirRel

    " Direnv
    let $DIRENV_DIR = s:ProjectBaseDir

    function! g:Compiler_version()
        if exists('g:ProjectBuildDir')
            let cmakefile = g:ProjectBuildDir . '/CMakeCache.txt'
            if filereadable(cmakefile)
                for line in readfile(cmakefile)
                    if match(line, 'NEW_COMPILER:BOOL=OFF') >= 0
                        return 'old'
                    elseif match(line, 'NEW_COMPILER:BOOL=ON') >= 0
                        return 'new'
                    endif
                endfor
            endif
        endif
        return 0
    endfunction

    " vim path
    execute 'cd '.s:ProjectSrcDir
    execute 'set path-=./**'
    execute 'set path+=' .  s:ProjectSrcDir.'/**'

    if (count(['pfd', 'tiny'], g:project_type) > 0)
        let g:ProjectBuildDir = s:ProjectSrcDir.'/.build/target/firmware/Debug'
        let g:DebugRemote = v:true
        let g:termdebugger = 'arm-none-eabi-gdb'
        let s:gdb_connect_script = g:ProjectBuildDir.'/gdbinit'
    elseif (count(['dlcpro', 'dlcpro-new'], g:project_type) > 0)
        set wildignore-=**/firmware/src/device-control/**
        set wildignore+=**/shg-firmware/**
        set titlestring=%<%t\ (%{expand('%:p:h')})%=project:\ %{g:project_type}\ \ \ \ compiler:\ %{g:Compiler_version()}
        let g:DeviceIP = 'dlc_pro__040083'
        let g:DebugRemote = v:true
        let g:ProjectBuildDir = s:ProjectSrcDir.'/.build/'.g:project_type
        if (g:project_type == 'dlcpro-new')
            let s:firware_file_name = 'DLCpro-archive-SSW7.fw'
        else
            let s:firware_file_name = 'DLCpro-archive.fw'
        endif
        let s:firmware_file = g:ProjectBuildDir.'/artifacts/'.s:firware_file_name
        let g:DeviceType = 'TApro'
        let g:PowerswitchIP = 'elab-stefan'
        let g:Powerplug = '1'
        let g:termdebugger = 'arm-none-eabi-gdb'
        let s:gdb_connect_script = g:ProjectBuildDir.'/gdbinit'
        command! DlcProGuiStart execute("!~/dlcpro/pc-gui/start-gui&")
    elseif ((g:project_type == 'dlcpro-tui') || (g:project_type == 'dlcpro-tui-simulator'))
        let s:Program = '/user-interface/src/user-interface'
        let s:Elffile = s:Program
        let g:ProgramRemote = '/opt/app/bin/user-interface'
        set wildignore-=**/firmware/src/device-control/**
        set wildignore+=**/shg-firmware/**
        let g:DeviceIP = 'dlc_pro__040083'
        let g:DebugRemote = v:true
    elseif (g:project_type == 'dlcpro-can')
        let s:Program = '/canopen/can-updater'
        let s:Elffile = s:Program
        let g:ProgramRemote = '/opt/app/bin/can-updater'
        set wildignore-=**/firmware/src/device-control/**
        set wildignore+=**/shg-firmware/**
        let g:DeviceIP = 'dlc_pro__040083'
        let g:DebugRemote = v:true
    elseif (g:project_type == 'dlcpro-specalyser')
        let s:Program = '/specalyser/specalyser'
        let s:Elffile = s:Program
        let g:ProgramRemote = '/opt/app/bin/specalyser'
        set wildignore-=**/firmware/src/device-control/**
        set wildignore+=**/shg-firmware/**
        let g:DeviceIP = 'dlc_pro__040083'
        let g:DebugRemote = v:true
    elseif (g:project_type == 'shg')
        let s:Program = '/shg-firmware/device-control/device-control-shg'
        let s:Elffile = s:Program
        let g:ProgramRemote = '/opt/app/bin/device-control-shg'
        set wildignore-=**/shg-firmware/**
        set wildignore+=**/firmware/src/device-control/**
        let g:DeviceIP = 'dlc_pro__040083'
        let g:DebugRemote = v:true
        " let g:GdbPort = '6666'
        " let g:SshOpts = '-o ForwardAgent=yes -o ProxyCommand="ssh -o RemoteCommand=none -q -W shg:22 root@%h" -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o LogLevel=ERROR'
        " let g:SshOpts2 = "-L localhost:1998:localhost:1998 -L localhost:1999:localhost:1999"
    elseif (g:project_type == 'dlcpro-gui')
        let g:ProjectBuildDir = s:ProjectSrcDir.'/.build' " FIXME (for DeviceDebug)
        let s:Program = '/TOPAS_DLC_pro'
        let s:Elffile = s:Program
        let g:termdebugger = 'gdb'
        let g:DebugRemote = v:false
        command! DlcProGuiStart execute("!~/dlcpro/pc-gui/start-gui&")
    elseif (g:project_type == 'topmode')
        let g:ProjectBuildDir = s:ProjectSrcDir.'/.build/'
        let g:DeviceIP = 'topmode_stefan'
        let g:DebugRemote = v:true
        let g:termdebugger = 'arm-none-eabi-gdb'
        let s:gdb_connect_script = g:ProjectBuildDir.'/gdbinit'
        let s:firware_file_name = 'TopMode-CHARM-Control-1.5.4-dev.fw'
        let s:firmware_file = g:ProjectBuildDir.'/artifacts/'.s:firware_file_name
        command! TopmodeGuiStart execute("!~/topmode/pc-gui/start-gui&")
    elseif (g:project_type == 'topmode-gui')
        let g:DebugRemote = v:false
        command! TopmodeGuiStart execute("!~/topmode/pc-gui/start-gui&")
    elseif (g:project_type == 'digifalc')
        let s:Program = '/digifalc-image.bin'
        let s:Elffile = '/application/digifalc.elf'
        let g:DebugRemote = v:true
        let g:termdebugger = 'arm-none-eabi-gdb'
    elseif (g:project_type == 'servoboard')
        let s:Program = '/servo-board-image.bin'
        let s:Elffile = '/application/servo-board.elf'
        let g:DebugRemote = v:true
        let g:termdebugger = 'arm-none-eabi-gdb'
    elseif (g:project_type == 'dl-motor')
        let s:Program = '/dl-motor-image.bin'
        let s:Elffile = '/application/dl-motor.elf'
        let g:DebugRemote = v:true
        let g:termdebugger = 'arm-none-eabi-gdb'
    elseif (g:project_type == 'operation-panel-f1')
        let g:stm32_target = 'STM32F10X'
        let s:Program = '/firmware/operation_panel_'.g:stm32_target.'.bin'
        let s:Elffile = '/firmware/operation_panel_'.g:stm32_target.'.elf'
        " let s:makegoals = ['artifacts']
        let g:DebugRemote = v:true
        " let g:GdbPort = '3333'
        let g:termdebugger = 'arm-none-eabi-gdb'
        " let s:stm_cfg = 'stm32f1x'
    elseif (g:project_type == 'operation-panel-f4')
        let g:stm32_target = 'STM32F4XX'
        let s:Program = '/firmware/operation_panel_'.g:stm32_target.'.bin'
        let s:Elffile = '/firmware/operation_panel_'.g:stm32_target.'.elf'
        " let s:makegoals = ['artifacts']
        let g:DebugRemote = v:true
        " let g:GdbPort = '3333'
        let g:termdebugger = 'arm-none-eabi-gdb'
        " let s:stm_cfg = 'stm32f4x'
    elseif (g:project_type == 'decof')
        " let s:makegoals = ['all']
        let g:DebugRemote = v:false
    else
        echo "no project"
    endif

    let g:BuildType = 'Default'

    " Settings for invoke development
    let s:invoke = 'invoke'
    let s:tasks_file_dev = '/home/stefan/tools/invoke/'.g:project_type.'/tasks.py'
    if filereadable(s:tasks_file_dev)
        call system('cp '.s:tasks_file_dev.' tasks.py') " copy development version to project
    elseif filereadable('tasks.py')
        " do nothing
    else
        echoerr 'tasks.py not found'
    endif

    " editor settings
    set spell spelllang=en,de
    set expandtab
    set cinoptions=l1,g2,h2,N-2,t0,+0,(0,w1,Ws,m1,)100,*100
    set textwidth=120

    " python tags
    execute "set tags+=" . s:ProjectBaseDir . '/tags'

    " compiler
    compiler gcc
    if exists("s:Program")
        let g:Program = g:ProjectBuildDir.s:Program
        let g:Elffile = g:ProjectBuildDir.s:Elffile
    endif
    command! -complete=customlist,GetAllMakeCompletions -nargs=* MakeCmd call s:Make('<args>', 'async')

    " configure quickfix window for asyncrun
    augroup QuickfixStatus
        autocmd BufWinEnter quickfix setlocal 
                    \ statusline=%t\ [%{g:asyncrun_status}]\ %{exists('w:quickfix_title')?\ '\ '.w:quickfix_title\ :\ ''}\ %=%-15(%l,%c%V%)\ %P
    augroup END

    function! s:DeviceFirmwareUpdate()
        call s:Make('kill', 'bang')
        call s:Make('flash', 'bang')
        call s:Make('run', 'bang')
    endfunction

    command! DeviceDebug call s:DeviceDebug(0)
    command! DeviceDebugAttach call s:DeviceDebug(1)

    " little helpers
    let $QT_FONT_DPI=96 " Size for qt-application in debugger


endfunction

" ====
" Make
" ====

" Add default value for all given options, if not already set
function! s:SetDefaults(commandline, option_defaults)

    let g:option_defaults = [
                \ {'name': '--project', 'value': g:project_type},
                \ {'name': '--device-ip', 'value': g:DeviceIP},
                \ {'name': '--build-type', 'value': g:BuildType},
                \ {'name': '--firmware-file', 'value': s:firmware_file},
                \ {'name': '--version-file', 'value': g:ProjectBuildDir.'/artifacts/VERSION'},
                \ {'name': '--laser1-type', 'value': g:DeviceType},
                \ {'name': '--powerswitch-ip', 'value': g:PowerswitchIP},
                \ {'name': '--powerplug', 'value': g:Powerplug},
                \ {'name': '--firmware-file', 'value': s:firmware_file},
                \ ]

    let commandline = a:commandline
    let task = split(commandline)[0]
    let options_allowed = system(s:invoke.' --complete -- '.task.' -')
    for option_default in a:option_defaults
        let option = option_default['name']
        let value = option_default['value']
        if options_allowed =~ option && commandline !~ option
            let commandline .= ' '.option.'='.value
        endif
    endfor
    return commandline
endfunction

function! s:Make(args, async_mode)
    " Add defaults for options
    let l:options = s:SetDefaults(a:args, g:option_defaults)

    if (a:async_mode == 'background')
        call system(s:invoke.' -e '.l:options.'&')
    else
        call asyncrun#quickfix_toggle(10, 1)
        let &makeprg = s:invoke.' -e'
        execute 'AsyncRun -mode='.a:async_mode.' -save=2 -program=make @ '.l:options
    endif
endfunction

" Tab-completion is done with plugin vim-bash-completion
let $BASH_COMPLETION_DIR = '/home/stefan/.invoke'
let invoke_completion_file = $BASH_COMPLETION_DIR.'/bash_completion'
if !filereadable(invoke_completion_file)
    call system('invoke --print-completion-script bash > '.invoke_completion_file)
endif
function! GetAllMakeCompletions(ArgLead, CmdLine, CursorPos)
    let l:words = split(a:CmdLine)
    let l:words[0] = 'invoke'
    let l:command = join(l:words)
    return bash#complete(l:command)
endfunction

function! g:JLinkSWOviewer()
    let cmd = '/JLinkSWOViewerCLExe -device STM32H743ZI -itmmask 0xffffffff -swofreq 450000'
    call asyncrun#quickfix_toggle(10, 1)
    execute 'AsyncRun -mode=async @ ' . cmd
endfunction

function! s:SendToDebugger(command)
    call term_sendkeys('', a:command . "\n")
endfunction

function! s:StartDebugger(elffile, attach)
    if (a:attach == 0)
        Termdebug
    else
        execute 'Termdebug ' . a:elffile
    endif
endfunction

function! s:DeviceDebug(attach)
    if g:DebugRemote
        call s:Make('kill', 'bang')
        " Close quickfix window
        execute 'cclose'
        autocmd! User TermdebugStartPre
        autocmd! User TermdebugStartPost
        autocmd! User TermdebugStopPost
        call s:Make('gdb-server', 'background')
        sleep 2
        if exists('s:gdb_connect_script')
            autocmd User TermdebugStartPost call term_sendkeys('',"source ".s:gdb_connect_script."\n")
        endif
        Termdebug
        call s:SendToDebugger('set confirm off')
        " Close Program window
        execute '2hide'
    else
        call s:StartDebugger(g:Elffile, a:attach)
        call s:SendToDebugger('file '.g:Elffile)
        call s:SendToDebugger('break main')
        call s:SendToDebugger('run')
    endif
endfunction

" ------
" Pandoc
" ------
command TopticaBeamer execute('!pandoc -s -t beamer -H toptica-style.tex -o %:r.pdf %')

" -----------------
" Jenkins validator
" -----------------
function! s:Jenkins_linter(jenkinsfile)
    if a:jenkinsfile == ''
        let jenkinsfile = expand("%")
    else
        let jenkinsfile = a:jenkinsfile
    endif

    if !filereadable(jenkinsfile)
        echoerr("File not found: ".jenkinsfile)
        return
    endif

    if !exists("s:user")
        let s:user = input("jenkins-user:")
    endif
    if !exists("s:passwd")
        let s:passwd = inputsecret("password:")
        echo "\n"
    endif
    let user_pass = s:user.":".s:passwd

    let l:out = system("curl --no-progress-meter --user '".user_pass."' -X POST -F 'jenkinsfile=<".jenkinsfile."' ".g:jenkins_url."/pipeline-model-converter/validate")
    if match(l:out, "HTTP ERROR 401") >= 0
        " Forget credentials on authorization error
        unlet s:user
        unlet s:passwd
    endif
    echo l:out
endfunction