#include "ccv.h"
#include <ctype.h>
#include <getopt.h>

static void exit_with_help(void)
{
	printf(
<<<<<<< HEAD
	"\n  \033[1mUSAGE\033[0m\n\n    dpmcreate [OPTION...]\n\n"
	"  \033[1mREQUIRED OPTIONS\033[0m\n\n"
	"    --positive-list : text file contains a list of positive files in format:\n"
	"                      <file name> x y width height \\newline\n"
	"    --background-list : text file contains a list of image files that don't contain any target objects\n"
	"    --negative-count : the number of negative examples we should collect from background files to initialize SVM\n"
	"    --model-component : the number of root filters in our mixture model\n"
	"    --model-part : the number of part filters for each root filter\n"
	"    --working-dir : the directory to save progress and produce result model\n"
	"    --symmetric : 0 or 1, whether to exploit symmetric property of the object\n\n"
	"  \033[1mOTHER OPTIONS\033[0m\n\n"
	"    --base-dir : change the base directory so that the program can read images from there\n"
	"    --iterations : how many iterations are needed for stochastic gradient descent [DEFAULT TO 1000]\n"
	"    --root-relabels : how many relabel procedures are needed for root model optimization [DEFAULT TO 20]\n"
	"    --data-minings : how many data mining procedures are needed for discovering hard examples [DEFAULT TO 50]\n"
	"    --relabels : how many relabel procedures are needed for part model optimization [DEFAULT TO 10]\n"
	"    --alpha : the step size for stochastic gradient descent [DEFAULT TO 0.01]\n"
	"    --alpha-ratio : decrease the step size for each iteration [DEFAULT TO 0.995]\n"
	"    --margin-c : the famous C in SVM [DEFAULT TO 0.002]\n"
	"    --balance : to balance the weight of positive examples and negative examples [DEFAULT TO 1.5]\n"
	"    --negative-cache-size : the cache size for negative examples it should be smaller than negative-count and larger than 100 [DEFAULT TO 2000]\n"
	"    --include-overlap : the percentage of overlap between expected bounding box and the bounding box from detection. Beyond this threshold, it is ensured to be the same object [DEFAULT TO 0.7]\n"
	"    --grayscale : 0 or 1, whether to exploit color in a given image [DEFAULT TO 0]\n"
	"    --discard-estimating-constant : 0 or 1, when estimating bounding boxes, discarding constant (which may be accumulated error) [DEFAULT TO 1]\n"
	"    --percentile-breakdown : 0.00 - 1.00, the percentile use for breakdown threshold [DEFAULT TO 0.05]\n\n"
=======
	"\033[1mUSAGE\033[0m\n\tdpmcreate [OPTION...]\n\n"
	"\033[1mREQUIRED OPTIONS\033[0m\n"
	"\t--positive-list : text file contains a list of positive files in format:\n"
	"\t                  <file name> x y width height \\newline\n"
	"\t--background-list : text file contains a list of image files that don't contain any target objects\n"
	"\t--negative-count : the number of negative examples we should collect from background files to initialize SVM\n"
	"\t--model-component : the number of root filters in our mixture model\n"
	"\t--model-part : the number of part filters for each root filter\n"
	"\t--working-dir : the directory to save progress and produce result model\n"
	"\t--symmetric : 0 or 1, whether to exploit symmetric property of the object\n\n"
	"\033[1mOTHER OPTIONS\033[0m\n"
	"\t--base-dir : change the base directory so that the program can read images from there\n"
	"\t--iterations : how many iterations needed for stochastic gradient descent [DEFAULT TO 20]\n"
	"\t--relabels : how many relabel procedure needed [DEFAULT TO 5]\n"
	"\t--alpha : the step size for stochastic gradient descent [DEFAULT TO 0.1]\n"
	"\t--alpha-ratio : decrease the step size for each iteration [DEFAULT TO 0.9]\n"
	"\t--margin-c : the famous C in SVM [DEFAULT TO 0.002]\n"
	"\t--balance : to balance the weight of positive examples and negative examples [DEFAULT TO 1.75]\n"
	"\t--negative-cache-size : the cache size for negative examples it should be smaller than negative-count and larger than 100 [DEFAULT TO 500]\n"
	"\t--include-overlap : the percentage of overlap between expected bounding box and the bounding box from detection. Beyond this threshold, it is ensured to be the same object [DEFAULT TO 0.7]\n"
	"\t--exclude-overlap : the percentage of overlap between expected bounding box and the bounding box from detection. Below this threshold, it is ensured to not be the same object [DEFAULT TO 0.5]\n"
	"\t--grayscale : 0 or 1, whether to exploit color in a given image [DEFAULT TO 1]\n"
	"\t--percentile-breakdown : 0.00 - 1.00, the percentile use for breakdown threshold [DEFAULT TO 0.05]\n"
>>>>>>> added a simple config script
	);
	exit(-1);
}

