#!/usr/bin/php -q
<?

$extra_field_types = array(1 => "select", 
                           2 => "checkbox", 
                           3 => "radio", 
                           4 => "text", 
                           5 => "multiselect", 
                           6 => "textarea");

$required_fields = array("status", 
                         "priority", 
                         "submitted_by", 
                         "assigned_to", 
                         "open_date", 
                         "close_date", 
                         "summary", 
                         "details", 
                         "last_modified_date");

$statuses = NULL;
$closed_status_id = NULL;
$users = NULL;
$nobody_id = NULL;

function command_line_error($message) {

	global $stderr;
	global $progname;

	fwrite($stderr, "$progname: $message\n");
	fwrite($stderr, "run $progname with no arguments for usage\n");

	return;

} // end command_line_error()

function check_int($str) {

	if (preg_match("/^\d+$/", $str) == 0)
		return(false);

	return(true);

} // end check_int()

function get_tracker($tracker_id) {

	global $db;
	global $stderr;
	global $progname;
	global $required_fields;
	global $extra_field_types;

	$query = "SELECT groups.group_id AS group_id, 
	                 group_name, 
	                 unix_group_name, 
	                 name, 
	                 description 
	            FROM artifact_group_list, groups 
	           WHERE artifact_group_list.group_id = groups.group_id
	             AND artifact_group_list.group_artifact_id = $tracker_id";
	$res = pg_query($db, $query);
	if (!$res) {
		return(NULL);
	}

	if (pg_num_rows($res) == 0) {
		pg_free_result($res);
		fwrite($stderr, "$progname: can't find tracker ID $tracker_id\n");
		return(NULL);
	}

	$row = pg_fetch_array($res, 0);
	pg_free_result($res);

	$arr = array("id" => intval($tracker_id), 
	             "name" => $row["name"], 
	             "description" => $row["description"], 
	             "group_id" => intval($row["group_id"]), 
	             "group_name" => $row["group_name"], 
	             "group_unix_name" => $row["unix_group_name"]);

	$query = "SELECT extra_field_id, field_name, field_type, alias 
	            FROM artifact_extra_field_list 
	           WHERE group_artifact_id = $tracker_id 
	           ORDER BY extra_field_id";
	$res = pg_query($db, $query);
	if (!$res) {
		return(NULL);
	}

	$arr["extra fields"] = array();
	for ($i = 0;$i < pg_num_rows($res);$i++) {
		$row = pg_fetch_array($res, $i);
		if (!array_key_exists($row["field_type"], $extra_field_types)) {
			$msg = "unknown type " .  $row["field_type"] . 
			       " for extra field ID " .  $row["extra_field_id"] . 
			       " (\"" .  $row["field_name"] . "\")" . 
			       " of tracker ID " .  $tracker_id . 
			       " (\"" .  $arr["name"] . "\")\n";
			fwrite($stderr, $msg);
			return(NULL);
		}
		$ef_arr = array("id" => intval($row["extra_field_id"]), 
		                "name" => strtolower(trim($row["field_name"])), 
		                "type" => $row["field_type"], 
		                "alias" => $row["alias"], 
		                "values" => array());
		if (in_array($ef_arr["name"], $required_fields)) {
			fwrite($stderr, "$progname: extra field \"" . $ef_arr["name"] 
			                . "\" has the name of a required field\n");
			return(NULL);
		}
		$arr["extra fields"][intval($ef_arr["id"])] = $ef_arr;
	}
	pg_free_result($res);

	$query = "SELECT extra_field_id, element_id, element_name 
	            FROM artifact_extra_field_elements 
	           WHERE extra_field_id IN (SELECT extra_field_id 
	                                      FROM artifact_extra_field_list 
	                                     WHERE group_artifact_id = $tracker_id) 
	           ORDER BY element_id";
	$res = pg_query($db, $query);
	if (!$res) {
		return(NULL);
	}
	for ($i = 0;$i < pg_num_rows($res);$i++) {
		$row = pg_fetch_array($res, $i);
		$extra_field_id = intval($row["extra_field_id"]);
		$element_id = intval($row["element_id"]);
		$element_name = $row["element_name"];
		$value = array("extra_field_id" => $extra_field_id, 
		               "id" => $element_id, 
		               "name" => $element_name);
		$arr["extra fields"][$extra_field_id]["values"][$element_id] = $value;
	}
	pg_free_result($res);

	$query = "SELECT user_id " . 
	         "  FROM artifactperm_user_vw " . 
	         " WHERE group_artifact_id = $tracker_id " . 
	         "   AND perm_level IN (1, 2) " . 
	         " ORDER BY user_id";
	$res = pg_query($db, $query);
	if (!$res) {
		return(NULL);
	}
	$arr["technician_ids"] = array();
	for ($i = 0;$i < pg_num_rows($res);$i++) {
		$row = pg_fetch_array($res, $i);
		$arr["technician_ids"][] = intval($row["user_id"]);
	}
	pg_free_result($res);

	return($arr);

} // end get_tracker()

