#!/bin/env python

import curses
import os
import sys
import time


#parse arguments
logFile = None
directories = []
nextLogFile = False
for w in sys.argv[1:]:
    if w == "-l":
        nextLogFile = True
    elif nextLogFile:
        logFile = w
        nextLogFile = False
    else:
        directories.append(w)

historyBytes = {}
historyInodes = {}
for dir in directories:
    historyBytes[dir] = []
    historyInodes[dir] = []
historyMaxSize = 60

if logFile:
    dirstring = "# Recommended gnuplot commands:\n"
    dirstring += "#    set key autotitles columnheader\n"
    dirstring += "#    plot \"{0}\" u 1:3 w l, \'\' u 1:5 w l, \'\' u 1:7 w l \n\n".format(logFile)
    dirstring += "time  "
    for dir in directories:
        dirstring = dirstring + "\"{0}: bytes\"   \"{1}: inodes\"  ".format(dir,dir) 
    dirstring = dirstring + '\n'
    with open(logFile,"w") as f:
        f.write(dirstring)
   



def prettyTable(stringTable):
    
    nrows = len(stringTable)
    ncolumns = len(stringTable[0])

    # the maximum width of each column entry is the width of the column
    columnWidths = []
    for i in range(0,ncolumns):
        column = list(stringTable[j][i] for j in range(0,nrows))
        columnWidth = max(map(len,column))
        columnWidths.append(columnWidth)
    
    tableString = ""

    # print header
    for row in stringTable[0:2]:
        for i in range(0,ncolumns):
            width = columnWidths[i]
            tableEntry = row[i]      
            tableString += tableEntry + ' ' * (width-len(tableEntry))
            if i < ncolumns-1:
                tableString += " | "
            else:
                tableString += "\n"

    # print horizontal line    
    tableString += '_'*(sum(columnWidths)+3*(ncolumns-1))+'\n'

    # following lines
    for row in stringTable[2:]:
        for i in range(0,ncolumns):
            width = columnWidths[i]
            tableEntry = row[i]      
            tableString += tableEntry + ' ' * (width-len(tableEntry))
            if i < ncolumns-1:
                tableString += " | "
            else:
                tableString += "\n"

    return tableString


def shrink(text, xmax, ymax):
    returnString = ""
    y = 0
    x = 0 
    for c in text:
        if c == '\n':
            y += 1
            x = 0
            returnString += '\n'
            if y == ymax:
                return returnString
        elif x < xmax:
            returnString += c
            x += 1
    return returnString

def bytesToHuman (bytes):
    if bytes == 0:
        return "0 KB"
    units = ["K","M","G","T"]
    _bytes = bytes/1024
    unitsIndex = 0
    resultString = ""
    while unitsIndex < len(units) and abs(_bytes) > 0:
        if(unitsIndex == len(units) -1):
            resultString = "{0: >4d}{1:s} ".format(_bytes,units[unitsIndex]) + resultString
            _bytes = 0
        else:
            resultString = "{0: >4d}{1:s} ".format(_bytes%1024,units[unitsIndex]) + resultString
            _bytes = _bytes/1024
        unitsIndex += 1
    return resultString

def display(screen):
    lastDisplay = ""
    try:
        curses.start_color()
        curses.use_default_colors()
        curses.init_pair(1, -1, -1)
        screen.bkgd(curses.color_pair(1))
       
        startTime = 0;

        while 1:
            outString = ""
            logString = "{0}  ".format(startTime)
            startTime = startTime + 1
            for dir in directories:
                outString = outString + "\nVolume: {0}\n".format(dir)
                statbuf = os.statvfs(dir)
                numberOfFreeBytes = statbuf.f_bfree * statbuf.f_bsize
                totNumberOfBytes = statbuf.f_blocks * statbuf.f_bsize
                fillState = totNumberOfBytes - numberOfFreeBytes
                relFillState = fillState/float(totNumberOfBytes)*100
                numberOfFreeInodes = statbuf.f_ffree
                totNumberOfInodes = statbuf.f_files
                fillStateInodes = totNumberOfInodes - numberOfFreeInodes
                relFillStateInodes = 0
                if totNumberOfInodes > 0:
                    relFillStateInodes = fillStateInodes/float(totNumberOfInodes)*100
                else:
                    reFillStateInodes = 0

                historyBytes[dir].append(fillState)
                historyInodes[dir].append(fillStateInodes)

                speed01 = 0
                speed03 = 0
                inodeSpeed01 = 0
                inodeSpeed03 = 0
                if len(historyBytes[dir]) > historyMaxSize:
                    historyBytes[dir].pop(0)
                    historyInodes[dir].pop(0)
                if len(historyBytes[dir]) > 1:
                    status0 = historyBytes[dir][-1]
                    status1 = historyBytes[dir][-2]
                    status2 = historyBytes[dir][0]
                    speed01 = status0-status1
                    if abs(speed01) > 1024**2:
                        speed01 = speed01/1024.0**2
                        speed01 = "{0:.2f}MB/s".format(speed01)
                    else:
                        speed01 = speed01/1024.0
                        speed01 = "{0:.2f}KB/s".format(speed01)
                    speed03 = (status0 - status2)/float(len(historyBytes[dir]))
                    if abs(speed03) > 1024**2:
                        speed03 = speed03/1024.0**2
                        speed03 = "{0:.2f}MB/s".format(speed03)
                    else:
                        speed03 = speed03/1024.0
                        speed03 = "{0:.2f}KB/s".format(speed03)
                    inodes0 = historyInodes[dir][-1]
                    inodes1 = historyInodes[dir][-2]
                    inodes2 = historyInodes[dir][0]
                    inodeSpeed01 = str(inodes0 - inodes1) + '/s'
                    inodeSpeed03 = (inodes0 - inodes2)/float(len(historyInodes[dir]))
                    inodeSpeed03 = "{0:.2f}/s".format(inodeSpeed03)
                                
                #make table
                headerLine = ['*', 'use', 'avail', 'tot', 'use%', 'speed', 'speed']
                subheaderLine = ['', '', '', '', '', '(1s avg)', '({0}s avg)'.format(len(historyBytes[dir]))]
                bytesLine = ['bytes',
                             bytesToHuman(fillState),
                             bytesToHuman(numberOfFreeBytes),
                             bytesToHuman(totNumberOfBytes),
                             "{0:.2g}%".format(relFillState),
                             str(speed01),
                             str(speed03)]
                inodesLine = [ 'inodes',
                               str(fillStateInodes),
                               str(numberOfFreeInodes),
                               str(totNumberOfInodes),
                               "{0:.2g}%".format(relFillStateInodes),
                               str(inodeSpeed01),
                               str(inodeSpeed03)]
                outString += prettyTable([headerLine,subheaderLine,bytesLine,inodesLine]) +'\n'
                logString += "{0}  {1}  ".format(fillState,fillStateInodes)

            outString = "GRIMSEL Disk Utility\n" + outString
            lastDisplay = outString
            logString += '\n'
            if logFile:
                with open(logFile,"a") as f:
                    f.write(logString)
                
            screen.erase()
            ymax , xmax = screen.getmaxyx()
            screen.addstr(shrink(outString,xmax-1,ymax-1))
            screen.refresh()
            time.sleep(1)
    except KeyboardInterrupt:
        raise Exception(lastDisplay)


try:                        
    curses.wrapper(display)
except Exception, msg:
    print msg
    
