/**
 * Copyright 2024 Beijing Baolande Software Corporation
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * Runtime Library Exception to the Apache 2.0 License:
 *
 * As an exception, if you use this Software to compile your source code and
 * portions of this Software are embedded into the binary product as a result,
 * you may redistribute such product without providing attribution as would
 * otherwise be required by Sections 4(a), 4(b) and 4(d) of the License.
 */

package redis_sdk.client.api

public interface ProtocolKeyword {

    /**
     *
     * @return byte[] encoded representation.
     */
    func getBytes(): Array<Byte>

    /**
     *
     * @return name of the command.
     */
    func name(): String
}

public enum CommandType <: ProtocolKeyword {

    // Authentication
    | ACL
    | AUTH
    | AUTH2

    // Connection
    | ECHO
    | HELLO
    | PING
    | QUIT
    | READONLY
    | READWRITE
    | RESET
    | SELECT
    | SWAPDB

    // Server
    | BGREWRITEAOF
    | BGSAVE
    | CLIENT
    | COMMAND
    | CONFIG
    | DBSIZE
    | DEBUG
    | FLUSHALL
    | FLUSHDB
    | INFO
    | MYID
    | LASTSAVE
    | REPLICAOF
    | ROLE
    | MONITOR
    | SAVE
    | SHUTDOWN
    | SLAVEOF
    | SLOWLOG
    | SYNC
    | MEMORY

    // Keys
    | COPY
    | DEL
    | DUMP
    | EXISTS
    | EXPIRE
    | EXPIREAT
    | EXPIRETIME
    | KEYS
    | MIGRATE
    | MOVE
    | OBJECT
    | PERSIST
    | PEXPIRE
    | PEXPIREAT
    | PEXPIRETIME
    | PTTL
    | RANDOMKEY
    | RENAME
    | RENAMENX
    | RESTORE
    | TOUCH
    | TTL
    | TYPE
    | SCAN
    | UNLINK

    // String
    | APPEND
    | GET
    | GETDEL
    | GETEX
    | GETRANGE
    | GETSET
    | MGET
    | MSET
    | MSETNX
    | SET
    | SETEX
    | PSETEX
    | SETNX
    | SETRANGE
    | STRLEN
    | STRALGO
    | SUBSTR

    // Numeric
    | DECR
    | DECRBY
    | INCR
    | INCRBY
    | INCRBYFLOAT

    // List
    | BLMOVE
    | BLMPOP
    | BLPOP
    | BRPOP
    | BRPOPLPUSH
    | LINDEX
    | LINSERT
    | LLEN
    | LMOVE
    | LMPOP
    | LPOP
    | LPOS
    | LPUSH
    | LPUSHX
    | LRANGE
    | LREM
    | LSET
    | LTRIM
    | RPOP
    | RPOPLPUSH
    | RPUSH
    | RPUSHX
    | SORT
    | SORT_RO

    // Hash
    | HDEL
    | HEXISTS
    | HGET
    | HGETALL
    | HINCRBY
    | HINCRBYFLOAT
    | HKEYS
    | HLEN
    | HSTRLEN
    | HMGET
    | HMSET
    | HRANDFIELD
    | HSET
    | HSETNX
    | HVALS
    | HSCAN

    // Transaction
    | DISCARD
    | EXEC
    | MULTI
    | UNWATCH
    | WATCH

    // HyperLogLog
    | PFADD
    | PFCOUNT
    | PFMERGE

    // Pub/Sub
    | PSUBSCRIBE
    | PUBLISH
    | PUNSUBSCRIBE
    | SUBSCRIBE
    | UNSUBSCRIBE
    | PUBSUB

    // Shard Pub/Sub
    | SSUBSCRIBE
    | SUNSUBSCRIBE
    | SPUBLISH

    // Sets
    | SADD
    | SCARD
    | SDIFF
    | SDIFFSTORE
    | SINTER
    | SINTERCARD
    | SINTERSTORE
    | SISMEMBER
    | SMISMEMBER
    | SMEMBERS
    | SMOVE
    | SPOP
    | SRANDMEMBER
    | SREM
    | SSCAN
    | SUNION
    | SUNIONSTORE

    // Sorted Set
    | BZMPOP
    | BZPOPMIN
    | BZPOPMAX
    | ZADD
    | ZCARD
    | ZCOUNT
    | ZDIFF
    | ZDIFFSTORE
    | ZINCRBY
    | ZINTER
    | ZINTERCARD
    | ZINTERSTORE
    | ZLEXCOUNT
    | ZMSCORE
    | ZMPOP
    | ZPOPMIN
    | ZPOPMAX
    | ZRANDMEMBER
    | ZRANGE
    | ZRANGEBYSCORE
    | ZRANGESTORE
    | ZRANK
    | ZREM
    | ZREMRANGEBYRANK
    | ZREMRANGEBYSCORE
    | ZREVRANGE
    | ZREVRANGEBYLEX
    | ZREVRANGEBYSCORE
    | ZREVRANK
    | ZSCAN
    | ZSCORE
    | ZUNION
    | ZUNIONSTORE
    | ZREMRANGEBYLEX
    | ZRANGEBYLEX

    // Functions
    | FCALL
    | FCALL_RO
    | FUNCTION

    // Scripting
    | EVAL
    | EVAL_RO
    | EVALSHA
    | EVALSHA_RO
    | SCRIPT

    // Bits
    | BITCOUNT
    | BITFIELD
    | BITFIELD_RO
    | BITOP
    | GETBIT
    | SETBIT
    | BITPOS