function get_statuses() {

	global $db;
	global $statuses;
	global $closed_status_id;
	global $stderr;
	global $progname;

	$have_open = false;
	$have_closed = false;

	if (!is_null($statuses)) {
		return(true);
	}

	$query = "SELECT id, status_name FROM artifact_status ORDER BY id";
	$res = pg_query($db, $query);
	if (!$res) {
		return(false);
	}

	$statuses = array();
	for ($i = 0;$i < pg_num_rows($res);$i++) {
		$row = pg_fetch_array($res, $i);
		$statuses[$row["id"]] = array("id" => intval($row["id"]), 
		                              "name" => $row["status_name"]);
		if(strcmp($row["status_name"], "Open") == 0) {
			$have_open = true;
		}
		if(strcmp($row["status_name"], "Closed") == 0) {
			if (!is_null($closed_status_id)) {
				fwrite($stderr, "$progname: multiple closed statuses found\n");
				return(false);
			}
			$closed_status_id = $row["id"];
			$have_closed = true;
		}
	}
	pg_free_result($res);

	if (!$have_open || !$have_closed) {
		fwrite($stderr, "$progname: missing an expected status\n");
		return(false);
	}

	return(true);

} // end get_statuses()

function get_users() {

	global $db;
	global $users;
	global $nobody_id;
	global $stderr;
	global $progname;

	if (!is_null($users)) {
		return(true);
	}

	$res = pg_query($db, "SELECT user_id, user_name, realname FROM users");
	if (!$res) {
		return(false);
	}

	$users = array();
	for ($i = 0;$i < pg_num_rows($res);$i++) {
		$row = pg_fetch_array($res, $i);
		if (strcmp($row["user_name"], "None") == 0 
		    && strcmp($row["realname"], "Nobody") == 0) {
			if (!is_null($nobody_id)) {
				fwrite($stderr, "$progname: duplicate IDs for user nobody found ($nobody_id and " . $row["user_id"] . ")\n");
				return(false);
			}
			$nobody_id = intval($row["user_id"]);
		}
		$users[$row["user_id"]] = array("id" => intval($row["user_id"]), 
		                                "user_name" => $row["user_name"], 
		                                "real_name" => $row["realname"]);
	}
	pg_free_result($res);

	if (is_null($nobody_id)) {
		fwrite($stderr, "$progname: couldn't find user nobody\n");
		return(false);
	}

	return(true);

} // end get_users()

function match_status($status) {

	global $statuses;

	if (!get_statuses()) {
		return(NULL);
	}

	$matching_ids = array();

	$status = strtolower(trim(strval($status)));

	if (check_int($status)) {
		$int_status = intval($status);
		if (array_key_exists($int_status, $statuses)) {
			$matching_ids[] = $int_status;
		}
	}

	foreach ($statuses as $id => $s) {
		$name = strtolower(trim($s["name"]));
		if(strcmp($status, $name) == 0) {
			$matching_ids[] = $id;
		}
	}

	$unique_ids = array_unique($matching_ids);
	asort($unique_ids);

	$arr = array();
	foreach ($unique_ids as $id) {
		$arr[] = $statuses[$id];
	}

	return($arr);

} // end match_status()

