'''
Created on 1 jun. 2017

@author: LortKrassbeter
'''
import pygame, os, copy
from pygame.locals import *
from pmworld import Tile, Region
import pmtools, eztext, logging
from pmtools import caselessEquals

class Tool:
    PMD = None
    tools = {}
    @classmethod
    def init(cls, PMD):
        cls.PMD = PMD
    def __init__(self, toolstring, options):
        self.toolname = toolstring.lower()
        self.action = self.tools[self.toolname]
        print(options)
        self.options = list(options)
    def use(self):
        if not self.action is None:
            self.action(*self.options)
    def draw(self, PMD):
        if caselessEquals(self.toolname, "tilebrush"):
            if len(self.options) > 0:
                tid = self.options[0]
                rt = PMD.world.getTile(tid)
                gp = PMD.gridPosition(PMD.cursorpos)
                gpinpx = (gp[0]*PMD.ZTS, gp[1]*PMD.ZTS)
                pygame.draw.rect(PMD.display_surf, pmtools.COLOR.BLUE, ((gpinpx[0]+PMD.campos[0], gpinpx[1]+PMD.campos[1]), (rt.dim[0]*PMD.ZTS, rt.dim[1]*PMD.ZTS)), 2)
    @classmethod
    def tilebrush(cls, tile=0, level=0, expand=True):
        logging.debug("Using tile brush with tile {} and expand {}".format(tile, expand))
        pos = cls.PMD.gridPosition(cls.PMD.cursorpos)
        cls.PMD.curregion.setTile(cls.PMD.world, pos[0], pos[1], level, tile, expand=expand)
    @classmethod
    def  tileerase(cls, level=0):
        pos = cls.PMD.gridPosition(cls.PMD.cursorpos)
        cls.PMD.curregion.setTile(cls.PMD.world, pos[0], pos[1], level, pmtools.EMPTY_TILE_ID, expand=False, override=True)
        

Tool.tools["tilebrush"] = Tool.tilebrush
Tool.tools["tileerase"] = Tool.tileerase

class Console():
    linedist = 5
    def __init__(self, PMD, rect, text_color=pmtools.COLOR.BLACK, bg_color=pmtools.COLOR.WHITE, fontsize=32, font=None):
        self.PMD = PMD
        self.font = font
        self.fontsize = fontsize
        self.rect = rect
        self.visible = True
        self.history = list()
        self.text_color = text_color
        self.bg_color = bg_color
        self.input = eztext.Input(x=rect.x, y=rect.y, color=self.text_color, bg_color=self.bg_color)
    def draw(self, surf):
        if self.visible:
            self.input.draw(surf)
            for i in range(len(self.history)):
                y = self.rect.y - (self.linedist+self.fontsize)*(i+1)
                pmtools.drawText(surf, self.history[-(i+1)], (self.rect.x, y), text_color=self.text_color, bg_color=self.bg_color, font=self.font, fontsize=self.fontsize)
    def show(self):
        self.visible = True
    def hide(self):
        self.visible = False
    def update(self, events):
        for event in events:
            if self.visible:
                self.input.update(event)
                if event.type == KEYDOWN:
                    if event.key == K_RETURN:
                        command = self.input.value
                        self.print(command)
                        sl = command.split(' ')
                        i = 0
                        for word in copy.copy(sl):
                            word = word.strip()
                            if len(word) == 0:
                                del sl[i]
                            else:
                                i += 1
                        self.input.value = ""
                        cmd = None
                        try:
                            cmd = COMMAND[sl[0]]
                        except KeyError:
                            self.print(self.PMD.text["cmd_desc_unknown"].format(sl[0]))
                        #try:
                        cmd(self.PMD, *sl[1:])
                        #except Exception as e: #TODO: cant catch all TypeErrors here -> differentiate errors
                            #self.print(self.PMD.text["cmd_missing_argument"])
                            #self.print(self.PMD.text["cmd_syntax_"+sl[0]].format(sl[0]))
            if event.type == KEYDOWN and event.key == K_TAB:
                self.visible = not self.visible
    def print(self, text):
        self.history.append(text)
        
