import psutil
import whatap.pack.smbase_pack as smbase_pack
import whatap.pack as pack
import time, os
from StringIO import StringIO
import subprocess
from . import CPUStat
import whatap.util.logging_util as logging_util
import whatap.util.process_util as process_util


#infra
oldCpu = None
def GetCpu():
    cpu_times = psutil.cpu_times(percpu=False)

    global oldCpu
    if not oldCpu:
        oldCpu = cpu_times
        return None

    c = smbase_pack.CpuLinux()
    all_cpu = cpu_times.user + cpu_times.iowait + cpu_times.idle + cpu_times.system + cpu_times.nice
    last_all_cpu = oldCpu.user + oldCpu.iowait + oldCpu.idle + oldCpu.system + oldCpu.nice
    jiff = float(100)
    cpu_diff = float(all_cpu - last_all_cpu)
    c.user = jiff * float(cpu_times.user - oldCpu.user) / cpu_diff
    c.system = jiff * float(cpu_times.system - oldCpu.system) / cpu_diff
    c.iowait = jiff * float(cpu_times.iowait - oldCpu.iowait) / cpu_diff
    c.idle = jiff * float(cpu_times.idle - oldCpu.idle) / cpu_diff
    c.nice = jiff * float(cpu_times.nice - oldCpu.nice) / cpu_diff
    c.irq = float(0)
    c.softirq = float(0)
    c.steal = float(0)
    cpu_load = psutil.getloadavg()
    c.load1 = cpu_load.load1
    c.load5 = cpu_load.load5
    c.load15 = cpu_load.load15

    oldCpu = cpu_times

    return c


oldCpuList = None
def GetCpuCore():
    cpu_times = psutil.cpu_times(percpu=True)
    jiff = float(100)

    global oldCpuList
    if not oldCpuList:
        oldCpuList = cpu_times
        return None

    cpuPerf = {}
    for core, ctimes in cpu_times.items():
        if core not in oldCpuList:
            continue
        c = smbase_pack.CpuLinux()
        all_cpu = ctimes.user + ctimes.iowait + ctimes.idle + ctimes.system + ctimes.nice
        last_all_cpu = oldCpuList[core].user + oldCpuList[core].iowait + oldCpuList[core].idle + oldCpuList[core].system + oldCpuList[core].nice
        cpu_diff = float(all_cpu - last_all_cpu)

        if cpu_diff == 0:
            c.user = 0
            c.system = 0
            c.iowait = 0
            c.idle = 0
            c.nice = 0
        else:
            c.user = jiff * float(ctimes.user - oldCpuList[core].user) / cpu_diff
            c.system = jiff * float(ctimes.system - oldCpuList[core].system) / cpu_diff
            c.iowait = jiff * float(ctimes.iowait - oldCpuList[core].iowait) / cpu_diff
            c.idle = jiff * float(ctimes.idle - oldCpuList[core].idle) / cpu_diff
            c.nice = jiff * float(ctimes.nice - oldCpuList[core].nice) / cpu_diff

        c.irq = float(0)
        c.softirq = float(0)
        c.steal = float(0)

        cpuPerf[core] = c

    oldCpuList = cpu_times

    return cpuPerf




oldStats = None
def GetCpuStat():
    now = time.time()

    cpuStats = psutil.cpu_stats_detail()
    global oldStats
    if not oldStats:
        oldStats = [cpuStats, now]
        return None

    difftime = float(now- oldStats[1])
    oldCpuStats = oldStats[0]

    cs = CPUStat() 
    cs.ctx = float(cpuStats[0] - oldCpuStats[0]) / difftime
    cs.interrupt = float(cpuStats[1] - oldCpuStats[1]) / difftime
    cs.syscall = float(cpuStats[2] - oldCpuStats[2]) / difftime
    cs.forkCount = float(cpuStats[3] - oldCpuStats[3]) / difftime
    cs.execCount = float(cpuStats[4] - oldCpuStats[4]) / difftime
    cs.runqueue = float(cpuStats[5])
    cs.blockqueue = float(cpuStats[6])
    cs.waitqueue = float(cpuStats[7])
    cs.pendingqueue = CPUStat.UNSUPPORTED

    oldStats = [cpuStats, now]

    return cs


def GetSwapMemory():
    m = smbase_pack.MemoryLinux()
    command = "swapinfo -t | grep total"
    try:
        swapinfo= subprocess.Popen(command, shell=True, stdout=subprocess.PIPE)
        smem = swapinfo.stdout.read().strip('\n').split()
        m.swapTotal = int(smem[1]) * 1024
        m.swapUsed = int(smem[2]) * 1024
        m.swapPused = float(smem[2]) / float(smem[1]) * 100.0
    except subprocess.CalledProcessError as e:
        logging_util.debug("memory cache check error", e)
        m.swapTotal = 0
        m.swapUsed = 0
        m.swapPused = 0

    return m