    // Geo
    | GEOADD
    | GEODIST
    | GEOHASH
    | GEOENCODE
    | GEODECODE
    | GEOPOS
    | GEORADIUS
    | GEORADIUS_RO
    | GEORADIUSBYMEMBER
    | GEORADIUSBYMEMBER_RO
    | GEOSEARCH
    | GEOSEARCHSTORE

    // Stream
    | XACK
    | XADD
    | XAUTOCLAIM
    | XCLAIM
    | XDEL
    | XGROUP
    | XINFO
    | XLEN
    | XPENDING
    | XRANGE
    | XREVRANGE
    | XREAD
    | XREADGROUP
    | XTRIM

    // JSON
    | JSONSET
    | JSONMSET
    | JSONGET
    | JSONMGET
    | JSONARRAPPEND
    | JSONARRINDEX
    | JSONARRINSERT
    | JSONARRLEN
    | JSONARRPOP
    | JSONARRTRIM
    | JSONCLEAR
    | JSONDEBUG
    | JSONDEL
    | JSONMERGE
    | JSONNUMINCRBY
    | JSONNUMMULTBY
    | JSONOBJKEYS
    | JSONOBJLEN
    | JSONSTRAPPEND
    | JSONSTRLEN
    | JSONTOGGLE
    | JSONTYPE
    | JSONRESP

    // Others
    | TIME
    | WAIT

    // Module
    | MODULE

    // Server Management
    | LOLWUT
    | LATENCY
    | WAITAOF

    // SENTINEL
    | SENTINEL

    // CLUSTER
    | ASKING
    | CLUSTER

    /**
     *
     * @return byte[] encoded representation.
     */
    public func getBytes(): Array<Byte> {
        return name().toArray()
    }

