/*
 * cameo.c - Toolpath adaptation and machine control
 *
 * Written 2010 by Werner Almesberger
 * Copyright 2010 Werner Almesberger
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 */


#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>

#include "path.h"
#include "gnuplot.h"


static int dog_bone = 0;


static void process_path(struct path *path, int inside)
{
	int left;
	struct path *new;

	left = path_tool_is_left(path);
	if (inside)
		new = path_offset(path, !left, path->notch);
	else
		new = path_offset(path, left, path->notch || dog_bone);
	path_replace(path, new);
}


static void process_paths(struct path *paths)
{
	struct path *leftmost, *path;

	/*
	 * We don't have an algorithm (yet) that can detect which paths are
	 * inside other paths. Therefore, we fake it by looking for the path
	 * that contains lowest x coordinate. This ought to be the outer
	 * boundary of the piece.
	 *
	 * Note that this heuristic falls apart when a job consists of
	 * multiple pieces. In this case, the #%outside hint can be used to
	 * explicitly tell cameo to treat the path as an outside edge.
	 */

	leftmost = path_find_leftmost(paths);
	for (path = paths; path; path = path->next)
		if (path != leftmost && !path->outside)
			process_path(path, 1);
	for (path = paths; path; path = path->next)
		if (path != leftmost && path->outside)
			process_path(path, 0);
	process_path(leftmost, 0);
}


static void usage(const char *name)
{
	fprintf(stderr,
"usage: %s [-d] r_mm [in.gnuplot [out.gnuplot]]\n\n"
"  -d  put a dog-bone notch in each concave external corner\n"
    , name);
	exit(1);
}


int main(int argc, char **argv)
{
	char *in = NULL, *out = NULL;
	double r;
	struct path *paths;
	int c;

	while ((c = getopt(argc, argv, "d")) != EOF)
		switch (c) {
		case 'd':
			dog_bone = 1;
			break;
		default:
			usage(*argv);
		}

	switch (argc-optind) {
	case 3:
		out = argv[optind+2];
		/* fall through */
	case 2:
		in = argv[optind+1];
		/* fall through */
	case 1:
		r = atof(argv[optind]);
		break;
	default:
		usage(*argv);
	}

	paths = gnuplot_read(in, r);
	process_paths(paths);
	gnuplot_write(out, paths);

	return 0;
}