#compdef chflags

local flags args own='-g *(-u$EUID)'

addflags() {
  for 1 2; do
    if [[ $1 = no* ]]; then
      flags+=("(${1#no})$1[set the $2 flag]"
               "($1)${1#no}[unset the $2 flag]")
    else
      flags+=("(no$1)$1[set the $2 flag]"
               "($1)no$1[unset the $2 flag]")
    fi
  done
}

addflags \
  uappnd 'user append-only' \
  uchg 'user immutable'

if (( ! EUID )); then
  addflags \
    arch archived \
    nodump nodump \
    sappnd 'system append-only' \
    schg 'system immutable'
  unset own
fi

if [[ $OSTYPE = (darwin|dragonfly|freebsd|netbsd)* ]]; then
  addflags opaque opaque

  if [[ $OSTYPE = darwin* ]]; then
    addflags hidden hidden
  fi

  if [[ $OSTYPE = (dragonfly|freebsd)* ]]; then
    addflags uunlnk 'user undeletable'
    (( EUID )) || addflags sunlnk 'system undeletable'
  fi

  [[ $OSTYPE = dragonflybsd* ]] && {
    addflags \
      cache XXX \
      nouhistory 'user nohistory'

    (( EUID )) || addflags \
      noscache XXX \
      noshistory 'system nohistory'
  }

  [[ $OSTYPE = freebsd* ]] && addflags \
    uarch archive \
    uhidden hidden \
    uoffline offline \
    urdonly 'DOS, Windows and CIFS readonly' \
    ureparse 'Windows reparse point' \
    usparse 'sparse file' \
    usystem 'DOS, Windows and CIFS system'

fi

if [[ $OSTYPE = (darwin|dragonfly|freebsd)* ]]; then
  args=(
    "-f[don't display diagnostic messages]"
    '-v[verbose output]'
  )
fi

_arguments -s -A "-*" : $args \
  - opth \
  '-h[act on symlinks]' \
  - optR \
  '-R[recurse directories]' \
  '(-L -P)-H[follow symlinks on the command line (specify with -R)]' \
  '(-H -P)-L[follow all symlinks (specify with -R)]' \
  '(-L -H)-P[do not follow symlinks (specify with -R)]' \
  ':file flag:_values -s , "file flags" $flags[@]' \
  '*:file:_files "$own"'
