// Busqueda.cpp : implementation file
//

#include "stdafx.h"
#include "Proyecto.h"
#include "ProyectoDoc.h"
#include "ProyectoView.h"
#include "Busqueda.h"
#include "CCurvatura.h"
#include <math.h>
#include "funciones.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

#define SIGMA_POR_DEFECTO 3.00
#define PI 3.14159265

// Columnas del grid que contiene los resultados obtenidos
enum En
{
	imagen = 0,
	directorio = 1,
	parecido = 2,
	numpuntos = 3
};

/////////////////////////////////////////////////////////////////////////////
// CBusqueda dialog


CBusqueda::CBusqueda(CWnd* pParent /*=NULL*/)
	: CDialog(CBusqueda::IDD, pParent)
{	
	//{{AFX_DATA_INIT(CBusqueda)
	m_TxtDimensionX = _T("");
	m_TxtDimensionY = _T("");
	m_TxtImage = _T("");
	m_TxtSigma = _T("");
	m_ChkTodas = FALSE;
	m_TxtBD = _T("");
	m_Desc = -1;
	m_Parec = -1;
	m_TxtMejores = _T("");
	m_TxtParecido = _T("");
	m_ChkImagen = FALSE;
	m_ChkMejora = FALSE;
	m_ChkRotacion = FALSE;
	m_Label = _T("");
	//}}AFX_DATA_INIT

	// Realizamos un enlace a la BD
	m_pBd = ((CProyectoView *) pParent)->GetDocument()->m_db;
	// Realizamos un enlace a la configuración actual
	m_Opt = ((CProyectoView *) pParent)->GetDocument()->opt;
}

void CBusqueda::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	
	//{{AFX_DATA_MAP(CBusqueda)
	DDX_Control(pDX, IDC_BARRA, m_Barra);
	DDX_Control(pDX, IDC_COMBOBD, m_BD);
	DDX_Control(pDX, IDC_BUT_BUSQUEDA, m_ButBuscar);
	DDX_Control(pDX, IDCANCEL, m_BotCerrar);
	DDX_Control(pDX, IDC_VISTA2, m_Image2);
	DDX_Control(pDX, IDC_VISTA1, m_Image1);
	DDX_Control(pDX, IDC_EDIT_SIGMA, m_Sigma);
	DDX_Control(pDX, IDC_BUT_EXAMIN, m_BotOpenFile);
	DDX_Text(pDX, IDC_EDIT_DIMENSIONX, m_TxtDimensionX);
	DDX_Text(pDX, IDC_EDIT_DIMENSIONY, m_TxtDimensionY);
	DDX_Text(pDX, IDC_EDIT_IMAGE, m_TxtImage);
	DDX_Text(pDX, IDC_EDIT_SIGMA, m_TxtSigma);
	DDX_Control(pDX, IDC_GRID, m_Grid);
	DDX_Check(pDX, IDC_TODAS, m_ChkTodas);
	DDX_CBString(pDX, IDC_COMBOBD, m_TxtBD);
	DDX_Radio(pDX, IDC_DESC, m_Desc);
	DDX_Radio(pDX, IDC_PAREC, m_Parec);
	DDX_Text(pDX, IDC_EDIT_MEJORES, m_TxtMejores);
	DDX_Text(pDX, IDC_EDIT_PARECIDO, m_TxtParecido);
	DDX_Check(pDX, IDC_CHK_IMAGEN, m_ChkImagen);
	DDX_Check(pDX, IDC_CHK_MEJORA, m_ChkMejora);
	DDX_Check(pDX, IDC_CHK_ROTACION, m_ChkRotacion);
	DDX_Text(pDX, IDC_LABEL, m_Label);
	//}}AFX_DATA_MAP
}

BEGIN_MESSAGE_MAP(CBusqueda, CDialog)
	//{{AFX_MSG_MAP(CBusqueda)
	ON_BN_CLICKED(IDC_BUT_EXAMIN, OnButExamin)
	ON_BN_CLICKED(IDC_BUT_BUSQUEDA, OnButBusqueda)
	ON_BN_CLICKED(IDC_TODAS, OnTodas)
	ON_CBN_SELCHANGE(IDC_COMBOBD, OnSelchangeCombobd)
	ON_BN_CLICKED(IDC_ASC, OnAsc)
	ON_BN_CLICKED(IDC_DESC, OnDesc)
	ON_BN_CLICKED(IDC_NOMBRE, OnNombre)
	ON_BN_CLICKED(IDC_NPUNTOS, OnNpuntos)
	ON_BN_CLICKED(IDC_PAREC, OnParec)
	ON_EN_CHANGE(IDC_EDIT_MEJORES, OnChangeEditMejores)
	ON_EN_CHANGE(IDC_EDIT_PARECIDO, OnChangeEditParecido)
	ON_BN_CLICKED(IDC_CHK_MEJORA, OnChkMejora)
	ON_BN_CLICKED(IDC_CHK_ROTACION, OnChkRotacion)
	ON_BN_CLICKED(IDC_AYUDA, OnAyuda)
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CBusqueda message handlers
// Función que ejecuta la hebra para buscar la imagen
UINT EjecucionHebra(LPVOID pParam)
{
	// 'p' apunta a la ventana de Busqueda
	CBusqueda * p = (CBusqueda *) pParam;
	
	// Inicializamos la barra de progreso y el label informativo
	p->SetDlgItemText(IDC_LABEL, "Iniciando búsqueda ...");
	p->m_Barra.SetPos(0);
	p->m_Barra.ShowWindow(SW_SHOW);
	
	if (!p->m_ChkImagen)
		p->BuscarComoImagen();
	else
		p->BuscarComoPatron();

	// Mostramos los resultados sin realizar un UpdateData(true) (el 1 lo indica)	
	p->MostrarResultados(1);
	
	// Borramos los resultados si no lo estaban ya
	if (p->stpar != NULL)
		delete p->stpar;
	
	// Seleccionamos el primero de los resultados en el grid (si hay alguno)
	if (p->m_Grid.GetRows() > 1)
	{
		p->m_Grid.SetRowSel(1);
		p->SelectGrid(); // Llamamos a una función que llama a OnSelChangeGrid
	}
	
	// Poner la BD en un estado consistente (Borro las tablas temporales y
	// actualizo las penalizaciones de las imágenes a 0)
	p->BorrarPuntoCons();
	p->BorrarPuntoM();
	p->m_pBd->ExecuteSQL("UPDATE Imagen SET Penalizacion = 0");
	
	// Quitamos la barra de progreso y el label informativo
	p->m_Barra.SetPos(0);
	p->m_Barra.ShowWindow(SW_HIDE);
	p->SetDlgItemText(IDC_LABEL, "");

	// Cambiamos el título del botón de "Cancelar" a "Buscar"
	p->SetDlgItemText(IDC_BUT_BUSQUEDA, "Buscar");
	
	// Habilitamos los botones
	p->m_ButBuscar.EnableWindow(true);

	return 0;
}

BEGIN_EVENTSINK_MAP(CBusqueda, CDialog)
    //{{AFX_EVENTSINK_MAP(CBusqueda)
	ON_EVENT(CBusqueda, IDC_GRID, 69 /* SelChange */, OnSelChangeGrid, VTS_NONE)
	//}}AFX_EVENTSINK_MAP
END_EVENTSINK_MAP()

// ************* //
// ** EVENTOS ** //
// ************* //

// ** Inicio ejecución ventana ** //

// Se dispara al iniciar la ejecución de la ventana
BOOL CBusqueda::OnInitDialog() 
{
	CDialog::OnInitDialog();
	
	CenterWindow();

	// Inicializo variables
	m_ChkImagen = 0;
	m_ChkRotacion = 0;
	m_ChkMejora = 1;
	m_Parec = 0;
	m_Desc = 0;
	m_TxtMejores = "20";
	m_TxtParecido = "0";

	m_Barra.SetPos(0);
	m_Barra.SetStep(2);	
	
	// y reflejo los cambios en las cajas de texto correspondientes
	UpdateData(false);

	// Borro de la BD los resultados obtenidos anteriormente
	BorrarResultados();

	// Cargo los grupos de imágenes y selecciono el primero de ellos
	CargarComboGrupoImagenes();
	m_BD.SetCurSel(0);

	// Carga el sigma correspondiente al grupo de imágenes seleccionado o el por defecto
	CargarSigma();

	// Muestro los títulos de los grids
	IniciaGrid();

	return TRUE;  // return TRUE unless you set the focus to a control
	              // EXCEPTION: OCX Property Pages should return FALSE
}

