import time
import whatap.pack.tagcount_pack as tagcount_pack
import whatap.osinfo as osinfo
import whatap.agent.secure.security_master as secure
from whatap.util.hash_util import HashUtil as hashutil
from whatap.value.list_value import ListValue
from whatap.value.null_value import NullValue

class TaskInfraProcessTopNAndGroup:
    PROCESS_TOPN = "infra_process_topn"

    PROCESS_TOPN_COMMAND = "cmd"
    PROCESS_TOPN_OWNER = "owner"
    PROCESS_TOPN_CMDLINE = "args"
    PROCESS_TOPN_STIME = "stime"
    PROCESS_TOPN_PID = "pid"
    PROCESS_TOPN_PPID = "ppid"
    PROCESS_TOPN_CPU = "cpu"
    PROCESS_TOPN_RSS = "rss"
    PROCESS_TOPN_VSZ = "vsz"
    PROCESS_TOPN_TOTAL_CHAR_IO = "totalCharIo"
    PROCESS_TOPN_THREAD_COUNT = "threadCnt"
    PROCESS_TOPN_PROCESSINFO = "procInfo"

    PROCESS_GROUP = "infra_process_group"
    PROCESS_GROUP_COMMAND = "cmd"
    PROCESS_GROUP_OWNER = "owner"
    PROCESS_GROUP_CPU = "cpu"
    PROCESS_GROUP_RSS = "rss"
    PROCESS_GROUP_VSZ = "vsz"
    PROCESS_GROUP_TOTAL_CHAR_IO = "totalCharIo"
    PROCESS_GROUP_THREAD_COUNT = "threadCnt"
    PROCESS_GROUP_PROCESS_COUNT = "procCnt"
    PROCESS_GROUP_NAME = "name"


    def __init__(self, interval = 5, topn = 40):
        self.intervalValue = interval
        self.recType = 2
        self.topn = topn

    def interval(self):
        return self.intervalValue

    def process(self, os_, pcode, oid, now):
        (topn, pg) = osinfo.GetTopNAndGroupProc(self.topn)
        topnPack = None
        pgPack = None

        mem_total = osinfo.GetMemorySize()
        if not mem_total or mem_total <= 0:
            mem_total = None

        secu = secure.GetSecurityMaster()
        if topn:
            topnPack = tagcount_pack.TagCountPack()
            topnPack.pcode = pcode
            topnPack.oid = oid
            topnPack.time = now
            topnPack.category = TaskInfraProcessTopNAndGroup.PROCESS_TOPN
            topnPack.putTag("oname", str(secu.oname))
            topnPack.putTag("!rectype", str(self.recType))

        
            idList = ListValue()
            commandList = ListValue()
            ownerList = ListValue()
            cmdlineList = ListValue()
            stimeList = ListValue()
            pidList = ListValue()
            ppidList = ListValue()
            cpuList = ListValue()
            cpuUserList = ListValue()
            cpuSysList = ListValue()
            rssList = ListValue()
            vszList = ListValue()
            totalCharIoList = ListValue()
            threadCountList = ListValue()
            processInfoList = ListValue()
            pRssList = ListValue()

            for proc in topn:
                key = hashutil.hashFromString("{}{}{}{}{}{}".format(proc.cmd1, proc.user, proc.cmd2, proc.createTime, proc.pid, proc.ppid))
                idList.addLong(key)
                commandList.addString(proc.cmd1)
                ownerList.addString(proc.user)
                cmdlineList.addString(proc.cmd2)
                stimeList.addLong(proc.createTime)
                pidList.addLong(proc.pid)
                ppidList.addLong(proc.ppid)
                cpuList.addFloat(proc.cpu)
                cpuUserList.addFloat(getattr(proc, 'cpuUser', 0.0))
                cpuSysList.addFloat(getattr(proc, 'cpuSys', 0.0))
                rssList.addLong(proc.memoryBytes)
                vszList.addLong(proc.vsz)
                totalCharIoList.addFloat(proc.totalCharIO)
                threadCountList.addLong(proc.threadCount)
                processInfoList.addString("{}, {}, {}, {}, {} ({})".format(proc.user, proc.pid, proc.ppid, proc.createTime, proc.cmd1, proc.cmd2))
                if mem_total:
                    pRssList.addFloat(float(proc.memoryBytes) / float(mem_total) * 100.0)
                else:
                    pRssList.addValue(NullValue())

            topnPack.put("@id", idList)
            topnPack.put(TaskInfraProcessTopNAndGroup.PROCESS_TOPN_COMMAND, commandList)
            topnPack.put(TaskInfraProcessTopNAndGroup.PROCESS_TOPN_OWNER, ownerList)
            topnPack.put(TaskInfraProcessTopNAndGroup.PROCESS_TOPN_CMDLINE, cmdlineList)
            topnPack.put(TaskInfraProcessTopNAndGroup.PROCESS_TOPN_STIME, stimeList)
            topnPack.put(TaskInfraProcessTopNAndGroup.PROCESS_TOPN_PID, pidList)
            topnPack.put(TaskInfraProcessTopNAndGroup.PROCESS_TOPN_PPID, ppidList)
            topnPack.put(TaskInfraProcessTopNAndGroup.PROCESS_TOPN_CPU, cpuList)
            topnPack.put("cpuUser", cpuUserList)
            topnPack.put("cpuSys", cpuSysList)
            topnPack.put(TaskInfraProcessTopNAndGroup.PROCESS_TOPN_RSS, rssList)
            topnPack.put(TaskInfraProcessTopNAndGroup.PROCESS_TOPN_VSZ, vszList)
            topnPack.put(TaskInfraProcessTopNAndGroup.PROCESS_TOPN_TOTAL_CHAR_IO, totalCharIoList)
            topnPack.put(TaskInfraProcessTopNAndGroup.PROCESS_TOPN_THREAD_COUNT, threadCountList)
            topnPack.put(TaskInfraProcessTopNAndGroup.PROCESS_TOPN_PROCESSINFO, processInfoList)
            topnPack.put("pRss", pRssList)

        if pg:
            pgPack = tagcount_pack.TagCountPack()
            pgPack.pcode = pcode
            pgPack.oid = oid
            pgPack.time = now
            pgPack.category = TaskInfraProcessTopNAndGroup.PROCESS_GROUP
            pgPack.putTag("oname", str(secu.oname))
            pgPack.putTag("!rectype", str(self.recType))

            idList = ListValue()
            commandList = ListValue()
            ownerList = ListValue()
            cpuList = ListValue()
            cpuUserList = ListValue()
            cpuSysList = ListValue()
            rssList = ListValue()
            vszList = ListValue()
            totalCharIoList = ListValue()
            threadCountList = ListValue()
            processCountList = ListValue()
            nameList = ListValue()
            pidListVal = ListValue()
            pRssList = ListValue()

            for _, proc in pg.items():
                hash_key = hashutil.hashFromString("{}\\{}\\".format(proc.user, proc.cmd1))
                idList.addLong(hash_key)
                commandList.addString(proc.cmd1)
                ownerList.addString(proc.user)
                cpuList.addFloat(proc.cpu)
                cpuUserList.addFloat(getattr(proc, 'cpuUser', 0.0))
                cpuSysList.addFloat(getattr(proc, 'cpuSys', 0.0))
                rssList.addLong(proc.memoryBytes)
                vszList.addLong(proc.vsz)
                totalCharIoList.addFloat(proc.totalCharIO)
                threadCountList.addLong(proc.threadCount)
                processCountList.addLong(proc.processCount)
                nameList.addString(proc.name if getattr(proc, 'name', None) else proc.cmd1)
                pids = getattr(proc, 'pids', [])
                pidListVal.addString(",".join(str(p) for p in pids))
                if mem_total:
                    avg_rss = float(proc.memoryBytes) / float(proc.processCount) if proc.processCount > 0 else 0.0
                    pRssList.addFloat(avg_rss / float(mem_total) * 100.0)
                else:
                    pRssList.addValue(NullValue())

            pgPack.put("@id", idList)
            pgPack.put(TaskInfraProcessTopNAndGroup.PROCESS_GROUP_COMMAND, commandList)
            pgPack.put(TaskInfraProcessTopNAndGroup.PROCESS_GROUP_OWNER, ownerList)
            pgPack.put(TaskInfraProcessTopNAndGroup.PROCESS_GROUP_CPU, cpuList)
            pgPack.put("cpuUser", cpuUserList)
            pgPack.put("cpuSys", cpuSysList)
            pgPack.put(TaskInfraProcessTopNAndGroup.PROCESS_GROUP_RSS, rssList)
            pgPack.put(TaskInfraProcessTopNAndGroup.PROCESS_GROUP_VSZ, vszList)
            pgPack.put(TaskInfraProcessTopNAndGroup.PROCESS_GROUP_TOTAL_CHAR_IO, totalCharIoList)
            pgPack.put(TaskInfraProcessTopNAndGroup.PROCESS_GROUP_THREAD_COUNT, threadCountList)
            pgPack.put(TaskInfraProcessTopNAndGroup.PROCESS_GROUP_PROCESS_COUNT, processCountList)
            pgPack.put(TaskInfraProcessTopNAndGroup.PROCESS_GROUP_NAME, nameList)
            pgPack.put("pidList", pidListVal)
            pgPack.put("pRss", pRssList)


        return [topnPack, pgPack]


