#!/usr/bin/python

#This takes a list of image files and acts as a tool to mark the crop region of the page

import re
import xml.etree.ElementTree as ET
import os
import sys
from io import StringIO
import cv2



def showControls():
    print(' -----------------------------------------------')
    print('| CONTROLS:                                     |')
    print('| * set new corner (base on loc):   left-click  |')
    print('| * set new seam corner (two-page): middle-click|')
    print('| * confirm corners:                enter       |')
    print('| * mark page as abnormal:          a           |')
    print('| * undo:                           backspace   |')
    print('| * start previous page over:       backspace(+)|')
    #print('| * start current page over:        delete      |')
    print('| * exit:                           esc         |')
    print('|                                               |')
    print(' -----------------------------------------------')



lastDidList=[]
tl=(-1,-1)
tr=(-1,-1)
bl=(-1,-1)
br=(-1,-1)
tm=(-1,-1)
bm=(-1,-1)

image=None
orig=None

abnorm=False

def draw():
    global image,tl,tr,bl,br,tm,bm,abnorm
    if tm[0]>=0 and bm[0]>=0:
        cv2.line(image, tm, bm, (0,255,0), 2)
    if tm[0]>=0 and tl[0]>=0:
        cv2.line(image, tm, tl, (0,255,0), 2)
    if tm[0]>=0 and tr[0]>=0:
        cv2.line(image, tm, tr, (0,255,0), 2)
    if bm[0]>=0 and bl[0]>=0:
        cv2.line(image, bm, bl, (0,255,0), 2)
    if bm[0]>=0 and br[0]>=0:
        cv2.line(image, bm, br, (0,255,0), 2)
    if tl[0]>=0 and tr[0]>=0:
        cv2.line(image, tl, tr, (255,0,0), 2)
    if br[0]>=0 and tr[0]>=0:
        cv2.line(image, br, tr, (255,0,0), 2)
    if br[0]>=0 and bl[0]>=0:
        cv2.line(image, br, bl, (255,0,0), 2)
    if tl[0]>=0 and bl[0]>=0:
        cv2.line(image, tl, bl, (255,0,0), 2)


    if tl[0]>=0:
        image[tl[1],tl[0]]=(0,0,255)
        cv2.circle(image, tl, 2, (0,0,200), 1)
        cv2.circle(image, tl, 5, (0,0,200), 2)
    if tr[0]>=0:
        image[tr[1],tr[0]]=(0,0,255)
        cv2.circle(image, tr, 2, (0,0,200), 1)
        cv2.circle(image, tr, 5, (0,0,200), 2)
    if bl[0]>=0:
        image[bl[1],bl[0]]=(0,0,255)
        cv2.circle(image, bl, 2, (0,0,200), 1)
        cv2.circle(image, bl, 5, (0,0,200), 2)
    if br[0]>=0:
        image[br[1],br[0]]=(0,0,255)
        cv2.circle(image, br, 2, (0,0,200), 1)
        cv2.circle(image, br, 5, (0,0,200), 2)
    if tm[0]>=0:
        image[tm[1],tm[0]]=(0,0,255)
        cv2.circle(image, tm, 2, (0,100,200), 1)
        cv2.circle(image, tm, 5, (0,100,200), 2)
    if bm[0]>=0:
        image[bm[1],bm[0]]=(0,0,255)
        cv2.circle(image, bm, 2, (0,100,200), 1)
        cv2.circle(image, bm, 5, (0,100,200), 2)

    if abnorm:
        cv2.putText(image, 'ABNORMAL', (image.shape[1]/2,image.shape[0]/2), cv2.FONT_HERSHEY_PLAIN, 2, (0,0,255))


    cv2.imshow("image", image)