// ** Fin ejecución ventana ** //

// Se dispara cuando pulsamos el botón "Cerrar"
void CBusqueda::OnCancel() 
{
	CDialog::OnCancel();
}

// Se dispara al cerrar la ventana
BOOL CBusqueda::DestroyWindow() 
{
	BorrarResultados();

	return CDialog::DestroyWindow();
}

// ** Botones ** //

// Se dispara cuando se pulsa el botón "..." ("Examinar").
void CBusqueda::OnButExamin() 
{
	HBITMAP hbm;
	CRect rect;
	int error;

	// Abro una ventana "Open"
	CFileDialog Dlg(true,"bmp","*.bmp");
	if (Dlg.DoModal() != IDOK) return;
	// Recupero el nombre del archivo seleccionado
	m_TxtImage = Dlg.GetPathName();
	
	UpdateData(false);
	error = datos.AbrirImagen(m_TxtImage,&m_TxtDimensionX,&m_TxtDimensionY);
	if (error != 0)
	{
		BorrarCajas();
		CargarSigma();
		MostrarError(error);
		return;
	}

	// Inicializo el grid y elimino la vista de la imagen seleccionada en dicho grid
	BorrarGrid();

	UpdateData(false);

	// Borro las imágenes anteriores (para no pintar encima)
	m_Image1.SetBitmap(NULL);

	// Dibujar la imagen original
	hbm = (HBITMAP) LoadImage (NULL, m_TxtImage, IMAGE_BITMAP, 200, 150, LR_LOADFROMFILE|LR_CREATEDIBSECTION|LR_DEFAULTSIZE);
	m_Image1.MoveWindow(457,34,0,0,true);
	m_Image1.SetBitmap(hbm);
}

// Se dispara al pulsar el botón de "Búsqueda" o "Cancelar" (es el mismo)
void CBusqueda::OnButBusqueda()
{
	CString nombre;

	// Obtenemos el nombre del botón
	GetDlgItemText(IDC_BUT_BUSQUEDA,nombre);

	if (strcmp(nombre,"Cancelar") == 0)
	{		
		// Si es "Cancelar", deshabilitamos el botón y ordenamos detener la ejecución
		m_ButBuscar.EnableWindow(false);
		ejecucion = false;
	}
	else
	{
		// Si es "Búsqueda", comenzamos la misma (lanzamos una hebra dedicada)
		ejecucion = true;
		UpdateData(true);

		if (m_TxtImage.GetLength() == 0)
			return;
		else
			// Modificamos el nombre del botón de "Buscar" a "Cancelar"
			SetDlgItemText(IDC_BUT_BUSQUEDA,"Cancelar");

		m_Image2.SetBitmap(NULL);
		IniciaGrid();

		// Borramos los resultados anteriores de la Base de Datos
		BorrarResultados();
		
		// Ejecutamos la búsqueda con una hebra dedicada
		pThread = AfxBeginThread(EjecucionHebra, this, THREAD_PRIORITY_NORMAL, 0, 0);
	}
}

// Se dispara al pulsar el botón de "Ayuda"
void CBusqueda::OnAyuda() 
{
	HtmlHelp(NULL, m_Opt->workdir + "\\Ayuda\\Ayuda.chm::/busqimag.htm", HH_DISPLAY_TOPIC, 0);
}

// ** Checkboxes ** //

// Se dispara cuando modificamos el checkbox "Todas"
void CBusqueda::OnTodas() 
{
	UpdateData(true);

	if (m_ChkTodas == 1)
		m_BD.EnableWindow(false); // Deshabilitamos el combo de los grupos de imágenes
	else
		m_BD.EnableWindow(true);  // Habilitamos el combo de los grupos de imágenes

	CargarSigma();
}

// Se dispara cuando modificamos el checkbox "Con Rotación"
void CBusqueda::OnChkRotacion() 
{
	CompruebaOpciones2();
}

// Se dispara cuando modificamos el checkbox "Con 1-Mejora"
void CBusqueda::OnChkMejora() 
{
	CompruebaOpciones();
}

// ** Option buttons ** //

// Se dispara cuando modificamos el OptionButton "IDC_PAREC" a "Parecido"
void CBusqueda::OnParec() 
{
	MostrarResultados(0); // con UpdateData(true);
	if (m_Grid.GetRows() > 1)
		OnSelChangeGrid();
	else
		m_Image2.SetBitmap(NULL);
}

// Se dispara cuando modificamos el OptionButton "IDC_NPUNTOS" a "Nº Puntos"
void CBusqueda::OnNpuntos() 
{
	MostrarResultados(0); // con UpdateData(true);
	if (m_Grid.GetRows() > 1)
		OnSelChangeGrid();
	else
		m_Image2.SetBitmap(NULL);
}

// Se dispara cuando modificamos el OptionButton "IDC_NOMBRE" a "Nombre"
void CBusqueda::OnNombre() 
{
	MostrarResultados(0); // con UpdateData(true);
	if (m_Grid.GetRows() > 1)
		OnSelChangeGrid();
	else
		m_Image2.SetBitmap(NULL);
}

// Se dispara cuando modificamos el OptionButton "IDC_ASC" a "ASC"
void CBusqueda::OnAsc() 
{
	MostrarResultados(0); // con UpdateData(true);
	if (m_Grid.GetRows() > 1)
		OnSelChangeGrid();
	else
		m_Image2.SetBitmap(NULL);
}

// Se dispara cuando modificamos el OptionButton "IDC_DESC" a "DESC"
void CBusqueda::OnDesc() 
{
	MostrarResultados(0); // con UpdateData(true);
	if (m_Grid.GetRows() > 1)
		OnSelChangeGrid();
	else
		m_Image2.SetBitmap(NULL);
}

// ** Combos ** //

// Se dispara cuando modificamos el combo de los grupos de imágenes
void CBusqueda::OnSelchangeCombobd() 
{
	CargarSigma();	
}

// ** Cajas de texto ** //

// Se dispara cuando modificamos la caja de texto de parecido
void CBusqueda::OnChangeEditParecido() 
{
	MostrarResultados(0); // con UpdateData(true);
	if (m_Grid.GetRows() > 1)
		OnSelChangeGrid();
	else
		m_Image2.SetBitmap(NULL);
}

// Se dispara cuando modificamos la caja de texto de mejores
void CBusqueda::OnChangeEditMejores() 
{
	MostrarResultados(0); // con UpdateData(true);
	if (m_Grid.GetRows() > 1)
		OnSelChangeGrid();
	else
		m_Image2.SetBitmap(NULL);
}

// ** Grids ** //

// Se dispara cuando se selecciona una fila del grid 1
void CBusqueda::OnSelChangeGrid() 
{
	DibujarImagen();
}

// ******************** //
// ** PROCEDIMIENTOS ** //
// ******************** //

