
import whatap.util.process_util as process_util
import whatap.util.text_util as text_util
import whatap.util.thread_util as thread_util
from whatap.agent.conf import configure as config
import re
import time
import datetime
import whatap.util.logging_util as logging_util
import logging
import logging.handlers
from logging.handlers import RotatingFileHandler
import inspect


NOT_AVAIL='N/A'

prtconf = process_util.executeCmd('prtconf')
clk_tck = float(process_util.executeCmd(command='getconf CLK_TCK'))
machineArch = process_util.executeCmd(command='getconf MACHINE_ARCHITECTURE')

cputype = None
totalsize = 0
for l in prtconf.split('\n'):
    l = l.strip()
    if l and l.startswith('Processor Type'):
        cputype = l.split(':')[1].strip()
    elif l and l.startswith('Good Memory Size'):
        totalsize = text_util.parse_size(l.split(':')[1].strip(), 0)

cpu_core = 1
cpuinfo = process_util.executeCmd('bindprocessor -q')

for l in cpuinfo.split('\n'):
    l = l.strip()
    if l and l.startswith('The available processors are'):
        cpu_core = len(l.split(':')[1].split())
    
system_info = {}

def GetCPUNum():
    return cpu_core

def GetCPUType():
    return cputype

def GetMemorySize():
    return totalsize

def GetMachineArch():
    return machineArch

oslevel = process_util.executeCmd('oslevel -s')

tokens = oslevel.strip().split('-')


def GetOSRelease():

    return "AIX {} TECH LVL {} - SVC Pack {}".format(float(int(tokens[0])/100)/10, tokens[1], tokens[2])



serverInfoV2 = None
_boot_epoch_ts = None


def _is_vios():
    if process_util.executeCommandShellWithTimeout('ioslevel 2>/dev/null', timeout=5).strip():
        return True
    if process_util.executeCommandShellWithTimeout('/usr/ios/cli/ioscli ioslevel 2>/dev/null', timeout=5).strip():
        return True
    return False


def _get_wpar_id():
    return process_util.executeCommandShellWithTimeout('uname -W 2>/dev/null', timeout=5).strip()


def _get_lparstat_i():
    return process_util.executeCommandShellWithTimeout('lparstat -i 2>/dev/null', timeout=10)


def _is_lpar(lpar_out):
    for kw in ('Partition Name', 'Partition Number', 'Online Virtual CPUs', 'Entitled Capacity'):
        if kw.lower() in lpar_out.lower():
            return True
    if re.search(r'Type\s*:', lpar_out, re.IGNORECASE):
        return True
    return False


def _get_lpar_type(lpar_out):
    m = re.search(r'Type\s*:\s*(\S+)', lpar_out, re.IGNORECASE)
    return m.group(1) if m else ''


def _classify_server():
    if _is_vios():
        return 'Virtual', 'VIOS'
    wpar_id = _get_wpar_id()
    if wpar_id and wpar_id.isdigit() and int(wpar_id) > 0:
        return 'Virtual', 'WPAR'
    lpar_out = _get_lparstat_i()
    if _is_lpar(lpar_out):
        ltype = _get_lpar_type(lpar_out).lower()
        if 'shared' in ltype:
            return 'Virtual', 'Micropartition'
        elif 'dedicated' in ltype:
            return 'Virtual', 'Dedicated LPAR'
        else:
            return 'Virtual', 'LPAR'
    if wpar_id and not wpar_id.isdigit():
        return 'Virtual', 'unknown'
    if lpar_out.strip():
        return 'Virtual', 'unknown'
    return 'Physical', 'Bare metal'


