from gamera.core import *
from gamera.core import Point,FloatPoint, ONEBIT, RGBPixel
from OMRnotes.scripts.classification.dist import Distance
from OMRnotes.scripts.classification.head import *
from OMRnotes.scripts.classification.halfhead import Halfheads
from OMRnotes.scripts.classification.seg import Seg
from OMRnotes.scripts.classification.searcher import Searcher2
from scipy import signal
import numpy as np

def getbeam(res):
    '''Hledani poctu tramcu u notovych linek
    
    vstup:
    
    res - list bodu s informaci o trajektorii
    
    pro jeden bod plati:
    
    r == 0 - vpravo ani vlevo je nalezena trajektorie
    
    r == 1 - vpravo je linka
    
    r == 2 - vlevo je linka
    
    r == 3 - vpravo i vlevo je nalezena trajektorie
    
    vystup:
    
    return - pocet urovni tramcu
    
    Funkce hleda podel bodu urovne trajektorii, ktere znamenaji tramce
    hledani se provadi pro prave i leve okoli a ukonceno je podminkou
    maximalni mezery pro levou i pravou cast nalezenych trajektorii
    (misto kde tramce konci)
    '''
    breakmax = 20
    lblock = False
    rblock = False
    lbreak = 0
    rbreak = 0
    lwid = 0
    rwid = 0
    lnum = 0
    rnum = 0
    for r in res:
        if r == 0:
            lbreak = lbreak + 1
            rbreak = rbreak + 1
        elif r == 1:
            lbreak = lbreak + 1
            rbreak = 0
            rwid = rwid + 1
        elif r == 2:
            lbreak = 0
            rbreak = rbreak + 1
            lwid = lwid + 1
        elif r == 3:
            rbreak = 0
            lbreak = 0
            rwid = rwid + 1
            lwid = lwid + 1
        if lbreak == 1 and lwid > 0 and not lblock:
            lnum = lnum + int(lwid / 20 + 1)
            lwid = 0
        if rbreak == 1 and rwid > 0 and not rblock:
            rnum = rnum + int(rwid / 20 + 1)
            rwid = 0
        if lbreak > breakmax:
            lblock = True
        if rbreak > breakmax:
            rblock = True
        if lblock and rblock:
            break

    if lnum == 0:
        return rnum
    else:
        return max([lnum, rnum])