void CBusqueda::BuscarComoImagen()
{
	CString sSQL, snpuntos, imag;	
	int i, ini, num, error, pos;
		
	stpar = NULL;

	// Obtengo los datos
	pos = m_TxtImage.ReverseFind('\\');
	imag = m_TxtImage.Right(m_TxtImage.GetLength() - pos - 1);

	error = datos.ObtenerDatos(atoi(m_TxtDimensionX),atoi(m_TxtDimensionY),
			(float) atof(m_TxtSigma), imag, m_Opt->margenumbral, m_Opt->numvecinos,
			m_Opt->maxptos, m_Opt->umbral_inf, m_Opt->umbral_sup, 0, 0, 0, 0, "");
	if (error != 0)
	{
		MostrarError(error);
		return;
	}
		
	IniciaGrid();
	
	// Calculo el número de imagenes que voy a tener y actualizo la variable total_filas
	total_analiz = 0;
	total_filas = TotalImagenes(datos.num_puntos,m_ChkTodas);
	stpar = (StParecido *) calloc(total_filas, (size_t) (sizeof(StParecido)));

	if (!ejecucion)
		return; // Acabo la ejecución abruptamente
	
	// Pongo a 0 el campo penalizacion de todas las imágenes que voy a buscar
	ActualizarPenalizaciones(datos.num_puntos);
	
	// Elimino todos los puntos de la tabla temporal PuntoCons
	BorrarPuntoCons();
			
	// Inserto en la tabla temporal PuntoCons los puntos de las imágenes con
	// un número total de puntos mayor al de la imagen a buscar
	if (!m_ChkMejora)
		InsertarMayores(datos.num_puntos,datos.num_puntos + m_Opt->margenmay,0);
	else
		// Si habilitamos la 1-mejora, obviamos aquí las
		// imágenes con 1 punto más que la que buscamos.
		InsertarMayores(datos.num_puntos + 1, datos.num_puntos + m_Opt->margenmay,0);

	// Inserto en la tabla temporal PuntoCons los puntos de las imágenes con
	// igual número total de puntos al de la imagen a buscar	
	InsertarIguales(datos.num_puntos);

	SetDlgItemText(IDC_LABEL, "Fase 1: Imágenes mayores e iguales.");

	// Busco en los mayores o iguales
	num = BuscarImagen(datos.num_puntos,1);

	if (num == -1)
		return; // Acabo la ejecución abruptamente
	
	total_analiz = total_analiz + num;
	
	// Elimino todos los puntos de la tabla temporal PuntoCons
	BorrarPuntoCons();

	// Inicializo la barra de progreso de los menores
	m_Barra.SetPos(0);

	SetDlgItemText(IDC_LABEL, "Fase 2: Imágenes menores.");

	if (!m_ChkMejora)
		ini = 1;
	else
		// Si habilitamos la 1-mejora, obviamos aquí las
		// imágenes con 1 punto menos que la que buscamos.
		ini = 2;
	
	for (i=ini;i<=m_Opt->margenmen;i++)
	{
		m_Barra.OffsetPos((100 / (m_Opt->margenmen - i + 1)) + 1);

		// Insertamos en PuntoCons los puntos npuntos - i. Si no hay ninguno en
		// la BD, pasamos directamente al siguiente menor.
 		if (InsertarMenores(datos.num_puntos - i) != 0)
		{
			// Guardo en PuntoM la nueva imagen a buscar
			CargarMenor(datos.num_puntos - i, datos.num_puntos);
			
			// Busco en los menores
			num = BuscarImagenM(datos.num_puntos); // - i
			if (num == -1)
				return; // Acabo la ejecución abruptamente

			total_analiz = total_analiz + num;

			// Elimino todos los puntos de la tabla temporal PuntoM
			BorrarPuntoM();
			
			// Elimino todos los puntos de la tabla temporal PuntoCons
			BorrarPuntoCons();
		}
	}

	num = 0;
	// Calcular la 1-mejora si es seleccionada
	if (m_ChkMejora)
	{
		// Inicializo la barra de progreso de la 1-Mejora
		m_Barra.SetPos(0);		
		
		SetDlgItemText(IDC_LABEL, "Fase 3: 1-Mejora superior.");

		if (ExistenPuntos(datos.num_puntos + 1))
		{
			// Calcular la 1-mejora (1 punto más)
			for (i=1;i<=datos.num_puntos + 1;i++) //cambio a +1
			{
				InsertarMayores(datos.num_puntos, datos.num_puntos + 1,i);
				num = BuscarImagen(datos.num_puntos,0);
				if (num == -1)
					return; // Acabo la ejecución abruptamente

				BorrarPuntoCons();
				ActualizarPenalizaciones(datos.num_puntos);
				m_Barra.OffsetPos((100 / (2 * datos.num_puntos)) + 1);
			}
			
			total_analiz = total_analiz + num;
		}
		else
			m_Barra.SetPos(50);

		num = 0;
		SetDlgItemText(IDC_LABEL, "Fase 3: 1-Mejora inferior.");

		for (i=1;i<=datos.num_puntos + 1;i++)  //cambio a +1
		{
			// Calcular la 1-mejora (1 punto menos)
			if (InsertarMenores(datos.num_puntos - 1) != 0)
			{
				CargarMenor1Mej(datos.num_puntos - 1,i);
				num = BuscarImagenM(datos.num_puntos);
				if (num == -1)
					return; // Acabo la ejecución abruptamente

				BorrarPuntoM();
				BorrarPuntoCons();
				ActualizarPenalizaciones(datos.num_puntos);
			}

			m_Barra.OffsetPos((100 / (2 * datos.num_puntos)) + 1);
		}
		
		total_analiz = total_analiz + num;
	}
	
	m_Barra.ShowWindow(SW_HIDE);
	SetDlgItemText(IDC_LABEL, "");

	GuardarResultados();
}

void CBusqueda::BuscarComoPatron()
{
	CString snpuntos, imag;
	int max_puntos, i, error, pos;

	stpar = NULL;

	// Obtengo los datos
	pos = m_TxtImage.ReverseFind('\\');
	imag = m_TxtImage.Right(m_TxtImage.GetLength() - pos - 1);
	
	error = datos.ObtenerDatos(atoi(m_TxtDimensionX),atoi(m_TxtDimensionY),
			(float) atof(m_TxtSigma), imag, m_Opt->margenumbral, m_Opt->numvecinos,
			m_Opt->maxptos, m_Opt->umbral_inf, m_Opt->umbral_sup, 0, 0, 0, 0, "");
	if (error != 0)
	{
		MostrarError(error);
		return;
	}
	
	IniciaGrid();
	
	// Calculo el número de imagenes que voy a tener y actualizo la variable total_filas
	total_analiz = 0;
	total_filas = TotalImagenes(-1,m_ChkTodas);
	stpar = (StParecido *) calloc(total_filas, (size_t) (sizeof(StParecido)));

	if (!ejecucion)
		return; // Acabo la ejecución abruptamente

	// Busco el máximo nº puntos que hay en una imagen de la Base de Datos
	max_puntos = MaximoNumPuntos(m_ChkTodas);

	// Inicializo la barra de progreso
	m_Barra.SetPos(0);
	SetDlgItemText(IDC_LABEL, "Buscando el patrón en las imágenes ...");

	for (i=1;i<=max_puntos;i++)
	{
		if (!ejecucion)
			return; // Acabo la ejecución abruptamente

		m_Barra.OffsetPos((100 / max_puntos) + 1);
		BuscarPatron(datos.num_puntos, i, total_filas);
	}
	
	m_Barra.ShowWindow(SW_HIDE);
	SetDlgItemText(IDC_LABEL, "");

	GuardarResultados();

}