def initServerV2():
    global serverInfoV2
    global _boot_epoch_ts

    bootEpoch = process_util.executeCommandShellWithTimeout(''' uptime | perl -ne \'/.*up (\d+) days, +(\d+):(\d+),.*/; $total=((($1*24+$2)*60+$3)*60); $now=time(); $now-=$total; print $now,"\n";\' ''')
    _boot_epoch_ts = float(bootEpoch)
    bootTime = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(_boot_epoch_ts))

    serverInfoV2 = {
        "hostname":process_util.executeCommandShellWithTimeout('''hostname'''),
        "model":process_util.executeCommandShellWithTimeout('''lsattr -El sys0 -a modelname | awk '{print $2}' | cut -d, -f2'''),
        "hwSerial":process_util.executeCommandShellWithTimeout('''lsattr -El sys0 -a systemid | awk '{print $2}' | cut -d, -f2'''),
        "OSVersion":process_util.executeCommandShellWithTimeout('''echo "AIX "`oslevel -qs 2>/dev/null |head -1`'''),
        "OSType":process_util.executeCommandShellWithTimeout('''uname -s'''),
        "firmware":process_util.executeCommandShellWithTimeout('''lsattr -El sys0 -a fwversion | awk '{print $2}' | cut -d, -f2'''),
        "nCores":process_util.executeCommandShellWithTimeout('''prtconf -v | grep proc | grep Processor |wc -l'''),
        "lCores":process_util.executeCommandShellWithTimeout('''bindprocessor -q | awk '{print $NF+1}' |bc'''),
        "frequency":process_util.executeCommandShellWithTimeout('''lsattr -El proc0 -a frequency | awk '{print $2/1000000}' | bc'''),
        "cpuType": process_util.executeCommandShellWithTimeout("""lsattr -El proc0 -a type | awk '{print $2}'"""),
        "memTotal":  process_util.executeCommandShellWithTimeout("""lsattr -El sys0 -a realmem | awk '{print $2/1024}' | bc"""),
        "IP_all":  process_util.executeCommandShellWithTimeout("""ifconfig -a | grep -w inet | egrep -v "127.0.0.1|0.0.0.0" | awk '{print $2}' | cut -d'/' -f 1"""),
        "timezone":  process_util.executeCommandShellWithTimeout("""cat /etc/environment | grep TZ | awk -F= '{print $2}'"""),
        "ibmLparMode":  process_util.executeCommandShellWithTimeout("""lparstat -i | grep ^Mode | awk -F: '{print $2}'"""),
        "ibmLparType":  process_util.executeCommandShellWithTimeout("""lparstat -i | grep ^Type | awk -F: '{print $2}'"""),
        "ibmEc":  process_util.executeCommandShellWithTimeout("""lparstat -i | grep "Entitled Capacity" | grep -v Pool | awk -F: '{print $2}'"""),
        "bootTime": bootTime,    
    }
    server_type, server_type_detail = _classify_server()
    serverInfoV2['serverType'] = server_type
    serverInfoV2['serverTypeDetail'] = server_type_detail
    bitmode = process_util.executeCommandShellWithTimeout('getconf KERNEL_BITMODE 2>/dev/null').strip()
    proc_type = process_util.executeCommandShellWithTimeout(
        "prtconf 2>/dev/null | awk -F: '/Processor Type/ {gsub(/^[ \\t]+|[ \\t]+$/, \"\", $2); print $2; exit}'"
    ).strip()
    if bitmode == '64' and 'power' in proc_type.lower():
        arch = 'ppc64'
    elif bitmode == '32' and 'power' in proc_type.lower():
        arch = 'ppc'
    else:
        arch = 'unknown'
    serverInfoV2['systemArchitecture'] = arch

    if "Capped" != serverInfoV2['ibmLparMode']:
        serverInfoV2["ibmPoolID"]= process_util.executeCommandShellWithTimeout("""lparstat -i | grep "Shared Pool ID" | awk -F: '{print $2}'""")
        serverInfoV2["ibmMinVp"]=  process_util.executeCommandShellWithTimeout("""lparstat -i | grep "Minimum Capacity" | grep -v Pool | awk -F: '{print $2}'""")
        serverInfoV2["ibmMaxVp"]=  process_util.executeCommandShellWithTimeout("""lparstat -i | grep "Maximum Capacity" | grep -v Pool | awk -F: '{print $2}'""")
        serverInfoV2["ibmCpuPool"]=  process_util.executeCommandShellWithTimeout("""lparstat -i | grep "Active CPUs in Pool" | awk -F: '{print $2}'""")
        serverInfoV2["ibmWeight"]=  process_util.executeCommandShellWithTimeout("""lparstat -i | grep "Variable Capacity Weight" | grep -v Desired | awk -F: '{print $2}'""")

def GetServerInfoV2():
    global serverInfoV2
    if serverInfoV2 == None:
        initServerV2()

    if _boot_epoch_ts is not None:
        serverInfoV2['uptime'] = int((time.time() - _boot_epoch_ts) / 86400)

    return serverInfoV2



lasttime = 0
errptLogger = None

def initErrptLogger(logPath, logMaxBytes = 4 * 1024 * 1024, logBackupCount = 3):
    logger = logging.getLogger("ErrptLogger")
    logger.propagate = False
    formatter = logging.Formatter('%(message)s')
    handler = RotatingFileHandler(
            filename=logPath,
            maxBytes=logMaxBytes,
            backupCount=logBackupCount
            )

    handler.setFormatter(formatter)
    logger.setLevel(logging.INFO)

    if logger.handlers:
        logger.handlers = []

    logger.addHandler(handler)

    global errptLogger
    errptLogger = logger


def send(*args):
    message = " ".join([str(x) for x in args])
    extra = {}

    if errptLogger != None:
        errptLogger.info(message, extra = extra)



def runErrptRedirect():
    global lasttime
    now = datetime.datetime.now().strftime('%m%d%H%M%y')
    if lasttime != 0 and lasttime != now :
        command = "errpt -s {} -e {}".format(lasttime, now)
        output = process_util.executeCommandShellWithTimeout(command, 10)

        errpts = output.split("\n")
        for errpt in errpts[1:]:
            send(errpt)

    lasttime = now

def InitErrptRedirect():
    
    logPath = config.GetConfig().ErrptLogPath
    logSize = config.GetConfig().ErrptLogSize * 1024 * 1024
    logBackupCount = config.GetConfig().ErrptLogFileCount
    errptInterval = config.GetConfig().ErrptReditectInterval
    if errptInterval < 60:
        errptInterval = 60

    logging_util.info("Init Errpt Redirect : ", logPath)
    initErrptLogger(logPath, logMaxBytes = logSize, logBackupCount = logBackupCount) 

    try:
        if config.GetConfig().ErrptReditectEnabled:
            thread_util.asyncLoop(runErrptRedirect, errptInterval)
    except Exception, e:
        logging_util.error(e)


def GetNtpInfo():
    from whatap.osinfo.ntp_common import build_ntp_info
    daemon = ""
    in_use = False
    try:
        xntpd = process_util.executeCommandShellWithTimeout('ps -ef 2>/dev/null | grep xntpd | grep -v grep | head -1', timeout=5).strip()
        if xntpd:
            daemon = 'xntpd'
            in_use = True
    except Exception:
        pass
    return build_ntp_info(daemon, in_use)
