import glob
import random

from siege.log import Log
from siege.world.realm import Layer
from siege.worldgen import BoolStamp, ColorStamp, Terraform
from siege.util import Random, TileVector, TileRect


def createStampColor(red, green, blue, alpha=255):
    return red | (green << 8) | (blue << 16) | (alpha << 24)


CAVE_ENTRANCE_COLOR = createStampColor(48, 141, 255)


CONNECTOR_COLORS = [
    createStampColor(255, 0, 255),  # default
    createStampColor(255, 246, 0),  # underground connector for tunnel stamps
]

STAMP_ROOT_DIR = 'mods/core/terraform/stamp'


def globStamps(directory):
    return glob.glob('{0}/{1}/*.png'.format(STAMP_ROOT_DIR, directory))


def loadStamps(directory, canFlip=True):
    return [ColorStamp(f, canFlip) for f in globStamps(directory)]


def loadBoolStamps(directory):
    return [BoolStamp(f, True, True) for f in globStamps(directory)]


def getColors(stamp, allColors):
    allCoords = []
    for color in allColors:
        if stamp.has(color):
            coords = stamp.getColor(color)
            allCoords += coords
    return allCoords


def shouldFlipX(stamp):
    return stamp.forceFlipX() or (stamp.canFlipX() and Random.getBool())


class ConnectorSide(object):
    NONE = 0
    TOP = 1
    RIGHT = 2
    BOTTOM = 4
    LEFT = 8
    HORIZONTAL = RIGHT | LEFT
    VERTICAL = TOP | BOTTOM
    ALL = TOP | RIGHT | BOTTOM | LEFT

    @staticmethod
    def get(connector, size):
        side = ConnectorSide.NONE
        if connector.x == 0:
            side |= ConnectorSide.LEFT
        elif connector.x == size.x - 1:
            side |= ConnectorSide.RIGHT
        if connector.y == 0:
            side |= ConnectorSide.TOP
        elif connector.y == size.y - 1:
            side |= ConnectorSide.BOTTOM
        return side

    @staticmethod
    def hasOpposite(side, other):
        return ((side & ConnectorSide.HORIZONTAL) + (other & ConnectorSide.HORIZONTAL) == ConnectorSide.HORIZONTAL) or \
            ((side & ConnectorSide.VERTICAL) + (other & ConnectorSide.VERTICAL) == ConnectorSide.VERTICAL)

    @staticmethod
    def sharesSide(self, side, other):
        return side & other


class SurfaceStamp(object):
    def __init__(self, stamp):
        self.stamp = stamp
        self._findConnectors()

    def isIncline(self):
        picIncline = self.leftConnector.y > self.rightConnector.y
        if self.stamp.forceFlipX():
            return not picIncline
        else:
            return picIncline

    def slope(self):
        if self.stamp.forceFlipX():
            return self.leftConnector.y - self.rightConnector.y
        else:
            return self.rightConnector.y - self.leftConnector.y

    def _findConnectors(self):
        connectors = getColors(self.stamp, CONNECTOR_COLORS)
        if len(connectors) > 2:
            for connector in connectors:
                Log.info("Connector Locations: ({}, {})".format(connector.x, connector.x))
            assert len(connectors) == 2, "Stamps has more than two connectors: " + self.stamp.image
        self.rightConnector = None
        self.leftConnector = None
        for connector in connectors:
            side = ConnectorSide.get(connector, self.stamp.getSize())
            if side & ConnectorSide.LEFT:
                self.leftConnector = connector
            elif side & ConnectorSide.RIGHT:
                self.rightConnector = connector
        assert self.rightConnector, "Stamp does not have right connector: " + self.stamp.image
        assert self.leftConnector, "Stamp does not have left connector: " + self.stamp.image


class PlacedSurfaceStamp(SurfaceStamp):
    def __init__(self, stamp, position, flip):
        super(PlacedSurfaceStamp, self).__init__(stamp)
        self.position = TileVector(position.x, position.y)
        self.flip = flip

    def getRight(self):
        return self.position.y + (self.leftConnector.y if self.flip else self.rightConnector.y)

    def getLeft(self):
        return self.position.y + (self.rightConnector.y if self.flip else self.leftConnector.y)

    def getArea(self):
        return TileRect(self.position.x, self.position.y, self.stamp.getSize().x, self.stamp.getSize().y)

    def alignWith(self, leftStamp):
        """ Align this stamp with the prior adjacent stamp. """
        self.position.y = leftStamp.getRight() - (self.rightConnector.y if self.flip else self.leftConnector.y)

    def exceedsBiomeHeight(self, realBiome):
        """
                         (19,3)
          (4,4)            |-------|
            |--------------| STAMP |
            |              |-------|
            |       BIOME          |
            |                      |
            |----------------------|

        """
        return realBiome.area.y > self.position.y

    def applyStamp(self, layers, automata, rules):
        Terraform.applySimpleStamp(self.stamp, self.position, rules, self.flip, layers[Layer.Ground], layers[Layer.Wall], automata)

    def __str__(self):
        return "left({}, {}) - right({}, {})".format(self.position.x, self.getLeft(), self.position.x + self.stamp.getSize().x, self.getRight())


class PlacedStamp(object):
    def __init__(self, stamp):
        self.stamp = stamp
        self.position = TileVector()
        self.connectors = getColors(stamp, CONNECTOR_COLORS)
        assert len(self.connectors) > 0, "Stamp does not have any connectors %s" % stamp.image
        random.shuffle(self.connectors)
        self.flipX = shouldFlipX(stamp)
        self.flipY = False
        self.size = stamp.getSize()