int CBusqueda::BuscarImagen(int npuntos, int usarbarra)
{
	ODynaset dyna, dyna2;
	CString scurvat, sdist, ssigno, sSQL, sSQLNueva;
	int i, j, ind, pos, ipenaliz, res;
	char sorden[10], scurva[10], sdis[10], ssign[10];
	double parec;

	if (usarbarra == 1)
		m_Barra.SetPos(0);

	// Probamos todas las combinaciones y nos quedamos con la mejor para cada uno
	for (i=0;i<npuntos;i++)
	{
		if (!ejecucion)
			return -1;

		if (usarbarra == 1)
		{
			if (!m_ChkRotacion)
				m_Barra.SetPos(100);
			else
				m_Barra.OffsetPos((100 / npuntos) + 1);
		}

		sSQLNueva = "";
		sSQL = "SELECT Nombre,AVG(CDEG(*)) * 100 AS Parec FROM Imagen,PuntoCons WHERE Nombre = INombre";

		if (m_ChkTodas == false)
			sSQL = sSQL + " AND GrNombre = '" + m_TxtBD + "'";
		
		sSQL = sSQL + " AND (";

		// Este bucle añade tantas condiciones en el WHERE como puntos tiene la imagen
		for (ind=0;ind<npuntos;ind++)
		{
			if (ind != 0)
				sSQL = sSQL + " OR ";

			pos = ((ind + i) % npuntos);
			
			itoa(ind + 1,sorden,10);
			itoa(datos.curva.intervalos[pos].val_curv,scurva,10);
			itoa(datos.curva.intervalos[pos].dist_sig,sdis,10);
			itoa(datos.curva.intervalos[pos].signo,ssign,10);

			if (ind == 0)
			{
				sSQL = sSQL + "(Curvatura FEQ " + CString(scurva) + " THOLD 0 AND Distancia FEQ ";
				sSQL = sSQL + CString(sdis) + " THOLD 0 AND Signo FEQ " + CString(ssign);
				sSQL = sSQL + " THOLD 0 AND Orden = " + CString(sorden) + ")";			
			}
			else
			{
				sSQL = sSQL + "(Orden = " + CString(sorden) + " AND Curvatura FEQ " + CString(scurva) + " THOLD 0";
				sSQL = sSQL + " AND Distancia FEQ " + CString(sdis) + " THOLD 0 AND Signo FEQ ";
				sSQL = sSQL + CString(ssign) + " THOLD 0)";
			}
		}

		// Cierro la consulta agrupando por cada imagen.
		sSQL = sSQL + ") GROUP BY Nombre ORDER BY Nombre";

		// Traduzco la sentencia FSQL a SQL y veo si hay errores
		if (!PreConsulta(&sSQL,&sSQLNueva))
		{
			MessageBox("Error en la traducción de la consulta.", "Fuzzy Finder", MB_ICONERROR);
			return -1;
		}

		// Abro el dynaset
		oresult err = dyna.Open(*m_pBd, sSQLNueva);
		if (err != OSUCCESS)
		{
			AfxMessageBox(dyna.GetErrorText(),MB_OK);
			return -1;
		}
		
		j = 0;
		dyna.MoveFirst();
		// Recorro el dynaset actualizando los máximos de cada imagen, dependiendo
		// de si se encontró una combinación más parecida o no.
		while (!dyna.IsEOF())
		{			
			if (i == 0)
			{
				dyna.GetFieldValue("Nombre", stpar[j + total_analiz].nombre, 100);
				sSQL = "SELECT NumPuntos FROM Imagen WHERE Nombre = '";
				sSQL = sSQL + CString(stpar[j + total_analiz].nombre) + "'";
				dyna2.Open(*m_pBd,sSQL);
				dyna2.GetFieldValue("NumPuntos",&stpar[j + total_analiz].numpuntos);
				dyna2.Close();
			}

			dyna.GetFieldValue("Parec", &parec);

			sSQL = "SELECT Penalizacion FROM Imagen WHERE Nombre = '";
			sSQL = sSQL + CString(stpar[j + total_analiz].nombre) + "'";
			dyna2.Open(*m_pBd,sSQL);
			
			dyna2.GetFieldValue("Penalizacion",&ipenaliz);
			parec = parec - ipenaliz;

			if (parec > (double) stpar[j + total_analiz].parecido)
				stpar[j + total_analiz].parecido = Redondear(parec);
			
			dyna2.Close();
			dyna.MoveNext();
			j++;
		}

		if (i == 0)
			res = j;

		dyna.Close();

		if (!m_ChkRotacion)
			i = npuntos;
	}

	// Borro la tabla temporal PuntoCons
	BorrarPuntoCons();

	return res;
}

int CBusqueda::BuscarImagenM(int npuntos)
{
	ODynaset dyna, dynaM, dyna2;
	CString sSQL, sSQLNueva;
	int i, j, res, ind, pos, icurvat, isigno, idist, ipenaliz;
	char sorden[10], scurvat[10], sdist[10], ssigno[10];
	double parec;

	dynaM.Open(*m_pBd, "SELECT * FROM PuntoM ORDER BY Orden");
	
	// Probamos todas las combinaciones y nos quedamos con la mejor para cada uno
	for (i=0;i<npuntos;i++)
	{		
		if (!ejecucion)
			return -1;

		dynaM.MoveFirst();
		
		sSQLNueva = "";
		sSQL = "SELECT Nombre,AVG(CDEG(*)) * 100 AS Parec FROM Imagen,PuntoCons WHERE Nombre = INombre";

		if (m_ChkTodas == false)
			sSQL = sSQL + " AND GrNombre = '" + m_TxtBD + "'";
		
		sSQL = sSQL + " AND (";

		// Este bucle añade tantas condiciones en el WHERE como puntos tiene la imagen
		for (ind=0;ind<npuntos;ind++)
		{
			if (ind != 0)
				sSQL = sSQL + " OR ";

			pos = ((ind + i) % npuntos) + 1;
			itoa(ind + 1,sorden,10);
			
			dynaM.GetFieldValue("Curvatura",&icurvat);
			dynaM.GetFieldValue("Distancia",&idist);
			dynaM.GetFieldValue("Signo",&isigno);
			itoa(icurvat,scurvat,10);
			itoa(idist,sdist,10);
			itoa(isigno,ssigno,10);

			if (ind == 0)
			{
				sSQL = sSQL + "(Curvatura FEQ " + CString(scurvat) + " THOLD 0 AND Distancia FEQ ";
				sSQL = sSQL + CString(sdist) + " THOLD 0 AND Signo FEQ " + CString(ssigno);
				sSQL = sSQL + " THOLD 0 AND Orden = " + CString(sorden) + ")";			
			}
			else
			{
				sSQL = sSQL + "(Orden = " + CString(sorden) + " AND Curvatura FEQ " + CString(scurvat) + " THOLD 0";
				sSQL = sSQL + " AND Distancia FEQ " + CString(sdist) + " THOLD 0 AND Signo FEQ ";
				sSQL = sSQL + CString(ssigno) + " THOLD 0)";
			}

			dynaM.MoveNext();
		}

		// Cierro la consulta agrupando por cada imagen.
		sSQL = sSQL + ") GROUP BY Nombre";

		// Traduzco la sentencia FSQL a SQL y veo si hay errores
		if (!PreConsulta(&sSQL,&sSQLNueva))
		{
			MessageBox("Error en la traducción de la consulta.", "Fuzzy Finder", MB_ICONERROR);
			return -1;
		}

		// Abro el dynaset
		oresult err = dyna.Open(*m_pBd, sSQLNueva);
		if (err != OSUCCESS)
		{
			AfxMessageBox(dyna.GetErrorText(),MB_OK);
			return -1;
		}
			
		j = 0;
		dyna.MoveFirst();
		// Recorro el dynaset actualizando los máximos de cada imagen, dependiendo
		// de si se encontró una combinación más parecida o no.
		while (!dyna.IsEOF())
		{			
			if (i == 0)
			{
				dyna.GetFieldValue("Nombre", stpar[j + total_analiz].nombre, 100);
				sSQL = "SELECT NumPuntos FROM Imagen WHERE Nombre = '";
				sSQL = sSQL + CString(stpar[j + total_analiz].nombre) + "'";
				dyna2.Open(*m_pBd,sSQL);
				dyna2.GetFieldValue("NumPuntos",&stpar[j + total_analiz].numpuntos);
				dyna2.Close();
			}

			dyna.GetFieldValue("Parec", &parec);

			sSQL = "SELECT Penalizacion FROM Imagen WHERE Nombre = '";
			sSQL = sSQL + CString(stpar[j + total_analiz].nombre) + "'";
			dyna2.Open(*m_pBd,sSQL);

			dyna2.GetFieldValue("Penalizacion",&ipenaliz);
			parec = parec - ipenaliz;

			if (parec > (double) stpar[j + total_analiz].parecido)
				stpar[j + total_analiz].parecido = Redondear(parec);
			
			dyna2.Close();
			dyna.MoveNext();
			j++;
		}

		if (i == 0)
			res = j;

		dyna.Close();

		if (!m_ChkRotacion)
			i = npuntos;
	}
	
	dynaM.Close();
	
	return res;
}

