import subprocess, os, platform, json, glob, hashlib, sys, traceback, urllib, urllib2
class MCNostalgia() :
    def __init__(self, path=None, execute=None, bindir=None, outputdir=None, origdir=None, patchdir="patches") :
        if path == None :
            self.path =  os.getcwd()
        else :
            self.path = path
        self.ostype = self.detectOS()
        if execute == None :
            if self.ostype == "windows" :
                self.execute = self.path+"\\bin\\bspatch.exe"
            else : self.execute = "bspatch"
        else : self.execute = execute
        self.patchdir = os.path.abspath(patchdir)
        if bindir == None :
            self.bindir = self.getMCBinPath()
        else : self.bindir = bindir
        if outputdir == None :
            self.outputdir = self.bindir
        else :
            self.outputdir = outputdir
        if origdir == None :
            self.origdir = self.bindir
        self.order = []
    def fetchAvailableVersions(self) :
        data = {"pversion":1, "list":True}
        urlobj = urllib2.urlopen("http://sonicrules.org/mcnweb.py", urllib.urlencode(data))
        urldata = urlobj.read()
        urlobj.close()
        jsondict = json.loads(urldata)
        uorder = jsondict[u"order"]
        for version in uorder :
            self.order.append(str(version))
        return self.order
    def fetchVersion(self, version) :
        if self.order == [] :
            self.fetchAvailableVersions()
        if version in self.order and version not in self.getDownloadedVersions() :
            data = {"pversion":1, "mcversion":version}
            urlobj = urllib2.urlopen("http://sonicrules.org/mcnweb.py", urllib.urlencode(data))
            urldata = urlobj.read()
            urlobj.close()
            jsondict = json.loads(urldata)
            url = str(jsondict[u"url"])
            os.mkdir(os.path.join(self.patchdir, version))
            for filename in ["minecraft.ptch", "lwjgl.ptch", "checksum.json", "lwjgl_util.ptch", "jinput.ptch"] :
                print "Downloading", filename
                urlobj = urllib2.urlopen(url + "/" + filename)
                data = urlobj.read()
                urlobj.close()
                x = open(os.path.join(self.patchdir, version, filename), "wb")
                x.write(data)
                x.close()
            del data
    def checkFiles(self) :
        try :
            jarfiles = [os.path.split(path)[1] for path in glob.glob(os.path.join(self.bindir, "*.jar"))]
            if "minecraft.jar" in jarfiles and "lwjgl.jar" in jarfiles and "lwjgl_util.jar" in jarfiles and "jinput.jar" in jarfiles :
                return True
            return False
        except :
            return False
    def patch(self, origfile, outputfile, patchfile) :
        try :
            subprocess.call([self.execute, origfile, outputfile, patchfile])
        except OSError :
            traceback.print_exc()
            if self.ostype == "linux" :
                print "You got an OSError.  Since you are running Linux, you probably are missing the bspatch command.  In most distributions, it is in the bsdiff package.  Please install this and try again"
            elif self.ostype == "windows" :
                print "You got an OSError.  Since you are running Windows, you are probably missing a file in your .minecraft bin folder.  To fix this, delete your .minecraft bin folder, run the launcher, and login."
            elif self.ostype == "mac" :
                print "You got an OSError.  Since you are running a Mac, you are probably missing files in your minecraft bin folder.  To fix this, delete your minecraft bin folder, run the launcher, and login."
    def patchTo(self, mcversion) :
        if mcversion not in self.getDownloadedVersions() :
            self.fetchVersion(mcversion)
        hashinfo = self.getInfoForHashing(mcversion)
        for filename in ["minecraft", "lwjgl_util", "jinput", "lwjgl"] :
            self.patch(os.path.join(self.origdir, filename+".jar"), os.path.join(self.outputdir, filename+".jar"), os.path.join(self.patchdir, mcversion, filename+".ptch"))
            if self.checksum(mcversion, filename, hashinfo) :
                print "Patched", filename + ".jar", "successfully!"
            else :
                print filename + ".jar", "was not patched successfully."
                return False
        return True
    def checkOrig(self, version) :
        hashinfo = self.getInfoForHashing(version)
        for filename in ["minecraft", "lwjgl_util", "jinput", "lwjgl"] :
            fileobj = open(os.path.join(self.origdir, filename+".jar"), "rb")
            file_read = fileobj.read()
            fileobj.close()
            if hashlib.md5(file_read).hexdigest() != hashinfo["CurrentVersion"][filename] :
                #print "Hashlib md5 = ", hashlib.md5(file_read).hexdigest()
                return False
        return True    
    def checksum(self, mcversion, filename, hashinfo) :
        #print "Checksums not implemented yet!"
        fileobj = open(os.path.join(self.outputdir, filename+".jar"), "rb")
        file_read = fileobj.read()
        fileobj.close()
        if hashlib.md5(file_read).hexdigest() == hashinfo["OldVersion"][filename] :
            return True
        else : return False
    def getInfoForHashing(self, version) :
        fileobj = open(os.path.join(self.patchdir, version, "checksum.json"), "r")
        file_read = fileobj.read()
        fileobj.close()
        checksumdict = json.loads(file_read)
        oldversion = checksumdict[u"OldVersion"]
        currentversion = checksumdict[u"CurrentVersion"]
        return {"CurrentVersion":{"jinput":str(currentversion[u"jinput"]), "lwjgl_util":str(currentversion[u"lwjgl_util"]), "lwjgl":str(currentversion[u"lwjgl"]), "minecraft":str(currentversion[u"minecraft"]), "version":str(currentversion[u"version"])}, "OldVersion":{"jinput":str(oldversion[u"jinput"]), "lwjgl_util":str(oldversion[u"lwjgl_util"]), "lwjgl":str(oldversion[u"lwjgl"]), "minecraft":str(oldversion[u"minecraft"]), "version":str(oldversion[u"version"])}}
        
    def getDownloadedVersions(self) :
        versions = []
        for root, dirs, files in os.walk(os.path.join(self.path, self.patchdir)) :
            for directory in dirs :
                filename = glob.glob(os.path.join(self.path, self.patchdir, directory) + os.sep + "checksum.json")
                if len(filename) == 1 :
                    versions.append(directory)
        versions.sort()
        return versions
    
    def detectOS(self) :
        #plat = platform.uname()[0].lower()
        plat = sys.platform
        #if plat in ["linux", "unix", "solaris", "sunos"] :
        if plat.startswith("linux") :
            return "linux"
        elif plat == "darwin" :
            return "mac"
        elif plat.startswith("win") :
            return "windows"
        else :
            return "other"
    def normalize(self, path) :
        return os.path.normcase(path)
    def getMCBinPath(self) :
        ostype = self.detectOS()
        if ostype == "linux" :
            mcpath = os.path.expanduser('~/.minecraft/bin')
        elif ostype == "mac" :
            mcpath = os.path.expanduser('~/Library/Application Support/minecraft/bin')
        elif ostype == "windows" :
            if os.path.expandvars('$appdata') != None:
                mcpath = self.normalize(os.path.expandvars('$appdata/.minecraft/bin'))
            else:
                mcpath = self.normalize(os.path.expanduser('~/.minecraft/bin'))
        return mcpath    
