import json
import urllib2
from directories import userCachePath, getDataDir
import os
import time
import base64  # @UnusedImport
from pymclevel.mclevelbase import PlayerNotFound
import urllib
from PIL import Image
from urllib2 import HTTPError
import atexit
import threading
import traceback
import logging

logger = logging.getLogger()

def deprecated(func):
    def new_func(*args, **kwargs):
        #logger.warn("Function \""+str(func.__name__)+"\" is deprecated and should not be used")
        return func(*args, **kwargs)   
    new_func.__name__ = func.__name__
    new_func.__doc__ = func.__doc__
    new_func.__dict__.update(func.__dict__)
    return new_func

#def getPlayerSkinURL(uuid):
#    try:
#        playerJSONResponse = urllib2.urlopen('https://sessionserver.mojang.com/session/minecraft/profile/{}'.format(uuid))
#        print playerJSONResponse
#        texturesJSON = json.loads(playerJSONResponse)['properties']
#        for prop in properties:
#            if prop['name'] == 'textures':
#                b64 = base64.b64decode(prop['value']);
#                print b64
#                return json.loads(b64)['textures']['SKIN']['url']
#    except:
#        raise

#print getPlayerSkinURL('4566e69fc90748ee8d71d7ba5aa00d20')


class __PlayerCache:
    
    SUCCESS = 0
    FAILED = 1

    def __convert(self):
        jsonFile = None
        fp = open(userCachePath)
        try:
            jsonFile = json.load(fp)
            fp.close()
        except ValueError:
            fp.close()
            # Assuming JSON file is corrupted, deletes file and creates new one
            os.remove(userCachePath)
            with open(userCachePath, 'w') as json_out:
                json.dump([], json_out)
        if jsonFile is not None:
            for old_player in jsonFile.keys():
                player = jsonFile[old_player]
                new_player = {"Playername": player["username"], "UUID (No Separator)": old_player.replace("-", ""),
                              "UUID (Separator)": old_player, "WasSuccessful": True, "Timstamp": player["timestamp"]}
                self._playerCacheList.append(new_player)
            self._save()
            print "Convert usercache.json"
            
    def fixAllOfPodshotsBugs(self):
        for player in self._playerCacheList:
            if "Timstamp" in player:
                player["Timestamp"] = player["Timstamp"]
                del player["Timstamp"]
        self._save()
    
    
    def __init__(self):
        self._playerCacheList = []
        if not os.path.exists(userCachePath):
            out = open(userCachePath, 'w') 
            json.dump(self._playerCacheList, out)
            out.close()
        f = open(userCachePath, 'r')
        line = f.readline()
        if line.startswith("{"):
            f.close()
            self.__convert()
        f.close()
        try:
            json_in = open(userCachePath)
            self._playerCacheList = json.load(json_in)
        except:
            logger.warning("Usercache.json may be corrupted")
            self._playerCacheList = []
        finally:
            json_in.close()
        self.fixAllOfPodshotsBugs()
        self.refresh_lock = threading.Lock()
        self.player_refreshing = threading.Thread(target=self._refreshAll)
        self.player_refreshing.daemon = True
        self.player_refreshing.start()
        #self._refreshAll()
        

    def _save(self):
        out = open(userCachePath, "w")
        json.dump(self._playerCacheList, out, indent=4, separators=(',', ':'))
        out.close()
            
    def _removePlayerWithName(self, name):
        toRemove = None
        for p in self._playerCacheList:
            if p["Playername"] == name:
                toRemove = p
        if toRemove is not None:
            self._playerCacheList.remove(toRemove)
            self._save()
    
    def _removePlayerWithUUID(self, uuid, seperator=True):
        toRemove = None
        for p in self._playerCacheList:
            if seperator:
                if p["UUID (Separator)"] == uuid:
                    toRemove = p
            else:
                if p["UUID (No Separator)"] == uuid:
                    toRemove = p
        if toRemove is not None:
            self._playerCacheList.remove(toRemove)
            self._save()
            
    def nameInCache(self, name):
        isInCache = False
        for p in self._playerCacheList:
            if p["Playername"] == name:
                isInCache = True
        return isInCache
    
    def uuidInCache(self, uuid, seperator=True):
        isInCache = False
        for p in self._playerCacheList:
            if seperator:
                if p["UUID (Separator)"] == uuid:
                    isInCache = True
            else:
                if p["UUID (No Separator)"] == uuid:
                    isInCache = True
        return isInCache
    
    def _refreshAll(self):
        with self.refresh_lock:
            playersNeededToBeRefreshed = []
            try:
                t = time.time()
            except:
                t = 0
            for player in self._playerCacheList:
                if player["Timestamp"] != "<Invalid>":
                    if t - player["Timestamp"] > 21600:
                        playersNeededToBeRefreshed.append(player)
            for player in playersNeededToBeRefreshed:
                self.getPlayerFromUUID(player["UUID (Separator)"], forceNetwork=True, dontSave=True)
                self._save()
    
    def force_refresh(self):
        players = self._playerCacheList
        for player in players:
            self.getPlayerFromUUID(player["UUID (Separator)"], forceNetwork=True)
            
    @deprecated
    def getPlayerFromUUID(self, uuid, forceNetwork=False, dontSave=False):
        player = {}
        response = None
        if forceNetwork:
            if self.uuidInCache(uuid):
                self._removePlayerWithUUID(uuid)
            try:
                response = urllib2.urlopen("https://sessionserver.mojang.com/session/minecraft/profile/{}".format(uuid.replace("-",""))).read()
            except urllib2.URLError:
                return uuid
            if response is not None and response != "":
                playerJSON = json.loads(response)
                player["Playername"] = playerJSON["name"]
                player["UUID (No Separator)"] = playerJSON["id"]
                player["UUID (Separator)"] = uuid
                player["WasSuccessful"] = True
                player["Timestamp"] = time.time()
                self._playerCacheList.append(player)
                if not dontSave:
                    self._save()
                return playerJSON["name"]
            else:
                return uuid
        else:
            couldNotFind = False
            for p in self._playerCacheList:
                if p["UUID (Separator)"] == uuid and p["WasSuccessful"]:
                    couldNotFind = False
                    return p["Playername"]
                else:
                    couldNotFind = True
            if couldNotFind:
                result = self.getPlayerFromUUID(uuid, forceNetwork=True)
                if result == uuid:
                    player = {"Playername":"<Unknown>","UUID (Separator)":uuid,"UUID (No Separator)":uuid.replace("-",""),"Timestamp":"<Invalid>","WasSuccessful":False}
                    self._playerCacheList.append(player)
                    return uuid
    @deprecated
    def getPlayerFromPlayername(self, playername, forceNetwork=False, separator=True):
        response = None
        if forceNetwork:
            if self.nameInCache(playername):
                self._removePlayerWithName(playername)
            try:
                response = urllib2.urlopen("https://api.mojang.com/users/profiles/minecraft/{}".format(playername)).read()
            except urllib2.URLError:
                return playername
            if response is not None and response != "":
                playerJSON = json.loads(response)
                player = {"Playername": playername, "UUID (No Separator)": playerJSON["id"]}
                uuid = playerJSON["id"][:8]+"-"+playerJSON["id"][8:12]+"-"+playerJSON["id"][12:16]+"-"+playerJSON["id"][16:20]+"-"+playerJSON["id"][20:]
                player["UUID (Separator)"] = uuid
                player["WasSuccessful"] = True
                player["Timestamp"] = time.time()
                self._playerCacheList.append(player)
                self._save()
                if separator:
                    return uuid
                else:
                    return playerJSON["id"]
            else:
                return playername
        else:
            couldNotFind = False
            for p in self._playerCacheList:
                if p["Playername"] == playername and p["WasSuccessful"]:
                    couldNotFind = False
                    return p["UUID (Separator)"]
                else:
                    couldNotFind = True
            if couldNotFind:
                result = self.getPlayerFromPlayername(playername, forceNetwork=True)
                if result == playername:
                    player = {"Playername":playername,"UUID (Separator)":"<Unknown>","UUID (No Separator)":"<Unknown>","Timestamp":"<Invalid>","WasSuccessful":False}
                    self._playerCacheList.append(player)
                    return playername
    
    # 0 if for a list of the playernames, 1 is for a dictionary of all player data
    def getAllPlayersKnown(self, returnType=0, include_failed_lookups=False):
        toReturn = None
        if returnType == 0:
            toReturn = []
            for p in self._playerCacheList:
                if p["WasSuccessful"]:
                    toReturn.append(p["Playername"])
                elif include_failed_lookups:
                    toReturn.append(p["Playername"])      
        elif returnType == 1:
            toReturn = {}
            for p in self._playerCacheList:
                if p["WasSuccessful"]:
                    toReturn[p["Playername"]] = p
                elif include_failed_lookups:
                    toReturn[p["Playername"]] = p
        return toReturn
    
    def getFromCacheUUID(self, uuid, seperator=True):
        for player in self._playerCacheList:
            if seperator and player["UUID (Separator)"] == uuid:
                return player["UUID (Separator)"], player["Playername"], player["UUID (No Separator)"]
            elif player["UUID (No Separator)"] == uuid:
                return player["UUID (Separator)"], player["Playername"], player["UUID (No Separator)"]
            
    def getFromCacheName(self, name):
        for player in self._playerCacheList:
            if name == player["Playername"]:
                return player["UUID (Separator)"], player["Playername"], player["UUID (No Separator)"]
    
    def getPlayerInfo(self, arg, force=False):
        if arg.count('-') == 4:
            if self.uuidInCache(arg) and not force:
                return self.getFromCacheUUID(arg)
            else:
                return self._getPlayerInfoUUID(arg)
        else:
            if self.nameInCache(arg) and not force:
                return self.getFromCacheName(arg)
            else:
                return self._getPlayerInfoName(arg)
        
    def _getPlayerInfoUUID(self, uuid):
        response_name = None
        response_uuid = None
        player = {}
        if self.uuidInCache(uuid):
            self._removePlayerWithUUID(uuid)
        try:
            response_uuid = json.loads(urllib2.urlopen("https://sessionserver.mojang.com/session/minecraft/profile/{}".format(uuid.replace("-", ""))).read())
            response_name = json.loads(urllib2.urlopen("https://api.mojang.com/users/profiles/minecraft/{}".format(response_uuid["name"])).read())
        except urllib2.URLError:
            return uuid
        except ValueError:
            print "Caught value error while getting player info for "+uuid
            return uuid
        if response_name is not None and response_name != "" and response_uuid is not None and response_uuid != "":
            player["Playername"] = response_name["name"]
            player["UUID (Separator)"] = response_name["id"][:8]+"-"+response_name["id"][8:12]+"-"+response_name["id"][12:16]+"-"+response_name["id"][16:20]+"-"+response_name["id"][20:]
            player["UUID (No Separator)"] = response_name["id"]
            player["WasSuccessful"] = True
            player["Timestamp"] = time.time()
            self._playerCacheList.append(player)
            self._save()
            return player["UUID (Separator)"], player["Playername"], player["UUID (No Separator)"]
        else:
            return uuid
            #raise Exception("Couldn't find player")
    
    def _getPlayerInfoName(self, playername):
        response_name = None
        response_uuid = None