void CBusqueda::BuscarPatron(int npuntos, int ini, int total_filas)
{
	ODynaset dyna, dyna2;
	CString sSQL, sSQLNueva;
	int i, j, pos, inumptos;
	double parec;
	char sorden[10], scurvat[10], sdist[10], ssigno[10], str[100], smax[10];

	itoa(max(datos.num_puntos,ini),smax,10);
	sSQL = "SELECT Nombre,AVG(CDEG(*)) * 100 AS Parec FROM Imagen,Punto WHERE Nombre = INombre";
	sSQL = sSQL + " AND NumPuntos >= " + CString(smax);
	
	if (m_ChkTodas == false)
		sSQL = sSQL + " AND GrNombre = '" + m_TxtBD + "'";
		
	sSQL = sSQL + " AND (";

	for (i=0;i<npuntos;i++)
	{
		if (i != 0)
			sSQL = sSQL + " OR ";

		pos = i + ini - 1;
		itoa(pos,sorden,10);
		itoa(datos.curva.intervalos[i].val_curv,scurvat,10);
		itoa(datos.curva.intervalos[i].dist_sigr,sdist,10);
		itoa(datos.curva.intervalos[i].signo,ssigno,10);

		if (i == 0)
		{
			sSQL = sSQL + "(Curvatura FEQ " + scurvat + " THOLD 0";
			if (i != (npuntos - 1))
				sSQL = sSQL + " AND Distancia_real FEQ " + sdist + " THOLD 0";
			sSQL = sSQL + " AND Signo FEQ " + ssigno + " THOLD 0";
			sSQL = sSQL + " AND Orden = MOD(" + CString(sorden) + ",NumPuntos) + 1)";
		}
		else
		{
			sSQL = sSQL + "(Orden = MOD(" + CString(sorden) + ",NumPuntos) + 1";
			sSQL = sSQL + " AND Curvatura FEQ " + scurvat + " THOLD 0";
			if (i != (npuntos - 1))
				sSQL = sSQL + " AND Distancia_real FEQ " + sdist + " THOLD 0";
			sSQL = sSQL + " AND Signo FEQ " + ssigno + " THOLD 0)";
		}			
	}

	// Cierro la consulta agrupando por cada imagen.
	sSQL = sSQL + ") GROUP BY Nombre";

	// Traduzco la sentencia FSQL a SQL y veo si hay errores
	if (!PreConsulta(&sSQL,&sSQLNueva))
	{
		MessageBox("Error en la traducción de la consulta.", "Fuzzy Finder", MB_ICONERROR);
		return;
	}

	// Abro el dynaset
	oresult err = dyna.Open(*m_pBd, sSQLNueva);
	if (err != OSUCCESS)
	{
		AfxMessageBox(dyna.GetErrorText(),MB_OK);
		return;
	}
		
	if (ini == 1)
	{
		j = 0;
		while (!dyna.IsEOF())
		{
			dyna.GetFieldValue("Nombre", stpar[j].nombre, 100); 
	
			sSQL = "SELECT NumPuntos FROM Imagen WHERE Nombre = '";
			sSQL = sSQL + CString(stpar[j].nombre) + "'";
			dyna2.Open(*m_pBd,sSQL);
			dyna2.GetFieldValue("NumPuntos",&inumptos);
			stpar[j].numpuntos = inumptos;
			dyna2.Close();

			dyna.MoveNext();
			j++;
		}
	}
	
	dyna.MoveFirst();
	// Recorro el dynaset actualizando los máximos de cada imagen, dependiendo
	// de si se encontró una combinación más parecida o no.
	while (!dyna.IsEOF())
	{			
		dyna.GetFieldValue("Nombre", str, 100);
		j = Posicion(stpar, CString(str), total_filas);
			
		dyna.GetFieldValue("Parec", &parec);
		if (parec > (double) stpar[j].parecido)
			stpar[j].parecido = Redondear(parec);
			
		dyna.MoveNext();
	}

	dyna.Close();
}

void CBusqueda::InsertarMayores(int valor, int valor_fin, int punto)
{
	ODynaset dyna;
	CString sSQL;
	char snpuntos[10], snpuntosmax[10], snombre[100];
	int numptos;
	
	itoa(valor,snpuntos,10);
	itoa(valor_fin,snpuntosmax,10);

	// Traslado los puntos mayores de la tabla Punto a la tabla PuntoCons.
	sSQL = "INSERT INTO PuntoCons SELECT IdPunto,Signo,Distancia,Curvatura,Orden,INombre ";
	sSQL = sSQL + "FROM Imagen,Punto WHERE Nombre = INombre ";
	sSQL = sSQL + "AND NumPuntos > " + CString(snpuntos);
	sSQL = sSQL + " AND NumPuntos <= " + CString(snpuntosmax);
	m_pBd->ExecuteSQL(sSQL);	
	
	// Obtenemos todas las imágenes
	sSQL = "SELECT Nombre,NumPuntos FROM Imagen WHERE NumPuntos > " + CString(snpuntos);
	sSQL = sSQL + " AND NumPuntos <= " + CString(snpuntosmax);
	
	dyna.Open(*m_pBd,sSQL);

	while (!dyna.IsEOF())
	{
		dyna.GetFieldValue("NumPuntos",&numptos);
		dyna.GetFieldValue("Nombre",snombre,100);

		if (punto == 0)
		{
			// Eliminamos los puntos necesarios y reorganizamos la tabla PuntoCons
			if (m_ChkMejora)
				// Quitamos numptos - puntos de la imagen a buscar (valor - 1) 
				SuprimirPuntos(CString(snombre), numptos, valor - 1);
			else
				// Quitamos numptos - puntos de la imagen a buscar (valor) 
				SuprimirPuntos(CString(snombre), numptos, valor);
		}
		else
			SuprimirPuntoMej(CString(snombre), numptos, punto);
				
		dyna.MoveNext();
	}

	dyna.Close();
}

void CBusqueda::InsertarIguales(int valor)
{
	CString sSQL;
	char snpuntos[10];

	itoa(valor,snpuntos,10);

	sSQL = "INSERT INTO PuntoCons SELECT IdPunto,Signo,Distancia,Curvatura,Orden,INombre ";
	sSQL = sSQL + "FROM Imagen,Punto WHERE Nombre = INombre ";
	sSQL = sSQL + "AND NumPuntos = " + CString(snpuntos);

	m_pBd->ExecuteSQL(sSQL);	
}

int CBusqueda::InsertarMenores(int valor)
{
	CString sSQL;
	char smenor[10];
	int num;
	
	itoa(valor,smenor,10);
	// Introduzco en PuntoCons los puntos menores
	sSQL = "INSERT INTO PuntoCons SELECT IdPunto,Signo,Distancia,Curvatura,Orden,INombre ";
	sSQL = sSQL + "FROM Imagen,Punto WHERE Nombre = INombre ";
	sSQL = sSQL + "AND NumPuntos = " + CString(smenor);

	m_pBd->ExecuteSQL(sSQL);
	num = m_pBd->GetRowsProcessed();
	return num;
}

void CBusqueda::SuprimirPuntos(CString nombre, int nptos, int nptosref)
{
	ODynaset dyna;
	CString sSQL, sSQL2;
	char sidpunto[10], sordenant[10], sdist[10], spenaliz[10];
	int i, lim, idpunto, orden, dist, curvat, penaliz;

	sSQL = "SELECT IdPunto,Orden,Distancia,Curvatura FROM PuntoCons WHERE INombre = '" + nombre;
	sSQL = sSQL + "' ORDER BY Curvatura";

	lim = nptos - nptosref;
	for (i=0;i<lim;i++)
	{
		dyna.Open(*m_pBd,sSQL);
		
		// Obtenemos los datos necesarios antes de eliminar el punto
		dyna.GetFieldValue("IdPunto",&idpunto);
		dyna.GetFieldValue("Orden",&orden);
		dyna.GetFieldValue("Distancia",&dist);
		dyna.GetFieldValue("Curvatura",&curvat);

		// Eliminamos el punto
		itoa(idpunto,sidpunto,10);
		sSQL2 = "DELETE FROM PuntoCons WHERE IdPunto = " + CString(sidpunto);
		m_pBd->ExecuteSQL(sSQL2);
		
		// Añadimos la penalización a la imagen
		penaliz = ObtenerPenalizacion(curvat, nptos);
		itoa(penaliz,spenaliz,10);
		sSQL2 = "UPDATE Imagen SET Penalizacion = Penalizacion + " + CString(spenaliz);
		sSQL2 = sSQL2 + " WHERE Nombre = '" + nombre + "'";
		m_pBd->ExecuteSQL(sSQL2);

		// Actualizamos la distancia en el punto anterior
		itoa(dist,sdist,10);
		if (orden == 1)
			// El anterior es el último
			itoa(nptos,sordenant,10);
		else
			// El anterior es, eso, el anterior
			itoa(orden - 1,sordenant,10);

		sSQL2 = "UPDATE PuntoCons SET Distancia = Distancia + " + CString(sdist);
		sSQL2 = sSQL2 + " WHERE Orden = " + CString(sordenant);
		sSQL2 = sSQL2 + " AND INombre = '" + nombre + "'";
		m_pBd->ExecuteSQL(sSQL2);

		// Actualizamos IdPunto y Orden de todos los puntos de esa imagen
		sSQL2 = "UPDATE PuntoCons SET IdPunto = IdPunto - 1, Orden = Orden - 1";
		sSQL2 = sSQL2 + " WHERE IdPunto > " + sidpunto;
		sSQL2 = sSQL2 + " AND INombre = '" + nombre + "'";
		m_pBd->ExecuteSQL(sSQL2);
		
		nptos--;
		
		dyna.Close();
	}
}