    /**
     *  获取命令的名称
     *
     * @return name of the command.
     */
    public func name(): String {
        match (this) {

            // Authentication
            case ACL => return "ACL"
            case AUTH => return "AUTH"
            case AUTH2 => return "AUTH2"

            // Connection 
            case ECHO => return "ECHO"
            case HELLO => return "HELLO"
            case PING => return "PING"
            case QUIT => return "QUIT"
            case READONLY => return "READONLY"
            case READWRITE => return "READWRITE"
            case RESET => return "RESET"
            case SELECT => return "SELECT"
            case SWAPDB => return "SWAPDB"

            // Server
            case BGREWRITEAOF => return "BGREWRITEAOF"
            case BGSAVE => return "BGSAVE"
            case CLIENT => return "CLIENT"
            case COMMAND => return "COMMAND"
            case CONFIG => return "CONFIG"
            case DBSIZE => return "DBSIZE"
            case DEBUG => return "DEBUG"
            case FLUSHALL => return "FLUSHALL"
            case FLUSHDB => return "FLUSHDB"
            case INFO => return "INFO"
            case MYID => return "MYID"
            case LASTSAVE => return "LASTSAVE"
            case REPLICAOF => return "REPLICAOF"
            case ROLE => return "ROLE"
            case MONITOR => return "MONITOR"
            case SAVE => return "SAVE"
            case SHUTDOWN => return "SHUTDOWN"
            case SLAVEOF => return "SLAVEOF"
            case SLOWLOG => return "SLOWLOG"
            case SYNC => return "SYNC"
            case MEMORY => return "MEMORY"

            // Keys
            case COPY => return "COPY"
            case DEL => return "DEL"
            case DUMP => return "DUMP"
            case EXISTS => return "EXISTS"
            case EXPIRE => return "EXPIRE"
            case EXPIREAT => return "EXPIREAT"
            case EXPIRETIME => return "EXPIRETIME"
            case KEYS => return "KEYS"
            case MIGRATE => return "MIGRATE"
            case MOVE => return "MOVE"
            case OBJECT => return "OBJECT"
            case PERSIST => return "PERSIST"
            case PEXPIRE => return "PEXPIRE"
            case PEXPIREAT => return "PEXPIREAT"
            case PEXPIRETIME => return "PEXPIRETIME"
            case PTTL => return "PTTL"
            case RANDOMKEY => return "RANDOMKEY"
            case RENAME => return "RENAME"
            case RENAMENX => return "RENAMENX"
            case RESTORE => return "RESTORE"
            case TOUCH => return "TOUCH"
            case TTL => return "TTL"
            case TYPE => return "TYPE"
            case SCAN => return "SCAN"
            case UNLINK => return "UNLINK"

            // String
            case APPEND => return "APPEND"
            case GET => return "GET"
            case GETDEL => return "GETDEL"
            case GETEX => return "GETEX"
            case GETRANGE => return "GETRANGE"
            case GETSET => return "GETSET"
            case MGET => return "MGET"
            case MSET => return "MSET"
            case MSETNX => return "MSETNX"
            case SET => return "SET"
            case SETEX => return "SETEX"
            case PSETEX => return "PSETEX"
            case SETNX => return "SETNX"
            case SETRANGE => return "SETRANGE"
            case STRLEN => return "STRLEN"
            case STRALGO => return "STRALGO"
            case SUBSTR => return "SUBSTR"

            // Numeric
            case DECR => return "DECR"
            case DECRBY => return "DECRBY"
            case INCR => return "INCR"
            case INCRBY => return "INCRBY"
            case INCRBYFLOAT => return "INCRBYFLOAT"

            // List
            case BLMOVE => return "BLMOVE"
            case BLMPOP => return "BLMPOP"
            case BLPOP => return "BLPOP"
            case BRPOP => return "BRPOP"
            case BRPOPLPUSH => return "BRPOPLPUSH"
            case LINDEX => return "LINDEX"
            case LINSERT => return "LINSERT"
            case LLEN => return "LLEN"
            case LMOVE => return "LMOVE"
            case LMPOP => return "LMPOP"
            case LPOP => return "LPOP"
            case LPOS => return "LPOS"
            case LPUSH => return "LPUSH"
            case LPUSHX => return "LPUSHX"
            case LRANGE => return "LRANGE"
            case LREM => return "LREM"
            case LSET => return "LSET"
            case LTRIM => return "LTRIM"
            case RPOP => return "RPOP"
            case RPOPLPUSH => return "RPOPLPUSH"
            case RPUSH => return "RPUSH"
            case RPUSHX => return "RPUSHX"
            case SORT => return "SORT"
            case SORT_RO => return "SORT_RO"

            // Hash
            case HDEL => return "HDEL"
            case HEXISTS => return "HEXISTS"
            case HGET => return "HGET"
            case HGETALL => return "HGETALL"
            case HINCRBY => return "HINCRBY"
            case HINCRBYFLOAT => return "HINCRBYFLOAT"
            case HKEYS => return "HKEYS"
            case HLEN => return "HLEN"
            case HSTRLEN => return "HSTRLEN"
            case HMGET => return "HMGET"
            case HMSET => return "HMSET"
            case HRANDFIELD => return "HRANDFIELD"
            case HSET => return "HSET"
            case HSETNX => return "HSETNX"
            case HVALS => return "HVALS"
            case HSCAN => return "HSCAN"

            // Transaction
            case DISCARD => return "DISCARD"
            case EXEC => return "EXEC"
            case MULTI => return "MULTI"
            case UNWATCH => return "UNWATCH"
            case WATCH => return "WATCH"

            // HyperLogLog
            case PFADD => return "PFADD"
            case PFCOUNT => return "PFCOUNT"
            case PFMERGE => return "PFMERGE"

            // Pub/Sub
            case PSUBSCRIBE => return "PSUBSCRIBE"
            case PUBLISH => return "PUBLISH"
            case PUNSUBSCRIBE => return "PUNSUBSCRIBE"
            case SUBSCRIBE => return "SUBSCRIBE"
            case UNSUBSCRIBE => return "UNSUBSCRIBE"
            case PUBSUB => return "PUBSUB"

            // Shard Pub/Sub
            case SSUBSCRIBE => return "SSUBSCRIBE"
            case SUNSUBSCRIBE => return "SUNSUBSCRIBE"
            case SPUBLISH => return "SPUBLISH"

            // Sets
            case SADD => return "SADD"
            case SCARD => return "SCARD"
            case SDIFF => return "SDIFF"
            case SDIFFSTORE => return "SDIFFSTORE"
            case SINTER => return "SINTER"
            case SINTERCARD => return "SINTERCARD"
            case SINTERSTORE => return "SINTERSTORE"
            case SISMEMBER => return "SISMEMBER"
            case SMISMEMBER => return "SMISMEMBER"
            case SMEMBERS => return "SMEMBERS"
            case SMOVE => return "SMOVE"
            case SPOP => return "SPOP"
            case SRANDMEMBER => return "SRANDMEMBER"
            case SREM => return "SREM"
            case SSCAN => return "SSCAN"
            case SUNION => return "SUNION"
            case SUNIONSTORE => return "SUNIONSTORE"

            // Sorted Set
            case BZMPOP => return "BZMPOP"
            case BZPOPMIN => return "BZPOPMIN"
            case BZPOPMAX => return "BZPOPMAX"
            case ZADD => return "ZADD"
            case ZCARD => return "ZCARD"
            case ZCOUNT => return "ZCOUNT"
            case ZDIFF => return "ZDIFF"
            case ZDIFFSTORE => return "ZDIFFSTORE"
            case ZINCRBY => return "ZINCRBY"
            case ZINTER => return "ZINTER"
            case ZINTERCARD => return "ZINTERCARD"
            case ZINTERSTORE => return "ZINTERSTORE"
            case ZLEXCOUNT => return "ZLEXCOUNT"
            case ZMSCORE => return "ZMSCORE"
            case ZMPOP => return "ZMPOP"
            case ZPOPMIN => return "ZPOPMIN"
            case ZPOPMAX => return "ZPOPMAX"
            case ZRANDMEMBER => return "ZRANDMEMBER"
            case ZRANGE => return "ZRANGE"
            case ZRANGEBYSCORE => return "ZRANGEBYSCORE"
            case ZRANGESTORE => return "ZRANGESTORE"
            case ZRANK => return "ZRANK"
            case ZREM => return "ZREM"
            case ZREMRANGEBYRANK => return "ZREMRANGEBYRANK"
            case ZREMRANGEBYSCORE => return "ZREMRANGEBYSCORE"
            case ZREVRANGE => return "ZREVRANGE"
            case ZREVRANGEBYLEX => return "ZREVRANGEBYLEX"
            case ZREVRANGEBYSCORE => return "ZREVRANGEBYSCORE"
            case ZREVRANK => return "ZREVRANK"
            case ZSCAN => return "ZSCAN"
            case ZSCORE => return "ZSCORE"
            case ZUNION => return "ZUNION"
            case ZUNIONSTORE => return "ZUNIONSTORE"
            case ZREMRANGEBYLEX => return "ZREMRANGEBYLEX"
            case ZRANGEBYLEX => return "ZRANGEBYLEX"

            // Functions
            case FCALL => return "FCALL"
            case FCALL_RO => return "FCALL_RO"
            case FUNCTION => return "FUNCTION"

            // Scripting
            case EVAL => return "EVAL"
            case EVAL_RO => return "EVAL_RO"
            case EVALSHA => return "EVALSHA"
            case EVALSHA_RO => return "EVALSHA_RO"
            case SCRIPT => return "SCRIPT"

            // Bits
            case BITCOUNT => return "BITCOUNT"
            case BITFIELD => return "BITFIELD"
            case BITFIELD_RO => return "BITFIELD_RO"
            case BITOP => return "BITOP"
            case GETBIT => return "GETBIT"
            case SETBIT => return "SETBIT"
            case BITPOS => return "BITPOS"

            // Geo
            case GEOADD => return "GEOADD"
            case GEODIST => return "GEODIST"
            case GEOHASH => return "GEOHASH"
            case GEOENCODE => return "GEOENCODE"
            case GEODECODE => return "GEODECODE"
            case GEOPOS => return "GEOPOS"
            case GEORADIUS => return "GEORADIUS"
            case GEORADIUS_RO => return "GEORADIUS_RO"
            case GEORADIUSBYMEMBER => return "GEORADIUSBYMEMBER"
            case GEORADIUSBYMEMBER_RO => return "GEORADIUSBYMEMBER_RO"
            case GEOSEARCH => return "GEOSEARCH"
            case GEOSEARCHSTORE => return "GEOSEARCHSTORE"

            // Stream
            case XACK => return "XACK"
            case XADD => return "XADD"
            case XAUTOCLAIM => return "XAUTOCLAIM"
            case XCLAIM => return "XCLAIM"
            case XDEL => return "XDEL"
            case XGROUP => return "XGROUP"
            case XINFO => return "XINFO"
            case XLEN => return "XLEN"
            case XPENDING => return "XPENDING"
            case XRANGE => return "XRANGE"
            case XREVRANGE => return "XREVRANGE"
            case XREAD => return "XREAD"
            case XREADGROUP => return "XREADGROUP"
            case XTRIM => return "XTRIM"

            // JSON
            case JSONSET => "JSON.SET"
            case JSONMSET => "JSON.MSET"
            case JSONGET => "JSON.GET"
            case JSONMGET => "JSON.MGET"
            case JSONARRAPPEND => "JSON.ARRAPPEND"
            case JSONARRINDEX => "JSON.ARRINDEX"
            case JSONARRINSERT => "JSON.ARRINSERT"
            case JSONARRLEN => "JSON.ARRLEN"
            case JSONARRPOP => "JSON.ARRPOP"
            case JSONARRTRIM => "JSON.ARRTRIM"
            case JSONCLEAR => "JSON.CLEAR"
            case JSONDEBUG => "JSON.DEBUG"
            case JSONDEL => "JSON.DEL"
            case JSONMERGE => "JSON.MERGE"
            case JSONNUMINCRBY => "JSON.NUMINCRBY"
            case JSONNUMMULTBY => "JSON.NUMMULTBY"
            case JSONOBJKEYS => "JSON.OBJKEYS"
            case JSONOBJLEN => "JSON.OBJLEN"
            case JSONSTRAPPEND => "JSON.STRAPPEND"
            case JSONSTRLEN => "JSON.STRLEN"
            case JSONTOGGLE => "JSON.TOGGLE"
            case JSONTYPE => "JSON.TYPE"
            case JSONRESP => "JSON.RESP"

            // Others
            case TIME => return "TIME"
            case WAIT => return "WAIT"

            // Module
            case MODULE => return "MODULE"

            // Server Management
            case LOLWUT => return "LOLWUT"
            case WAITAOF => return "WAITAOF"
            case LATENCY => return "LATENCY"

            // SENTINEL
            case SENTINEL => return "SENTINEL"

            // CLUSTER
            case ASKING => return "ASKING"
            case CLUSTER => return "CLUSTER"
        }
    }