function match_extra_field($tracker, $spec) {

	$matching_ids = array();

	if (check_int($spec)) {
		$id = intval($spec);
		if (array_key_exists($id, $tracker["extra fields"])) {
			$matching_ids[] = $id;
		}
	}

	foreach ($tracker["extra fields"] as $ef) {
		if (strcmp($spec, $ef["alias"]) == 0) {
			$matching_ids[] = $ef["id"];
		}
	}

	$unique_ids = array_unique($matching_ids);
	asort($unique_ids);

	$arr = array();
	foreach ($unique_ids as $id) {
		$arr[] = $tracker["extra fields"][$id];
	}

	return($arr);

} // end match_extra_field()

function match_user($user) {

	global $users;

	if (!get_users()) {
		return(NULL);
	}

	$matching_ids = array();

	$user = strtolower(trim(strval($user)));
	if (check_int($user)) {
		$int_user = intval($user);
		if (array_key_exists($int_user, $users)) {
			$matching_ids[] = $int_user;
		}
	}

	foreach ($users as $id => $u) {
		$user_name = strtolower(trim($u["user_name"]));
		$real_name = strtolower(trim($u["real_name"]));
		if (strcmp($user, $user_name) == 0 || strcmp($user, $real_name) == 0) {
			$matching_ids[] = $id;
		}
	}

	$unique_ids = array_unique($matching_ids);
	asort($unique_ids);

	$arr = array();
	foreach ($unique_ids as $id) {
		$arr[] = $users[$id];
	}

	return($arr);

} // end match_user()

function read_file($tracker, $fname) {

	global $progname;
	global $stderr;
	global $required_fields;
	global $extra_field_types;

	$arr = array();
	foreach ($required_fields as $name) {
		$arr[$name] = array();
	}
	foreach ($tracker["extra fields"] as $ef) {
		$arr[$ef["id"]] = array();
	}

	$data = file_get_contents($fname);
	if($data === false) {
		return(NULL);
	}

	$line_no = 0;
	while (strlen($data) > 0) {
		$line_no++;
		if (preg_match("/\n/", $data) == 0) {
			$line = $data;
			$data = "";
		} else {
			list($line, $data) = preg_split("/\n/", $data, 2);
		}
		$line = trim($line);
		if (strlen($line) == 0) {
			$arr["details"][] = trim($data);
			break;
		}
		if (preg_match("/:/", $line) == 0) {
			fwrite($stderr, "$progname: missing colon on line $line_no " . 
			                "of $fname\n");
			return(NULL);
		}
		list($name, $value) = preg_split("/:/", $line, 2);
		$name = strtolower(trim($name));
		$value = trim($value);
		if (in_array($name, $required_fields)) {
			$arr[$name][] = $value;
		} else {
			$extra_fields = match_extra_field($tracker, $name);
			if (count($extra_fields) == 0) {
				fwrite($stderr, "$progname: can't find field \"$name\"\n");
				return(NULL);
			} elseif (count($extra_fields) > 1) {
				fwrite($stderr, "$progname: ambiguous field \"$name\"\n");
				return(NULL);
			}
			$arr[$extra_fields[0]["id"]][] = $value;
		}
	}

	return($arr);

} // end read_file()