bimage=None
def clicker(event, x, y, flags, param):
        # grab references to the global variables
        global image,tl,tr,bl,br,tm,bm,lastDidList,orig

        """if event == cv2.EVENT_LBUTTONDOWN:
            if len(segPts)>0:
                #change last boundary
                image=bimage.copy()
                segPts[-1]=x
                ll=max(0,segPts[-1]-1)
                rr=min(image.shape[1], segPts[-1]+1)
                image[:,ll:rr,0] = color[(colorIdx+len(color)-1)%len(color)][0] * image[:,ll:rr,0]
                image[:,ll:rr,1] = color[(colorIdx+len(color)-1)%len(color)][1] * image[:,ll:rr,1]
                image[:,ll:rr,2] = color[(colorIdx+len(color)-1)%len(color)][2] * image[:,ll:rr,2]
                cv2.imshow("image", image)
"""
        if event == cv2.EVENT_LBUTTONDOWN:
                # a new boundary
                if x<image.shape[1]/2 and y<image.shape[0]/2:
                    tl=(x,y)
                    if 0 in lastDidList:
                        image=orig.copy()
                        lastDidList.remove(0)
                    lastDidList.append(0)
                if x>image.shape[1]/2 and y<image.shape[0]/2:
                    tr=(x,y)
                    if 1 in lastDidList:
                        image=orig.copy()
                        lastDidList.remove(1)
                    lastDidList.append(1)
                if x<image.shape[1]/2 and y>image.shape[0]/2:
                    bl=(x,y)
                    if 2 in lastDidList:
                        image=orig.copy()
                        lastDidList.remove(2)
                    lastDidList.append(2)
                if x>image.shape[1]/2 and y>image.shape[0]/2:
                    br=(x,y)
                    if 3 in lastDidList:
                        image=orig.copy()
                        lastDidList.remove(3)
                    lastDidList.append(3)
                draw()

        elif event == cv2.EVENT_MBUTTONDOWN:
                # a new boundary
                if y<image.shape[0]/2:
                    tm=(x,y)
                    if 1 in lastDidList:
                        image=orig.copy()
                        lastDidList.remove(1)
                    lastDidList.append(4)
                if y>image.shape[0]/2:
                    bm=(x,y)
                    if 3 in lastDidList:
                        image=orig.copy()
                        lastDidList.remove(3)
                    lastDidList.append(5)
                draw()

def segmenter(imDir,imagePath,dispHeight):
    global image,tl,tr,bl,br,tm,bm,lastDidList,orig,abnorm
    print('opening '+imDir+imagePath)
    orig = cv2.imread(imDir+imagePath)
    scale = orig.shape[0]/dispHeight
    orig = cv2.resize(orig,(0,0),None,1.0/scale,1.0/scale)
    #print 'opened'
    assert orig is not None
    redo=True
    while redo: #undo loop
        abnorm=False
        lastDidList=[]
        tl=(-1,-1)
        tr=(-1,-1)
        bl=(-1,-1)
        br=(-1,-1)
        tm=(-1,-1)
        bm=(-1,-1)
        redo=False
        image = orig.copy()
        draw()
        while True:
            # display the imageWork and wait for a keypress
            key = cv2.waitKey(33) & 0xFF #so it is robust on all systems
            #print key
            if key == 13 and tl[0]>=0 and tr[0]>=0 and bl[0]>=0 and br[0]>=0: #enter
                toWrite = imagePath+','+str(int(scale*tl[0]))+','+str(int(scale*tl[1]))+','+str(int(scale*tr[0]))+','+str(int(scale*tr[1]))+','+str(int(scale*br[0]))+','+str(int(scale*br[1]))+','+str(int(scale*bl[0]))+','+str(int(scale*bl[1]))
                if abnorm:
                    if tm[0]>=0 and bm[0]>=0:
                        toWrite += ',ABNORMAL,'+str(int(scale*tm[0]))+','+str(int(scale*tm[1]))+','+str(int(scale*bm[0]))+','+str(int(scale*bm[1]))
                    else:
                        toWrite += ',ABNORMAL'
                else:
                    if tm[0]>=0 and bm[0]>=0:
                        toWrite += ',DOUBLE,'+str(int(scale*tm[0]))+','+str(int(scale*tm[1]))+','+str(int(scale*bm[0]))+','+str(int(scale*bm[1]))
                    else:
                        toWrite += ',SINGLE'
                toWrite+='\n';
                return toWrite, False, False
            elif key == 8: #backspace
                if len(lastDidList)>0:
                    imageWork = orig.copy()
                    lastDid=lastDidList.pop()
                    if lastDid==0:
                        tl=(-1,-1)
                    elif lastDid==1:
                        tr=(-1,-1)
                    elif lastDid==2:
                        bl=(-1,-1)
                    elif lastDid==3:
                        br=(-1,-1)
                    elif lastDid==4:
                        tm=(-1,-1)
                    elif lastDid==5:
                        bm=(-1,-1)
                    image=orig.copy()
                    draw()
                else:
                    return '', True, False
            elif key == 127: #del
                #if len(lastDidList)>0:
                    print('[CLEAR]')
                    redo=True
                    break
                #else:
                #    return '', True, False
            elif key == 27: #esc
                print('esc')
                return '', False, True
                #exit(0)
                #break
            elif key == 97: #'a'
                #return imagePath+',-1,-1,-1,-1,-1,-1,-1,-1,ABNORMAL\n', False, False
                abnorm = not abnorm
                image=orig.copy()
                draw()

    #return newWords, newWordBoxes

