#!/usr/bin/env python

# Modified 9/26/22 by Lee.Marzke@zenimax.com to tolerate accent characters in p4 usernames
# Replace unicode chars in p4 users (user name) with ASCII equiv.
# From SDP prompt, run 'pip install unidecode' to install module into /p4/common/bin/python/bin installed by SDP


from __future__ import print_function

import re
import sys
import os
import platform
import unidecode
from subprocess import *

case_sensitive = False
P4BIN = os.getenv ('P4BIN', 'p4')
P4CCFG = os.getenv ('P4CCFG', '/p4/common/config')

if platform.system() == "Windows":
    p4 = "p4.exe"
else:
    p4 = P4BIN


def loadconfig():
    global case_sensitive

    robots = set()
    servers = []

    cfgFilePath = "%s/TotalUsers.cfg" % P4CCFG
    cfgfile = open(cfgFilePath, "r")
    log("DEBUG", "cfgfile = %s" % (cfgFilePath))

    for line in cfgfile.readlines():
        if (re.search("^#", line) or re.search("^\s*$", line)):
            continue

        if re.search("^case_sensitive", line):
            if re.match("^case_sensitive=1.*", line):
                case_sensitive = True
                log("DEBUG", "Operating in case sensitive mode.")
            else:
                log("DEBUG", "Operating in case insensitive mode.")

        if re.search("^ROBOT", line):
            robotuser = (re.match("^ROBOT\|(.*)", line).groups()[0])
            if case_sensitive:
                log("DEBUG", "Robot user %s added." % (robotuser))
                robots.add(robotuser)
            else:
                log("DEBUG", "Robot user %s added." % (robotuser.lower()))
                robots.add(robotuser.lower())

        if re.search("^SERVER", line):
            server = (re.match("^SERVER\|(.*)\|(.*)\|(.*)", line).groups())
            log("DEBUG", "Server %s added." % (server[0]))
            servers.append(server)

    if servers == []:
        log("ERROR", "No servers found in config file.")

    cfgfile.close()
    return servers, robots


def log(msglevel="DEBUG", message=""):
    if msglevel == "ERROR":
        print(message)
        sys.exit(1)
    else:
        print(message)


def runp4cmd(cmd):
    try:
        pipe = Popen(p4 + cmd, shell=True, stdin=PIPE, stdout=PIPE, universal_newlines=True)
        stdout, stderr = pipe.communicate()
        log("DEBUG", stdout)
        if pipe.returncode != 0:
            log("ERROR", "%s%s generated the following error: %s" % (p4, cmd, stderr))
        else:
            return stdout
    except OSError as err:
        log("ERROR", "Execution failed: %s" % (err))


def process_servers(servers, robots):
    """
    Each server line contains four components as follows:
    SERVER|port|user
    """
    users = []
    useremail = {}
    accesstimes = {}
    userserver = {}

    for server in servers:
        args = " -p %s -u %s " % (server[0], server[1])
        runp4cmd(args + "login -a < /p4/common/config/.p4passwd.p4_%s.admin" % server[2])
        runp4cmd(args + "users | iconv -c -f utf8 -t ascii//TRANSLT//IGNORE > users.txt")
        userfile = open("users.txt", "r")
        for userline in userfile.readlines():
            userline = unidecode.unidecode( userline )
            user = re.match("(.*) <(.*)> .*accessed (.*)", userline).groups()
            if case_sensitive:
                username = user[0]
            else:
                username = user[0].lower()
                if username not in users and username not in robots:
                    users.append(username)
                    if (user[1] != None):
                        useremail[username] = user[1]
                    else:
                        useremail[username] = username
                    accesstimes[username] = user[2]
                    userserver[username] = server[0]
        userfile.close()
        os.remove("users.txt")
    count = 0
    users.sort()

    totalusersfile = "totalusers.csv"

    totalusers = open(totalusersfile, "w")

    for user in users:
        totalusers.write("%s,%s,%s,%s\n" % (user, useremail[user], accesstimes[user], userserver[user]))
        count += 1

    totalusers.close()
    print("\nTotal number of users: %s" % (count))
    print("User list is in %s" % (totalusersfile))


if __name__ == "__main__":
    if len(sys.argv) > 1:
        print("This program doesn't accept any arguments. Just update the totalusers.cfg file "
              "and run the program.")
    servers, robots = loadconfig()
    process_servers(servers, robots)
    sys.exit(0)