def save(PMD, what, *options):
    path = PMD.resourcePath
    comp = [True, True]
    if caselessEquals(what, PMD.text["cmd_region"]):
        comp[1] = False
    elif caselessEquals(what, PMD.text["cmd_tile"]):
        comp[0] = False
    elif not caselessEquals(what, PMD.text["cmd_all"]):
        PMD.console.print(PMD.text["cmd_undefined_argument"].format(what))
        return
    if len(options) > 1:
        if os.path.exists(options[1]) and os.path.isdir(options[1]):
            path = options[1]
        else:
            PMD.console.print(PMD.text["cmd_path_problem"].format(options[1]))
            return
    PMD.world.save(path, comp)
    
def load(PMD, what, *options):
    path = PMD.resourcePath
    comp = [True, True, True]
    if caselessEquals(what, PMD.text["cmd_region"]):
        comp[1] = False
        comp[2] = False
    elif caselessEquals(what, PMD.text["cmd_tile"]):
        comp[0] = False
        comp[2] = False
    elif caselessEquals(what, PMD.text["cmd_texture"]):
        comp[0] = False
        comp[1] = False
    elif not caselessEquals(what, PMD.text["cmd_all"]):
        PMD.console.print(PMD.text["cmd_undefined_argument"].format(what))
        return
    if len(options) > 1:
        if os.path.exists(options[1]) and os.path.isdir(options[1]):
            path = options[1]
        else:
            PMD.console.print(PMD.text["cmd_path_problem"].format(options[1]))
            return
    PMD.world.load(path, comp)
    
def printlist(PMD, what, *options):
    print(what, PMD.text["cmd_tile"])
    if caselessEquals(what, PMD.text["cmd_tile"]):
        PMD.console.print(PMD.text["cmd_printlist_header"])
        for tid in PMD.world.tiles().keys():
            PMD.console.print("{}: {}".format(tid, PMD.world.getTile(tid).name))
    elif caselessEquals(what, PMD.text["cmd_region"]):
        PMD.console.print(PMD.text["cmd_printlist_header"])
        for rid in PMD.world.regions().keys():
            PMD.console.print("{}: {}".format(rid, PMD.world.getRegion(rid).name))
    elif caselessEquals(what, PMD.text["cmd_tool"]):
        for tool in Tool.tools.keys():
            PMD.console.print("- "+tool)
    elif caselessEquals(what, PMD.text["cmd_spritesheet"]):
        for ssname in PMD.world.spritesheets().keys():
            PMD.console.print("- "+ssname)
    else:
        PMD.console.print(PMD.text["cmd_printlist_unknown_object"].format(what))
    
#Creates object with given arguments
def create(PMD, obj, *options):
    if caselessEquals(obj, PMD.text["cmd_tile"]):
        opt = checkCreateTileOptions(PMD, options)
        if not opt is None:
            t = Tile(*opt)
            PMD.world.addTile(t)
        else:
            return
    elif caselessEquals(obj, PMD.text["cmd_region"]):
        opt = checkCreateRegionOptions(PMD, options)
        if not opt is None:
            r = Region(*opt)
            PMD.world.addRegion(r)
        else:
            return
    else:
        PMD.console.print(PMD.text["cmd_create_unknown_object"].format(obj))
        return
    PMD.console.print(PMD.text["cmd_creation_success"])
        
def checkCreateTileOptions(PMD, options):
    texpos = -1
    dim = (1, 1)
    if len(options) > 2: #name, texture name, texture pos given
        if not pmtools.isName(options[0]):
            PMD.console.print(PMD.text["cmd_name_error"])
            return
        try:
            PMD.world.getSpritesheet(options[1])
            texpos = int(options[2])
        except KeyError:
            PMD.console.print(PMD.text["cmd_create_unknown_spritesheet"].format(options[1]))
            return
        except ValueError:
            PMD.console.print(PMD.text["cmd_value_error_int"].format(options[2]))
            return
        if len(options) > 4: # + dimension given
            try:
                dim[0] = int(options[3])
                dim[1] = int(options[4])
            except ValueError:
                PMD.console.print(PMD.text["cmd_value_error_int"].format(options[3]+","+options[4]))
                return
    else:
        PMD.console.print(PMD.text["cmd_missing_argument"])
        return
    return [options[0], (options[1], texpos), None, dim, None]

