# -*- coding: utf-8 -*-

#  Copyright © 2013-2017  B. Clausius <barcc@gmx.de>
#
#  This program is free software: you can redistribute it and/or modify
#  it under the terms of the GNU General Public License as published by
#  the Free Software Foundation, either version 3 of the License, or
#  (at your option) any later version.
#
#  This program is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#  GNU General Public License for more details.
#
#  You should have received a copy of the GNU General Public License
#  along with this program.  If not, see <http://www.gnu.org/licenses/>.

from .debug import DEBUG_SHADER

N_ = lambda s: s

if DEBUG_SHADER:
    import os
    from . import config
    def shaders(names):
        for filename in os.listdir(config.SHADER_DIR):
            name = os.path.splitext(filename)[0]
            if name not in names:
                names.append(name)
        return names
else:
    shaders = lambda s: s
    
def tuple_validator(minlen, maxlen, itemtype, value, valuerange=None):
    if type(value) is not tuple:
        return False
    if not (minlen <= len(value) <= maxlen):
        return False
    for v in value:
        if type(v) is not itemtype:
            return False
        if valuerange is not None and not valuerange[0] <= v <= valuerange[1]:
            return False
    return True
    
def validate_mtype(v):
    from .model import Model
    return v in Model.cache_index['types']
    
def validate_draw_accels(v):
    if type(v) is not list: return False
    for t in v:
        if type(t) is not tuple or len(t) != 2: return False
        if type(t[0]) is not str or type(t[1]) is not str: return False
    return True
    
deprecated = type('DeprecatedType', (), {})
    
def migrate_game_size_blocks_moves_position(settings):
    mtype = settings['game.type']
    size = settings['game.size']
    blocks = settings['game.blocks']
    moves = settings['game.moves']
    position = settings['game.position']
    
    if not tuple_validator(3, 100, int, size, (1, 10)):
        return
    from .model import Model
    defaultsize = Model.cache_index['type'][mtype]['defaultsize']
    if len(size) < len(defaultsize):
        return
    if len(size) > len(defaultsize):
        size = size[:len(defaultsize)]
    try:
        size = Model.cache_index['normsize'][mtype][size]
    except KeyError:
        return
    settings['games',mtype,'size'] = size
    
    if type(blocks) is not str:
        return
    
    if type(moves) is not str:
        moves = ''
    
    if type(position) is not int or position < 0:
        position = 0
    return mtype, size, blocks, moves, position
    
def migrate_theme_face_N_color_image_mode(settings):
    mtype = settings['game.type']
    facenames = ('Up', 'Down', 'Left', 'Right', 'Front', 'Back')
    for i, facename in enumerate(facenames):
        color = settings['theme.face',i,'color']
        image = settings['theme.face',i,'image']
        mode = settings['theme.face',i,'mode']
        if type(color) is str:  settings['theme.faces',facename,'color'] = color
        if type(image) is str:  settings['theme.faces',facename,'image'] = image
        if type(mode) in ['tiled', 'mosaic']:  settings['theme.faces',facename,'mode'] = mode
        
def migrate_2_3(settings):
    for facename in ('Up', 'Down', 'Left', 'Right', 'Front', 'Back',
                     'Front_Left', 'Front_Right', 'Back_Right', 'Back_Left'):
        for attr in ('color', 'image', 'mode'):
            oldkey = '.'.join(('theme.faces', facename, attr))
            if oldkey in settings.keystore.keystore:
                settings['theme.faces', facename.lower(), attr] = settings[oldkey]
                
    
