import numpy as np
from datetime import datetime, timedelta 
import sys
from time import strptime
from PIL import Image, ImageFont

def divide_chunks(l, n):
    """
    Splits a list into chunks of length n. Used to process the images in chunks.
    """
    for i in range(0, len(l), n):
        yield l[i : i + n]

# Sourced from https://gist.github.com/victorkristof/b9d794fe1ed12e708b9d
def datenum_to_datetime(datenum):
    """
    Convert Matlab datenum into Python datetime.
    :param datenum: Date in datenum format
    :return:        Datetime object corresponding to datenum.
    """
    days = datenum % 1
    hours = days % 1 * 24
    minutes = hours % 1 * 60
    seconds = np.round(minutes % 1 * 60)
    return datetime.fromordinal(int(datenum)) \
           + timedelta(days=int(days)) \
           + timedelta(hours=int(hours)) \
           + timedelta(minutes=int(minutes)) \
           + timedelta(seconds=int(seconds)) \
           - timedelta(days=366)


# Sourced from https://stackoverflow.com/questions/32237862/find-the-closest-date-to-a-given-date
def nearest(items, pivot):
    """
    This function will return the datetime in items 
    which is the closest to the date pivot
    """
    return min(items, key=lambda x: abs(x - pivot))


def progressbar(it, prefix="", size=60, out=sys.stdout): # Python3.3+
    count = len(it)
    def show(j):
        x = int(size*j/count)
        print("{}[{}{}] {}/{}".format(prefix, u"#"*x, "."*(size-x), j, count), 
                end='\r', file=out, flush=True)
    show(0)
    for i, item in enumerate(it):
        yield item
        show(i+1)
    print("\n", flush=True, file=out)
    
    
class RegisteredImage():
    
    def __init__(self, pathname, filename):
        self.pathname = pathname
        self.filename = filename
        filename_list = filename.split(".")
        date = filename_list[3].split("_")
        if 'snap' in filename_list:
            self.contributor = filename_list[8] # Mitch filename format
        else:
            self.contributor = filename_list[6] # Leaman filename format
        self.site = filename_list[6]
        self.posix_time = filename_list[0]
        self.timezone = filename_list[4]
        self.year = filename_list[5]
        self.month = '{:02d}'.format(strptime(filename_list[2],'%b').tm_mon) # Ensure 2-digit format
        self.day = date[0]
        self.hour = date[1]
        self.minute = date[2]
        self.second = date[3]
        
        self.tide = None
        self.tag = None
        self.width = None
        self.height = None
        self.font = None

    def get_tide(self, site_tide_data, ts):

        # Account for daylight savings
        # ASSUMPTION: All .mat tide files are either AEST or AEDT 
        if self.timezone == 'AEDT':
            self.hour = str(int(self.hour) - 1)
        date_string = self.year + '-' + self.month + '-' + self.day + ' ' + self.hour + ':' + self.minute + ':' + self.second
        img_datetime = datetime.strptime(date_string, "%Y-%m-%d %H:%M:%S") # Image date/time as a datetime object
        
        tide_date = nearest(site_tide_data, img_datetime)
        mat_index = site_tide_data.index(tide_date)  # Retrieve the index of the .mat tide/time
        mat_tide = round(ts[1][mat_index][0], 2) # Associated tide
        
        #print('Image date/time: ' + date_string)
        #print('Tide record:     ' + str(tide_date))
        self.tide = "{:.2f}".format(mat_tide)
    
    def create_tag(self):
        # Create image tag
        hour = self.hour.zfill(2)
        minute = self.minute.zfill(2)

        if self.tide:
            tide = self.tide
            if float(self.tide) >= 0:
                tide = '+' + self.tide
            self.tag = ('Date:' + self.year + '/' + self.month + '/' + self.day +  
                   ' Time:' + hour + ':' + minute + 
                   ' Tide:' + tide + 'm AHD' +
                   ' Contributor:' + self.contributor)
        else:
            self.tag = ('Date:' + self.year + '/' + self.month + '/' + self.day +  
                   ' Time:' + hour + ':' + minute + 
                   ' Contributor:' + self.contributor)
    
    def get_dimensions(self):
        image = Image.open(self.pathname)      
        # White Text Box 
        self.width, self.height = image.size          


    def get_font(self):
        
        image = Image.open(self.pathname)
        fontsize = 1
        if self.tide:
            img_fraction = 0.95
        else:
            img_fraction = 0.85
        font = ImageFont.truetype("fonts/Courier New Bold.ttf", fontsize) 
        generic_large_tag = "1641775682.Mon.Jan.10_11_48_02.AEDT.2022.byron.snap.KateThornborough123"
        
        while font.getsize(generic_large_tag)[0] < img_fraction*image.size[0]:
            # iterate until the text size is just larger than the criteria
            fontsize += 1
            font = ImageFont.truetype("fonts/Courier New Bold.ttf", fontsize) 
        self.font = ImageFont.truetype("fonts/Courier New Bold.ttf", fontsize)