int main(int argc, char** argv)
{
	static struct option dpm_options[] = {
		/* help */
		{"help", 0, 0, 0},
		/* required parameters */
		{"positive-list", 1, 0, 0},
		{"background-list", 1, 0, 0},
		{"working-dir", 1, 0, 0},
		{"negative-count", 1, 0, 0},
		{"model-component", 1, 0, 0},
		{"model-part", 1, 0, 0},
		{"symmetric", 1, 0, 0},
		/* optional parameters */
		{"base-dir", 1, 0, 0},
		{"iterations", 1, 0, 0},
		{"root-relabels", 1, 0, 0},
		{"data-minings", 1, 0, 0},
		{"relabels", 1, 0, 0},
		{"alpha", 1, 0, 0},
		{"alpha-ratio", 1, 0, 0},
		{"balance", 1, 0, 0},
		{"negative-cache-size", 1, 0, 0},
		{"margin-c", 1, 0, 0},
		{"percentile-breakdown", 1, 0, 0},
		{"include-overlap", 1, 0, 0},
		{"grayscale", 1, 0, 0},
		{"discard-estimating-constant", 1, 0, 0},
		{0, 0, 0, 0}
	};
	char* positive_list = 0;
	char* background_list = 0;
	char* working_dir = 0;
	char* base_dir = 0;
	int negative_count = 0;
	ccv_dpm_param_t detector = { .interval = 8, .min_neighbors = 0, .flags = 0, .threshold = 0.0 };
<<<<<<< HEAD
	ccv_dpm_new_param_t params = {
		.components = 0,
		.detector = detector,
		.parts = 0,
		.min_area = 3000,
		.max_area = 5000,
		.symmetric = 1,
		.alpha = 0.01,
		.balance = 1.5,
		.alpha_ratio = 0.995,
		.iterations = 1000,
		.data_minings = 50,
		.root_relabels = 20,
		.relabels = 10,
		.negative_cache_size = 2000,
		.C = 0.002,
		.percentile_breakdown = 0.05,
		.include_overlap = 0.7,
		.grayscale = 0,
		.discard_estimating_constant = 1,
	};
=======
	ccv_dpm_new_param_t params = { .components = 0,
								   .detector = detector,
								   .parts = 0,
								   .min_area = 3000,
								   .max_area = 5000,
								   .symmetric = 1,
								   .alpha = 0.1,
								   .balance = 1.75,
								   .alpha_ratio = 0.9,
								   .iterations = 20,
								   .relabels = 5,
								   .negative_cache_size = 500,
								   .C = 0.002,
								   .percentile_breakdown = 0.05,
								   .include_overlap = 0.7,
								   .exclude_overlap = 0.1,
								   .grayscale = 0 };
>>>>>>> added a simple config script
	int i, k;
	while (getopt_long_only(argc, argv, "", dpm_options, &k) != -1)
	{
		switch (k)
		{
			case 0:
				exit_with_help();
			case 1:
				positive_list = optarg;
				break;
			case 2:
				background_list = optarg;
				break;
			case 3:
				working_dir = optarg;
				break;
			case 4:
				negative_count = atoi(optarg);
				break;
			case 5:
				params.components = atoi(optarg);
				break;
			case 6:
				params.parts = atoi(optarg);
				break;
			case 7:
				params.symmetric = !!atoi(optarg);
				break;
			case 8:
				base_dir = optarg;
				break;
			case 9:
				params.iterations = atoi(optarg);
				break;
			case 10:
				params.root_relabels = atoi(optarg);
				break;
			case 11:
				params.data_minings = atoi(optarg);
			case 12:
				params.relabels = atoi(optarg);
				break;
			case 13:
				params.alpha = atof(optarg);
				break;
			case 14:
				params.alpha_ratio = atof(optarg);
				break;
			case 15:
				params.balance = atof(optarg);
				break;
			case 16:
				params.negative_cache_size = atoi(optarg);
				break;
			case 17:
				params.C = atof(optarg);
				break;
			case 18:
				params.percentile_breakdown = atof(optarg);
				break;
			case 19:
				params.include_overlap = atof(optarg);
				break;
			case 20:
				params.grayscale = !!atoi(optarg);
				break;
			case 21:
				params.discard_estimating_constant = !!atoi(optarg);
				break;
		}
	}
	assert(positive_list != 0);
	assert(background_list != 0);
	assert(working_dir != 0);
	assert(negative_count > 0);
	assert(params.components > 0);
	assert(params.parts > 0);
	ccv_enable_cache(512 * 1024 * 1024);
	FILE* r0 = fopen(positive_list, "r");
	assert(r0 && "positive-list doesn't exists");
	FILE* r1 = fopen(background_list, "r");
	assert(r1 && "background-list doesn't exists");
	char* file = (char*)malloc(1024);
	int x, y, width, height;
	int capacity = 32, size = 0;
	char** posfiles = (char**)ccmalloc(sizeof(char*) * capacity);
	ccv_rect_t* bboxes = (ccv_rect_t*)ccmalloc(sizeof(ccv_rect_t) * capacity);
	int dirlen = (base_dir != 0) ? strlen(base_dir) + 1 : 0;
	while (fscanf(r0, "%s %d %d %d %d", file, &x, &y, &width, &height) != EOF)
	{
		posfiles[size] = (char*)ccmalloc(1024);
		if (base_dir != 0)
		{
			strncpy(posfiles[size], base_dir, 1024);
			posfiles[size][dirlen - 1] = '/';
		}
		strncpy(posfiles[size] + dirlen, file, 1024 - dirlen);
		bboxes[size] = ccv_rect(x, y, width, height);
		++size;
		if (size >= capacity)
		{
			capacity *= 2;
			posfiles = (char**)ccrealloc(posfiles, sizeof(char*) * capacity);
			bboxes = (ccv_rect_t*)ccrealloc(bboxes, sizeof(ccv_rect_t) * capacity);
		}
	}
	int posnum = size;
	fclose(r0);
	size_t len = 1024;
	ssize_t read;
	capacity = 32, size = 0;
	char** bgfiles = (char**)ccmalloc(sizeof(char*) * capacity);
	while ((read = getline(&file, &len, r1)) != -1)
	{
		while(read > 1 && isspace(file[read - 1]))
			read--;
		file[read] = 0;
		bgfiles[size] = (char*)ccmalloc(1024);
		if (base_dir != 0)
		{
			strncpy(bgfiles[size], base_dir, 1024);
			bgfiles[size][dirlen - 1] = '/';
		}
		strncpy(bgfiles[size] + dirlen, file, 1024 - dirlen);
		++size;
		if (size >= capacity)
		{
			capacity *= 2;
			bgfiles = (char**)ccrealloc(bgfiles, sizeof(char*) * capacity);
		}
	}
	fclose(r1);
	int bgnum = size;
	free(file);
	ccv_dpm_mixture_model_new(posfiles, bboxes, posnum, bgfiles, bgnum, negative_count, working_dir, params);
	for (i = 0; i < posnum; i++)
		free(posfiles[i]);
	ccfree(posfiles);
	ccfree(bboxes);
	for (i = 0; i < bgnum; i++)
		free(bgfiles[i]);
	ccfree(bgfiles);
	ccv_disable_cache();
	return 0;
}