schema = {
    # key:              (default,   range/enum/validator)
    #                               None: value without restriction
    #                               tuple: contains two values (min, max)
    #                               list: contains strings for the enum text,
    #                                     the index is the enum value
    #                               function: returns True, if value is valid
    'version':              (1,         lambda v: type(v) is int),
    'window.size':          ((850, 650),lambda v: tuple_validator(2, 2, int, v, (10,10000))),
    'window.divider':       (620,       (0, 10000)),
    'window.sidepane_width':(220,       (0, 10000)),
    'window.toolbar':       (True,      deprecated),
    'window.editbar':       (True,      lambda v: type(v) is bool),
    'window.statusbar':     (True,      lambda v: type(v) is bool),
    #TODO: reintroduce it, but per game.type
    #'draw.default_rotation':((-30.,39.),lambda v: tuple_validator(2, 2, float, v)),
    #TODO: deprecated
    'draw.lighting':        (True,     lambda v: type(v) is bool),
    'draw.shader':          (0,         shaders(['lighting', 'simple', 'label'])),
    'draw.selection':       (1,         ['quadrant', 'simple', 'gesture']),
    'draw.speed':           (30,        (1, 100)),
    'game.type':            ('Cube',    validate_mtype),
    'game.size':            (None,      deprecated),
    'game.blocks':          (None,      deprecated),
    'game.moves':           (None,      deprecated),
    'game.position':        (None,      deprecated),
    'games.*.size':         (None,      lambda v: tuple_validator(0, 10, int, v, (1, 10))),
    'theme.face.*.color':       (None,          deprecated),
    'theme.face.*.image':       (None,          deprecated),
    'theme.face.*.mode':        (None,          deprecated),
    
    'theme.faces.Up.color':          (None, deprecated),
    'theme.faces.Down.color':        (None, deprecated),
    'theme.faces.Left.color':        (None, deprecated),
    'theme.faces.Right.color':       (None, deprecated),
    'theme.faces.Front.color':       (None, deprecated),
    'theme.faces.Back.color':        (None, deprecated),
    'theme.faces.Front_Left.color':  (None, deprecated),
    'theme.faces.Front_Right.color': (None, deprecated),
    'theme.faces.Back_Right.color':  (None, deprecated),
    'theme.faces.Back_Left.color':   (None, deprecated),
    'theme.faces.Up.image':          (None, deprecated),
    'theme.faces.Down.image':        (None, deprecated),
    'theme.faces.Left.image':        (None, deprecated),
    'theme.faces.Right.image':       (None, deprecated),
    'theme.faces.Front.image':       (None, deprecated),
    'theme.faces.Back.image':        (None, deprecated),
    'theme.faces.Front_Left.image':  (None, deprecated),
    'theme.faces.Front_Right.image': (None, deprecated),
    'theme.faces.Back_Right.image':  (None, deprecated),
    'theme.faces.Back_Left.image':   (None, deprecated),
    'theme.faces.Up.mode':           (None, deprecated),
    'theme.faces.Down.mode':         (None, deprecated),
    'theme.faces.Left.mode':         (None, deprecated),
    'theme.faces.Right.mode':        (None, deprecated),
    'theme.faces.Front.mode':        (None, deprecated),
    'theme.faces.Back.mode':         (None, deprecated),
    'theme.faces.Front_Left.mode':   (None, deprecated),
    'theme.faces.Front_Right.mode':  (None, deprecated),
    'theme.faces.Back_Right.mode':   (None, deprecated),
    'theme.faces.Back_Left.mode':    (None, deprecated),
    
    'theme.faces.up.color':     ('#a81407',     lambda v: type(v) is str), # rot
    'theme.faces.down.color':   ('#d94b1c',     lambda v: type(v) is str), # orange
    'theme.faces.left.color':   ('#e3e3e3',     lambda v: type(v) is str), # weiß
    'theme.faces.right.color':  ('#f0c829',     lambda v: type(v) is str), # gelb
    'theme.faces.front.color':  ('#1d6311',     lambda v: type(v) is str), # dunkelgrün
    'theme.faces.back.color':   ('#00275e',     lambda v: type(v) is str), # dunkelblau
    
    'theme.faces.front_left.color':      ('#65b5b3', lambda v: type(v) is str), # hellblau
    'theme.faces.front_right.color':     ('#f0c829', lambda v: type(v) is str), # gelb
    'theme.faces.back_right.color':      ('#771193', lambda v: type(v) is str), # violett
    'theme.faces.back_left.color':       ('#e3e3e3', lambda v: type(v) is str), # weiß
    
    'theme.faces.down_back_right.color': ('#00275e', lambda v: type(v) is str), # dunkelblau
    'theme.faces.down_front_right.color':('#646464', lambda v: type(v) is str), # grau
    'theme.faces.down_front.color':      ('#1d6311', lambda v: type(v) is str), # dunkelgrün
    'theme.faces.down_front_left.color': ('#f260b8', lambda v: type(v) is str), # pink
    'theme.faces.down_back_left.color':  ('#9b661b', lambda v: type(v) is str), # braun
    
    'theme.faces.up_back.color':         ('#86d624', lambda v: type(v) is str), # hellgrün
    'theme.faces.up_back_right.color':   ('#771193', lambda v: type(v) is str), # violett
    'theme.faces.up_front_right.color':  ('#f0c829', lambda v: type(v) is str), # gelb
    'theme.faces.up_front_left.color':   ('#65b5b3', lambda v: type(v) is str), # hellblau
    'theme.faces.up_back_left.color':    ('#e3e3e3', lambda v: type(v) is str), # weiß
    
    'theme.faces.*.image':      ('',            lambda v: type(v) is str),
    'theme.faces.*.mode':       (0,             ['tiled', 'mosaic']),
    'theme.bgcolor':            ('#7e9190',     lambda v: type(v) is str),
    'draw.accels':          ([('r', 'Num+6'), ('r-', 'Shift+Num+Right'),
                              ('l', 'Num+4'), ('l-', 'Shift+Num+Left'),
                              ('u', 'Num+8'), ('u-', 'Shift+Num+Up'),
                              ('d', 'Num+2'), ('d-', 'Shift+Num+Down'),
                              ('f', 'Num+5'), ('f-', 'Shift+Num+Clear'),
                              ('b', 'Num+0'), ('b-', 'Shift+Num+Ins'),
                              ('R', 'Ctrl+Num+8'), ('L', 'Ctrl+Num+2'),
                              ('U', 'Ctrl+Num+4'), ('D', 'Ctrl+Num+6'),
                              ('F', 'Ctrl+Num+5'), ('B', 'Ctrl+Num+0'),
                             ],         validate_draw_accels),
    'draw.zoom':            (1.4,       (0.1, 100.0)),
    #TRANSLATORS: The following 6 words are for the antialiasing levels: disabled, ugly, low, medium, high, higher
    'draw.samples':         (3,         [N_('disabled'), N_('ugly'), N_('low'),
                                         N_('medium'), N_('high'), N_('higher')]),
    'draw.mirror_faces':    (False,     lambda v: type(v) is bool),
    'draw.mirror_distance': (2.1,       (0.1, 10.0)),
    'action.edit_moves':    ('Ctrl+L',  lambda v: type(v) is str),
    'action.edit_cube':     ('',        lambda v: type(v) is str),
    'action.selectmodel':   ('Ctrl+M',  lambda v: type(v) is str),
    'action.initial_state': ('',        lambda v: type(v) is str),
    'action.reset_rotation':('Ctrl+R',  lambda v: type(v) is str),
    'action.preferences':   ('Ctrl+P',  lambda v: type(v) is str),
   }