function prepare_values($tracker, &$values) {

	global $progname;
	global $stderr;
	global $extra_field_types;
	global $required_fields;
	global $closed_status_id;
	global $nobody_id;

	// --- check that required fields each have one and only one value ---

	foreach ($required_fields as $rf) {
		if (count($values[$rf]) == 0) {
			fwrite($stderr, "$progname: missing required field \"$rf\"\n");
			return(false);
		}
		if (count($values[$rf]) > 1) {
			fwrite($stderr, "$progname: multiple values for " . 
			                "required field \"$rf\"\n");
			return(false);
		}
		$values[$rf] = $values[$rf][0];
	}

	// --- resolve required fields ---

	$s = match_status($values["status"]);
	if (count($s) == 0) {
		fwrite($stderr, "$progname: bad value for status\n");
		return(NULL);
	}
	if (count($s) > 1) {
		fwrite($stderr, "$progname: ambiguous value for status\n");
		return(NULL);
	}
	$values["status"] = $s[0]["id"];

	if (preg_match("/^[1-5]$/", $values["priority"]) == 0) {
		fwrite($stderr, "$progname: bad value for priority\n");
		return(NULL);
	}
	$values["priority"] = intval($values["priority"]);

	foreach (array("submitted_by", "assigned_to") as $field) {
	$u = match_user($values[$field]);
	if (count($u) == 0) {
		fwrite($stderr, "$progname: bad value or unknown user for $field\n");
		return(NULL);
	}
	if (count($u) > 1) {
		fwrite($stderr, "$progname: ambiguous value for $field\n");
		return(NULL);
	}
	$values[$field] = $u[0]["id"];
	}

	$u = match_user($values["assigned_to"]);
	if (count($u) == 0) {
		fwrite($stderr, "$progname: bad value or unknown user " . 
		                "for assigned_to\n");
		return(NULL);
	}
	if (count($u) > 1) {
		fwrite($stderr, "$progname: ambiguous value for assigned_to\n");
		return(NULL);
	}
	if ($u[0]["id"] != $nobody_id 
	    && !in_array($u[0]["id"], $tracker["technician_ids"])) {
		fwrite($stderr, "$progname: assigned_to user is not a " . 
		                "valid technician\n");
		return(NULL);
	}
	$values["assigned_to"] = $u[0]["id"];

	foreach (array("open_date", "close_date", "last_modified_date") as $field) {
		$date = resolve_date($values[$field]);
		if (is_null($date)) {
			fwrite($stderr, "$progname: error resolving date \"" . 
			                 $values[$field] . "\" for $field\n");
			return(NULL);
		}
		$values[$field] = $date;
	}

	foreach (array("summary", "details") as $field) {
		if (strlen($values[$field]) == 0) {
			fwrite($stderr, "$progname: empty $field\n");
			return(NULL);
		}
		$values[$field] = htmlspecialchars($values[$field]);
	}

	// --- check multiplicity of extra fields and resolve values ---
	// --- also check that extra fields with multiple values don't have ---
	// --- duplicate values ---

	foreach ($tracker["extra fields"] as $ef) {

		if (count($values[$ef["id"]]) == 0) {
			if ($ef["type"] == 1
			    || $ef["type"] == 2
			    || $ef["type"] == 3
			    || $ef["type"] == 5) {
				$values[$ef["id"]] = array(100);
			}
			continue;
		}

		if (count($values[$ef["id"]]) > 1 
		    && $ef["type"] != 2 
		    && $ef["type"] != 5) {
			fwrite($stderr, "$progname: multiple values for field \"" . 
			                $ef["name"] . "\"\n");
			return(false);
		}

		if ($ef["type"] == 4 || $ef["type"] == 6) {
			continue;
		}
		
		for ($i = 0;$i < count($values[$ef["id"]]);$i++) {
			$v = match_extra_field_value($tracker, 
			                             $ef["id"], 
			                             $values[$ef["id"]][$i]);
			if (count($v) == 0) {
				fwrite($stderr, "$progname: bad value \"" . 
			                    $values[$ef["id"]][$i] . 
			                    "\" for extra field \"" . 
			                    $ef["alias"] . "\"\n");
				return(false);
			}
			if (count($v) > 1) {
				fwrite($stderr, "$progname: ambiguous value \"" . 
				                $values[$ef["id"]][$i] . 
				                "\" for extra field \"" . 
				                $ef["alias"] . "\"\n");
				return(false);
			}
			$values[$ef["id"]][$i] = $v[0]["id"];
		}

		$unique_vals = array_unique($values[$ef["id"]]);
		if (count($values[$ef["id"]]) > count($unique_vals)) {
			fwrite($stderr, "$progname: duplicate values " . 
			                "for extra field \"" . $ef["alias"] . "\"\n");
			return(false);
		}

	}

	// --- check that closed items have a close date ---


	if ($values["status"] == $closed_status_id && $values["close_date"] == 0) {
		fwrite($stderr, "$progname: closed status with 0 close_date\n");
		return(false);
	}

	// --- check that last_modified_date is not earlier than other dates ---

	if ($values["last_modified_date"] < $values["open_date"]) {
		fwrite($stderr, "$progname: last_modified_date is earlier " . 
		                "than open_date\n");
		return(false);
	}
	if ($values["last_modified_date"] < $values["close_date"]) {
		fwrite($stderr, "$progname: last_modified_date is earlier " . 
		                "than close_date\n");
		return(false);
	}

	return(true);

} // end prepare_values()

