

# refer: https://en.wikipedia.org/wiki/Private_network

# 100.64.0.0 – 100.127.255.255

# rfc: https://www.ietf.org/rfc/rfc1700.txt
#

___x_cmd_ip_validate(){
    ___x_cmd is ip "$@"
}

___x_cmd_ip_isprivate(){
    local x_
    ___x_cmd_ip_typeno_ "$@"
    case "$x_" in
        1|8|13) ;;
        *)      return 1
    esac
}

# _type=0 # public
# _type=1 # private
# _type=2 # unicast
# _type=3 # multicast
# _type=4 # broadcast

___x_cmd_ip_type(){
    local x_
    ___x_cmd_ip_type_ "$@"
    [ "$x_" != 0 ]
}

___x_cmd_ip_type_(){
    ___x_cmd_ip_typeno_ "$@"
    case "$x_" in
        0)      x_=this                 ;;
        1)      x_=private-a            ;;
        2)      x_=public-data          ;;
        3)      x_=cable-television     ;;
        4)      x_=reserved-but-subject ;;
        5)      x_=loopback             ;;
        6)      x_=reserved             ;;
        7)      x_=link-local           ;;
        8)      x_=private-b            ;;
        9)      x_=reserve              ;;
        10)     x_=reserve              ;;
        11)     x_=test-net             ;;
        12)     x_=6to4-relay-anycast   ;;
        13)     x_=private-use-c        ;;
        14)     x_=benchmark-test       ;;
        15)     x_=reserved             ;;
        16)     x_=multicast            ;;
        17)     x_=reserved-future      ;;

        18)     x_=carrier-grade-nat    ;;  # rfc6598

        *)      x_=public               ;;
    esac
}

___x_cmd_ip_typeno_(){
    local ip="$1"
    x_=127

    case "$ip" in
        0\.*)                   x_=0 ;;
        10\.*)                  x_=1 ;;
        14\.*)                  x_=2 ;;
        24\.*)                  x_=3 ;;
        39\.*)                  x_=4 ;;
        127\.*)                 x_=5 ;;
        128\.0\.*)              x_=6 ;;
        169\.*\.*)              x_=7 ;;

        172\.*)                 ip="${ip#*\.}"
                                ! ___x_cmd is minmax 16 31  "${ip%%\.*}"  || x_=8 ;;

        191\.255\.*)            x_=9 ;;
        192\.0\.0\.*)           x_=10 ;;
        192\.0\.2\.*)           x_=11 ;;

        192\.88\.99\.*)         x_=12 ;;

        192\.168|192\.168\.*)   x_=13 ;;

        192\.18\.*)             ip="${ip#*\.}"
                                ! ___x_cmd is minmax 18 19  "${ip%%\.*}"  || x_=14 ;;

        223\.255\.255\.*)       x_=15 ;;

        224\.*)                 ! ___x_cmd is minmax 224 339 "${ip%%\.*}" || x_=16 ;;
        240\.*)                 ! ___x_cmd is minmax 240 255 "${ip%%\.*}" || x_=17 ;;

        100\.*)                 ip="${ip#*\.}"
                                ! ___x_cmd is minmax 64 127 "${ip%%\.*}" || x_=18 ;;
    esac
}

# ref: https://en.wikipedia.org/wiki/Classful_network
___x_cmd_ip_class(){
    local x_
    ___x_cmd_ip_class_ "$@" || return
    printf "%s\n" "$x_"
}

___x_cmd_ip_class_(){
    local ip="$1"
    local ip1="${ip%%\.*}"

    # assume ip is valid ...

    x_=A
    if      [ "$ip1" -ge 240 ]; then    x_=E
    elif    [ "$ip1" -ge 224 ]; then    x_=D
    elif    [ "$ip1" -ge 192 ]; then    x_=C
    elif    [ "$ip1" -ge 128 ]; then    x_=B
    fi
}

___x_cmd_ip_fill0(){
    local x_
    ___x_cmd_ip_fill0_ "$@" || return
    printf "%s\n" "$x_"
}

___x_cmd_ip_fill0_(){
    case "$1" in
        *\.*\.*\.?*)    x_="$1" ;;
        *\.*\.?*)       x_="${1%\.}.0"       ;;
        *\.?*)          x_="${1%\.}.0.0"     ;;
        *)              x_="${1%\.}.0.0.0"   ;;
    esac
}

___x_cmd_ip_info(){
    [ $# -gt 0 ] || set -- --help

    case "$1" in
        -h|--help)      ___x_cmd help -m ip info "$@"; return 0 ;;
    esac

    local x_

    ___x_cmd_ip_fill0_ "$1"
    local ip="$x_"

    printf "ip:\t%s\n" "$ip"

    ___x_cmd_ip_class_ "$ip"
    printf "class:\t%s\n" "$x_"

    ___x_cmd_ip_type_ "$ip"
    printf "type:\t%s\n" "$x_"
}


# x1_, x2_, x3_, x4_
___x_cmd_ip_parse_(){
    local x_
    ___x_cmd_ip_fill0_      "$1";


    x1_="${x_%%\.*}";    x_="${x_#"${x1_}."}"
    x2_="${x_%%\.*}";    x_="${x_#"${x2_}."}"
    x3_="${x_%%\.*}";    x4_="${x_#"${x3_}."}"
}

___x_cmd_ip_parse(){
    local x1_
    local x2_
    local x3_
    local x4_

    ___x_cmd_ip_parse_ "$@"

    printf "%s\n" "$x1_" "$x2_" "$x3_" "$x4_"
}

___x_cmd_ip_maskop_(){
    local ip="$1"
    local mask="$2"

    ___x_cmd_ip_fill0_      "$ip";      ip="$x_"
    ___x_cmd_ip_maskaddr_   "$mask";    mask="$x_"

    local x1
    local x2

    x1="${ip%%\.*}";    ip="${ip#"${x1}."}"
    x2="${mask%%\.*}";  mask="${mask#"${x2}."}"
    x_="$(( x1 & x2 ))"

    x1="${ip%%\.*}";    ip="${ip#"${x1}."}"
    x2="${mask%%\.*}";  mask="${mask#"${x2}."}"
    x_="$x_.$(( x1 & x2 ))"

    x1="${ip%%\.*}";    ip="${ip#"${x1}."}"
    x2="${mask%%\.*}";  mask="${mask#"${x2}."}"
    x_="$x_.$(( x1 & x2 ))"

    x_="$x_.$(( ip & mask ))"
}
