if polyglot#init#is_disabled(expand('<sfile>:p'), 'autohotkey', 'indent/autohotkey.vim')
  finish
endif

" Vim indent file
" Language:   AutoHotkey
" Maintainer: Hirotoshi Namikawa <hnamikaw1@gmail.com>
" URL:        http://github.com/hnamikaw/vim-autohotkey
" License:    Same as Vim.

if exists('b:did_indent')
    finish
endif

setlocal autoindent
setlocal indentexpr=GetAutoHotkeyIndent()
setlocal indentkeys=!^F,o,O,0{,0},=if,=else,=return
setlocal expandtab

let b:undo_indent = 'setlocal '.join([
            \   'autoindent<',
            \   'indentexpr<',
            \   'indentkeys<',
            \   'expandtab<',
            \ ])

let s:TRUE = !0
let s:FALSE = 0

" Check BEGIN BLOCK
" TRUE:
" {
" { ; with comment
" if {
" if { ; with comment
"
" FALSE:
" ; if { comment
" sleep 1000 ; {
function! IsBeginBlockByStr(str)
    return a:str =~? '^[^;]*{\s*\(;.*\)\?$' ? s:TRUE : s:FALSE
endfunction

" Check END BLOCK
" TRUE:
" }
" } ; with comment
" } else {
" } else { ; with comment
"
" FALSE:
" ; } else {
function! IsEndBlockByStr(str)
    return a:str =~? '^\s*}.*\(;.*\)\?$' ? s:TRUE : s:FALSE
endfunction

" Check DOUBLE CORON
" TRUE:
" LAlt up::
" LAlt up:: ; with comment
"
" FALSE:
" ; LAlt up::
" sleep 1000 ; ::
function! IsDoubleCoronByStr(str)
    return a:str =~? '^[^;]*::\s*\(;.*\)\?$' ? s:TRUE : s:FALSE
endfunction

" Check RETURN
" TRUE:
" return
" return 1
" return ; with comment
"
" FALSE:
" ; return
function! IsReturnByStr(str)
    return a:str =~? '^\s*return.*\(;.*\)\?$' ? s:TRUE : s:FALSE
endfunction

" Check IF STATEMENT(without BLOCK)
" TRUE:
" if
" if ; with comment
" else
" else ; with comment
"
" FALSE:
" if {
" else {
function! IsIfStatementByStr(str)
    return a:str =~? '^\s*\(if\|else\)[^{]*\(;.*\)\?$' ? s:TRUE : s:FALSE
endfunction

" Check inside of BLOCK.
" TRUE:
" if {
"     hogehoge
"     fugafuga <--- line_num
" }
"
" FALSE:
" foobar <--- line_num
function! IsInsideOfBlockByNum(line_num)
    let block_indent_level = 0

    for scan_line_num in range(1, a:line_num)
        if IsBeginBlockByStr(getline(scan_line_num)) == s:TRUE
            let block_indent_level += 1
        endif

        if IsEndBlockByStr(getline(scan_line_num)) == s:TRUE
            let block_indent_level -= 1
        endif
    endfor

    return block_indent_level >= 1 ? s:TRUE : s:FALSE
endfunction

function! AddIndentByInd(indent)
    return a:indent + &l:shiftwidth
endfunction

function! UnIndentByInd(indent)
    return a:indent - &l:shiftwidth
endfunction

function! GetAutoHotkeyIndent()
    let  l0_num = v:lnum
    let  l1_num = v:lnum - 1
    let pl1_num = prevnonblank(l1_num)
    let pl2_num = prevnonblank(pl1_num - 1)

    let  l0_str = getline(l0_num)
    let pl1_str = getline(pl1_num)
    let pl2_str = getline(pl2_num)
    let pl1_ind = indent(pl1_num)
    let pl2_ind = indent(pl2_num)

    " Case: Next line of IF STATEMENT(without BLOCK)
    " if bar = 1
    "     callFunc1() <--- AddIndent
    "
    " if bar = 1
    " { <--- No! AddIndent
    if IsIfStatementByStr(pl1_str) == s:TRUE && IsBeginBlockByStr(l0_str) == s:FALSE
        return AddIndentByInd(pl1_ind)
    endif

    " Case: End of IF STATEMENT(without BLOCK)
    " if bar = 1
    "     callFunc1()
    " if bar = 2 <--- UnIndent
    "
    " Case: End of IF STATEMENT(without BLOCK) and END BLOCK(of outer block)
    " if foo
    " {
    "     if bar = 3
    "         callFunc3()
    " } <--- UnIndent (2level)
    if IsIfStatementByStr(pl2_str) == s:TRUE && IsBeginBlockByStr(pl1_str) == s:FALSE
        if IsEndBlockByStr(l0_str) == s:FALSE
            return UnIndentByInd(pl1_ind)
        else
            return UnIndentByInd(pl2_ind)
        endif
    endif

    " Case: Next line of BEGIN BLOCK
    " Swap(ByRef Left, ByRef Right)
    " {
    "     temp := Left <--- AddIndent
    "     Left := Right
    "     Right := temp
    " }
    if IsBeginBlockByStr(pl1_str) == s:TRUE
        return AddIndentByInd(pl1_ind)
    endif

    " Case: END BLOCK
    " Swap(ByRef Left, ByRef Right)
    " {
    "     temp := Left
    "     Left := Right
    "     Right := temp
    " } <--- UnIndent
    if IsEndBlockByStr(l0_str) == s:TRUE
        return UnIndentByInd(pl1_ind)
    endif

    " Case: Next line of DOUBLE CORON
    " #n::
    "     Run Notepad <--- AddIndent
    " return
    if IsDoubleCoronByStr(pl1_str) == s:TRUE
        return AddIndentByInd(pl1_ind)
    endif

    " Case: RETURN
    " Note: It is not nothing if in the BLOCK.
    " #n::
    "     Run Notepad
    " return <--- UnIndent
    " ~~~
    " if foo
    " {
    "     callFunc1()
    "     return <--- No! UnIndent
    " }
    if IsReturnByStr(l0_str) == s:TRUE && IsInsideOfBlockByNum(l0_num) == s:FALSE
        return UnIndentByInd(pl1_ind)
    endif

    " Case: Top line.
    if pl1_num == 0
        return 0
    endif

    " Case: It does not match anything.
    return pl1_ind
endfunction

let b:did_indent = 1
