#!/usr/bin/python
# -*- python -*-

import subprocess
import os
import sys
import platform
import re
import random
import string
import getpass

USAGE = """usage: %prog [options]"""

def run_process(name, args):
    if platform.system() == 'Windows':
        name = name + ".exe"

    args.insert(0, name)
    p = subprocess.Popen(args, stdout = subprocess.PIPE, stderr = subprocess.PIPE)
    output = p.stdout.read()
    error = p.stderr.read()
    p.wait()
    rc = p.returncode
    return output, error

def get_server_guts(initargs_path):
    dump_guts_path = os.path.join(basedir(), "dump-guts")
    args = [dump_guts_path, "--initargs-path", initargs_path]

    output, error = run_process("escript", args)
    tokens = output.rstrip("\0").split("\0")
    d = {}
    if len(tokens) > 1:
        for i in xrange(0, len(tokens), 2):
            d[tokens[i]] = tokens[i+1]
    return d, error

def read_server_guts(options):
    initargs_variants = [os.path.abspath(os.path.join(options.root, "var", "lib", "couchbase", "initargs")),
                         "/opt/couchbase/var/lib/couchbase/initargs",
                         os.path.expanduser("~/Library/Application Support/Couchbase/var/lib/couchbase/initargs")]

    guts = None
    errors = ""

    for initargs_path in initargs_variants:
        d, error = get_server_guts(initargs_path)
        if len(d) > 0:
            guts = d
            break

        errors += "Checking for server guts in " + initargs_path + "...\n"
        errors += error

    if not guts:
        print errors

    return guts

def read_guts(guts, key):
    if not (key in guts):
        return ""
    return guts[key]

def basedir():
    mydir = os.path.dirname(sys.argv[0])
    if mydir == "":
        mydir = "."
    return mydir

def remote_shell_name():
    tmp = ''.join(random.choice(string.ascii_letters) for i in xrange(20))
    return 'cb-%s@127.0.0.1' % tmp

def main():
    from optparse import OptionParser

    mydir = os.path.dirname(sys.argv[0])

    # this variable is consumed by the erl script on MacOS installation
    if platform.system() == 'Darwin':
        os.environ["COUCHBASE_TOP"] = os.path.abspath(os.path.join(mydir, ".."))

    # copied from cbcollect_info as is, though probably just adding erldir
    # will be sufficient
    # all this path setting trickery should be removed as soon
    # as we'll figure out how to set necessary env variables
    # on windows before running the python script
    # so the script will rely on something like $COUCHBASE_TOP instead of
    # sys.argv[0] to calculate various paths
    erldir = os.path.join(mydir, 'erlang', 'bin')
    if os.name == 'posix':
        path = [mydir,
                '/bin',
                '/sbin',
                '/usr/bin',
                '/usr/sbin',
                '/opt/couchbase/bin',
                erldir,
                os.environ['PATH']]
        os.environ['PATH'] = ':'.join(path)
    elif os.name == 'nt':
      path = [mydir, erldir, os.environ['PATH']]
      os.environ['PATH'] = ';'.join(path)

    parser = OptionParser(usage=USAGE)
    parser.add_option("-r", dest="root",
                      help="root directory - defaults to %s" % (mydir + "/.."),
                      default=os.path.abspath(os.path.join(mydir, "..")))
    options, args = parser.parse_args()

    guts = read_server_guts(options)

    if not guts:
        print("Failed to obtain node connect information")
        sys.exit(1)

    node = read_guts(guts, "node")

    if not node:
        print("Failed to obtain node name")
        sys.exit(1)

    cookie = read_guts(guts, "cookie")

    if not cookie:
        print("Failed to obtain cookie for node " + node)
        sys.exit(1)

    password = getpass.getpass("\nPlease enter the new administrative password (or <Enter> for system generated password):")

    if password == "":
        password = "generated"
    else:
        password = "\"" + password.replace("\\", "\\\\").replace("\"", "\\\"") + "\""

    confirm = raw_input("\nRunning this command will reset administrative password.\nDo you really want to do it? (yes/no)")

    if confirm != "yes":
        exit(0)

    print("Resetting administrative password...")

    args = ["-noinput", "-name", remote_shell_name(), "-setcookie", cookie, "-eval", \
            "Res = rpc:call('" + node + "', menelaus_web, reset_admin_password, [" + password + "]), io:format(\"~p~n\", [Res]).", \
            "-run", "init", "stop"]

    res, error = run_process("erl", args)

    m = re.match(r"{ok,\s*<<\"(.*)\">>}", res)
    if m:
        print m.group(1)
    elif res.strip(' \t\n\r') == "{badrpc,nodedown}":
        print "Node is down. Please start the server first"
    else:
        print(res)

if __name__ == '__main__':
    main()
