#include <windows.h>
#include <vfw.h>
#include <stdio.h>
#include <math.h>

#include "iup.h"
//#include "cd.h"

#include "img.h"
#include "edges.h"
#include "treeinterp.h"
#include "img_dim.h"

static char arq_mdl[BUFSIZ];
static char arq_img[BUFSIZ];
static int img_carregada = 0;
static unsigned char img_orig[3*WIDTHHEIGHT];
static unsigned char laplaciana[3*WIDTHHEIGHT];

extern Ihandle *mainDialog;
extern Ihandle *InputCanvas;

extern void Dialogos();

static BITMAPINFOHEADER bmiHeader;
static HDC              hInputDC;
static HDRAWDIB         hDrawDibDC;

static int Redraw_in_cb (Ihandle *, float , float )
{
 if (img_carregada!=0) DrawDibDraw(hDrawDibDC, hInputDC, 0, 0, WIDTH, HEIGHT, &bmiHeader, img_orig, 0, 0, WIDTH, HEIGHT, 0);
 return IUP_DEFAULT;
}

#define NLINHAS 9
static TreeInterpLinha LINHA[NLINHAS];

void CarregaModelo(char *fname)
{
 GeomPonto2D PONTOS[16];
 int i;
 FILE *fd = fopen(fname, "r");
 for (i=0; i<16; i++)
  fscanf(fd, "%f %f", &(PONTOS[i].x), &(PONTOS[i].y));
 LINHA[0].v1x = PONTOS[0].x,  LINHA[0].v1y = PONTOS[0].y,  LINHA[0].v2x = PONTOS[1].x, LINHA[0].v2y = PONTOS[1].y,
 LINHA[1].v1x = PONTOS[2].x,  LINHA[1].v1y = PONTOS[2].y,  LINHA[1].v2x = PONTOS[3].x, LINHA[1].v2y = PONTOS[3].y,
 LINHA[2].v1x = PONTOS[3].x,  LINHA[2].v1y = PONTOS[3].y,  LINHA[2].v2x = PONTOS[4].x, LINHA[2].v2y = PONTOS[4].y,
 LINHA[3].v1x = PONTOS[4].x,  LINHA[3].v1y = PONTOS[4].y,  LINHA[3].v2x = PONTOS[5].x, LINHA[3].v2y = PONTOS[5].y,
 LINHA[4].v1x = PONTOS[6].x,  LINHA[4].v1y = PONTOS[6].y,  LINHA[4].v2x = PONTOS[7].x, LINHA[4].v2y = PONTOS[7].y,
 LINHA[5].v1x = PONTOS[7].x,  LINHA[5].v1y = PONTOS[7].y,  LINHA[5].v2x = PONTOS[8].x, LINHA[5].v2y = PONTOS[8].y,
 LINHA[6].v1x = PONTOS[8].x,  LINHA[6].v1y = PONTOS[8].y,  LINHA[6].v2x = PONTOS[9].x, LINHA[6].v2y = PONTOS[9].y,
 LINHA[7].v1x = PONTOS[14].x, LINHA[7].v1y = PONTOS[14].y, LINHA[7].v2x = PONTOS[0].x, LINHA[7].v2y = PONTOS[0].y,
 LINHA[8].v1x = PONTOS[15].x, LINHA[8].v1y = PONTOS[15].y, LINHA[8].v2x = PONTOS[1].x, LINHA[8].v2y = PONTOS[1].y;
 fclose(fd);
}

static int Load_modelo_cb()
{
 sprintf(arq_mdl, "*.mdl");
 if (!IupGetFile (arq_mdl)) CarregaModelo(arq_mdl);
 return IUP_DEFAULT;
}

static int Load_imag_cb()
{
 sprintf(arq_img, "*.*");
 if (!IupGetFile (arq_img)) {
  load(arq_img, img_orig);
  img_carregada = 1;
  DrawDibDraw(hDrawDibDC, hInputDC, 0, 0, WIDTH, HEIGHT, &bmiHeader, img_orig, 0, 0, WIDTH, HEIGHT, 0);
 }
 return IUP_DEFAULT;
}

int Exit_cb()
{
 return IUP_CLOSE;
}