void CBusqueda::SuprimirPuntoMej(CString nombre, int nptos, int i)
{
	ODynaset dyna;
	CString sSQL;
	char sidpunto[10], sordenant[10], sdist[10], spenaliz[10], sorden[10];
	int idpunto, orden, curvat, dist, penaliz, j;

	sSQL = "SELECT IdPunto,Orden,Distancia,Curvatura FROM PuntoCons WHERE INombre = '" + nombre;
	sSQL = sSQL + "' ORDER BY Orden";

	dyna.Open(*m_pBd,sSQL);

	for (j=1;j<i;j++)
		dyna.MoveNext();
		
	// Obtenemos los datos necesarios antes de eliminar el punto
	dyna.GetFieldValue("IdPunto",&idpunto);
	dyna.GetFieldValue("Orden",&orden);
	dyna.GetFieldValue("Curvatura",&curvat);
	dyna.GetFieldValue("Distancia",&dist);

	// Eliminamos el punto
	itoa(orden,sorden,10);
	sSQL = "DELETE FROM PuntoCons WHERE Orden = " + CString(sorden);
	sSQL = sSQL + " AND INombre = '" + nombre + "'";
	m_pBd->ExecuteSQL(sSQL);
		
	// Añadimos la penalización a la imagen
	penaliz = ObtenerPenalizacion(curvat, nptos);
	itoa(penaliz,spenaliz,10);
	sSQL = "UPDATE Imagen SET Penalizacion = Penalizacion + " + CString(spenaliz);
	sSQL = sSQL + " WHERE Nombre = '" + nombre + "'";
	m_pBd->ExecuteSQL(sSQL);

	// Actualizamos la distancia en el punto anterior
	itoa(dist,sdist,10);
	if (orden == 1)
		// El anterior es el último
		itoa(nptos,sordenant,10);
	else
		// El anterior es, eso, el anterior
		itoa(orden - 1,sordenant,10);

	sSQL = "UPDATE PuntoCons SET Distancia = Distancia + " + CString(sdist);
	sSQL = sSQL + " WHERE Orden = " + CString(sordenant);
	sSQL = sSQL + " AND INombre = '" + nombre + "'";
	m_pBd->ExecuteSQL(sSQL);

	// Actualizamos IdPunto y Orden de todos los puntos de esa imagen
	itoa(idpunto,sidpunto,10);
	sSQL = "UPDATE PuntoCons SET IdPunto = IdPunto - 1, Orden = Orden - 1";
	sSQL = sSQL + " WHERE IdPunto > " + sidpunto;
	sSQL = sSQL + " AND INombre = '" + nombre + "'";
	m_pBd->ExecuteSQL(sSQL);
		
	nptos--;
		
	dyna.Close();
}

void CBusqueda::CargarMenor(int nummenor, int numref)
{
	ODynaset dyna;
	CString sSQL, ssigno;
	int i, iorden, dist, curvat, lim, penaliz;
	char sorden[10], sdist[10], spenaliz[10], snummenor[10], sordenant[10], scurv[10], signo[10];

	// Introduzco los datos del grid a la tabla temporal PuntoM
	for (i=0;i<datos.num_puntos;i++)
	{			
		itoa(i + 1,sorden,10);
		itoa(datos.curva.intervalos[i].val_curv,scurv,10);
		itoa(datos.curva.intervalos[i].dist_sig,sdist,10);
		itoa(datos.curva.intervalos[i].signo,signo,10);
		
		// Introduzco en PuntoM los puntos menores
		sSQL = "INSERT INTO PuntoM (Orden,Signo,Distancia,Curvatura) VALUES (";
		sSQL = sSQL + CString(sorden) + ",";
		sSQL = sSQL + CString(signo) + ",";
		sSQL = sSQL + CString(sdist) + ",";
		sSQL = sSQL + CString(scurv) + ")";
		m_pBd->ExecuteSQL(sSQL);
	}

	lim = numref - nummenor;
	for (i=0;i<lim;i++)
	{
		dyna.Open(*m_pBd,"SELECT * FROM PuntoM ORDER BY Curvatura");
		
		// Obtenemos los datos necesarios antes de eliminar el punto
		dyna.GetFieldValue("Orden",&iorden);
		dyna.GetFieldValue("Distancia",&dist);
		dyna.GetFieldValue("Curvatura",&curvat);

		// Eliminamos el punto
		itoa(iorden,sorden,10);
		sSQL = "DELETE FROM PuntoM WHERE Orden = " + CString(sorden);
		m_pBd->ExecuteSQL(sSQL);
		
		// Añadimos la penalización a la imagen
		penaliz = ObtenerPenalizacion(curvat, numref);

		// Actualizo la penaliz en todas las imágenes de PuntoCons
		itoa(penaliz,spenaliz,10);
		itoa(nummenor,snummenor,10);
		sSQL = "UPDATE Imagen SET Penalizacion = Penalizacion + " + CString(spenaliz);
		sSQL = sSQL + " WHERE Nombre IN (SELECT INombre FROM PuntoCons";
		sSQL = sSQL + " WHERE NumPuntos = " + CString(snummenor) + ")";
		m_pBd->ExecuteSQL(sSQL);
		
		// Actualizamos la distancia en el punto anterior
		itoa(dist,sdist,10);
		if (iorden == 1)
			// El anterior es el último
			itoa(numref,sordenant,10);
		else
			// El anterior es, eso, el anterior
			itoa(iorden - 1,sordenant,10);

		sSQL = "UPDATE PuntoM SET Distancia = Distancia + " + CString(sdist);
		sSQL = sSQL + " WHERE Orden = " + CString(sordenant);
		m_pBd->ExecuteSQL(sSQL);

		// Actualizamos Orden de todos los puntos de esa imagen
		sSQL = "UPDATE PuntoM SET Orden = Orden - 1 WHERE Orden > " + CString(sorden);
		m_pBd->ExecuteSQL(sSQL);
		
		numref--;
		
		dyna.Close();
	}
}

