# THIS IS A SOURCE CODE FILE FROM I'M NOT EVEN HUMAN THE GAME.
# IT COULD BE USED IN A DIFFERENT PIECE OF SOFTWARE ( LIKE A
# DIFFERENT GAME ), BUT IT WAS ORIGINALLY WRITTEN FOR I'M NOT
# EVEN HUMAN THE GAME.

# THE DEVELOPERS OF THE GAME ARE : (C) J.Y.AMIHUD, AYYZEE AND 
# OTHER CONTRIBUTORS. THIS AND OTHER FILES IN THIS GAME,
# UNLESS SPECIFICALLY NOTED, COULD BE USED UNDER THE TERMS OF
# GNU GENERAL PUBLIC LICENSE VERSION 3 OR ANY LATER VERSION.

import os
import json
import math
import cairo

from modules import ui

def draw(game, outlayer, x, y, w, h, grid=True):

    """This function will draw the level it self"""

    x = int(x)
    y = int(y)
    w = int(w)
    h = int(h)

    # To make it a bit more nice, I will use a separate image
    # layer for the level.

    surface = cairo.ImageSurface(cairo.FORMAT_ARGB32,w,h)
    layer = cairo.Context(surface)
    layer.set_antialias(cairo.ANTIALIAS_NONE)


    if game.current["testing"]:
        ui.color(game, layer, "red")
        layer.rectangle(0,0,w-1,h-1)
        layer.stroke()

    sidex = 64
    sidey = 36
    offsetx = int(sidex / 2)
    offsety = int(sidey / 2)

    # moving the game world
    if game.current["MMB"] and grid\
    and int(game.current["mx"]) in range(x, x+w)\
    and int(game.current["my"]) in range(y, y+h):
        game.current["camera"][0] += (game.current["mx"] - game.previous["mx"])
        game.current["camera"][1] += (game.current["my"] - game.previous["my"])
        
    if "world_mo" not in game.current:
        game.current["world_mo"] = [0,0,0]
    wmod = 1000000000 # Artbitrary large number
    wmo  = [-500,-500,0]    # This updates game.current["world_mo"] for the next frame

    # List of chunks in the current rendering
    rendered_chunks = []

    render_coordinates = "0:0"

    # Coordinates of the character
    x79 = game.current["state"]["4211D79"]["xyz"][0] + game.current["camera"][0]
    y79 = game.current["state"]["4211D79"]["xyz"][1] + game.current["camera"][1]

    # Colision to 0
    game.current["state"]["4211D79"]["colision"] = False

    # MAIN LOOP
    
    for lh in range(-2, 5): # For a few vertical levels
        
        
        for th in range(int(h/offsety)+6): # For cells from top to bottom

            # Calculating the cell offset from the camera
            offx = game.current["camera"][0] % sidex
            offy = game.current["camera"][1] % sidey
            if th % 2 == 0:
                offx += offsetx
                
            for tw in range(int(w/sidex)+3): # For cells from right to left

                # Where to draw the cell
                drawx = (tw-2)*sidex+offx
                drawy = (th-3)*offsety+offy

                # Where is the cell's center
                centerx = offsetx+((tw-2)*sidex+offx)
                centery = offsety+((th-3)*offsety+offy)

                # What is the cell's coordinates
                xaddr = 0-int( (game.current["camera"][0] - drawx) / offsetx )
                yaddr = 0-int( (game.current["camera"][1] - drawy) / offsety )

                # The address of the cell
                celladdr = [xaddr, yaddr]

                # Distance of the cell to the mouse
                dtox = game.current["mx"]-x
                dtoy = game.current["my"]-y

                # Position of the character
                if not grid:
                    dtox = x79
                    dtoy = y79 
                dtomouse = ui.distance([dtox, dtoy],
                            [centerx,centery])

                # If mouse in screen
                if int(game.current["mx"]) in range(int(x), int(x+w))\
                and int(game.current["my"]) in range(int(y), int(y+h)):
                    mouseinscreen = True
                else:
                    mouseinscreen = False
                
                
                # Figuring out if the cell is closest to the mouse ( mouse over the cell )
                if dtomouse < wmod and (mouseinscreen or not grid):
                    wmo = celladdr
                    wmod = dtomouse
                    
                # The chunk address for the cell ( a json file for the world cache )                
                chunk = str(int(xaddr/100))+":"+str(int(yaddr/100))+":"+str(game.current["camera"][2]+lh)

                # Loading chunk from the json
                if chunk not in game.chunks[1]:
                    load_chunk(game, chunk)
                # Checking if the chunk is not rendered, to remove it from cache
                if not chunk in rendered_chunks:
                    rendered_chunks.append(chunk)

                # Address inside the chunk    
                addr  = str(xaddr)+":"+str(yaddr)
                

                # If current Vertical Layer
                if lh == 0:

                    if grid:
                        # Grid
                        ui.image(game, layer,
                                 drawx,
                                 drawy,
                                 "assets/grid.png", "grid", color=False)

                    # If mouse over this cell
                    selectedcells = [game.current["world_mo"]]
                    if game.current["editor_brush"] > 1:
                        bax = game.current["world_mo"][0]
                        bay = game.current["world_mo"][1]
                        bs =  game.current["editor_brush"] - 1
                        for bx in range(bax-bs, bax+bs):
                            for by in range(bay-bs, bay+bs):
                                selectedcells.append([bx,by])
                    
                    if celladdr in selectedcells:
                        render_coordinates = addr

                        # Selection image grid thingy
                        if grid:
                            ui.image(game, layer,
                                     drawx,
                                     drawy,
                                     "assets/grid.png", "selected", color=False)
                            
                            # Pressing RMB to delete things in editor
                            if game.current["RMB"]:
                                try:
                                    
                                    del game.chunks[1][chunk][addr]
                                except:
                                    pass

                            # Pressing LMB to draw
                            if game.current["LMB"]:
                            

                                types = game.current["editor_selection"][0]
                                asset = game.current["editor_selection"][1]
                                version = game.elements[types][asset][game.current["editor_selection"][2]]["title"]

                                addfile = types+"/"+asset

                                # Making sure they are both in the list
                                for i in (version, addfile):
                                    if i not in game.chunks[0]:
                                        game.chunks[0].append(i)
                                        # Getting their indexes
                                version = game.chunks[0].index(version)
                                addfile = game.chunks[0].index(addfile)

                                
                                game.chunks[1][chunk][addr] = [addfile, version]
                                        

                            # SAVE CHUNK
                            if (not game.current["LMB"] and game.previous["LMB"])\
                            or (not game.current["RMB"] and game.previous["RMB"]):
                                save_chunk(game, chunk)
                      
                            
                            
                            
                # Try drawing the asset in this cell
                try:

                    chunkasst = game.chunks[1][chunk][addr]
                    chunkasst = [ game.chunks[0][chunkasst[0]],  game.chunks[0][chunkasst[1]] ]


                    # Dynamic transparency 
                    dalpha = 1

                    #        [ 0:0 ]
                    #    [ -1:1 ][ 1:1 ]
                    #        [ 0:2 ]
                    #
                    seltmp = game.current["world_mo"]
                    tcolumns = [
                        seltmp,
                        [seltmp[0]-1, seltmp[1]+1],
                        [seltmp[0]+1, seltmp[1]+1],
                        [seltmp[0], seltmp[1]+2]]
                    
                    for i in tcolumns:
                        if celladdr[0] == i[0]\
                        and celladdr[1] in range( i[1]-(lh*2), i[1]+1)\
                        and ( mouseinscreen or not grid ):
                            if celladdr == seltmp and lh == 0 and grid:
                                dalpha = 1
                            else:
                                dalpha = 0.25
                                if lh > 1:
                                    dalpha = 0.1
                            
                        
                    # Draw cell        
                    ui.image(game, layer,
                             drawx,
                             drawy,
                             "assets/elements/"+chunkasst[0], chunkasst[1],
                             offset=True, alpha=dalpha)

                    # Highlight cell in red when mouse over
                    if celladdr in selectedcells:
                        if lh == 0:

                            if not grid:
                                game.current["state"]["4211D79"]["colision"] = \
                                    [drawx+offsetx - game.current["camera"][0],
                                     drawy+offsety - game.current["camera"][1]]
                            else:
                                ui.color(game, layer, "red", 0.5)
                                ui.image(game, layer,
                                         drawx,
                                         drawy,
                                         "assets/elements/"+chunkasst[0], chunkasst[1],
                                         offset=True, color=True)

                        # Select the current thing for the editor.
                        try:
                            if game.previous["MMB"] and not game.current["MMB"]\
                            and int(game.current["mx"]) == int(game.previous["MMB"][0])\
                            and int(game.current["my"]) == int(game.previous["MMB"][1]):

                                types = chunkasst[0].split("/")[0]
                                asset = chunkasst[0].split("/")[1]
                                for version, names in enumerate(game.elements[types][asset]):
                                    if names["title"] == chunkasst[1]:
                                        break

                                game.current["editor_selection"][0] = types
                                game.current["editor_selection"][1] = asset
                                game.current["editor_selection"][2] = version
                        except Exception as e:
                            print(e)
                    
                        
                except:
                    pass
                
                
    if not grid:
        ui.image(game, layer,
                 x79,
                 y79,
                 "assets/elements/characters/4211D79_standing.png", "selected", offset=True)
                            

    # If Editor Show the currently selected item
    if grid:
        types = game.current["editor_selection"][0]
        asset = game.current["editor_selection"][1]
        version = game.elements[types][asset][game.current["editor_selection"][2]]
        ui.image(game, layer,
                 game.current["mx"]-x-offsetx,
                 game.current["my"]-y-offsety,
                 "assets/elements/"+types+"/"+asset, version["title"], offset=True, alpha=0.5)

    # Select the mouse over cell
    game.current["world_mo"] = wmo


    # Removing chunks that are not rendered currently from the memory
    for i in list(game.chunks[1].keys()):
        if i not in rendered_chunks:
            del game.chunks[1][i]

    # The current Z ( height ) rendering in top, right corner
    ui.color(game, layer, "yellow")
    ui.text(game,layer, str(game.current["camera"][2]),
                        40,
                        40)
    ui.text(game,layer, render_coordinates,
                        40,
                        60)
    

    # Numpad + to go up
    if 65451 in game.current["keys"]:
        game.current["camera"][2] += 1
        game.current["keys"] = []

    # Numpad - to go down
    if 65453 in game.current["keys"]:
        game.current["camera"][2] -= 1
        game.current["keys"] = []
    
    # Drawing the world to the outlayer
    outlayer.set_source_surface(surface, x , y)
    outlayer.paint()


    
