#!/usr/bin/env python

# Run2dmorph originally written by Allison Hsiang
#
# 2016-06: Python port initalized by Kaylea Nelson
# 2017-05: Python port completed by Allison Hsiang
# 2022-04: Python2 to Python3 conversion by Allison Hsiang

import settings
import initialize
import images
import extractoutline
import extractmorph
import extractcoordinates
import aspectratio
import save

from datetime import datetime
import os
import socket
import sys
import pandas


def morph2d(settings_file):
    version = '2017.5.5'
    print ('\nRUN2DMORPH (v.%s)\n' % version)

    print (str(datetime.now()) + '\n')

    # Load settings file
    print ('Loading settings from %s...\n' % settings_file)
    run = settings.parse(settings_file)
    settings.save(run)

    # Create output directories
    initialize.makeOutputDirectories(run)

    # Pull list of all images in input directory
    image_list = images.list_files(run['in_directory'],run['input_ext'])

    # Initialize output 2D data frame
    data2D = pandas.DataFrame(columns=['SampleID','ObjectID','Area','Eccentricity','Perimeter','MajorAxisLength','MinorAxisLength','Rugosity','Height','Width','AspectRatio'])

    # Get count/names of failed extractions
    num_failed = 0
    failed_imgs = []

    for img in image_list:
        # Load image (also resizes if necessary)
        image = images.load(img,run)

        # Generate names for saving output files
        sample_id = run['sampleID']
        object_id = os.path.splitext(os.path.basename(img))[0]
        object_name = '_'.join([sample_id,object_id])

        # Extract edge and cleaned images
        try:
            edge_unsmoothed,edge_smoothed,image_clean,image_smoothed,image_border = extractoutline.extractOutline(run,object_id,image,False)
            # Get region properties: Area, eccentricity, perimeter, major axis length, minor axis length, and rugosity
            original_props = extractmorph.getRegionProps(image_clean)
            smoothed_props = extractmorph.getRegionProps(image_smoothed)
            measures = extractmorph.extractMorphology(original_props,smoothed_props)
            # Get minimum bounding box and aspect ratio
            mbb,contour = aspectratio.getMBB(image_clean)
            height,width,aspect_ratio = aspectratio.measureMBB(mbb)
            # Save aspect ratio image if requested
            if run['draw_aspect_ratio']:
                save.saveMBBFigure(run,mbb,contour,aspect_ratio,object_name)
            # Save measurements to data frame
            data2D = save.saveObject2D(data2D,sample_id,object_id,measures,height,width,aspect_ratio)

            # Extract unsmoothed and smoothed coordinates if requested and save to file
            if run['get_coordinates']:
                coordinates_unsmoothed = extractcoordinates.extractCoordinates(edge_unsmoothed,run['downsample'],run['num_points'],original_props,measures['MajorAxisLength'])
                coordinates_smoothed = extractcoordinates.extractCoordinates(edge_smoothed,run['downsample'],run['num_points'],smoothed_props,measures['MajorAxisLength'])
                save.saveCoordinates(run,coordinates_unsmoothed,sample_id,object_id,object_name,'original')
                save.saveCoordinates(run,coordinates_smoothed,sample_id,object_id,object_name,'smoothed')
        except:
            num_failed += 1
            failed_imgs.append(img)
            pass # Move to next object if outline cannot be extracted

    # Write final collection of measurements into CSV file
    output_path = os.path.join(run['out_directory'],'_'.join([run['sampleID'],'morph2d','properties.csv']))
    data2D.to_csv(output_path)

    # Write list of failed objects to file
    if failed_imgs:
        failed_img_list_path = os.path.join(run['out_directory'],'_'.join([run['sampleID'],'morph2d','failed_extractions.txt']))
        with open(failed_img_list_path, 'w') as f:
            for img in failed_imgs:
                f.write('{}{}'.format(os.path.basename(img), os.linesep))

    print ('INFO: Extracted outlines from {}/{} objects.'.format(len(image_list)-num_failed, len(image_list)))

    print ('INFO: Run2dmorph process completed.\n')


if __name__ == "__main__":
    if socket.gethostname() == 'tide.geology.yale.edu':
        os.nice(10)

    if len(sys.argv) == 2:
        morph2d(sys.argv[1])

    else:
        print ('Usage: run2dmorph <settings_file>')
        sys.exit('Error: incorrect usage')