void CBusqueda::CargarMenor1Mej(int npuntos, int numi)
{
	ODynaset dyna;
	CString sSQL, ssigno;
	int i, j, iorden, dist, curvat, penaliz;
	char sorden[10], sdist[10], spenaliz[10], snpuntos[10], sordenant[10], signo[10], scurv[10];

	// Introduzco los datos del grid a la tabla temporal PuntoM
	for (i=0;i<datos.num_puntos;i++)
	{			
		itoa(i + 1,sorden,10);
		itoa(datos.curva.intervalos[i].val_curv,scurv,10);
		itoa(datos.curva.intervalos[i].dist_sig,sdist,10);
		itoa(datos.curva.intervalos[i].signo,signo,10);

		// Introduzco en PuntoM los puntos menores
		sSQL = "INSERT INTO PuntoM (Orden,Signo,Distancia,Curvatura) VALUES (";
		sSQL = sSQL + CString(sorden) + ",";
		sSQL = sSQL + CString(signo) + ",";
		sSQL = sSQL + CString(sdist) + ",";
		sSQL = sSQL + CString(scurv) + ")";
		m_pBd->ExecuteSQL(sSQL);
	
	}

	dyna.Open(*m_pBd,"SELECT * FROM PuntoM ORDER BY Orden");
		
	for (j=1;j<numi;j++)
		dyna.MoveNext();
	
	// Obtenemos los datos necesarios antes de eliminar el punto
	dyna.GetFieldValue("Orden",&iorden);
	dyna.GetFieldValue("Distancia",&dist);
	dyna.GetFieldValue("Curvatura",&curvat);

	// Eliminamos el punto
	itoa(iorden,sorden,10);
	sSQL = "DELETE FROM PuntoM WHERE Orden = " + CString(sorden);
	m_pBd->ExecuteSQL(sSQL);
		
	// Añadimos la penalización a la imagen
	penaliz = ObtenerPenalizacion(curvat, npuntos + 1);

	// Actualizo la penalización en todas las imágenes de PuntoCons
	itoa(penaliz,spenaliz,10);
	itoa(npuntos,snpuntos,10);
	sSQL = "UPDATE Imagen SET Penalizacion = Penalizacion + " + CString(spenaliz);
	sSQL = sSQL + " WHERE Nombre IN (SELECT INombre FROM PuntoCons";
	sSQL = sSQL + " WHERE NumPuntos = " + CString(snpuntos) + ")";
	m_pBd->ExecuteSQL(sSQL);
		
	// Actualizamos la distancia en el punto anterior
	itoa(dist,sdist,10);
	if (iorden == 1)
		// El anterior es el último
		itoa(npuntos + 1,sordenant,10);
	else
		// El anterior es, eso, el anterior
		itoa(iorden - 1,sordenant,10);

	sSQL = "UPDATE PuntoM SET Distancia = Distancia + " + CString(sdist);
	sSQL = sSQL + " WHERE Orden = " + CString(sordenant);
	m_pBd->ExecuteSQL(sSQL);

	// Actualizamos Orden de todos los puntos de esa imagen
	sSQL = "UPDATE PuntoM SET Orden = Orden - 1 WHERE Orden > " + CString(sorden);
	m_pBd->ExecuteSQL(sSQL);
		
	dyna.Close();
}

bool CBusqueda::PreConsulta(CString *sSQL, CString *sSQLNueva)
{
	ODynaset dyna;
	CString sFSQL;
	char cad[4000];
	int i;

	// -- 1ª Consulta -- //
	// Creo los parámetros
	OParameterCollection params = m_pBd->GetParameters();
	params.Add("SSQL", *sSQL, OPARAMETER_INVAR, OTYPE_VARCHAR2);
	params.Add("NUMERR", 0, OPARAMETER_OUTVAR, OTYPE_NUMBER);

	// Ejecuto la sentencia del paquete FSQL_PKG
	sFSQL = "DECLARE NUMERR NUMBER(4); BEGIN NUMERR:=FSQL_PKG.FSQL2SQL(:SSQL); END;";
	m_pBd->ExecuteSQL(sFSQL);
	
	// Miro si hay errores en la ejecución de la sentencia
	params.GetParameter("NUMERR").GetValue(&i);
	if (i != 0)
		return false;		
		
	// Borro los parámetros
	params.Remove("SSQL");
	params.Remove("NUMERR");

	// -- 2ª Consulta -- //
	// Concateno la consulta
	dyna.Open(*m_pBd, "SELECT ATRIBUTO FROM FSQL_QUERY WHERE ATRIBUTO IS NOT NULL AND SESSIONID=USERENV('SESSIONID') ORDER BY INDICE");
	int l;
	while (!dyna.IsEOF())
	{
		dyna.GetFieldValue("ATRIBUTO",cad,4000);
		CString str(cad);
		l = str.GetLength();
		*sSQLNueva =  *sSQLNueva + " " + str;
		dyna.MoveNext();
		l++;
	}

	return true;
}

void CBusqueda::IniciaGrid()
{
	m_Grid.SetRedraw(false);
	m_Grid.Clear();
	m_Grid.SetRows(1);
	
	m_Grid.SetColAlignment((En) imagen, 1);
	m_Grid.SetColWidth((En) imagen, 1000);
	m_Grid.SetTextMatrix(0,(En) imagen, "Imagen");

	m_Grid.SetColWidth((En) directorio, 1750);
	m_Grid.SetTextMatrix(0,(En) directorio, "Carpeta");

	m_Grid.SetColWidth((En) parecido, 1000);
	m_Grid.SetTextMatrix(0,(En) parecido, "Parecido (%)");

	m_Grid.SetColWidth((En) numpuntos, 500);
	m_Grid.SetTextMatrix(0,(En) numpuntos, "Ptos");

	m_Grid.SetRedraw(true);
}

void CBusqueda::GuardarResultados()
{
	CString sSQL;
	char sparec[10], snpuntos[10];
	int i;

	BorrarResultados();
	
	// Añado los nuevos datos a la tabla
	for (i=0;i<total_filas;i++)
	{
		itoa(stpar[i].parecido,sparec,10);
		itoa(stpar[i].numpuntos,snpuntos,10);
		sSQL = "INSERT INTO Resultado VALUES ('" + CString(stpar[i].nombre) + "',";
		sSQL = sSQL + CString(sparec) + "," + CString(snpuntos) + ")";
		m_pBd->ExecuteSQL(sSQL);
	}
}

void CBusqueda::MostrarResultados(int modo)
{
	ODynaset dyna;
	CString sSQL, str;
	int i, iparec, inpuntos, pos;
	char snombre[100], sparec[10], snpuntos[10], *pdest;

	if (modo == 0)
		UpdateData(true);

	sSQL = "SELECT * FROM Resultado";

	if (m_TxtParecido.GetLength() != 0)
		sSQL = sSQL + " WHERE Parecido >= " + m_TxtParecido;
	else
		sSQL = sSQL + " WHERE Parecido >= 0";
	
	switch(m_Parec)
	{
	case 0:
		sSQL = sSQL + " ORDER BY Parecido";
		break;
	case 1:
		sSQL = sSQL + " ORDER BY NumPuntos";
		break;
	case 2:
		sSQL = sSQL + " ORDER BY Nombre";
		break;
	}
	
	if (m_Desc == 0)
		sSQL = sSQL + " DESC";
	else
		sSQL = sSQL + " ASC";

	if (m_TxtMejores.GetLength() != 0)
		sSQL = "SELECT * FROM (" + sSQL + ") WHERE ROWNUM <= " + m_TxtMejores;

	dyna.Open(*m_pBd,sSQL);

	i = 1;
	IniciaGrid();
	while (!dyna.IsEOF())
	{
		m_Grid.SetRows(m_Grid.GetRows() + 1);

		dyna.GetFieldValue("Nombre",snombre,100);
		dyna.GetFieldValue("Parecido",&iparec);
		dyna.GetFieldValue("NumPuntos",&inpuntos);

		pdest = strrchr(snombre, '\\');
		pos = pdest - snombre + 1;
		str = CString(snombre);
		
		m_Grid.SetTextMatrix(i, (En) imagen, str.Right(str.GetLength() - pos));
		m_Grid.SetTextMatrix(i, (En) directorio, str.Left(pos - 1));
		itoa(iparec,sparec,10);
		m_Grid.SetTextMatrix(i, (En) parecido, CString(sparec));
		itoa(inpuntos,snpuntos,10);
		m_Grid.SetTextMatrix(i, (En) numpuntos, CString(snpuntos));

		dyna.MoveNext();
		i++;
	}
}

void CBusqueda::ActualizarPenalizaciones(int valor)
{
	CString sSQL;
	char ssup[10], sinf[10];

	itoa(valor - m_Opt->margenmen,sinf,10);
	itoa(valor + m_Opt->margenmay,ssup,10);

	sSQL = "UPDATE Imagen SET Penalizacion = 0 WHERE NumPuntos >= ";
	sSQL = sSQL + CString(sinf) + " AND NumPuntos <= " + CString(ssup);
	m_pBd->ExecuteSQL(sSQL);
}

int CBusqueda::ObtenerPenalizacion(int curvat, int numptos)
{
	int res;
	double penaliz_base;

	penaliz_base = (1.0 / (double) numptos) * 100.0;
	res = Aproximar(penaliz_base + (((double) curvat / 100.0) * (double) m_Opt->factor_penal));
	
	return res;
}