/* exemplo de restrição particular: algumas linhas do meu modelo tem que estar na 
 visualização e verifico a inclinação da visualização da linha de fundo para verificar 
 direção do eixo z (para cima) */
static int Restricao(int nlinhas, TreeInterpLinha *linha, unsigned char *F)
{
 unsigned char *pF, *pF_max;
 int a=0, b=0, c=0, d=0;
 for (pF=F, pF_max=&F[nlinhas-1]; pF<=pF_max; pF++) {
  a += (*pF==0 || *pF==2 || *pF==5);
  b += (*pF==1 || *pF==3);
  c += (*pF==1 || *pF==4);
  d += (*pF==3 || *pF==6);
 }
 int r = (a==3 && (b==2 || c==2 || d==2));
 if (!r) return 0;
 int f0, cont, fa[2];
 TreeInterpLinha l0;
 for (f0=0; f0<nlinhas; f0++)
  if (F[f0] == 0) break;
 l0 = linha[f0];
 if (!l0.dx || !l0.dy) return 0;

 cont = 0;
 fa[2];
 for (fa[0]=0; fa[0]<nlinhas; fa[0]++)
  if (F[fa[0]] == 1) {
   cont = 1;
   break;
  }
 for (fa[cont]=0; fa[cont]<nlinhas; fa[cont]++)
  if (F[fa[cont]] == 4) {
   cont++;
   break;
  }
 if (cont < 2) {
  for (fa[cont]=0; fa[cont]<nlinhas; fa[cont]++)
   if (F[fa[cont]] == 6) {
    cont++;
    break;
   }
  if (cont < 2)
   for (fa[cont]=0; fa[cont]<nlinhas; fa[cont]++)
    if (F[fa[cont]] == 3)
     break;
 }
 if (((l0.dx < 0)? l0.dy : -l0.dy) >= 0) return linha[fa[0]].v1y >= linha[fa[1]].v1y;
 return linha[fa[1]].v1y >= linha[fa[0]].v1y;
}

int Reconhecimento_cb()
{
 ConvolucaoLaplacianadaGaussianaCor(img_orig, laplaciana, 320);
 static TreeInterpLinha linha[30];
 int nlinhas = edgedetect(laplaciana, 10, 10, 20, linha);
 unsigned char *R = new unsigned char [nlinhas];
 if (nlinhas>4) {
  TreeInterpretation(NLINHAS, LINHA, nlinhas, linha, Restricao, R);
  for (int i=0; i<nlinhas; i++)
   printf("R[%d] = %d - Linha: (%.16f, %.16f) - (%.16f, %.16f)\n", i, (int)R[i], linha[i].v1x, linha[i].v1y, linha[i].v2x, linha[i].v2y);
 }
 return IUP_DEFAULT;
}

static void SetFunctions ()
{
 IupSetFunction("load_modelo_cb",          (Icallback)Load_modelo_cb);
 IupSetFunction("load_imag_cb",            (Icallback)Load_imag_cb);
 IupSetFunction("exit_cb",                 (Icallback)Exit_cb);
 IupSetFunction("reconhecimento_cb",       (Icallback)Reconhecimento_cb);
 IupSetFunction("redraw_in_cb",            (Icallback)Redraw_in_cb);
}
/*
int main ()
{
 bmiHeader.biSize        = 40;
 bmiHeader.biWidth       = WIDTH;
 bmiHeader.biHeight      = HEIGHT;
 bmiHeader.biPlanes      = 1;
 bmiHeader.biCompression = BI_RGB;
 bmiHeader.biBitCount    = 24;
 bmiHeader.biSizeImage   = 0;

 hDrawDibDC = DrawDibOpen();

 IupOpen();
 Dialogos();
 IupShow(mainDialog);
 CarregaModelo("real.mdl");
 hInputDC  = GetDC((HWND)IupGetAttribute(InputCanvas,  IUP_WID));
 SetFunctions();
 IupMainLoop();
 IupClose();

 ReleaseDC((HWND)IupGetAttribute(InputCanvas,  IUP_WID), hInputDC);
 DesalocaMemoria();
 return 1;
}*/