function match_extra_field_value($tracker, $extra_field_id, $spec) {

	$values = $tracker["extra fields"][$extra_field_id]["values"];

	$matching_ids = array();

	if (check_int($spec)) {
		$int_spec = intval($spec);
		if (array_key_exists($int_spec, $values)) {
			$matching_ids[] = $int_spec;
		}
	}

	foreach ($values as $id => $v) {
		if (strcmp($spec, $v["name"]) == 0) {
			$matching_ids[] = $id;
		}
	}

	$unique_ids = array_unique($matching_ids);
	asort($unique_ids);

	$arr = array();
	foreach ($unique_ids as $id) {
		$arr[] = $values[$id];
	}

	return($arr);

} // end match_extra_field_value()

function resolve_date($date) {

	global $stderr;
	global $progname;

	if (check_int($date)) {
		return(intval($date));
	}

	if (preg_match("/^(\d{4})\-(\d{2})\-(\d{2})\s+(\d{2}):(\d{2}):(\d{2})$/", 
	               $date, 
	               $match_array) == 0) {
		return(NULL);
	}

	list(, $year, $month, $day, $hour, $minute, $second) = $match_array;

	$hour = intval($hour);
	$minute = intval($minute);
	$second = intval($second);
	$month = intval($month);
	$day = intval($day);
	$year = intval($year);

	return(mktime($hour, $minute, $second, $month, $day, $year));

} // end resolve_date()

function create_artifact($tracker, $values) {

	global $stderr;
	global $progname;
	global $db;

	$group_artifact_id = $tracker["id"];
	$status_id = $values["status"];
	$priority = $values["priority"];
	$submitted_by = $values["submitted_by"];
	$assigned_to = $values["assigned_to"];
	$open_date = $values["open_date"];
	$close_date = $values["close_date"];
	$summary = "'" . pg_escape_string($values["summary"]) . "'";
	$details = "'" . pg_escape_string($values["details"]) . "'";
	$last_modified_date = $values["last_modified_date"];

	$query = "SELECT artifact_id " . 
	         "  FROM artifact " . 
	         " WHERE group_artifact_id = $group_artifact_id " . 
	         "   AND summary = $summary " . 
	         "   AND details = $details";
	$res = pg_query($db, $query);
	if(!$res) {
		return(NULL);
	}
	if (pg_num_rows($res) > 0) {
		$id = intval(pg_fetch_result($res, 0, "artifact_id"));
		fwrite($stderr, "$progname: duplicate artifact (existing ID $id)\n");
		pg_free_result($res);
		return(NULL);
	}
	pg_free_result($res);

	$query = "INSERT INTO artifact (group_artifact_id, " . 
	         "                      status_id, " . 
	         "                      priority, " . 
	         "                      submitted_by, " . 
	         "                      assigned_to, " . 
	         "                      open_date, " . 
	         "                      close_date, " . 
	         "                      summary, " . 
	         "                      details, " . 
	         "                      last_modified_date)" . 
	         "VALUES ($group_artifact_id, " . 
	         "        $status_id, " . 
	         "        $priority, " . 
	         "        $submitted_by, " . 
	         "        $assigned_to, " . 
	         "        $open_date, " . 
	         "        $close_date, " . 
	         "        $summary, " . 
	         "        $details, " . 
	         "        $last_modified_date)";
	$res = pg_query($db, $query);
	if (!$res) {
		return(NULL);
	}
	pg_free_result($res);

	$res = pg_query("SELECT CURRVAL('artifact_artifact_id_seq') AS id");
	if (!$res) {
		return(NULL);
	}
	if (pg_num_rows($res) == 0) {
		fwrite($stderr, "$progname: error getting artifact ID\n");
		return(NULL);
	}
	$id = pg_fetch_result($res, 0, "id");
	pg_free_result($res);

	foreach ($values as $field => $vals) {
		if (!is_int($field)) {
			continue;
		}
		foreach ($vals as $v) {
			$field_data = "'" . pg_escape_string($v) . "'";
			$query = "INSERT INTO artifact_extra_field_data (artifact_id, " . 
			         "                                       field_data, " . 
			         "                                       extra_field_id) " . 
			         "VALUES ($id, $field_data, $field)";
			$res = pg_query($db, $query);
			if (!$res) {
				return(NULL);
			}
		}
	}

	return($id);

} // end create_artifact()