def update_elements(game):

    """This function caches all assets"""

    game.elements = {}
    
    # elements
    #   Element type ( blocks, characters, vehicles )
    #     Image assets
    
    for types in os.listdir(os.getcwd()+"/assets/elements"):

        game.elements[types] = {}

        for asset in os.listdir(os.getcwd()+"/assets/elements/"+types):

            if asset.endswith(".png"):
                asseturl = "assets/elements/"+types+"/"+asset
                ui.cache_sprite_sheet(game, asseturl, [types, asset])

    # Now let's generate the selection for the editor
    game.current["editor_selection"] = [
        list(game.elements.keys())[0],
        list(list(game.elements.values())[0].keys())[0],
        0]

    # Make the brush 0
    game.current["editor_brush"] = 1


    # YANK THAT CODE LATER

    # every chunk is 100 by 100
    game.chunks = [[],{}]

def save_chunk(game, chunk):

    """This function saves the chunk"""

    # Getting the raw chunk
    savedata = [[], game.chunks[1][chunk].copy()]

    # Adding all the asset names to it
    for ind in savedata[1]:

        i = savedata[1][ind]
        savedata[1][ind] = i.copy()
        
        for n, b in enumerate(i):
            add = game.chunks[0][b]
            if add not in savedata[0]:
                savedata[0].append(add)

            savedata[1][ind][n] = savedata[0].index(add)
            
        
                
    # Save the json
    savefilename = "assets/worlds/"+game.settings["world"]+"/"+chunk+".json"

    with open(savefilename, 'w') as f:
        json.dump(savedata, f)

def load_chunk(game, chunk):

    """This function loads a chunk."""

    # Load the json
    loadfilename = "assets/worlds/"+game.settings["world"]+"/"+chunk+".json"


    
    try:
        with open(loadfilename) as f:
            loaddata = json.load(f)
        
    except:
        loaddata = [[],{}]

    for ind in  loaddata[1]:

        i = loaddata[1][ind]
        
        for n, b in enumerate(i):
            add = loaddata[0][b]
            if add not in game.chunks[0]:
                game.chunks[0].append(add)

            loaddata[1][ind][n] = game.chunks[0].index(add)

    game.chunks[1][chunk] = loaddata[1]

    
