#
#  Config.py

import yaml
import getopt, sys
import k, levels

from Krank  import *
from Sound  import *
from Level  import *
from Tools  import *

#-----------------------------------------------------------------------------------------------
#-----------------------------------------------------------------------------------------------

class Config (dict):
    
    def __init__(self):
        #log(log='startup')
        self['music_volume'] = 1.0
        self['sound_volume'] = 1.0
        self['scores'] = [[], [], [], []]
        self['stage'] = 1
        self['screen'] = ()
        self['totalTime'] = 0
        self['stageTime'] = [0,0,0,0]
        self['totalSolved'] = [0,0,0,0]
        self.stage = 1
        self.fullscreen = 0
        
        k.config = self
        
        self.load()
        
        try:
            opts, args = getopt.getopt(sys.argv[1:], 'whfs:')
        except getopt.GetoptError as err:
            print(str(err))
            self.usage_exit(-1)

        for o, a in opts:
        	if o == '-h': self.usage_exit(0)
        	if o == '-w': self.fullscreen = 0
        	if o == '-f': self.fullscreen = 1
        	if o == '-s': 
        		try:
        		    w,h=a.split('x', 2)
        		    self['screen']=int(w),int(h)
        		except ValueError as err:
        		    print("Invalid screen size:", a, "\n\t", str(err))
        		    self.usage_exit(-1)
        
    #-------------------------------------------------------------------------------------------
    def usage_exit(self, retcode):
        print("Usage:")
        print("\tkrank -h      for display this screen")
        print("\tkrank -f      for start in fullscreen mode")
        print("\tkrank -w      for start in windowed mode")
        print("\tkrank -s WxH  for start in screen (-f or -w) with defined size")
        print("\nexamples:")
        print("\tkrank -f -s 800x600")
        print("\tkrank -w -s 921x652")
        sys.exit(retcode)

    #-------------------------------------------------------------------------------------------
    def score (self, level):
        si = k.level.isBonus() and 4 or self.stage-1
        li = k.level.isBonus() and self.stage-1 or level-1

        # stats
        self['totalTime']       += k.level.time//1000
        self['stageTime'][si]   += k.level.time//1000
        self['totalSolved'][si] += 1

        # failsafe
        while len(self['scores']) < self.stage:
            self['scores'].append([])
        
        while len(self['scores'][si]) < level:
            self['scores'][si].append({'time': sys.maxsize, 'score': sys.maxsize})
                    
        if self['scores'][si][li]['time'] == 0: self['scores'][si][li]['time']  = sys.maxsize

        # first time level solved 
        if self['scores'][si][level-1]['score'] == sys.maxsize:
            self.makeLevelAvailable()

        # update scores
        secs = k.level.time//1000

        self['scores'][si][li]['time']  = min(self['scores'][si][li]['time'], secs)
        self['scores'][si][li]['score'] = min(self['scores'][si][li]['score'], int(k.score))
        
        if level == levels.numLevels:
            self.stage = min(3, self.stage+1)
            if len(self['scores']) < self.stage:
                self['scores'].append([])
            self['stage'] = self.stage
            log('stage', self.stage)
        
        self.save()
        
    #-------------------------------------------------------------------------------------------
    def abort (self):
        si = k.level.isBonus() and 4 or self.stage-1
        self['totalTime']     += k.level.time//1000
        self['stageTime'][si] += k.level.time//1000
        
    #-------------------------------------------------------------------------------------------
    def makeLevelAvailable (self):
        if len(self['scores'][self.stage - 1]) < levels.numLevels:
        	    self['scores'][self.stage - 1].append({'time': sys.maxsize, 'score': sys.maxsize})
            
    #-------------------------------------------------------------------------------------------
    def apply(self):
        k.sound.musicVolume = self['music_volume']
        k.sound.soundVolume = self['sound_volume']
        
    #-------------------------------------------------------------------------------------------
    def getConfigFilePath(self):
        if os.sys.platform == 'darwin':
            return os.path.expanduser('~/Library/Preferences/krank.cfg')
        elif os.sys.platform.startswith('linux'):
            return os.path.expanduser('~/.krankcfg')
        else:
            return os.path.join(os.environ['APPDATA'], 'krank.cfg')
        
    #-------------------------------------------------------------------------------------------
    def save(self):
        self['music_volume'] = k.sound.musicVolume
        self['sound_volume'] = k.sound.soundVolume
        self['screen']       = k.world.rect.size
        self['stage']        = k.config.stage
        self['fullscreen']   = k.config.fullscreen
        try:
            config_file = self.getConfigFilePath()
            if os.access(config_file, os.R_OK|os.W_OK):
            	os.unlink(config_file)
            	print("Old config file has been converted in yaml format")
            	print("\tnew config name is ", config_file+'.yaml')
            config_file += '.yaml'
            log('writing config to', config_file, log='config')
            log(self, log='config')
            file = open(config_file, 'w+')
            file.write("# vim: filetype=yaml :\n")
            yaml.dump(self, file)
        except Exception as e:
            log(e)
        
    #-------------------------------------------------------------------------------------------
    def load(self):
        try:            
            config_file = self.getConfigFilePath()
            log('reading config from', config_file, log='config')
            log(self, log='config')
            yaml_type=0
            
            if not os.access(config_file, os.R_OK):
                config_file += '.yaml'
                file = open(config_file, 'r')
                self.update(yaml.load(file, Loader=yaml.FullLoader))
            else:
                file = open(config_file, 'r')
                self.update(pickle.load(file))
            
            self.stage = self['stage']
            k.config.fullscreen=self['fullscreen']
            while len(self['scores']) < 4: self['scores'].append([])
            log(self, log='config')
        except Exception as e:
            log(e)
        
    #-------------------------------------------------------------------------------------------
    def bestTimeString (self, level=0, stage=0):
        time = self.bestTime(level, stage)
        if time < sys.maxsize//1000:
            return k.level.timeString(time)
        return ""

    #-------------------------------------------------------------------------------------------
    def bestScoreString (self, level=0, stage=0):
        score = self.bestScore(level, stage)
        if score < sys.maxsize:
            return "%d" % score
        return ""
        
    #-------------------------------------------------------------------------------------------
    def bestTime (self, level=0, stage=0):
        score = self.getScore(level, stage)
        return score['time']
        
    #-------------------------------------------------------------------------------------------
    def bestScore (self, level=0, stage=0):
        score = self.getScore(level, stage)
        return score['score']
    
    #-------------------------------------------------------------------------------------------
    def getScore (self, level=0, stage=0):
        if not stage:
            stage = self.stage
        if not level:
            level = k.level.number
        return self['scores'][stage-1][level-1]
    
    #-------------------------------------------------------------------------------------------
    def setStage (self, stage):
        if stage != self.stage:
            k.sound.play('exit')
            self.stage = stage
            self.save()
            Level('menu_levels')
            
    #-------------------------------------------------------------------------------------------
    def lastSolvedLevel (self, stage=0):
        if not stage:
            stage = self.stage
        scores = self['scores'][stage-1]
        for index in range(-1, -len(scores), -1):
            score = scores[index]
            if score['score'] < sys.maxsize:
                return len(scores)+index+1
        return 0
    
    #-------------------------------------------------------------------------------------------
    def numAvailableLevels (self, stage=0):
        if not stage:
            stage = self.stage
        return min(levels.numLevels, len(self['scores'][stage-1]))
    
    #-------------------------------------------------------------------------------------------
    def numSolvedLevels (self, stage=0):
        if not stage:
            stage = self.stage
        return len([s for s in self['scores'][stage-1] if s['score'] < sys.maxsize])
    
    
