import os, time
import psutil
import whatap.util.process_util as process_util
import whatap.agent.conf.configure as conf
import re
from . import _DiskPerf

proc_diskstats='/proc/diskstats'

filesystems = { "btrfs": True, "ext2": True, "ext3": True, "ext4": True, "reiser": True, "xfs": True,
        "ffs": True, "ufs": True, "jfs": True, "jfs2": True, "vxfs": True, "hfs": True, "ntfs": True, "fat32": True,
        "zfs": True, "refs": True, "nfs": True, "nfs2": True, "nfs3": True, "nfs4": True, "cifs": True, "ocfs2": True }

class _DiskIORaw:
    def __init__(self):
        self.fsname = None
        self.writeIoCount = None
        self.readIoCount = None
        self.writeIoByte = None
        self.readIoByte = None
        self.busyTime = None
        self.timestamp = None



oldDiskIoMap = None


def getLvmMap():
    lvmtabFile = open('/etc/lvmtab', 'rb')
    if not lvmtabFile:
        return None

    lvm = lvmtabFile.read()
    lvm = re.findall("[^\x00-\x1F\x7F-\xFF]{4,}", lvm)

    vg_map = {}
    current_vg = None

    vg_pattern = re.compile(r'/dev/(vg\w+)')
    pv_pattern = re.compile(r'/dev/dsk/(\w+)')

    for line in lvm:
        vg_match = vg_pattern.match(line.strip())
        pv_match = pv_pattern.match(line.strip())

        if vg_match:
            current_vg = vg_match.group(1)
            vg_map[current_vg] = []
        elif pv_match and current_vg:
            pv = pv_match.group(1)
            vg_map[current_vg].append(pv)

    lvmtabFile.close()

    return vg_map


#fs_in_counters 
#0 : read_count
#1 : write_count
#2 : read_bytes
#3 : write_btyes
#4 : read_time
#5 : write_time
#6 : busy


def getDisk():
    global oldDiskIoMap
    mnttabFile = open('/etc/mnttab','r')
    if not mnttabFile:
        return None

    lvmMap = getLvmMap()

    diskIoEnabled = conf.GetConfig().DiskIOEnabled
    ioCountersMap = {}
    if diskIoEnabled:
        ioCounters = psutil.fs_io_counters()
        timestamp = time.time()
        for fs, v in ioCounters.items():
            ioCountersRaw = _DiskIORaw()
            ioCountersRaw.fsname = fs
            ioCountersRaw.writeIoCount = v.write_count
            ioCountersRaw.readIoCount = v.read_count
            ioCountersRaw.writeIoByte = v.write_bytes
            ioCountersRaw.readIoByte = v.read_bytes
            ioCountersRaw.busyTime = v.busy_time
            ioCountersRaw.timestamp = timestamp
            ioCountersMap[fs] = ioCountersRaw

    try:
        diskQuotas = []
        for l in mnttabFile.readlines():
            words = l.split()
            if words[2] in filesystems:
                deviceId = words[0]
                p = _DiskPerf()
                p.mountPoint = words[1]
                p.deviceId = deviceId
                p.fileSystem = words[2]

                f_bsize, f_frsize, f_blocks, f_bfree, f_bavail, f_files, f_ffree, f_favail, f_flag, f_namemax = os.statvfs(p.mountPoint)
                p.totalSpace = int(f_frsize * f_blocks)
                p.usedSpace = int(f_frsize * (f_blocks - f_bfree))
                p.usedPercent = float(100.0) - float(100*f_bavail) / float(f_blocks - f_bfree + f_bavail)
                p.freeSpace = int(f_frsize * f_bavail )
                p.freePercent = float(100.0) * float(f_bavail) / float(f_blocks - f_bfree + f_bavail)
                if f_files == 0:
                    p.inodePercent = 0
                else:
                    p.inodePercent = float(100.0) * float(f_files- f_ffree) / float(f_files)

                p.blksize = int(f_frsize)

                if oldDiskIoMap and p.mountPoint in oldDiskIoMap and p.mountPoint in ioCountersMap:
                    ioCounters = ioCountersMap[p.mountPoint]
                    oldIoCounters = oldDiskIoMap[p.mountPoint]
                    timediff = ioCounters.timestamp - oldIoCounters.timestamp
                    p.writeIops = (ioCounters.writeIoCount - oldIoCounters.writeIoCount) / timediff
                    p.readIops = (ioCounters.readIoCount - oldIoCounters.readIoCount) / timediff
                    p.writeBps = (ioCounters.writeIoByte - oldIoCounters.writeIoByte) / timediff * 1024
                    p.readBps = (ioCounters.readIoByte - oldIoCounters.readIoByte) / timediff * 1024

                    nowBusyTime = ioCounters.busyTime
                    oldBusyTime = oldIoCounters.busyTime

                    maxBusyTime = 0
                    for k, v in nowBusyTime.items():
                        busyTime = 0
                        if k in oldBusyTime:
                            busyTime = v - oldBusyTime[k]
                        if busyTime > maxBusyTime:
                            maxBusyTime = busyTime

                    p.ioPercent = min(float(maxBusyTime) / float(timediff * 1000) * 100, 100.0)



                diskQuotas.append(p)
    finally:
        mnttabFile.close()

    oldDiskIoMap = ioCountersMap

    return diskQuotas


