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

#  Copyright © 2013-2015  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
        
    
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.toolbar':       (True,      lambda v: type(v) is bool),
    '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':          (1,         shaders(['simple', 'lighting'])),
    'draw.selection':       (1,         ['quadrant', 'simple']),
    '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':     ('#a81407',     lambda v: type(v) is str),
    'theme.faces.Down.color':   ('#d94b1c',     lambda v: type(v) is str),
    'theme.faces.Left.color':   ('#f0c829',     lambda v: type(v) is str),
    'theme.faces.Right.color':  ('#e3e3e3',     lambda v: type(v) is str),
    'theme.faces.Front.color':  ('#1d6311',     lambda v: type(v) is str),
    'theme.faces.Back.color':   ('#00275e',     lambda v: type(v) is str),
    'theme.faces.Front_Left.color': ('#1d6311', lambda v: type(v) is str),
    'theme.faces.Front_Right.color':('#9431a8', lambda v: type(v) is str),
    'theme.faces.*.image':      ('',            lambda v: type(v) is str),
    'theme.faces.*.mode':       (0,             ['tiled', 'mosaic']),
    'theme.bgcolor':        ('#B9a177', lambda v: type(v) is str),
    'draw.accels':          ([('r', 'KP+6'), ('r-', 'Shift+KP+Right'),
                              ('l', 'KP+4'), ('l-', 'Shift+KP+Left'),
                              ('u', 'KP+8'), ('u-', 'Shift+KP+Up'),
                              ('d', 'KP+2'), ('d-', 'Shift+KP+Down'),
                              ('f', 'KP+5'), ('f-', 'Shift+KP+Clear'),
                              ('b', 'KP+0'), ('b-', 'Shift+KP+Ins'),
                              ('R', 'Ctrl+KP+8'), ('L', 'Ctrl+KP+2'),
                              ('U', 'Ctrl+KP+4'), ('D', 'Ctrl+KP+6'),
                              ('F', 'Ctrl+KP+5'), ('B', 'Ctrl+KP+0'),
                             ],         validate_draw_accels),
    'draw.zoom':            (1.4,       (0.1, 100.0)),
    # 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),
   }