$progname = basename(array_shift($argv));

$stderr = fopen("php://stderr", "w");

if(count($argv) == 0)
	{
	print "\n";
	print "usage: $progname [command] [command options]\n";
	print "\n";
	print "commands and options are:\n";
	print "\n";
	print "    tracker <tracker id> -- show information about a tracker\n";
	print "\n";
	print "    check <tracker id> <file> [file ...] -- check files\n";
	print "\n";
	print "    create <tracker id> <file> [file ...] -- create an artifact\n";
	print "\n";
	print "$progname create takes as agruments files containing information \n";
	print "about the artifacts to be created, one file per artifact.  Each \n";
	print "file should contain lines of the form \"name: value\" where \n";
	print "\"name\" is the name of an artifact variable and \"value\" is \n";
	print "the value for this variable.  \"name\" and \"value\" may take \n";
	print "field IDs, and extra field value IDs\n";
	print "\n";
	print "Leave a blank line after these name/value pair lines; $progname \n";
	print "will read the artifact summary from the line after the first \n";
	print "blank line to the end of the file\n";
	print "\n";
	exit(1);
	}

$db = pg_connect("dbname=gforge user=gforge");
if(!$db)
	{
	fwrite($stderr, "$progname: error connecting to database\n");
	exit(1);
	}

$command = strtolower(array_shift($argv));

