// system headers
#include <stdio.h>
#include <stdlib.h>

// global VeriFinger SDK headers
#include <NCore.h>
#include <NTypes.h>
#include <NImages.h>
#include <FncExtractor.h>
#include <NTemplate.h>

char title[] = "Fingerprint features extraction from image tutorial, Version 6.0.0.0, Copyright (C) 2008 Neurotechnology\n";

int usage()
{
	printf("usage:\n");
	printf("\tFeaturesExtractionFromImage <image> <template>\n");
	printf("\n");
	printf("\t<image> - image filename to extract.\n");
	printf("\t<template> - filename to store extracted features.\n");
	printf("\n\nExample:\n");
	printf("\tFeaturesExtractionFromImage image.jpg template.bin\n");

	return 1;
}

HNImage load_image_from_file(const char *file_name)
{
	NResult		res;
	HNImage		image = NULL;
	HNImage		grayscale_image = NULL;
	NFloat		horizontalResolution = 0.0;
	NFloat		verticalResolution = 0.0;

	res = NImageCreateFromFileA(file_name, NULL, &image);
	if (NFailed(res))
	{
		printf("Failed to create image from file. Error %d.\n", res);
		return NULL;
	}

	res = NImageGetHorzResolution(image, &horizontalResolution);
	if (NFailed(res))
	{
		printf("Failed to get horizontal resolution for image. Error %d.\n", res);
		NImageFree(image);
		return NULL;
	}

	res = NImageGetVertResolution(image, &verticalResolution);
	if (NFailed(res))
	{
		printf("Failed to get vertical resolution for image. Error %d.\n", res);
		NImageFree(image);
		return NULL;
	}

	if (verticalResolution < 250)
	{
		printf("Vertical resolution is less than 250 (Resolution %f). Forcing 500 resolution.\n", verticalResolution);
		verticalResolution = 500;
	}

	if (horizontalResolution < 250)
	{
		printf("Horizontal resolution is less than 250 (Resolution %f). Forcing 500 resolution.\n", horizontalResolution);
		horizontalResolution = 500;
	}

	res = NImageCreateFromImageEx(npfGrayscale, 0, horizontalResolution, verticalResolution, image, &grayscale_image);
	NImageFree(image);
	if (NFailed(res))
	{
		printf("Failed to create grayscale image. Error %d.\n", res);
		return NULL;
	}

	return grayscale_image;
}

HNFRecord extract_record_from_image(HNImage grayscale_image)
{
	NResult				res;
	HFncExtractor		extractor = NULL;
	HNFRecord			record;
	int	extractionStatus;

	res = FnceCreate(&extractor);
	if (NFailed(res))
	{
		printf("Failed to create extractor. Error %d.\n", res);
		return NULL;
	}

	res = FnceExtractUnpackedFromImage(extractor, grayscale_image, nfpUnknown, nfitLiveScanPlain, &record);
	if (NFailed(res))
	{
		printf("Failed to extract features from image. Error %d.\n", res);
		FnceFree(extractor);
		return NULL;
	}

	FnceFree(extractor);

	return record;
}


int main(int argc, char **argv)
{
	HNImage				grayscale_image = NULL;
	HNFRecord			record;
	NSizeType			template_buffer_size;
	char				*template_buffer = NULL;
	FILE				* f = NULL;
	NByte				quality;
	NResult				result = 0;

	printf(title);
	if (argc < 3)
	{
		return usage();
	}

	grayscale_image = load_image_from_file(argv[1]);
	if (!grayscale_image)
	{
		return 1;
	}

	record = extract_record_from_image(grayscale_image);
	NImageFree(grayscale_image);
	if (!record)
	{
		return 2;
	}

	result = NFRecordGetQuality(record, &quality);
	if (NFailed(result))
	{
		printf("Failed to get quality.\n");
	}
	else
	{
		printf("Quality: %d\n", quality);
	}

	NFRecordGetSize(record, 0, &template_buffer_size);
	template_buffer = (char *)malloc(template_buffer_size);
	NFRecordSaveToMemory(record, template_buffer, template_buffer_size, 0, &template_buffer_size);

	NFRecordFree(record);
	if (!template_buffer)
	{
		return 3;
	}

	f = fopen(argv[2], "wb+");
	if (f)
	{
		fwrite(template_buffer, 1, template_buffer_size, f);
		fclose(f);
	}
	else
	{
		printf("Failed to open file %s.", argv[2]);
	}

	free(template_buffer);
	return 0;
}