def checkCreateRegionOptions(PMD, options):
    width = 1
    levels = 1
    if len(options) > 0: #name given
        print(options[0])
        if not pmtools.isName(options[0]):
            PMD.console.print(PMD.text["cmd_name_error"])
            return
        if len(options) > 1: # + width given
            try:
                width = int(options[1])
            except ValueError:
                PMD.console.print(PMD.text["cmd_value_error_int"].format(options[2]))
                return
            if len(options) > 2: # + levels given
                try:
                    levels = int(options[2])
                except ValueError:
                    PMD.console.print(PMD.text["cmd_value_error_int"].format(options[2]))
                    return
    else:
        PMD.console.print(PMD.text["cmd_missing_argument"])
        return
    return [options[0], width, [[]*levels], levels, None]
        
#Equips certain tool to specified binding
def equip(PMD, tool, binding, *options):
    try:
        bindnum = pmtools.BINDINGS[binding]
    except KeyError:
        PMD.console.print(PMD.text["cmd_unknown_binding"].format(binding))
        return
    options = checkToolOptions(PMD, tool, options)
    if not options is None:
        try:
            PMD.tools[bindnum] = Tool(tool, options)
        except KeyError:
            PMD.console.print(PMD.text["cmd_equip_unknown_tool"].format(tool))
            return

def checkToolOptions(PMD, tool, options):
    opt = []
    if caselessEquals(tool, "tilebrush"):
        if len(options) > 0:
            try:
                tid = int(options[0])
            except ValueError:
                PMD.console.print(PMD.text("cmd_value_error_int".format(options[0])))
                return
            try:
                PMD.world.getTile(tid)
            except KeyError:
                PMD.console.print(PMD.text("cmd_unknown_tileid").format(tid))
                return
            opt.append(tid)
        if len(options) > 1:
            try:
                lvl = int(options[1])
            except ValueError:
                PMD.console.print(PMD.text("cmd_value_error_int".format(options[1])))
                return
            opt.append(lvl)
        if len(options) > 2:
            try:
                expand = bool(options[2])
            except ValueError:
                PMD.console.print(PMD.text("cmd_value_error_bool".format(options[2])))
                return
            opt.append(expand)
    elif caselessEquals(tool, "tileerase"):
        if len(options) > 0:
            try:
                lvl = int(options[0])
            except ValueError:
                PMD.console.print(PMD.text("cmd_value_error_int".format(options[0])))
                return
            opt.append(lvl)
    return opt

#Enables to change properties of a tool
def tool(PMD, binding, *options):
    try:
        bindnum = pmtools.BINDINGS[binding]
        tool = PMD.tools[bindnum]
        options = checkToolOptions(PMD, tool.toolname, options)
        if not options is None:
            tool.options = options
    except KeyError:
        PMD.console.print(PMD.text["cmd_unknown_binding"]+binding)

def helpcommand(PMD, *options):
    if len(options) == 0:
        for k in COMMAND.keys():
            try:
                hm = "- {}: {}".format(k, PMD.text["cmd_desc_"+k])
                PMD.console.print(hm)
            except KeyError as e:
                logging.warning("Command without help text: {}".format(e.args[0]))
    elif len(options) > 0:
        try:
            COMMAND[options[0]]
        except KeyError:
            PMD.console.print(PMD.text["cmd_desc_unknown"])
        PMD.console.print(PMD.text["cmd_syntax_"+options[0]].format(options[0]))

def select(PMD, what, *options):
    if caselessEquals(what, PMD.text["cmd_region"]):
        if len(options) > 0:
            regid = int(options[0])
            reg = PMD.world.getRegion(regid)
            PMD.curregion = reg

def crop(PMD, *options):
    PMD.curregion.crop()

COMMAND = {"help": helpcommand, "create": create, "equip": equip, "tool": tool, "save": save, "load": load, "list": printlist, "select": select, "crop": crop}

