"""
Map image generation classes.
"""

import math
import logging

from PIL import Image, ImageDraw

from btmux_maplib.img_generator import rgb_vals
from btmux_maplib.img_generator.exceptions import InvalidImageMode

logger = logging.getLogger(__name__)


class MuxMapImage(object):
    """
    This class serves as a base class for map image types. You generally only
    need to over-ride render_hexes() to have something that works. See
    PixelHexMapImage for an example.
    
    DO NOT USE THIS CLASS DIRECTLY!
    """

    # Reference to the MuxMap object to image.
    map = None
    # The PIL Image object.
    map_img = None
    # Imaging mode, see set_mode().
    mode = "color"
    # Show some debug information.
    debug = True

    # A lowercase list of valid imaging modes.
    # color: Standard color terrain/elevation map.
    # elevmap: Elevation only, looks grayscaled aside from water.
    VALID_MODES = ["color", "elevmap"]
    
    def __init__(self, map):
        """
        Default init routine.
        
        Args:
        * map: (MuxMap) The map object to create an image of.
        """

        self.map = map
        
    def set_mode(self, mode):
        mode_lower = mode.lower()
        if mode_lower not in self.VALID_MODES:
            raise InvalidImageMode(mode_lower)
        else:
            self.mode = mode_lower
            logger.debug("Imaging mode set to: %s", self.mode)
   
    def handle_resizing(self, min_dimension, max_dimension):
        """
        Given a min and/or max dimension, calculate the overall re-size ratio
        for the image and re-size if necessary. Return the scaling multiplier
        used.
        """

        map_width = float(self.map_img.size[0])
        map_height = float(self.map_img.size[1])
        resize_mul = 1.0
        
        if min_dimension is not None and \
                (map_width < min_dimension or map_height < min_dimension):
            # Determine the smallest side to bring up to our limit.
            smallest_dim = min(map_width, map_height)
            # Bicubic gives the best look when scaling up.
            resize_filter = Image.BICUBIC
            resize_mul = float(min_dimension) / smallest_dim
            logger.debug('Under-sized, re-size needed: (%d/%d) = %f',
                         min_dimension, smallest_dim, resize_mul)
            self.resize_img(resize_mul, resize_filter)
        elif max_dimension is not None and \
                (map_width > max_dimension or map_height > max_dimension):
            # Determine the largest side to bring down to our limit.
            largest_dim = max(map_width, map_height)
            # Anti-aliasing looks best when scaling down.
            resize_filter = Image.ANTIALIAS
            resize_mul = float(max_dimension) / largest_dim

            logger.debug('Over-sized, re-size needed: (%d/%d) = %f',
                max_dimension, largest_dim, resize_mul)
            self.resize_img(resize_mul, resize_filter)

        return resize_mul

    def resize_img(self, resize_mul, resize_filter):
        """
        Re-size the map image by a float value. 1.0 = 100%.
        """
        map_width = self.map_img.size[0]
        map_height = self.map_img.size[1]

        logger.debug('Re-Size Mul: %f', resize_mul)
        logger.debug('Before  Width: %d  Height: %d', map_width, map_height)
        logger.debug('After   Width: %d  Height: %d',
                     map_width * resize_mul, map_height * resize_mul)

        # Re-size the image with the appropriate size multiplier.     
        self.map_img = self.map_img.resize(
            (int(map_width * resize_mul), int(map_height * resize_mul)),
            resize_filter)

    def render_hexes(self):
        """
        Stub to alert people trying to use this class. MuxMapImage is not
        meant to be used directly, and future sub-classes need a fall-through.
        """