    /**
     * 将字符串转换成命令
     *
     * @return
     */
    public func fromString(value: String): CommandType {
        let cmdName = value.toAsciiUpper()
        match (cmdName) {

            // Authentication
            case "ACL" => return ACL
            case "AUTH" => return AUTH
            case "AUTH2" => return AUTH2

            // Connection
            case "ECHO" => return ECHO
            case "HELLO" => return HELLO
            case "PING" => return PING
            case "QUIT" => return QUIT
            case "READONLY" => return READONLY
            case "READWRITE" => return READWRITE
            case "RESET" => return RESET
            case "SELECT" => return SELECT
            case "SWAPDB" => return SWAPDB

            // Server
            case "BGREWRITEAOF" => return BGREWRITEAOF
            case "BGSAVE" => return BGSAVE
            case "CLIENT" => return CLIENT
            case "COMMAND" => return COMMAND
            case "CONFIG" => return CONFIG
            case "DBSIZE" => return DBSIZE
            case "DEBUG" => return DEBUG
            case "FLUSHALL" => return FLUSHALL
            case "FLUSHDB" => return FLUSHDB
            case "INFO" => return INFO
            case "MYID" => return MYID
            case "LASTSAVE" => return LASTSAVE
            case "REPLICAOF" => return REPLICAOF
            case "ROLE" => return ROLE
            case "MONITOR" => return MONITOR
            case "SAVE" => return SAVE
            case "SHUTDOWN" => return SHUTDOWN
            case "SLAVEOF" => return SLAVEOF
            case "SLOWLOG" => return SLOWLOG
            case "SYNC" => return SYNC
            case "MEMORY" => return MEMORY

            // Keys
            case "COPY" => return COPY
            case "DEL" => return DEL
            case "DUMP" => return DUMP
            case "EXISTS" => return EXISTS
            case "EXPIRE" => return EXPIRE
            case "EXPIREAT" => return EXPIREAT
            case "EXPIRETIME" => return EXPIRETIME
            case "KEYS" => return KEYS
            case "MIGRATE" => return MIGRATE
            case "MOVE" => return MOVE
            case "OBJECT" => return OBJECT
            case "PERSIST" => return PERSIST
            case "PEXPIRE" => return PEXPIRE
            case "PEXPIREAT" => return PEXPIREAT
            case "PEXPIRETIME" => return PEXPIRETIME
            case "PTTL" => return PTTL
            case "RANDOMKEY" => return RANDOMKEY
            case "RENAME" => return RENAME
            case "RENAMENX" => return RENAMENX
            case "RESTORE" => return RESTORE
            case "TOUCH" => return TOUCH
            case "TTL" => return TTL
            case "TYPE" => return TYPE
            case "SCAN" => return SCAN
            case "UNLINK" => return UNLINK

            // String
            case "APPEND" => return APPEND
            case "GET" => return GET
            case "GETDEL" => return GETDEL
            case "GETEX" => return GETEX
            case "GETRANGE" => return GETRANGE
            case "GETSET" => return GETSET
            case "MGET" => return MGET
            case "MSET" => return MSET
            case "MSETNX" => return MSETNX
            case "SET" => return SET
            case "SETEX" => return SETEX
            case "PSETEX" => return PSETEX
            case "SETNX" => return SETNX
            case "SETRANGE" => return SETRANGE
            case "STRLEN" => return STRLEN
            case "STRALGO" => return STRALGO
            case "SUBSTR" => return SUBSTR

            // Numeric
            case "DECR" => return DECR
            case "DECRBY" => return DECRBY
            case "INCR" => return INCR
            case "INCRBY" => return INCRBY
            case "INCRBYFLOAT" => return INCRBYFLOAT

            // List
            case "BLMOVE" => return BLMOVE
            case "BLMPOP" => return BLMPOP
            case "BLPOP" => return BLPOP
            case "BRPOP" => return BRPOP
            case "BRPOPLPUSH" => return BRPOPLPUSH
            case "LINDEX" => return LINDEX
            case "LINSERT" => return LINSERT
            case "LLEN" => return LLEN
            case "LMOVE" => return LMOVE
            case "LMPOP" => return LMPOP
            case "LPOP" => return LPOP
            case "LPOS" => return LPOS
            case "LPUSH" => return LPUSH
            case "LPUSHX" => return LPUSHX
            case "LRANGE" => return LRANGE
            case "LREM" => return LREM
            case "LSET" => return LSET
            case "LTRIM" => return LTRIM
            case "RPOP" => return RPOP
            case "RPOPLPUSH" => return RPOPLPUSH
            case "RPUSH" => return RPUSH
            case "RPUSHX" => return RPUSHX
            case "SORT" => return SORT
            case "SORT_RO" => return SORT_RO

            // Hash
            case "HDEL" => return HDEL
            case "HEXISTS" => return HEXISTS
            case "HGET" => return HGET
            case "HGETALL" => return HGETALL
            case "HINCRBY" => return HINCRBY
            case "HINCRBYFLOAT" => return HINCRBYFLOAT
            case "HKEYS" => return HKEYS
            case "HLEN" => return HLEN
            case "HSTRLEN" => return HSTRLEN
            case "HMGET" => return HMGET
            case "HMSET" => return HMSET
            case "HRANDFIELD" => return HRANDFIELD
            case "HSET" => return HSET
            case "HSETNX" => return HSETNX
            case "HVALS" => return HVALS
            case "HSCAN" => return HSCAN

            // Transaction
            case "DISCARD" => return DISCARD
            case "EXEC" => return EXEC
            case "MULTI" => return MULTI
            case "UNWATCH" => return UNWATCH
            case "WATCH" => return WATCH

            // HyperLogLog
            case "PFADD" => return PFADD
            case "PFCOUNT" => return PFCOUNT
            case "PFMERGE" => return PFMERGE

            // Pub/Sub
            case "PSUBSCRIBE" => return PSUBSCRIBE
            case "PUBLISH" => return PUBLISH
            case "PUNSUBSCRIBE" => return PUNSUBSCRIBE
            case "SUBSCRIBE" => return SUBSCRIBE
            case "UNSUBSCRIBE" => return UNSUBSCRIBE
            case "PUBSUB" => return PUBSUB

            // Shard Pub/Sub
            case "SSUBSCRIBE" => return SSUBSCRIBE
            case "SUNSUBSCRIBE" => return SUNSUBSCRIBE
            case "SPUBLISH" => return SPUBLISH

            // Sets
            case "SADD" => return SADD
            case "SCARD" => return SCARD
            case "SDIFF" => return SDIFF
            case "SDIFFSTORE" => return SDIFFSTORE
            case "SINTER" => return SINTER
            case "SINTERCARD" => return SINTERCARD
            case "SINTERSTORE" => return SINTERSTORE
            case "SISMEMBER" => return SISMEMBER
            case "SMISMEMBER" => return SMISMEMBER
            case "SMEMBERS" => return SMEMBERS
            case "SMOVE" => return SMOVE
            case "SPOP" => return SPOP
            case "SRANDMEMBER" => return SRANDMEMBER
            case "SREM" => return SREM
            case "SSCAN" => return SSCAN
            case "SUNION" => return SUNION
            case "SUNIONSTORE" => return SUNIONSTORE

            // Sorted Set
            case "BZMPOP" => return BZMPOP
            case "BZPOPMIN" => return BZPOPMIN
            case "BZPOPMAX" => return BZPOPMAX
            case "ZADD" => return ZADD
            case "ZCARD" => return ZCARD
            case "ZCOUNT" => return ZCOUNT
            case "ZDIFF" => return ZDIFF
            case "ZDIFFSTORE" => return ZDIFFSTORE
            case "ZINCRBY" => return ZINCRBY
            case "ZINTER" => return ZINTER
            case "ZINTERCARD" => return ZINTERCARD
            case "ZINTERSTORE" => return ZINTERSTORE
            case "ZLEXCOUNT" => return ZLEXCOUNT
            case "ZMSCORE" => return ZMSCORE
            case "ZMPOP" => return ZMPOP
            case "ZPOPMIN" => return ZPOPMIN
            case "ZPOPMAX" => return ZPOPMAX
            case "ZRANDMEMBER" => return ZRANDMEMBER
            case "ZRANGE" => return ZRANGE
            case "ZRANGEBYSCORE" => return ZRANGEBYSCORE
            case "ZRANGESTORE" => return ZRANGESTORE
            case "ZRANK" => return ZRANK
            case "ZREM" => return ZREM
            case "ZREMRANGEBYRANK" => return ZREMRANGEBYRANK
            case "ZREMRANGEBYSCORE" => return ZREMRANGEBYSCORE
            case "ZREVRANGE" => return ZREVRANGE
            case "ZREVRANGEBYLEX" => return ZREVRANGEBYLEX
            case "ZREVRANGEBYSCORE" => return ZREVRANGEBYSCORE
            case "ZREVRANK" => return ZREVRANK
            case "ZSCAN" => return ZSCAN
            case "ZSCORE" => return ZSCORE
            case "ZUNION" => return ZUNION
            case "ZUNIONSTORE" => return ZUNIONSTORE
            case "ZREMRANGEBYLEX" => return ZREMRANGEBYLEX
            case "ZRANGEBYLEX" => return ZRANGEBYLEX

            // Functions
            case "FCALL" => return FCALL
            case "FCALL_RO" => return FCALL_RO
            case "FUNCTION" => return FUNCTION

            // Scripting
            case "EVAL" => return EVAL
            case "EVAL_RO" => return EVAL_RO
            case "EVALSHA" => return EVALSHA
            case "EVALSHA_RO" => return EVALSHA_RO
            case "SCRIPT" => return SCRIPT

            // Bits
            case "BITCOUNT" => return BITCOUNT
            case "BITFIELD" => return BITFIELD
            case "BITOP" => return BITOP
            case "GETBIT" => return GETBIT
            case "SETBIT" => return SETBIT
            case "BITPOS" => return BITPOS

            // Geo
            case "GEOADD" => return GEOADD
            case "GEODIST" => return GEODIST
            case "GEOHASH" => return GEOHASH
            case "GEOENCODE" => return GEOENCODE
            case "GEODECODE" => return GEODECODE
            case "GEOPOS" => return GEOPOS
            case "GEORADIUS" => return GEORADIUS
            case "GEORADIUS_RO" => return GEORADIUS_RO
            case "GEORADIUSBYMEMBER" => return GEORADIUSBYMEMBER
            case "GEORADIUSBYMEMBER_RO" => return GEORADIUSBYMEMBER_RO
            case "GEOSEARCH" => return GEOSEARCH
            case "GEOSEARCHSTORE" => return GEOSEARCHSTORE

            // Stream
            case "XACK" => return XACK
            case "XADD" => return XADD
            case "XAUTOCLAIM" => return XAUTOCLAIM
            case "XCLAIM" => return XCLAIM
            case "XDEL" => return XDEL
            case "XGROUP" => return XGROUP
            case "XINFO" => return XINFO
            case "XLEN" => return XLEN
            case "XPENDING" => return XPENDING
            case "XRANGE" => return XRANGE
            case "XREVRANGE" => return XREVRANGE
            case "XREAD" => return XREAD
            case "XREADGROUP" => return XREADGROUP
            case "XTRIM" => return XTRIM

            // JSON
            case "JSON.SET" => return JSONSET
            case "JSON.GET" => return JSONGET
            case "JSON.MGET" => return JSONMGET
            case "JSON.MSET" => return JSONMSET
            case "JSON.ARRAPPEND" => return JSONARRAPPEND
            case "JSON.ARRINDEX" => JSONARRINDEX
            case "JSON.ARRINSERT" => return JSONARRINSERT
            case "JSON.ARRLEN" => return JSONARRLEN
            case "JSON.ARRPOP" => return JSONARRPOP
            case "JSON.ARRTRIM" => return JSONARRTRIM
            case "JSON.CLEAR" => return JSONCLEAR
            case "JSON.DEBUG" => return JSONDEBUG
            case "JSON.DEL" => return JSONDEL
            case "JSON.MERGE" => return JSONMERGE
            case "JSON.NUMINCRBY" => return JSONNUMINCRBY
            case "JSON.NUMMULTBY" => return JSONNUMMULTBY
            case "JSON.OBJKEYS" => return JSONOBJKEYS
            case "JSON.OBJLEN" => return JSONOBJLEN
            case "JSON.STRAPPEND" => return JSONSTRAPPEND
            case "JSON.STRLEN" => return JSONSTRLEN
            case "JSON.TOGGLE" => return JSONTOGGLE
            case "JSON.RESP" => return JSONRESP

            // Others
            case "TIME" => return TIME
            case "WAIT" => return WAIT

            // Module
            case "MODULE" => return MODULE

            // Server Management
            case "LOLWUT" => return LOLWUT
            case "WAITAOF" => return WAITAOF
            case "LATENCY" => return LATENCY

            // SENTINEL
            case "SENTINEL" => return SENTINEL

            // CLUSTER
            case "ASKING" => return ASKING
            case "CLUSTER" => return CLUSTER
            case _ => throw IllegalArgumentException("Unsupported command ${value}")
        }
    }
}