_bufpages_cache = None
_BUFPAGES_CMD = "sysdef | grep bufpages | awk '{print $2}'"


def _get_bufpages():
    global _bufpages_cache
    if _bufpages_cache is not None:
        return _bufpages_cache
    try:
        output = process_util.executeCommandShellWithTimeout(_BUFPAGES_CMD, 1)
        if output:
            _bufpages_cache = int(output.strip())
        else:
            _bufpages_cache = 0
    except Exception, e:
        logging_util.debug("bufpages init error", e)
        _bufpages_cache = 0
    return _bufpages_cache


oldMemoryStat = None
def GetMemory():
    memory = psutil.virtual_memory_detail()
    now = time.time()

    global oldMemoryStat
    if not oldMemoryStat:
        oldMemoryStat = [memory, now]
        return None

    m = smbase_pack.MemoryLinux()
    m.cached = _get_bufpages() * memory[5]
    m.total = memory[0] # total
    m.free = memory[3] # free

    m.available = m.free+ m.cached
    m.pavailable = float(m.available) / float(m.total) * float(100.0)
    m.used = m.total - m.available
    m.pused = float(float(m.used)/float(m.total)*100.0)
    m.buffers = 0
    m.shared = 0
    m.pageFault = 0
 
    oldMemory = oldMemoryStat[0]
    difftime = float(now - oldMemoryStat[1])

    m.swapIn = float(memory[6] - oldMemory[6]) / difftime
    m.swapOut = float(memory[7] - oldMemory[7]) / difftime
    m.fileSystemIn = float(memory[8] - oldMemory[8]) / difftime
    m.fileSystemOut = float(memory[9] - oldMemory[9]) / difftime
    m.scannedPage = float(memory[10] - oldMemory[10]) / difftime
    m.freedPage = float(memory[11] - oldMemory[11]) / difftime

    oldMemoryStat = [memory, now]
    return m




oldVmstat = None

def GetCpuMemory():
    jiff = float(100)
    
    logging_util.debug("[base] start cpu_times")
    cpu_times = psutil.cpu_times(percpu=False)
    global oldVmstat
    if not oldVmstat:
        oldVmstat = cpu_times
        return None, None, None
    logging_util.debug("[base] end cpu_times")
    c = smbase_pack.CpuLinux()


    all_cpu = cpu_times.user + cpu_times.iowait + cpu_times.idle + cpu_times.system + cpu_times.nice
    last_all_cpu = oldVmstat.user + oldVmstat.iowait + oldVmstat.idle + oldVmstat.system + oldVmstat.nice

    cpu_diff = float(all_cpu - last_all_cpu)
    c.user = jiff * float(cpu_times.user - oldVmstat.user) / cpu_diff
    c.system = jiff * float(cpu_times.system - oldVmstat.system) / cpu_diff
    c.iowait = jiff * float(cpu_times.iowait - oldVmstat.iowait) / cpu_diff
    c.idle = jiff * float(cpu_times.idle - oldVmstat.idle) / cpu_diff
    c.nice = jiff * float(cpu_times.nice - oldVmstat.nice) / cpu_diff
    c.irq = float(0)
    c.softirq = float(0)
    c.steal = float(0)

    logging_util.debug("[base] start getloadavg")
    cpu_load = psutil.getloadavg()
    logging_util.debug("[base] end getloadavg")
    c.load1 = cpu_load.load1
    c.load5 = cpu_load.load5
    c.load15 = cpu_load.load15
    oldVmstat = cpu_times

    p = smbase_pack.MemoryLinux()
    logging_util.debug("[base] start virtual_memory")
    vmem = psutil.virtual_memory()
    logging_util.debug("[base] end virtual_memory")

    #
    logging_util.debug("[base] start sysdef")
    p.cached = _get_bufpages() * vmem.pagesize
    logging_util.debug("[base] end sysdef")

    p.total = vmem.total
    p.free = vmem.free
    p.used = vmem.used - p.cached
    p.available = vmem.available + p.cached
    p.pused = float(p.used) / float(p.total) * 100.0
    p.pavailable = float(p.available) / float(p.total) * 100.0

    p.buffers = 0
    p.shared = 0

    logging_util.debug("[base] start swapinfo")
    command = "swapinfo -t | grep total"
    output = process_util.executeCommandShellWithTimeout(command, 1)
    if output == "":
        p.swapTotal = 0
        p.swapUsed = 0
        p.swapPused = 0
    else:
        smem = output.strip('\n').split()
        p.swapTotal = int(smem[1])
        p.swapUsed = int(smem[2])
        p.swapPused = float(smem[2]) / float(smem[1]) * 100.0

    logging_util.debug("[base] end swapinfo")

    p.pageFault = 0

    uptime = int(time.time()) - int(psutil.boot_time())

    return c, p, uptime

