import os, getpass, time, math, threading
import oommflink_net as net

CHUNK_SIZE = 2**19 # 512kb

ConfFileWriteLock = threading.Lock()
FileListLock = threading.Lock()

#####################
# UTILITY FUNCTIONS #
#####################

def countFileChunks(path):
    size = os.path.getsize(path)
    return int(math.ceil(size / float(CHUNK_SIZE))) #Slice into chunks, and count.

def printableFileSize(path):
    size = os.path.getsize(path)
    #Not pretty.
    if size < 2**10: # B range
        return str(size) + " B"
    elif size < 2**20: #K range
        return str(size/2**10) + " kB"
    elif size < 2**30: #M range
        return str(size/2**20) + " MB"
    else:
        return str(size/2**30) + " GB"

#Takes any number of strings, returns the path referenced to the cwd designated by those strings.
def localPath(*args):
    return os.path.sep.join(["."] + list(args))

###########
# BACKEND #
###########

class _OOMMFLink(object):
    def __init__(self):
        #Before construction, pick up configuration options to properly display them in the GUI.
        #These may all be defaults - and that's OK!
        self.conf = self.getConfig()

        self.batchname = ""
        self.sendqueue = []

        #If you get information on what the server is doing, it goes here.
        self.netStats = {"runningSims":[],
                         "queuedSims":[],
                         "doneSims":[],
                         "erroredSims":[]}

        net.UploadManager.linkToData(self)

    def confUpdate(self, key, val, lazy=False):
        self.conf[key] = val
        if not lazy: #For some reason, we don't think this is worth writing right now
            self.writeConf()

    def updateBatchname(self, name):
        self.batchname = name

    def addFile(self, filename):
        with FileListLock:
            self.sendqueue.append(filename)

    def upload(self):
        print "Entering Upload..."
        with FileListLock:
            net.UploadManager.upload(servername=self.conf["server"], port=int(self.conf["port"]), username=self.conf["username"],
                                     batchname=self.batchname, filenames=self.sendqueue)

            #Not sure if you succeeded or not - hold off on resetting.

    def estimateChunkLoad(self):
        numChunks = 0
        for file in self.sendqueue:
            numChunks += countFileChunks(file)
        return numChunks

    def reset(self):
        self.batchname = ""
        self.sendqueue = []

    def getNetstats(self):
        #Might the queue be empty? Yes. Fortunately, no one will notice.
        net.UploadManager.getNetstats(servername=self.conf["server"], port=int(self.conf["port"]), username=self.conf["username"],
                                      batchname=self.batchname, filenames=self.sendqueue, netstat=True)

    def clearQueueItems(self, indices):
        with FileListLock:
            #Slow, but safe.
            victims = [self.sendqueue[i] for i in indices]
            for item in victims:
                self.sendqueue.remove(item)

    def getConfig(self):
        #Returns a dictionary - set default values now
        #Yes, initialize everything to strings - ensure code is adequately defensive.
        #It's what you'd get from the file, and what we'll be dealing with in wx
        #You must check to numberize later.
        confValues = {"server":"127.0.0.1",
                      "port":"16101",
                      "username":getpass.getuser()}

        #Try to open the file; if not, use default values.
        if os.path.exists(localPath("oommflink.conf")):
            with open(localPath("oommflink.conf"), "r") as f:
                for line in f.readlines():
                    #Assign the key-value pairs. Hope the user doesn't hurt you too much.
                    if len(line.split(" ", 1)) == 2:
                        #Looks well-formed
                        key, val = line.strip().split(" ",1)
                        confValues[key] = val
                    else:
                        #Ignore this conf value - malformed.
                        continue
        return confValues

    def writeConf(self):
        with ConfFileWriteLock:
            #Write the dictionary to a file
            with open("." + os.path.sep + "oommflink.conf", "w") as f:
                for key, val in self.conf.iteritems():
                    f.write(key + " " + val + "\n")

    def goDown(self):
        for item in self.runningSims:
            if item.subprocess:
                item.subprocess.terminate()

###################
# IMPORT-TIME FUN #
###################

#Make the singleton config/data manager
OOMMFLink = _OOMMFLink()