if (strcmp($command, "tracker") == 0) {

	if (count($argv) < 1) {
		command_line_error("no tracker ID given");
		exit(1);
	}

	$tracker_id_str = array_shift($argv);
	if (!check_int($tracker_id_str)) {
		command_line_error("bad tracker ID \"$tracker_id_str\"");
		exit(1);
	}

	$tracker_id = intval($tracker_id_str);

	$tracker = get_tracker($tracker_id);
	if (is_null($tracker)) {
		exit(1);
	}

	if (!get_statuses()) {
		exit(1);
	}

	if (!get_users()) {
		exit(1);
	}

	print "\n";
	print "tracker ID " . $tracker["id"] . ": \"" . $tracker["name"] . "\"\n";
	print "\n";
	print "group ID " . $tracker["group_id"] 
	      . ": \"" . $tracker["group_name"] 
	      . "\" (" . $tracker["group_unix_name"] . ")\n";
	print "\n";
	print "tracker description: " . $tracker["description"] . "\n";
	print "\n";
	print "technicians:\n";
	print "\n";
	foreach ($tracker["technician_ids"] as $id) {
		if (!array_key_exists($id, $users)) {
			fwrite($stderr, "$progname: internal error: can't find " . 
			                "user ID $id\n");
			exit(1);
		}
		print "    $id: " . $users[$id]["user_name"] . " (" .  
		      $users[$id]["real_name"] . ")\n";
	}
	print "\n";
	print "fields:\n";
	print "\n";
	print "    status (required)\n";
	print "\n";
	foreach ($statuses as $s) {
		print "        " . $s["id"] . ": " . $s["name"] . "\n";
	}
	print "\n";
	print "    priority (required)\n";
	print "\n";
	print "        1\n";
	print "        2\n";
	print "        3\n";
	print "        4\n";
	print "        5\n";
	print "\n";
	print "    submitted_by (required)\n";
	print "\n";
	print "        a user ID, login, or real name\n";
	print "\n";
	print "    assigned_to (required)\n";
	print "\n";
	print "        a user ID, login, or real name; must be a valid technician or Nobody\n";
	print "\n";
	print "    open_date (required)\n";
	print "\n";
	print "        seconds since epoch or YYYY-MM-DD HH:MM:SS\n";
	print "\n";
	print "    close_date (required; must be greater than 0 if " . 
	      "status is Closed)\n";
	print "\n";
	print "        seconds since epoch or YYYY-MM-DD HH:MM:SS\n";
	print "\n";
	print "    summary (required)\n";
	print "\n";
	print "        a string\n";
	print "\n";
	print "    details (required)\n";
	print "\n";
	print "        a string, read from stdin\n";
	print "\n";
	print "    last_modified_date (required)\n";
	print "\n";
	print "        seconds since epoch or YYYY-MM-DD HH:MM:SS\n";
	print "\n";
	foreach ($tracker["extra fields"] as $ef) {
		print "    " .  $ef["id"] . 
		      ": " . $ef["alias"] . 
		      " (\"" . $ef["name"] . 
		      "\"; " . $extra_field_types[$ef["type"]] . 
		      ")\n";
		print "\n";
		foreach ($ef["values"] as $val) {
			print "        " . $val["id"] . ": " . $val["name"] . "\n";
		}
		if (count($ef["values"]) > 0) {
			print "\n";
		}
	}

} elseif (strcmp($command, "check") == 0) {

	if (count($argv) < 2) {
		command_line_error("not enough arguments");
		exit(1);
	}

	$tracker_id_str = array_shift($argv);
	if (!check_int($tracker_id_str)) {
		command_line_error("bad tracker ID \"$tracker_id_str\"");
		exit(1);
	}

	$tracker_id = intval($tracker_id_str);

	$tracker = get_tracker($tracker_id);
	if (is_null($tracker)) {
		exit(1);
	}

	foreach($argv as $fname) {
		$values = read_file($tracker, $fname);
		if (is_null($values)) {
			print "$fname: error\n";
		} elseif (!prepare_values($tracker, $values)) {
			print "$fname: error\n";
		} else {
			print "$fname: okay\n";
		}
	}

} elseif (strcmp($command, "create") == 0) {

	if (count($argv) < 2) {
		command_line_error("not enough arguments");
		exit(1);
	}

	$tracker_id_str = array_shift($argv);
	if (!check_int($tracker_id_str)) {
		command_line_error("bad tracker ID \"$tracker_id_str\"");
		exit(1);
	}

	$tracker_id = intval($tracker_id_str);

	$tracker = get_tracker($tracker_id);
	if (is_null($tracker)) {
		exit(1);
	}

	$res = pg_query($db, "BEGIN");
	if (!$res) {
		exit(1);
	}
	pg_free_result($res);

	foreach($argv as $fname) {
		$values = read_file($tracker, $fname);
		if (is_null($values)) {
			fwrite($stderr, "failed on $fname\n");
			fwrite($stderr, "rolling back all artifacts\n");
			pg_query($db, "ROLLBACK");
			exit(1);
		}
		if(!prepare_values($tracker, $values)) {
			fwrite($stderr, "failed on $fname\n");
			fwrite($stderr, "rolling back all artifacts\n");
			pg_query($db, "ROLLBACK");
			exit(1);
		}
		$id = create_artifact($tracker, $values);
		if (is_null($id)) {
			fwrite($stderr, "failed on $fname\n");
			fwrite($stderr, "rolling back all artifacts\n");
			pg_query($db, "ROLLBACK");
			exit(1);
		}
		print "$fname -> $id\n";
	}

	$res = pg_query($db, "COMMIT");
	if (!$res) {
		exit(1);
	}
	pg_free_result($res);

} else {

	fwrite($stderr, "$progname: unknown command \"$command\"\n");
	pg_close($db);
	exit(1);

}

pg_close($db);

exit(0);

?>