oldIOTotal = None
def GetDiskTotalIO():
    # v[0]=totalio v[1]=totalbyte v[2]=readio v[3]=writeio
    # v[4]=readbyte v[5]=writebyte v[6]=busytime v[7]=waittime v[8]=responsetime
    ioCounters = psutil.disk_io_counters_hpux()

    disk = [0, 0, 0, 0, 0, 0]
    for k, v in ioCounters.items():
        disk[0] += v[0]
        disk[1] += v[1]
        disk[2] += v[2]
        disk[3] += v[3]
        disk[4] += v[4]
        disk[5] += v[5]

    now = time.time()

    global oldIOTotal
    if not oldIOTotal:
        oldIOTotal = [disk, ioCounters, now]
        return None

    oldDisk = oldIOTotal[0]
    oldIoCounters = oldIOTotal[1]
    diffTime = float(now - oldIOTotal[2])

    ret = _DiskPerf()
    ret.totalIops = float(disk[0] - oldDisk[0]) / diffTime if diffTime > 0 else 0.0
    ret.totalBps  = float(disk[1] - oldDisk[1]) / diffTime if diffTime > 0 else 0.0
    ret.readIops  = float(disk[2] - oldDisk[2]) / diffTime if diffTime > 0 else 0.0
    ret.writeIops = float(disk[3] - oldDisk[3]) / diffTime if diffTime > 0 else 0.0
    ret.readBps   = float(disk[4] - oldDisk[4]) / diffTime if diffTime > 0 else 0.0
    ret.writeBps  = float(disk[5] - oldDisk[5]) / diffTime if diffTime > 0 else 0.0

    max_busy = 0.0
    max_disk_name = ""
    for k, v in ioCounters.items():
        if k not in oldIoCounters:
            continue
        oldv = oldIoCounters[k]
        busy_diff = float(v[6] - oldv[6])
        busy_pct = 100.0 * busy_diff / (diffTime * 1000) if diffTime > 0 else 0.0
        if busy_pct > max_busy:
            max_busy = busy_pct
            max_disk_name = k

    ret.busyMax = min(max_busy, 100.0)
    ret.diskName = max_disk_name

    oldIOTotal = [disk, ioCounters, now]
    return ret

oldIO = None
def GetDiskIO():
    ioCounters = psutil.disk_io_counters_hpux()

    now = time.time()

    global oldIO
    if not oldIO:
        oldIO = [ioCounters, now]
        return None

    oldDisk = oldIO[0]
    diffTime = float(now - oldIO[1])

    retArr = []
    for k, v in ioCounters.items():
        if k not in oldDisk:
            continue
        oldv = oldDisk[k]

        ret = _DiskPerf()
        ret.deviceId = k

        ioCount = float(v[0] - oldv[0])
        ret.totalIops= ioCount / diffTime
        ret.totalBps = float(v[1] - oldv[1]) / diffTime
        ret.readIops = float(v[2] - oldv[2]) / diffTime
        ret.writeIops = float(v[3] - oldv[3]) / diffTime
        ret.readBps = float(v[4] - oldv[4]) / diffTime
        ret.writeBps = float(v[5] - oldv[5]) / diffTime
        busyTime = float(v[6] - oldv[6])
        waitTime = float(v[7] - oldv[7])
        responseTime = float(v[8] - oldv[8])
        if ioCount == 0:
            ret.totalBusyTime = 0
            ret.totalWaitTime = 0
        else:
            ret.totalBusyTime = (responseTime - waitTime) / ioCount
            ret.totalWaitTime = waitTime / ioCount
        ret.ioPercent = 100 * busyTime / (diffTime * 1000)
        if ret.ioPercent > float(100):
            ret.ioPercent = float(100)

        retArr.append(ret)


    oldIO = [ioCounters, now]
    return retArr


def test():
    getDisk()
    time.sleep(5)
    for diskperf in getDisk():
        print [item for item in vars(diskperf).items()]

if __name__ == '__main__':
    test()