def findheads(imgstaff, img, sf, drawtemp):
    '''Hledani poctu tramcu
    
    vstup:
    
    imgstaff - obrazek s odebranymi linkami notove osnovy
    
    img - obrazek s vyfiltrovanymi hlavickami not
    
    sf - informace o odstranenych linkach
    
    drawtemp - zakresleni tramcu not (tato funkce bude presunuta)
    
    vystup:
    
    return - list nalezenych hlavicek
    
    Funkce v prvni fazi validuje hlavicky ze segmentu extrahovanych z obrazku vyfiltrovanych hlavicek
    Validace je zavisla na rozmerech, pomeru cernych a bilych pixelu v segmentu
    a okoli v nevyfiltrovanem obrazku. Validni segmentum z prvni faze je v druhe fazi hledana trajektorie linky v
    dolnim leve casti segmentu smerem dolu nebo prave horni casti segmentu smerem nahoru.
    Nejdelsi trajektorie jsou srovnany na zaklade primosti. Pokud trajektorie dosahuje minimalni stanovene
    delky, je detekovany sement hlavickou. V treti fazi jsou hledany tramce.
    Od koncu nalezenych trajektorii (notovych linek) jsou hledany trajektorie
    v pravem smeru linky uhlu v pravem i v levem okoli.
    Tyto trajektorie jsou nasledne validovany a na jejich
    zaklade je urcena rytmicka honota noty (na zaklade poctu tramcu)
    '''
    imgcc = img.cc_analysis()
    headlist = Quaters(sf)
    imgstaffrot1 = imgstaff.rotate(180, None, 1)
    imgstaffrot2 = imgstaff.rotate(0, None, 1)
    imgstaffrot3 = imgstaff.rotate(90, None, 1)
    imgstaffrot4 = imgstaff.rotate(-90, None, 1)
    imgstaffinv = imgstaff.image_copy()
    imgstaffinv.invert()
    imgstaff.draw_hollow_rect(FloatPoint(imgstaff.ul_x, imgstaff.ul_y),
                              FloatPoint(imgstaff.lr_x, imgstaff.lr_y),
                              1, 2)
    for j, item in enumerate(imgcc):
        offset = 2
        imgseg = imgstaff.subimage(Point(imgcc[j].ul_x - offset, imgcc[j].ul_y),
                                   Point(imgcc[j].lr_x + offset, imgcc[j].lr_y))
        numpixel1 = (imgcc[j].nrows) * (imgcc[j].ncols)
        numpixel2 = (imgcc[j].nrows) * (imgcc[j].ncols + offset * 2)
        r1 = imgcc[j].black_area()[0] / numpixel1
        r2 = imgseg.black_area()[0] / numpixel2
        minr1 = 0.6
        maxr1 = 0.99
        rx = 0.7
        maxr2 = ((r1 * numpixel1) + (rx * imgcc[j].nrows * 2 * offset)) / numpixel2
        if ((imgcc[j].width < (sf.staffspace_height * 2.5)) \
                    and (imgcc[j].width > (sf.staffspace_height * 0.8)) \
                    and (imgcc[j].height > (sf.staffspace_height * 0.8)) \
                    and (r1 > minr1) \
                    and (r1 <= maxr1) \
                    and (r2 < maxr2) \
            ):
            range1 = [[x, imgcc[j].ul_y] for x in range(imgcc[j].center_x, imgcc[j].ul_x + imgcc[j].width + 3)]
            range2 = [[x, imgcc[j].lr_y] for x in range(imgcc[j].ul_x - 3, imgcc[j].center_x)]
            sr1 = Searcher2(range1, imgstaff, imgstaffrot1, 180, 4, 7, 1)
            sr2 = Searcher2(range2, imgstaff, imgstaffrot2, 0, 4, 7, 1)
            lines1 = sr1.search2(500)
            lines2 = sr2.search2(500)
            print j

            if lines1:
                lines1max = max(lines1, key=lambda x: (abs(x[0])))
                lines1allmax = [lin for lin in lines1 if abs(lin[0]) >= (abs(lines1max[0]) - 2)]
                lines1max = min(lines1allmax, key=lambda x: (x[3]))
                c1 = abs(lines1max[0]) > 12
            else:
                c1 = False

            if lines2:
                lines2max = max(lines2, key=lambda x: (abs(x[0])))
                lines2allmax = [lin for lin in lines2 if abs(lin[0]) >= (abs(lines2max[0]) - 2)]
                lines2max = min(lines2allmax, key=lambda x: (x[3]))
                c2 = abs(lines2max[0]) > 12
            else:
                c2 = False

            if lines1 and lines2 and c1 and c2:
                c12 = abs(lines1max[0]) > abs(lines2max[0])
            else:
                c12 = False

            if c12 or (c1 and not c2):
                range1ur = [[lines1max[4][0][0], x] for x in
                            range(lines1max[4][0][1], (lines1max[1][0][1]))]
                range1ul = [[lines1max[4][0][0], x] for x in
                            range(lines1max[4][0][1], (4 * lines1max[1][0][1] + lines1max[4][0][1]) / 5)]
                sr1ur = Searcher2(range1ur, imgstaff, imgstaffrot3, 90, 3, 2, 5)
                sr1ul = Searcher2(range1ul, imgstaff, imgstaffrot4, -90, 3, 2, 5)
                lines1ur = sr1ur.search2(40)
                lines1ul = sr1ul.search2(40)

                res = [(int(lines1ul[i][0] > 8) * 2 + int(lines1ur[i][0] > 8)) for i, r in enumerate(range1ul)]
                num = getbeam(res)

                for lin in lines1ul:
                    if lin[0] > 8:
                        drawtemp.draw_line(FloatPoint(lin[1][0][0], lin[1][0][1]),
                                           FloatPoint(lin[4][0][0], lin[1][0][1]),
                                           RGBPixel(255, 0, num * 50), 1)
                for lin in lines1ur:
                    if lin[0] > 8:
                        drawtemp.draw_line(FloatPoint(lin[1][0][0], lin[1][0][1]),
                                           FloatPoint(lin[4][0][0], lin[1][0][1]),
                                           RGBPixel(0, 255, num * 50), 1)

                sub = imgstaff.subimage(Point(lines1max[4][0][0], imgcc[j].ul_y - lines1max[0]),
                                        Point(lines1max[4][0][0] + 1, imgcc[j].ul_y))
                headlist.append(Heads(j, 0, [imgcc[j]], sub, None, 1, sf, num))
            if (not c12) and c2:
                range2ul = [[lines2max[4][0][0], x] for x in
                            reversed(range((lines2max[1][0][1]), lines2max[4][0][1]))]
                range2ur = [[lines2max[4][0][0], x] for x in
                            reversed(range(lines2max[1][0][1], lines2max[4][0][1]))]
                sr2ul = Searcher2(range2ul, imgstaff, imgstaffrot4, -90, 3, 2, 5)
                sr2ur = Searcher2(range2ur, imgstaff, imgstaffrot3, 90, 3, 2, 5)
                lines2ul = sr2ul.search2(40)
                lines2ur = sr2ur.search2(40)

                res = [(int(lines2ul[i][0] > 8) * 2 + int(lines2ur[i][0] > 8)) for i, r in enumerate(range2ul)]
                num = getbeam(res)

                for lin in lines2ul:
                    if lin[0] > 8:
                        drawtemp.draw_line(FloatPoint(lin[1][0][0], lin[1][0][1]),
                                           FloatPoint(lin[4][0][0], lin[1][0][1]),
                                           RGBPixel(num * 50, 0, 255), 1)
                for lin in lines2ur:
                    if lin[0] > 8:
                        drawtemp.draw_line(FloatPoint(lin[1][0][0], lin[1][0][1]),
                                           FloatPoint(lin[4][0][0], lin[1][0][1]),
                                           RGBPixel(num * 50, 255, 0), 1)

                sub = imgstaff.subimage(Point(lines2max[4][0][0], imgcc[j].ll_y),
                                        Point(lines2max[4][0][0] + 1, imgcc[j].ll_y + lines2max[0]))
                headlist.append(Heads(j, 0, [imgcc[j]], sub, None, 2, sf, num))
    headlist = sorted(headlist, key=lambda x: ((x.staves * 10000) + x.seghead.center_x))
    return headlist