public enum CommandKeyword <: ProtocolKeyword & Hashable & Equatable<CommandKeyword> {
    | AGGREGATE
    | ALPHA
    | ASC
    | BY
    | DESC
    | GET
    | LIMIT
    | NO
    | NOSORT
    | ONE
    | SET
    | STORE
    | WEIGHTS
    | WITHSCORE
    | WITHSCORES
    | RESETSTAT
    | REWRITE
    | RESET
    | FLUSH
    | EXISTS
    | LOAD
    | LEN
    | HELP
    | SCHEDULE
    | MATCH
    | COUNT
    | TYPE
    | KEYS
    | REFCOUNT
    | ENCODING
    | IDLETIME
    | FREQ
    | REPLACE
    | GETNAME
    | SETNAME
    | SETINFO
    | LIST
    | ID
    | KILL
    | PERSIST
    | STREAMS
    | CREATE
    | MKSTREAM
    | SETID
    | DESTROY
    | DELCONSUMER
    | MAXLEN
    | GROUP
    | IDLE
    | TIME
    | BLOCK
    | NOACK
    | RETRYCOUNT
    | STREAM
    | GROUPS
    | CONSUMERS
    | JUSTID
    | WITHVALUES
    | NOMKSTREAM
    | MINID
    | CREATECONSUMER
    | SETUSER
    | GETUSER
    | DELUSER
    | WHOAMI
    | USERS
    | CAT
    | GENPASS
    | LOG
    | SAVE
    | DRYRUN
    | COPY
    | AUTH
    | AUTH2
    | NX
    | XX
    | EX
    | PX
    | EXAT
    | PXAT
    | ABSTTL
    | KEEPTTL
    | INCR
    | LT
    | GT
    | CH
    | INFO
    | PAUSE
    | UNPAUSE
    | UNBLOCK
    | REV
    | WITHCOORD
    | WITHDIST
    | WITHHASH
    | ANY
    | FROMMEMBER
    | FROMLONLAT
    | BYRADIUS
    | BYBOX
    | BYLEX
    | BYSCORE
    | STOREDIST
    | TO
    | FORCE
    | TIMEOUT
    | DB
    | UNLOAD
    | ABORT
    | IDX
    | MINMATCHLEN
    | WITHMATCHLEN
    | FULL
    | DELETE
    | LIBRARYNAME
    | WITHCODE
    | DESCRIPTION
    | GETKEYS
    | GETKEYSANDFLAGS
    | DOCS
    | FILTERBY
    | DUMP
    | MODULE
    | ACLCAT
    | PATTERN
    | DOCTOR
    | USAGE
    | SAMPLES
    | PURGE
    | STATS
    | LOADEX
    | CONFIG
    | ARGS
    | RANK
    | NOW
    | VERSION
    | ADDR
    | SKIPME
    | USER
    | LADDR
    | CHANNELS
    | NUMPAT
    | NUMSUB
    | SHARDCHANNELS
    | SHARDNUMSUB
    | LEFT
    | RIGHT
    | BEFORE
    | AFTER
    | NO_EVICT
    | NO_TOUCH
    | ON
    | OFF
    | INDENT
    | NEWLINE
    | SPACE
    | MEMORY