if len(sys.argv)<4:
    print('usage: '+sys.argv[0]+' imgDir imgList outAnn.csv [displayHeight]')
    print('output format: imageFile, tlx, tly, trx, try, brx, bry, blx, bly, type (,tmx, tmy, bmx, bmy)')
    exit(0)

inFile = sys.argv[2]
imDir = sys.argv[1]
if imDir[-1]!='/':
    imDir+='/'
outFile = sys.argv[3]
dispHeight=500.0
if len(sys.argv)>4:
    dispHeight=float(sys.argv[4])

cv2.namedWindow("image")
cv2.setMouseCallback("image", clicker)

didCount=0
did=[]
try:
    check = open(outFile,'r')
    did = check.read().splitlines()
    didCount=len(did)
    check.close()
    print('found '+outFile+', appending. Note: this is sychronizing based on count alone, if '+inFile+' hash changed, but sure to align '+outFile)
except IOError:
    print(('making new out:'+outFile))

out = open(outFile,'w')

print(' =============================================== ')
print(' !!! INSTRUCTIONS !!!')
print(' If the page does not contain a single page, or  ')
print(' an open book, mark as abnormal with INSERT (e.g.')
print(' two seperate pages).')
print(' Click on the four corners to include all the    ')
print(' full pages in the image (including two pages if ')
print(' fully present).')
print(' If two pages a full present also mark page seam ')
print(' (middle-click).')
print(' On placing points, prioritize the following to  ')
print(' be included/discluded from the polygons in the  ')
print(' following order:')
print('   1. Including the present page(s) content.')
print('   2. Discluding other pages and background.')
print('   3. Discluding the present page(s) boudary.')
print('   4. Including the present page(s) white area.')
#print ' book). If a corner is torn, click where it ought'
#print ' to be, based on page edges. The page seem on an '
#print ' open book is the page edge.'
print(' Use ESC to exit or the latest page you finished ')
print(' will be lost.')

#i=didCount
i=0
#pageCount=-1
prevSeg=''
seg=''
showControls()
inF = open(inFile,'r')
images = inF.read().splitlines()
end=False
doneOne=False
while i<len(images) and not end:
    if i%10==9:
        showControls()
    print((str(i+1)+' of '+str(len(images))))

    if len(did)>i:
        line = did[i].strip().split(',')
        typ = line[8]
        #print typ
        if typ != '-1':
            out.write(did[i].strip()+'\n')
            i+=1
            continue
        seg, undo, end = segmenter(imDir, images[i],dispHeight)
        out.write(seg)
        seg=''
        i+=1
    else:


        seg, undo, end = segmenter(imDir, images[i],dispHeight)
        if len(seg)>0:
            doneOne=True
        
        if undo and i>0 and doneOne:
            prevSeg=''
            print((str(i)+' of '+str(len(images))))
            prevSeg, undo, end = segmenter(imDir, images[i-1],dispHeight)
        else:
            out.write(prevSeg)
            prevSeg=seg
            seg=''
            i+=1
out.write(prevSeg)
out.write(seg)
