import numpy as np
from PIL import Image
import progressbar

from util.compute_boundary_acc import compute_boundary_acc
from util.file_buffer import FileBuffer

from argparse import ArgumentParser
import os
import re


parser = ArgumentParser()

parser.add_argument('--dir', help='Directory with image, gt, and mask')

parser.add_argument('--output', help='Output of temp results',
        default=None)

args = parser.parse_args()

def get_iu(seg, gt):
    intersection = np.count_nonzero(seg & gt)
    union = np.count_nonzero(seg | gt)
    
    return intersection, union 

total_new_i = 0
total_new_u = 0
total_old_i = 0
total_old_u = 0

total_old_correct_pixels = 0
total_new_correct_pixels = 0
total_num_pixels = 0

total_num_images = 0
total_seg_acc = 0
total_mask_acc = 0

small_objects = 0

all_h = 0
all_w = 0
all_max = 0

all_gts = [gt for gt in os.listdir(args.dir) if '_gt.png' in gt]
file_buffer = FileBuffer(os.path.join(args.dir, 'results_post.txt'))

if args.output is not None:
    os.makedirs(args.output, exist_ok=True)

for gt_name in progressbar.progressbar(all_gts):
    
    gt = np.array(Image.open(os.path.join(args.dir, gt_name)
                                ).convert('L'))

    seg = np.array(Image.open(os.path.join(args.dir, gt_name.replace('_gt', '_seg'))
                                ).convert('L'))

    mask_im = Image.open(os.path.join(args.dir, gt_name.replace('_gt', '_mask'))
                                ).convert('L')
    mask = seg.copy()
    this_class = int(re.search(r'\d+', gt_name[::-1]).group()[::-1]) - 1

    rmin = cmin = 0
    rmax, cmax = seg.shape

    all_h += rmax
    all_w += cmax
    all_max += max(rmax, cmax)

    mask_h, mask_w = mask.shape
    if mask_h != cmax:
        mask = np.array(mask_im.resize((cmax, rmax), Image.BILINEAR))

    if seg.sum() < 32*32:
        # Reject small objects, just copy input
        small_objects += 1
    else:
        if (cmax==cmin) or (rmax==rmin):
            # Should not happen. Check the input in this case.
            print(gt_name, this_class)
            continue
        class_mask_prob = np.array(mask_im.resize((cmax-cmin, rmax-rmin), Image.BILINEAR))
        mask[rmin:rmax, cmin:cmax] = class_mask_prob

    """
    Compute IoU and boundary accuracy
    """
    gt = gt > 128
    seg = seg > 128
    mask = mask > 128

    old_i, old_u = get_iu(gt, seg)
    new_i, new_u = get_iu(gt, mask)

    total_new_i += new_i
    total_new_u += new_u
    total_old_i += old_i
    total_old_u += old_u

    seg_acc, mask_acc = compute_boundary_acc(gt, seg, mask)
    total_seg_acc += seg_acc
    total_mask_acc += mask_acc
    total_num_images += 1
    
    if args.output is not None:
        gt = Image.fromarray(gt)
        seg = Image.fromarray(seg)
        mask = Image.fromarray(mask)

        gt.save(os.path.join(args.output, gt_name))
        seg.save(os.path.join(args.output, gt_name.replace('_gt.png', '_seg.png')))
        mask.save(os.path.join(args.output, gt_name.replace('_gt.png', '_mask.png')))

new_iou = total_new_i/total_new_u
old_iou = total_old_i/total_old_u
new_mba = total_mask_acc/total_num_images
old_mba = total_seg_acc/total_num_images

file_buffer.write('New IoU  : ', new_iou)
file_buffer.write('Old IoU  : ', old_iou)
file_buffer.write('IoU Delta: ', new_iou-old_iou)

file_buffer.write('New mBA  : ', new_mba)
file_buffer.write('Old mBA  : ', old_mba)
file_buffer.write('mBA Delta: ', new_mba-old_mba)

file_buffer.write('Avg. H+W  : ', (all_h+all_w)/total_num_images)
file_buffer.write('Avg. Max(H,W) : ', all_max/total_num_images)

file_buffer.write('Number of small objects: ', small_objects)