    /**
     *
     * @return byte[] encoded representation.
     */
    public func getBytes(): Array<Byte> {
        return name().toArray()
    }

    /**
     *
     * @return name of the command.
     */
    public func name(): String {
        match (this) {
            case AGGREGATE => "AGGREGATE"
            case ALPHA => "ALPHA"
            case ASC => "ASC"
            case BY => "BY"
            case DESC => "DESC"
            case GET => "GET"
            case LIMIT => "LIMIT"
            case NO => "NO"
            case NOSORT => "NOSORT"
            case ONE => "ONE"
            case SET => "SET"
            case STORE => "STORE"
            case WEIGHTS => "WEIGHTS"
            case WITHSCORE => "WITHSCORE"
            case WITHSCORES => "WITHSCORES"
            case RESETSTAT => "RESETSTAT"
            case REWRITE => "REWRITE"
            case RESET => "RESET"
            case FLUSH => "FLUSH"
            case EXISTS => "EXISTS"
            case LOAD => "LOAD"
            case LEN => "LEN"
            case HELP => "HELP"
            case SCHEDULE => "SCHEDULE"
            case MATCH => "MATCH"
            case COUNT => "COUNT"
            case TYPE => "TYPE"
            case KEYS => "KEYS"
            case REFCOUNT => "REFCOUNT"
            case ENCODING => "ENCODING"
            case IDLETIME => "IDLETIME"
            case FREQ => "FREQ"
            case REPLACE => "REPLACE"
            case GETNAME => "GETNAME"
            case SETNAME => "SETNAME"
            case SETINFO => "SETINFO"
            case LIST => "LIST"
            case ID => "ID"
            case KILL => "KILL"
            case PERSIST => "PERSIST"
            case STREAMS => "STREAMS"
            case CREATE => "CREATE"
            case MKSTREAM => "MKSTREAM"
            case SETID => "SETID"
            case DESTROY => "DESTROY"
            case DELCONSUMER => "DELCONSUMER"
            case MAXLEN => "MAXLEN"
            case GROUP => "GROUP"
            case IDLE => "IDLE"
            case TIME => "TIME"
            case BLOCK => "BLOCK"
            case NOACK => "NOACK"
            case RETRYCOUNT => "RETRYCOUNT"
            case STREAM => "STREAM"
            case GROUPS => "GROUPS"
            case CONSUMERS => "CONSUMERS"
            case JUSTID => "JUSTID"
            case WITHVALUES => "WITHVALUES"
            case NOMKSTREAM => "NOMKSTREAM"
            case MINID => "MINID"
            case CREATECONSUMER => "CREATECONSUMER"
            case SETUSER => "SETUSER"
            case GETUSER => "GETUSER"
            case DELUSER => "DELUSER"
            case WHOAMI => "WHOAMI"
            case USERS => "USERS"
            case CAT => "CAT"
            case GENPASS => "GENPASS"
            case LOG => "LOG"
            case SAVE => "SAVE"
            case DRYRUN => "DRYRUN"
            case COPY => "COPY"
            case AUTH => "AUTH"
            case AUTH2 => "AUTH2"
            case NX => "NX"
            case XX => "XX"
            case EX => "EX"
            case PX => "PX"
            case EXAT => "EXAT"
            case PXAT => "PXAT"
            case ABSTTL => "ABSTTL"
            case KEEPTTL => "KEEPTTL"
            case INCR => "INCR"
            case LT => "LT"
            case GT => "GT"
            case CH => "CH"
            case INFO => "INFO"
            case PAUSE => "PAUSE"
            case UNPAUSE => "UNPAUSE"
            case UNBLOCK => "UNBLOCK"
            case REV => "REV"
            case WITHCOORD => "WITHCOORD"
            case WITHDIST => "WITHDIST"
            case WITHHASH => "WITHHASH"
            case ANY => "ANY"
            case FROMMEMBER => "FROMMEMBER"
            case FROMLONLAT => "FROMLONLAT"
            case BYRADIUS => "BYRADIUS"
            case BYBOX => "BYBOX"
            case BYLEX => "BYLEX"
            case BYSCORE => "BYSCORE"
            case STOREDIST => "STOREDIST"
            case TO => "TO"
            case FORCE => "FORCE"
            case TIMEOUT => "TIMEOUT"
            case DB => "DB"
            case UNLOAD => "UNLOAD"
            case ABORT => "ABORT"
            case IDX => "IDX"
            case MINMATCHLEN => "MINMATCHLEN"
            case WITHMATCHLEN => "WITHMATCHLEN"
            case FULL => "FULL"
            case DELETE => "DELETE"
            case LIBRARYNAME => "LIBRARYNAME"
            case WITHCODE => "WITHCODE"
            case DESCRIPTION => "DESCRIPTION"
            case GETKEYS => "GETKEYS"
            case GETKEYSANDFLAGS => "GETKEYSANDFLAGS"
            case DOCS => "DOCS"
            case FILTERBY => "FILTERBY"
            case DUMP => "DUMP"
            case MODULE => "MODULE"
            case ACLCAT => "ACLCAT"
            case PATTERN => "PATTERN"
            case DOCTOR => "DOCTOR"
            case USAGE => "USAGE"
            case SAMPLES => "SAMPLES"
            case PURGE => "PURGE"
            case STATS => "STATS"
            case LOADEX => "LOADEX"
            case CONFIG => "CONFIG"
            case ARGS => "ARGS"
            case RANK => "RANK"
            case NOW => "NOW"
            case VERSION => "VERSION"
            case ADDR => "ADDR"
            case SKIPME => "SKIPME"
            case USER => "USER"
            case LADDR => "LADDR"
            case CHANNELS => "CHANNELS"
            case NUMPAT => "NUMPAT"
            case NUMSUB => "NUMSUB"
            case SHARDCHANNELS => "SHARDCHANNELS"
            case SHARDNUMSUB => "SHARDNUMSUB"
            case LEFT => "LEFT"
            case RIGHT => "RIGHT"
            case BEFORE => "BEFORE"
            case AFTER => "AFTER"
            case NO_TOUCH => "NO-TOUCH"
            case NO_EVICT => "NO-EVICT"
            case ON => "ON"
            case OFF => "OFF"
            case INDENT => "INDENT"
            case NEWLINE => "NEWLINE"
            case SPACE => "SPACE"
            case MEMORY => "MEMORY"
        }
    }

    public func hashCode(): Int64 {
        return name().hashCode()
    }

    public operator override func ==(other: CommandKeyword): Bool {
        return name() == other.name()
    }

    public operator override func !=(other: CommandKeyword): Bool {
        return name() != other.name()
    }
}

public enum FlushMode <: ProtocolKeyword {
    SYNC | ASYNC

    /**
     *
     * @return byte[] encoded representation.
     */
    public func getBytes(): Array<Byte> {
        return name().toArray()
    }

    /**
     *
     * @return name of the command.
     */
    public func name(): String {
        match (this) {
            case SYNC => "SYNC"
            case ASYNC => "ASYNC"
        }
    }
}

public enum SaveMode <: ProtocolKeyword {
    NOSAVE | SAVE

    /**
     *
     * @return byte[] encoded representation.
     */
    public func getBytes(): Array<Byte> {
        return name().toArray()
    }

    /**
     *
     * @return name of the command.
     */
    public func name(): String {
        match (this) {
            case NOSAVE => "NOSAVE"
            case SAVE => "SAVE"
        }
    }
}