void CBusqueda::BorrarPuntoCons()
{
	CString sSQL;

	sSQL = "DELETE FROM PuntoCons";
	m_pBd->ExecuteSQL(sSQL);
}

void CBusqueda::BorrarPuntoM()
{
	CString sSQL;

	sSQL = "DELETE FROM PuntoM";
	m_pBd->ExecuteSQL(sSQL);
}

void CBusqueda::BorrarResultados()
{
	m_pBd->ExecuteSQL("DELETE FROM Resultado");
}

void CBusqueda::DibujarImagen()
{
	HBITMAP hbm;
	CString simage, sdir;

	m_Image2.SetBitmap(NULL);
	simage = m_Grid.GetTextMatrix(m_Grid.GetRow(), (En) imagen);
	sdir = m_Grid.GetTextMatrix(m_Grid.GetRow(), (En) directorio);
	
	hbm = (HBITMAP) LoadImage (NULL, sdir + "\\" + simage, IMAGE_BITMAP, 200, 150, LR_LOADFROMFILE|LR_CREATEDIBSECTION|LR_DEFAULTSIZE);
	if (hbm == 0x00000000) // Si no encuentra la imagen ...
	{
		simage = m_Opt->workdir + ".\\Novista.bmp";
		hbm = (HBITMAP) LoadImage (NULL, simage, IMAGE_BITMAP, 200, 150, LR_LOADFROMFILE|LR_CREATEDIBSECTION|LR_DEFAULTSIZE);
	}
	
	m_Image2.MoveWindow(457,240,0,0,true);
	m_Image2.SetBitmap(hbm);
}

void CBusqueda::BorrarCajas()
{
	IniciaGrid();
	m_TxtImage = "";
	m_TxtSigma = "";
	m_TxtDimensionX = "";
	m_TxtDimensionY = "";
	
	m_Image1.SetBitmap(NULL);
	m_Image2.SetBitmap(NULL);

	UpdateData(false);
}

void CBusqueda::BorrarGrid()
{
	IniciaGrid();
	m_Image2.SetBitmap(NULL);
}

void CBusqueda::CargarSigma()
{
	ODynaset dyna;
	CString sSQL;
	double dsigma;

	UpdateData(true);

	if ((m_TxtBD.GetLength() != 0) && (m_ChkTodas == false))
	{
		sSQL = "SELECT Sigma FROM Grupo WHERE Nombre = '" + m_TxtBD + "'";
		dyna.Open(*m_pBd,sSQL);
		
		dyna.GetFieldValue("Sigma",&dsigma);
		m_TxtSigma.Format("%.2f",dsigma);
	
		dyna.Close();
	}
	else
		m_TxtSigma.Format("%.2f",SIGMA_POR_DEFECTO);

	UpdateData(false);
}

void CBusqueda::CompruebaOpciones()
{
	UpdateData(true);

	if ((m_ChkMejora) && (m_ChkRotacion))
		m_ChkRotacion = false;

	UpdateData(false);
}

void CBusqueda::CompruebaOpciones2()
{
	UpdateData(true);

	if ((m_ChkMejora) && (m_ChkRotacion))
		m_ChkMejora = false;

	UpdateData(false);
}

void CBusqueda::CargarComboGrupoImagenes()
{
	ODynaset dynaBD;
	char cad[100];
	int i = 0;
	
	// Borro el posible contenido anterior del combo
	m_BD.ResetContent();

	// Abro un dynaset para cargar el combo con los grupos de imágenes
	dynaBD.Open(*m_pBd,"SELECT Nombre FROM Grupo ORDER BY Nombre");
		
	if (!dynaBD.IsEOF())
	{
		while (!dynaBD.IsEOF())
		{			
			dynaBD.GetFieldValue("nombre", cad,100);
			CString str(cad);
			m_BD.InsertString(i, str);

			dynaBD.MoveNext();
			i++;
		}
	}
	
	dynaBD.Close();
}

void CBusqueda::SelectGrid()
{
	OnSelChangeGrid();
}

int CBusqueda::MaximoNumPuntos(int todas)
{
	ODynaset dyna;
	CString sSQL;
	int imaximo;

	sSQL = "SELECT Max(Orden) AS MaxPunto FROM Punto,Imagen ";
	sSQL = sSQL + "WHERE Nombre = INombre";
	if (todas == 0)
		sSQL = sSQL + " AND GrNombre = '" + m_TxtBD + "'";

	dyna.Open(*m_pBd,sSQL);
	dyna.GetFieldValue("MaxPunto",&imaximo);

	return imaximo;
}

int CBusqueda::TotalImagenes(int valor, int todas)
{
	ODynaset dyna;
	CString sSQL;
	char ssup[10], sinf[10], snpuntos[10];
	int cont;

	if (valor != -1)
	{
		itoa(valor - m_Opt->margenmen,sinf,10);
		itoa(valor + m_Opt->margenmay,ssup,10);

		sSQL = "SELECT Count(Nombre) AS Cont FROM Imagen WHERE NumPuntos >= ";
		sSQL = sSQL + CString(sinf) + " AND NumPuntos <= " + CString(ssup);

		if (todas == 0)
			sSQL = sSQL + " AND GrNombre = '" + m_TxtBD + "'";
	}
	else
	{
		itoa(datos.num_puntos,snpuntos,10);
		sSQL = "SELECT Count(Nombre) AS Cont FROM Imagen ";
		sSQL = sSQL + "WHERE NumPuntos >= " + CString(snpuntos);

		if (todas == 0)
			sSQL = sSQL + " AND GrNombre = '" + m_TxtBD + "'";
	}

	dyna.Open(*m_pBd,sSQL);
	dyna.GetFieldValue("Cont",&cont);

	return cont;
}

int CBusqueda::Posicion(StParecido *parec, CString str, int total_filas)
{
	int res;
	bool fin = false;

	res = 0;
	while ((res < total_filas) && (!fin))
	{
		if (strcmp(str,parec[res].nombre) == 0)
			fin = true;
		else
			res++;
	}

	return res;
}

bool CBusqueda::ExistenPuntos(int npuntos)
{
	ODynaset dyna;
	CString sSQL;
	char snpuntos[10];
	bool res;
	
	itoa(npuntos,snpuntos,10);
	sSQL = "SELECT Nombre FROM Imagen WHERE NumPuntos = " + CString(snpuntos);

	if (m_ChkTodas == 0)
	{
		sSQL = sSQL + " AND GrNombre = '" + m_TxtBD + "'";
	}

	dyna.Open(*m_pBd,sSQL);
	res = !dyna.IsEOF();
	dyna.Close();

	return (res);
}

void CBusqueda::MostrarError(int error)
{
	switch(error)
	{
	case 1:
		MessageBox("Error I/O: no se puede abrir el archivo. Utilice solo ficheros bmp.", "Fuzzy Finder", MB_ICONERROR);
		break;
	case 2:
		MessageBox("Error I/O: no se puede leer el archivo. Fichero bmp corrupto.", "Fuzzy Finder", MB_ICONERROR);
		break;
	case 3:
		MessageBox("Error I/O: no se puede escribir en el directorio de vistas seleccionado (ver Configuración).", "Fuzzy Finder", MB_ICONERROR);
		break;
	case 4:
		MessageBox("Imagen no válida: No es de 256 colores o no es una gama de grises.", "Fuzzy Finder", MB_ICONERROR);
		break;
	case 5:
		MessageBox("Imagen no válida: no posee un fondo homogéneo.", "Fuzzy Finder", MB_ICONERROR);
		break;
	case 6:
		MessageBox("Contorno no válido: contorno vacío.", "Fuzzy Finder", MB_ICONERROR);
		break;
	case 7:
		MessageBox("Contorno no válido: número de puntos característicos demasiado grande.", "Fuzzy Finder", MB_ICONERROR);
		break;
	case 8:
		MessageBox("Contorno no válido: no hay puntos característicos.", "Fuzzy Finder", MB_ICONERROR);
		break;
	case 9:
		MessageBox("Contorno no válido: sólo posee un punto característico.", "Fuzzy Finder", MB_ICONERROR);
		break;
	case 10:
		MessageBox("Error general: insuficiente memoria.", "Fuzzy Finder", MB_ICONERROR);
		break;
	}
}

