#!/usr/bin/env python
# encoding: utf-8
"""
cli
"""
####
#
#  Copyright (c) 2008-2012 Aerospike, Inc. All rights reserved.
#
# Permission is hereby granted, free of charge, to any person obtaining a copy of
# this software and associated documentation files (the "Software"), to deal in
# the Software without restriction, including without limitation the rights to
# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
# of the Software, and to permit persons to whom the Software is furnished to do
# so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
#
####

import sys
import argparse
import getpass

MININT64 = -9223372036854775808
MAXINT64 = 9223372036854775807
UNIX_SUCCESS = 0
UNIX_FAILURE = 1
ARGUMENT_ERROR = 2

try:
    import citrusleaf
except:
    print "unable to load Citrusleaf library (check PYTHONPATH)"
    sys.exit(-1);

def main(argv=None):

    if argv is None:
        argv = sys.argv

    parser = argparse.ArgumentParser(add_help=False)
    parser.add_argument("-h", "--host"
                        , default="127.0.0.1"
                        , help="server host name (default: %(default)s)")
    parser.add_argument("-p", "--port"
                        , type=int
                        , default=3000
                        , help="server port (default: %(default)s)")
    parser.add_argument("-U", "--user"
                        , help="user name")
    parser.add_argument("-P", "--password"
                        , nargs="?"
                        , const="prompt"
                        , help="password")
    parser.add_argument("-t", "--target"
                        , default="127.0.0.1:3000"
                        , help="a cluster node to query, <host:port> (default: %(default)s)")
    parser.add_argument("-o", "--operand"
                        , choices=['get', 'set', 'put', 'delete']
                        , default="get"
                        , help="Database operation, note that set and put are equivalent (default: %(default)s)")
    parser.add_argument("-n", "--namespace"
                        , default="test"
                        , help="the namespace to operate on (default: %(default)s)")
    parser.add_argument("-s", "--set"
                        , default=""
                        , help="the set the key belongs in")
    parser.add_argument("-k", "--key"
                        , required=True
                        , help="record key")
    parser.add_argument("--d64", "--digest-base64"
                        , dest="digest_base64"
                        , action="store_true"
                        , help="Interpret key as a base64 digest")
    parser.add_argument("--d16", "--digest-base16", "--digest-hex"
                        , dest="digest_base16"
                        , action="store_true"
                        , help="Interpret key as a base16 (hex) digest")
    parser.add_argument("-i", "--integer-key", "--key-integer"
                        , dest="integer_key"
                        , action="store_true"
                        , help="True if key is a integer")
    parser.add_argument("-b", "--bin"
                        , default=""
                        , help="bin name")
    parser.add_argument("-v", "--value"
                        , help="bin value")
    parser.add_argument("-e", "--recordttl"
                        , type=int
                        , help="record TTL")
    parser.add_argument("--verbose"
                        , action='store_true'
                        , help="make the request verbose")
    parser.add_argument("-u", "--usage"
                        , action='help'
                        , help="show program usage")
    args = parser.parse_args()

    if args.user != None:
        if args.password == "prompt":
            args.password = getpass.getpass("Enter Password:")

    set_key_modifiers = filter(lambda v: v, [args.digest_base64, args.digest_base16, args.integer_key])
    if len(set_key_modifiers) > 1:
        print "Only one key modifier may be used at a time."
        print ""
        parser.print_help()
        return ARGUMENT_ERROR

    if (args.operand in ("set", "put") and not args.value):
        print "Value is required."
        print ""
        parser.print_help()
        return ARGUMENT_ERROR

    cluster = citrusleaf.CitrusleafCluster()
    cluster.setUser(args.user, args.password)
    cluster.addHost(args.host, args.port)

    try:
        values = dict({args.bin : args.value})

        ## Begin Parse Key
        insertVal = args.key
        parsed_key = None
        if args.integer_key:
            insertType = "integer key"
            try:
                parsed_key = int(args.key)
                if parsed_key < MININT64 or parsed_key > MAXINT64:
                    print "key should be between " + str(MININT64) + " and " + str(MAXINT64)
                    return ARGUMENT_ERROR
            except:
                print " key should be integer when -i/--integer-key argument is set" 
                return ARGUMENT_ERROR
        elif args.digest_base64 or args.digest_base16:
            codec = "base64" if args.digest_base64 else "hex"
            insertType = "%s digest"%(codec)
            try:
                digest_compact = args.key.decode(codec)
                parsed_key = [ord(c) for c in digest_compact]

                if len(parsed_key) != 20:
                    print " digest is not 20 bytes"
                    return ARGUMENT_ERROR
            except ValueError:
                print " digest must be in base64 encoding: " + args.key
                return ARGUMENT_ERROR
        else:
            insertType = "key"
            parsed_key = args.key

        ## End Parse Key

        # from this point onwards key and digest are collectively treated as key and differentiated by the type(key) (for digest type(key) is List)
        if args.operand in ("get"):
            r, gen, values = citrusleaf.get(cluster, args.namespace, args.set, parsed_key, debug=args.verbose)
            if (values == None):
                print "no data retrieved"
                return UNIX_SUCCESS
            else:
                print values
                return UNIX_SUCCESS
        elif args.operand in ("set", "put"):
            r = citrusleaf.put(cluster, args.namespace, args.set, parsed_key, values, args.recordttl, debug=args.verbose)
            if (r != 0):
                print "set failed, ", r
                return UNIX_FAILURE
            else:
                print "succeeded: ", insertType, "=", insertVal, " set=",args.set," bin=", args.bin, " value=", args.value
                return UNIX_SUCCESS
        elif args.operand in ("delete"):
            r = citrusleaf.delete(cluster, args.namespace, args.set, parsed_key, debug=args.verbose)
            if (r != 0):
                print "delete of ", insertType, "=", insertVal, " set=",args.set," failed, ", r
                return UNIX_FAILURE
            else:
                print "delete succeeded: ", insertType, "=", insertVal, " set=",args.set
                return UNIX_SUCCESS
        else:
            print "operand must be one of set, get, or delete"
            print "    for usage, --usage"
            return ARGUMENT_ERROR
    except:
        raise
    finally:
        cluster.close()


if __name__ == "__main__":
    sys.exit(main())
