#!/bin/env python

# ColorImgSort
# Sorts images based on color
# by Ed Salisbury <ed@edsalisbury.net>
# Written: 2013/12/24

import argparse
import os
import os.path
import math
from PIL import Image


class ImgSort():

    def __init__(self, **kwargs):
        """Class constructor - sets up the internal variables"""

        self.path = kwargs['path']
        self.prefix = kwargs['prefix']
        self.num_points = kwargs['num_points']
        self.blur_radius = kwargs['blur_radius']
        self.num_colors = kwargs['num_colors']

    def points(self, width, height):
        """Returns points based on an image size and the number of points

        Returns points that are distributed evenly across an image.  If you
        think about intersecting lines, 9 points would create 3 horizontal
        lines and 3 vertical lines, and would return the 9 intersecting points.
        Due to the way this works, the number of points must be a perfect
        square (4, 9, 16, 25, etc.)
        """

        num_lines = int(math.sqrt(self.num_points))

        if num_lines ** 2 != self.num_points:
            raise RuntimeError("Number of points must be a perfect square")

        chunk_width = int(width / (num_lines + 1))
        chunk_height = int(height / (num_lines + 1))

        x_list = []
        y_list = []
        for i in range(1, num_lines + 1):
            x_list.append(chunk_width * i)
            y_list.append(chunk_height * i)

        xy_list = []
        for y in y_list:
            for x in x_list:
                xy_list.append((x, y))

        return xy_list

    def diamond_points(self, x, y):
        """Returns the list of points that form a diamond around the origin

        Makes concentric diamonds around a point (up to the specified radius),
        and returns all points within that diamond.
        """

        points = []

        orig_x = x
        orig_y = y

        # Origin
        points.append((x, y))

        for i in range(1, self.blur_radius + 1):
            # Top
            points.append((orig_x, orig_y - i))

            # NE side
            for x, y in zip(range(0, i), range(-i, 0)):
                points.append((orig_x + x, orig_y + y))

            # SE side
            for x, y in zip(range(i, 0, -1), range(0, i)):
                points.append((orig_x + x, orig_y + y))

            # SW side
            for x, y in zip(range(0, -i, -1), range(i, 0, -1)):
                points.append((orig_x + x, orig_y + y))

            # NW side
            for x, y in zip(range(-i, 0), range(0, -i, -1)):
                points.append((orig_x + x, orig_y + y))

        return points

    def sort(self):
        """Sorts a directory of images based on color

        Opens a directory, gets the file list, and determines the color at
        specific points in the images (using a simple blur), downsamples to
        a lower bitdepth and stores the filename in a dictionary, based on the
        color signature.  When completed, it will rename the files based on the
        dictionary entries, using the specified prefix.
        """

        img_files = os.listdir(self.path)

        img_list = {}

        for img_file in img_files:
            filename = os.path.join(self.path, img_file)

            try:
                img = Image.open(filename)
            except:
                continue

            print "Analyzing %s" % img_file