<?php



/**
 * A simple controller for AJAX requests related to the REDCap Publication Matching.
 *
 * NOTE: all JS for the HTML generated by this script is in pub_matching_settings.php
 */

// Config for non-project pages
require dirname(dirname(__FILE__)) . "/Config/init_global.php";

// If user is not a super user then do nothing
if (!ACCESS_SYSTEM_CONFIG) exit();

$db = new RedCapDB();

$ajaxData = "Invalid AJAX call!"; // holds the data that will be returned by the AJAX call

// heuristic to calculate the ideal pixel width of a text box
function getTextWidth($size) { return $size * 8 + 4; }

// given a project object, returns a pretty PI string
function projectToPrettyName($project) {
	$name = trim($project->project_pi_lastname);
	if (trim($project->project_pi_firstname)) $name .= ", " . trim($project->project_pi_firstname);
	if (trim($project->project_pi_mi)) $name .= " " . trim($project->project_pi_mi) . ".";
	if (trim($project->project_pi_alias)) $name .= " (" . trim($project->project_pi_alias) . ")";
	if (trim($project->project_pi_email)) $name .= " [" . trim($project->project_pi_email) . "]";
	return $name;
}

// generate the table for the TODO List or the Manage Projects tab
function getPubProjTable($projects) {
	global $db;
	// just in case $projects is indexed by something other than integers,
	// rebuild it because we need a simple, unique ID for each record
	$tmpProjects = array();
	foreach ($projects as $p) $tmpProjects[] = $p;
	$projects = $tmpProjects;
	$hdr = RCL::provideAny() . ' ' .
					RCView::div(array('class' => 'redcapMissing', 'style' => 'display: inline-block;'), RCL::missingData()) .
					RCL::andThenClick() . ' ' .
					RCView::button(array('id' => 'btnSavePITop'), RCL::saveAll()) .
					RCView::span(array('style' => 'float: right;'),
						RCView::button(array('id' => 'btnCancelPITop'), RCL::cancelAllChanges()));
	$rows = array($hdr, null);
	foreach ($projects as $idx => $p) {
		$myName = projectToPrettyName($p);
		$suggestions = array();
		// try to find existing PIs to suggest to the user for this project assuming
		// that we at least have some critera to search with
		if (trim($p->project_pi_firstname) || trim($p->project_pi_lastname) || trim($p->project_pi_email)) {
			$searches = $db->searchProjectsByPI(trim($p->project_pi_lastname),
							trim($p->project_pi_firstname), trim($p->project_pi_mi),
							trim($p->project_pi_alias), trim($p->project_pi_email), false);
			$scores = array();
			$fields = array("project_pi_firstname", "project_pi_lastname",
					"project_pi_mi", "project_pi_alias", "project_pi_email");
			// must have at least one of these to be considered a valid suggestion
			$importantFields = array('project_pi_lastname', 'project_pi_alias', 'project_pi_email');
			foreach ($searches as $search) {
				$score = 0; $important = false; $valueAdded = false;
				foreach ($fields as $field) {
					$needle = trim($p->$field);
					$haystack = trim($search->$field);
					// two points for a matching field
					if (strlen($needle) > 0 && stristr($haystack, $needle) !== false) {
						$score += 2;
						// give extra weight to more "important" fields
						if (in_array($field, $importantFields)) {
							$score += 1;
							$important = true;
						}
						// because the field is different from the original
						if (strlen($haystack) !== strlen($needle)) $valueAdded = true;
					}
					// one point for a potential fill for an empty field
					elseif (strlen($needle) == 0 && strlen($haystack) > 0) {
						$score += 1;
						$valueAdded = true; // because the user sees new information
					}
					// half a point for mismatches so we don't discard cases where
					// we have, for example, {Jim, James, Jimmy}
					elseif (strlen($needle) > 0 && strlen($haystack) > 0) {
						$score += 0.5;
						$valueAdded = true; // because the user sees new information
					}
				}
				if ($important && $valueAdded) $scores[$score][] = $search;
			}
			ksort($scores, SORT_NUMERIC);
			$scores = array_reverse($scores, true);
			$used = array();
			$maxSuggestions = 3;
			foreach ($scores as $score => $arr) {
				foreach ($arr as $elem) {
					$prettyName = projectToPrettyName($elem);
					if ($myName != $prettyName && empty($used[$prettyName])) {
						$suggestions[] = $elem;
						$used[$prettyName] = true;
					}
					if (count($suggestions) >= $maxSuggestions) break 2;
				}
			}
		}
		$pid = $p->project_id;
		if ($p->isExternal) $pid .= RedCapDB::DELIM . $p->custom_type;
		$h = '';
		$copyStyle = $p->project_pi_pub_exclude !== '0' ?
						'display: none;' : 'display: inline;';
		$h .= RCView::div(array('style' => 'float: right;', 'id' => "piCopyBox_$idx"),
						RCView::a(array('id' => "btnPICopy_$idx", 'class' => 'redcapControl',
								'alt' => RCL::pubPICopy(), 'title' => RCL::pubPICopy(), 'href' => '#',
								'style' => $copyStyle),
							RCL::copy()));
		$projDisplay = $p->isExternal ?
						RCView::span(array('style' => 'font-weight: bold; font-size: larger;'),
										RCView::escape($p->app_title)) :
						RCView::a(array('href' => APP_PATH_WEBROOT . "index.php?pid=$pid",
								'target' => '_blank',
								'style' => 'font-weight: bold; font-size: larger;'),
										RCView::escape($p->app_title));
		if (!empty($p->custom_type)) {
			$projDisplay .= RCView::SP .
				RCView::span(array('class' => 'redcapGhost',
						'style' => 'font-weight: bold; font-size: larger;'),
					RCView::escape('[' . $p->custom_type . ']'));
		}
		$h .= RCView::div(array('id' => "projTitle_$idx",
				'style' => 'margin-bottom: 1px; white-space: normal;'), $projDisplay);
		$h .= RCView::div(array('style' => 'clear: both; padding: 0px;') , '');
		$hideSearch = $p->project_pi_pub_exclude === '0';
		if (count($suggestions)) {
			$items = array();
			foreach ($suggestions as $s) {
				$lname = trim($s->project_pi_lastname);
				$fname = trim($s->project_pi_firstname);
				$mi = trim($s->project_pi_mi);
				$alias = trim($s->project_pi_alias);
				$email = trim($s->project_pi_email);
				$copyme = implode('%', array($lname, $fname, $mi, $alias, $email));
				$items[] = RCView::a(array('href' => '#', 'id' => "piSuggestCopy_$idx", 'class' => 'redcapControl',
						'data-copyme' => $copyme),
								RCView::escape(projectToPrettyName($s)));
			}
			$searchBox = RCView::div(array('id' => "piSearchBox_$idx",
					'style' => 'float: right; position: relative; z-index: 2;'),
							RCView::text(array('id' => "piSearch_$idx",
									'class' => 'redcapGhost',
									'style' => 'width: ' . getTextWidth(24) . 'px; margin-bottom: 6px;',
									'value' => RCL::searchPINameCopyShort())));
			$h .= RCView::div(array('id' => "piSearchSuggest_$idx",
					'style' => 'margin-bottom: 6px;' . ($hideSearch ? ' display: none;' : '')),
							$searchBox .
							RCL::pubSuggest() . RCView::br() .
							RCView::simpleList($items, false, array('class' => 'redcapCompact', 'style' => 'margin-top: 3px;')));
		}
		else {
			$h .= RCView::div(array('id' => "piSearchBox_$idx", 'style' => ($hideSearch ? 'display: none;' : '')),
							RCView::text(array('id' => "piSearch_$idx",
									'class' => 'redcapGhost',
									'style' => 'width: ' . getTextWidth(52) . 'px; margin-bottom: 6px;',
									'value' => RCL::searchPINameCopyLong())));
		}
		$h .= RCView::div(array('style' => 'clear: both; padding: 0px;') , '');
		$left = ''; // HTML for the left side of the row
		$inclAttrs = array('name' => "pi_data_exclude_$idx", 'id' => "pi_data_exclude_no_$idx", 'class' => 'x-form-field', 'value' => '0');
		$exclAttrs = array('name' => "pi_data_exclude_$idx", 'id' => "pi_data_exclude_yes_$idx", 'class' => 'x-form-field', 'value' => '1');
		$todoAttrs = array('name' => "pi_data_exclude_$idx", 'id' => "pi_data_exclude_todo_$idx", 'class' => 'x-form-field', 'value' => '');
		if ($p->project_pi_pub_exclude === '0') $inclAttrs['checked'] = 'checked';
		elseif ($p->project_pi_pub_exclude === '1') $exclAttrs['checked'] = 'checked';
		else $todoAttrs['checked'] = 'checked';
		$missingCls = strlen(trim($p->project_pi_pub_exclude)) ? '' : ' redcapMissing';
		$left .= RCView::div(array('id' => "projBoxExclude_$idx", 'class' => "redcapField$missingCls", 'style' => 'margin: 0px 0px 6px 6px;'),
						RCView::radio($inclAttrs) . ' ' . RCL::pubUseReady() . ' ' .
						RCView::radio($exclAttrs) . ' ' . RCL::pubUseExclude() . ' ' .
						RCView::radio($todoAttrs) . ' ' . RCL::todo());
		$left .= RCView::div(array('style' => 'clear: both; padding: 0px;') , '');
		$missingCls = strlen(trim($p->project_pi_firstname)) ? '' : ' redcapMissing';
		$left .= RCView::div(array('class' => "redcapField"),
						RCView::text(array('id' => "pi_data_firstname_$idx",
								'class' => "x-form-text x-form-field$missingCls", 'maxlength' => '128',
								'style' => 'width: ' . getTextWidth(10) . 'px;',
								'value' => trim($p->project_pi_firstname))) .
						RCView::br() . RCL::nameFirst());
		$left .= RCView::div(array('class' => 'redcapField'),
						RCView::text(array('id' => "pi_data_mi_$idx",
								'class' => 'x-form-text x-form-field', 'maxlength' => '1',
								'style' => 'width: ' . getTextWidth(1) . 'px;',
								'value' => trim($p->project_pi_mi))) .
						RCView::br() . RCL::nameMiddle());
		$missingCls = strlen(trim($p->project_pi_lastname)) ? '' : ' redcapMissing';
		$left .= RCView::div(array('class' => "redcapField"),
						RCView::text(array('id' => "pi_data_lastname_$idx",
								'class' => "x-form-text x-form-field$missingCls", 'maxlength' => '128',
								'style' => 'width: ' . getTextWidth(16) . 'px;',
								'value' => trim($p->project_pi_lastname))) .
						RCView::br() . RCL::nameLast());
		$left .= RCView::div(array('style' => 'clear: both; padding: 0px;') , '');
		$missingCls = strlen(trim($p->project_pi_email)) ? '' : ' redcapMissing';
		$left .= RCView::div(array('class' => "redcapField"),
						RCView::text(array('id' => "pi_data_email_$idx",
								'class' => "x-form-text x-form-field$missingCls", 'maxlength' => '255',
								'style' => 'width: ' . getTextWidth(20) . 'px;',
								'value' => trim($p->project_pi_email))) .
						RCView::br() . RCL::email());
		$left .= RCView::div(array('class' => 'redcapField'),
						RCView::text(array('id' => "pi_data_alias_$idx",
								'class' => 'x-form-text x-form-field', 'maxlength' => '128',
								'style' => 'width: ' . getTextWidth(11) . 'px;',
								'value' => trim($p->project_pi_alias))) .
						RCView::br() . RCL::alias() . " (e.g., Harris PA)");
		$left .= RCView::div(array('style' => 'clear: both; padding: 0px;') , '');
		$h .= RCView::div(array('id' => "projBoxLeft_$idx", 'style' => 'display: inline-block; padding: 0px;'), $left);
		$right = ''; // HTML for the right side of the row
		$right .= RCView::div(array('class' => "redcapField", 'style' => 'width: ' . getTextWidth(28) . 'px; white-space: normal;'),
						RCView::textarea(array('id' => "pi_data_insts_$idx",
								'class' => "x-form-field notesbox",
								'style' => 'width: ' . getTextWidth(27) . 'px; height: 60px'),
										trim($p->project_pub_matching_institution)) .
						RCView::br() . RCL::pubAltInstNames());
		$right .= RCView::div(array('style' => 'clear: both; padding: 0px;') , '');
		$h .= RCView::div(array('id' => "projBoxRight_$idx", 'style' => 'display: inline-block; padding: 0px;'), $right);
		$h .= RCView::hidden(array('id' => "pi_data_pid_$idx", 'value' => $pid));
		$rows[] = array($h);
	}
	// build the table rows that are used in the copy dialog (rows will be
	// switched on or off as needed by JS)
	$copyRows = '';
	foreach ($projects as $idx => $p) {
		$pid = $p->project_id;
		if ($p->isExternal) $pid .= RedCapDB::DELIM . $p->custom_type;
		$copyRows .= RCView::tr(array('id' => "pubCopyRow_$idx"),
			RCView::td(array('style' => 'white-space: nowrap; vertical-align: middle; width: 40%;'),
							RCView::checkbox(array('id' => "pubCopyChk_$idx")) .
							RCView::SP . RCView::SP . '&rarr;' .RCView::SP . RCView::SP .
							RCView::i(RCView::font(array('id' => "pubCopyPIName_$idx"), 'REPLACE ME, JS!'))) .
			RCView::td(array('style' => 'white-space: nowrap; overflow: hidden; vertical-align: middle; width: 60%;'),
							RCView::escape($p->app_title))
		);
	}
	$copyDialog = RCView::div(array('id' => 'pubCopyDialog', 'style' => 'display: none;',
					'title' => RCL::pubCopyTitle()),
					RCView::font(array('id' => 'pubCopyDialogName', 'class' => 'redcapBlockTitle'), 'REPLACE ME, JS!') .
					RCView::br() .
					RCView::font(array('style' => 'font-size: xx-large;'), '&darr; ') .
					RCView::font(array('style' => 'font-size: larger;'), '(' . RCL::pubCopySelect() . ')') .
					RCView::br() .
					RCView::a(array('href' => '#', 'id' => 'pubCopyDialogToggle', 'class' => 'redcapControl'), RCL::toggleAll()) .
					RCView::table(array('style' => 'margin-top: 10px; border: 1px solid black; width: 100%;'), $copyRows));
	return RCView::simpleGrid($rows, array(550))  .
					RCView::button(array('id' => 'btnSavePIBottom', 'style' => 'margin-right: 20px;'), RCL::saveAll()) .
					RCView::button(array('id' => 'btnCancelPIBottom'), RCL::cancelAllChanges().
					$copyDialog);
}

if ($_GET['action'] == 'getSetupDisplay') {
	// build the settings display
	$inputs = array(
			array('label' => RCL::pubMatching().
							 RCView::div(array('class'=>'cc_info'), RCL::pubMatchingHelp()) ,
				'info' => RCView::span(array('style'=>'color:#800000;'), RCL::pubMatchingStatsHelp()),
				'input' => RCView::selectEnabledDisabled(array('id' => 'pubEnabled'), $pub_matching_enabled)),
			array('label' => RCL::pubMatchingEmails(),
				'info' => RCL::pubMatchingEmailsHelp(),
				'input' => RCView::selectEnabledDisabled(array('id' => 'pubEmailsEnabled'), $pub_matching_emails)),
			array('label' => RCL::pubMatchingEmailFreq() . RCView::div(array('class'=>'requiredlabel'), RCL::required()),
				'info' => RCL::pubMatchingEmailFreqHelp(),
				'input' => RCView::text(array('id' => "pubEmailDays", 'onblur' => "redcap_validate(this,'1','','hard','int');",
								'class' => "x-form-text x-form-field", 'maxlength' => '6',
								'style' => 'width: ' . getTextWidth(3) . 'px;',
								'value' => intval($pub_matching_email_days)))),
			array('label' => RCL::pubMatchingEmailLimit() . RCView::div(array('class'=>'requiredlabel'), RCL::required()),
				'info' => RCL::pubMatchingEmailLimitHelp(),
				'input' => RCView::text(array('id' => "pubEmailLimit", 'onblur' => "redcap_validate(this,'1','','hard','int');",
								'class' => "x-form-text x-form-field", 'maxlength' => '6',
								'style' => 'width: ' . getTextWidth(3) . 'px;',
								'value' => intval($pub_matching_email_limit)))),
			array('label' => RCL::pubMatchingEmailSubject() . RCView::div(array('class'=>'requiredlabel'), RCL::required()),
				'info' => RCL::pubMatchingEmailSubjectHelp(),
        'input' => RCView::textarea(array('id' => 'pubEmailSubject', 'class' => 'x-form-field notesbox', 'style' => 'width: 250px; height: 30px;'),
          RCView::escape(empty($pub_matching_email_subject) ? RCL::pubEmailSubject() : $pub_matching_email_subject))),
      array('label' => RCL::pubMatchingEmailText() . RCView::div(array('class'=>'requiredlabel'), RCL::required()),
				'info' => RCL::pubMatchingEmailTextHelp(),
        'input' => RCView::textarea(array('id' => 'pubEmailText', 'class' => 'x-form-field notesbox', 'style' => 'width: 250px; height: 100px;'),
          RCView::escape(empty($pub_matching_email_text) ? RCL::pubEmailIntro() : $pub_matching_email_text))),
			array('label' => RCL::pubInstLabel() . RCView::div(array('class'=>'cc_info'), $lang['control_center_4434']) .
				RCView::div(array('class'=>'requiredlabel'), RCL::required()),
				'info' => RCL::pubMultiInst(),
				'input' => RCView::textarea(array('id' => 'pubInstNames', 'class' => 'x-form-field notesbox', 'style' => 'width: 250px; height: 50px;'),
					RCView::escape($pub_matching_institution)))
	);
	$ajaxData = RCView::p(array(), RCL::pubSetupHelp());
	$ajaxData .= RCView::simpleInputTable(RCView::div(array('style'=>'font-size:14px;color:#800000;font-weight:bold;'), RCL::customSettings()), $inputs);
	$ajaxData .= RCView::div(array('style' => 'text-align: center;'),
					RCView::button(array('id' => 'btnSavePubSettings'), RCL::saveChanges()));
}
elseif ($_GET['action'] == 'getProjTodoCount') {
	$ajaxData = '' . count($db->getPubProjGroupTodos());
}
elseif ($_GET['action'] == 'getProjTodoDisplay') {
	$groups = $db->getPubProjGroupTodos();
	if (count($groups) === 0) {
		$ajaxData = RCL::todoDone();
	}
	else {
		$selKey = empty($_GET['pub_sel_project_ids']) ? null : $_GET['pub_sel_project_ids'];
		if (!empty($_GET['decode_sel_project_ids'])) $selKey = html_entity_decode($selKey, ENT_QUOTES);
		$noDataKey = "";
		$opts = array();
		$firstKey = null; $firstGroup = null; $selGroup = null;
		foreach ($groups as $group) {
			if ($firstGroup === null) $firstGroup = $group;
			$proj = reset($group);
			$projectIds = array();
			foreach ($group as $proj) {
				$pid = $proj->project_id;
				if ($proj->isExternal) $pid .= RedCapDB::DELIM . $proj->custom_type;
				$projectIds[] = $pid;
			}
			$key = implode(RedCapDB::DELIM2, $projectIds);
			$piName = trim($proj->project_pi_lastname) ? trim($proj->project_pi_lastname) : RCL::noData();
			$piName .= ', ';
			$piName .= trim($proj->project_pi_firstname) ? trim($proj->project_pi_firstname) : RCL::noData();
			// special display when missing both first and last name
			if (!trim($proj->project_pi_lastname) && !trim($proj->project_pi_firstname)) {
				$piName = RCL::missingNames();
				$noDataKey = $key;
			}
			$piName .= ' (' . count($group) . ')';
			$opts[$key] = $piName;
			if ($firstKey === null) $firstKey = $key;
			if ($selKey !== null && $selKey == $key) $selGroup = $group;
		}
		if ($selGroup === null) {
			$selKey = $firstKey;
			$selGroup = $firstGroup;
		}
		$ajaxData = RCView::p(array(), RCL::pubTodoHelp()) .
					RCView::div(array('class'=>'blue','style'=>'margin-top:20px;padding:12px 10px 10px;width: 540px;'),
						RCView::img(array('src'=>'pencil.png')) .
						RCView::b(RCL::workingOn()) . RCView::SP . RCView::SP .
						RCView::select(array('id' => 'pubTodoProjIds'), $opts, $selKey) .
						RCView::hidden(array('id' => 'pubTodoNoDataIds', 'value' => $noDataKey))
					) .
					getPubProjTable($selGroup);
	}
	if (!$pub_matching_enabled) {
		$ajaxData = RCView::warnBox(RCView::escape(RCL::pubMatchingDisabledWarn())) .
			$ajaxData;
	}
}
elseif (isset($_POST['action']) && $_POST['action'] == 'savePIData') {
	$id2PI = array();
	foreach ($_POST as $key => $val) {
		if (preg_match('/^(pi_data_.*)_(\d+)$/', $key, $matches)) {
			$field = $matches[1];
			$id = $matches[2];
			$id2PI[$id][$field] = $val;
		}
	}
	$saved = 0;
	foreach ($id2PI as $data) {
		$pid = html_entity_decode($data['pi_data_pid'], ENT_QUOTES);
		$custom_type = null;
		if (strpos($pid, RedCapDB::DELIM) !== false)
			list($pid, $custom_type) = explode(RedCapDB::DELIM, $pid);
		$sqlArr = $db->updateProjectPI($pid,
						trim($data['pi_data_firstname']),
						trim($data['pi_data_mi']),
						trim($data['pi_data_lastname']),
						trim($data['pi_data_email']),
						trim($data['pi_data_alias']),
						$data['pi_data_exclude'],
						strip_tags(trim($data['pi_data_insts'])),
						$custom_type);
		if (count($sqlArr) > 0) {
			RCLog::modifyProject($sqlArr[0]);
			$saved++;
		}
	}
	$ajaxData = $saved == count($id2PI) ?
		RCView::confBox(RCL::saved()) : RCView::errorBox(RCL::saveFail());
}
elseif ($_GET['action'] == 'getProjDisplay') {
	$pid = empty($_GET['pub_project_id']) ? '' : $_GET['pub_project_id'];
	if (!empty($_GET['decode_project_id'])) $pid = html_entity_decode($pid, ENT_QUOTES);
	$authorSearch = empty($_GET['pub_author_search']) ? '' : trim($_GET['pub_author_search']);
	$projects = $db->getPubProjects();
	$projOpts = array('' => '');
	foreach ($projects as $p) {
		$projOpts[$p->project_id . ($p->isExternal ? RedCapDB::DELIM . $p->custom_type : '')] = $p->app_title;
	}
	$h = '';
	$ctrls = array();
	$ctrls[] = array(
			'label' => RCL::searchPIName() . ':',
			'input' => RCView::text(array('id' => 'pub_author_search', 'style' => 'width: ' . getTextWidth(40) . 'px;',
					'value' => $authorSearch)),
			'info' => RCL::searchPINameHelp());
	$ctrls[] = array(
			'label' => RCL::searchProj() . ':',
			'input' => RCView::select(array('id' => 'selPubPID'), $projOpts, $pid),
			'info' => RCL::searchProjHelp());
	$h .= RCView::simpleInputTable(RCL::pubManageHelp(), $ctrls);
	$displayProjects = array();
	if ($pid) {
		$realPid = $pid;
		$custom_type = null;
		if (strpos($pid, RedCapDB::DELIM) !== false)
			list($realPid, $custom_type) = explode(RedCapDB::DELIM, $pid);
		$displayProjects = array($db->getPubProject($realPid, $custom_type));
	}
	elseif ($authorSearch) {
		$lname = $fname = $mi = $alias = $email = '';
		if (preg_match('/^([^, ]+)/', $authorSearch, $matches)) $lname = $matches[1];
		if (preg_match('/,\s(\S+)/', $authorSearch, $matches)) $fname = $matches[1];
		if (preg_match('/\s([[:alpha:]])\.(\s|$)/', $authorSearch, $matches)) $mi = $matches[1];
		if (preg_match('/\((.*)\)/', $authorSearch, $matches)) $alias = $matches[1];
		if (preg_match('/\[(.*)\]/', $authorSearch, $matches)) $email = $matches[1];
		$displayProjects = $db->searchProjectsByPI($lname, $fname, $mi, $alias, $email);
	}
	if (count($displayProjects)) {
		$h .= getPubProjTable($displayProjects);
	}
	$ajaxData = $h;
	if (!$pub_matching_enabled) {
		$ajaxData = RCView::warnBox(RCView::escape(RCL::pubMatchingDisabledWarn())) .
			$ajaxData;
	}
}
elseif (isset($_POST['action']) && $_POST['action'] == 'savePubSettings') {
	// default to a fail message
	$ajaxData = RCView::errorBox(RCL::saveFail());
	$instStr = empty($_POST['pub_insts']) ? '' : $_POST['pub_insts'];
	$enablePub = empty($_POST['pub_enabled']) ? 0 : 1;
	$enablePubEmails = empty($_POST['pub_emails_enabled']) ? 0 : 1;
	$pubEmailDays = empty($_POST['pub_email_days']) ? 1 : intval($_POST['pub_email_days']);
	if ($pubEmailDays < 1) $pubEmailDays = 7; // use a sensible default for bad data
	$pubEmailLimit = empty($_POST['pub_email_limit']) ? 1 : intval($_POST['pub_email_limit']);
	if ($pubEmailLimit < 0) $pubEmailLimit = 3; // use a sensible default for bad data
	$pubEmailSubject = empty($_POST['pub_email_subject']) ? '' : trim($_POST['pub_email_subject']);
  $pubEmailText = empty($_POST['pub_email_text']) ? '' : trim($_POST['pub_email_text']);
	// normalize to UNIX newlines
	$instStr = str_replace("\r\n", "\n", $instStr);
	$instStr = str_replace("\r", "\n", $instStr);
	// clean up the inst list
	$lines = explode("\n", $instStr);
	$insts = array();
	foreach ($lines as $line) {
		$line = trim($line);
		if (empty($line)) continue;
		$insts[] = $line;
	}
	$newInsts = implode("\n", $insts);
	$successes = 0;
	$fieldToVal = array('pub_matching_enabled' => $enablePub,
		'pub_matching_emails' => $enablePubEmails,
		'pub_matching_email_days' => $pubEmailDays,
		'pub_matching_email_limit' => $pubEmailLimit,
		'pub_matching_email_subject' => $pubEmailSubject,
    'pub_matching_email_text' => $pubEmailText,
		'pub_matching_institution' => $newInsts);
	foreach ($fieldToVal as $field => $val) {
		$sqlArr = $db->updateConfig($field, $val);
		if (count($sqlArr) === 1) {
			if ($db->affectedRows()) RCLog::sysConfig($sqlArr[0]);
			$successes++;
		}
	}
	if ($successes == count($fieldToVal)) {
		$ajaxData = RCView::confBox(RCL::changesSaved());
	}
	// Enable/disable the PubMed cron job in the crons table
	$db->enablePubCrawlCron($enablePub);
}
elseif ($_GET['action'] == 'getAuthorTagsJSON') {
	$includeUsers = empty($_GET['includeUsers']) ? false : true;
	$ajaxData = json_encode($db->getPISearchStrings($includeUsers));
}
elseif ($_GET['action'] == 'getPIEmailsDisplay') {
	// Display list of PIs to be emailed
	$ajaxData = '';
	$rows = array();
	$rows[] = RCL::pisToBeEmailed();
	$rows[] = array(RCL::pi(), RCL::email(), RCL::pubsPending());
	$targets = $db->getPubMatchEmailTargets();
	foreach ($targets as $pi) {
		$row = array();
		$name = "$pi->project_pi_lastname, $pi->project_pi_firstname";
		if (!empty($pi->project_pi_mi)) $name .= " $pi->project_pi_mi.";
		$warn = '';
		if ($pi->MinEmailCount >= $pub_matching_email_limit) {
			$warn .= RCView::img(array('src' => 'error.png', 'title' => RCL::pubEmailLimitReached()));
			$warn .= RCView::SP;
		}
		$row[] = $warn . RCView::escape($name);
		$row[] = RCView::a(array('href' => "mailto:$pi->project_pi_email"), RCView::escape("$pi->project_pi_email"));
		// JS will launch this in a new window/tab
		$row[] = RCVIew::button(array('class' => 'pi_view_btn', 'data-pub-secret' => $pi->unique_hash), RCL::pubPIEmailLink()) .
			"($pi->ArticleCount " . RCL::pubs() . ')';
		$rows[] = $row;
	}
	if (empty($targets)) {
		$rows[] = array(RCView::div(array('style'=>'margin:5px;color:#C00000;'), $lang['pub_114']));
	}
	$ajaxData .= RCView::p(array(), RCL::pubEmailListHelp());
	$ajaxData .= RCView::simpleGrid($rows, array(200, 200, 125));
	// Example email
	$ajaxData .= RCView::p(array(), RCL::pubEmailHelp()) .
		RCView::div(array('style' => 'padding-top:10px;'),
			RCView::span(array('class' => 'redcapBlockTitle', 'style' => 'color:#800000;font-size:14px;'), RCView::b(RCL::pubEmailExample())) .
			RCView::SP . RCView::span(array('style' => 'color:#800000;'), RCL::pubEmailSetupNote())
		);
	$ajaxData .= RCView::div(array('class' => 'redcapSimple'),
		RCView::b(RCL::subjectCAPS()) . RCView::SP .
		RCView::i(empty($pub_matching_email_subject) ? RCL::pubEmailSubject() : $pub_matching_email_subject) .
		RCView::br() . RCView::br() .
		PubMedRedcap::getPIEmailBody('Watson', 3, array('REDCap', 'Example Program'), sha1(rand())));
	// Add any notices/warnings at top
	if (!$pub_matching_enabled) {
		$ajaxData = RCView::warnBox(RCView::escape(RCL::pubMatchingDisabledWarn())) .
			$ajaxData;
	}
	if (!$pub_matching_emails) {
		$ajaxData = RCView::warnBox(RCView::escape(RCL::pubMatchingEmailsDisabledWarn())) .
			$ajaxData;
	}
}
elseif ($_GET['action'] == 'getMatchDisplay') {
	$articleId2Matched = $db->getPubMatchesForStats();
	if (count($articleId2Matched)) {
		$exportTemplate = RCView::button(array('class' => 'jqbuttonmed', 'onclick' => 'window.location.href="' . APP_PATH_WEBROOT . 'ControlCenter/pub_matching_ajax.php?action=getMatchExport";','id' => 'TPL_DOM_ID'),
			RCView::img(array('src' => 'xls.gif', 'style' => 'vertical-align:middle')) .
			RCView::span(array('style' => 'vertical-align:middle'), RCL::exportExcelCSV())
		);
		$ajaxData = RCView::p(array(), RCL::pubMatchedIntro());
		$ajaxData .= RCView::p(array(), str_replace('TPL_DOM_ID', 'matchExport_top', $exportTemplate));
		foreach ($articleId2Matched as $articleId => $projects) {
			// use the first element to build the article citation
			reset($projects);
			$article = current($projects);
			$pmlink = ($article->pubsrc_id == RedCapDB::PUBSRC_PUBMED && $article->pub_id && preg_match('/^\d+$/', $article->pub_id)) ?
						RCView::a(array('href' => "http://www.ncbi.nlm.nih.gov/pubmed/$article->pub_id", 'target' => '_blank'),
										'PMID:' . RCView::SP . RCView::escape($article->pub_id)) : '';
			$htmlCitation = array();
			if (!empty($pmlink))
				$htmlCitation[] = $pmlink;
			if (!empty($article->journal_abbrev))
				$htmlCitation[] = RCView::i(RCView::escape($article->journal_abbrev));
			if (!empty($article->volume))
				$htmlCitation[] = RCView::b(RCView::escape($article->volume));
			if (!empty($article->issue))
				$htmlCitation[] = RCView::b('(' . RCView::escape($article->issue) . ')');
			if (!empty($article->pages))
				$htmlCitation[] = RCView::escape($article->pages);
			if (!empty($article->ConsensusDate))
				$htmlCitation[] = RCView::escape('(' . substr($article->ConsensusDate, 0, 4) . ')');
			// build the project list
			$plist = array();
			foreach ($projects as $p) {
				$projDisplay = $p->isExternal ?
						RCView::span(array(),
										RCView::escape($p->app_title)) :
						RCView::a(array('href' => APP_PATH_WEBROOT . "index.php?pid=$p->project_id",
								'target' => '_blank', 'style' => 'color:#800000;font-size:10px;'),
										RCView::escape($p->app_title));
				if (!empty($p->custom_type) && $pub_matching_experimental) {
					$projDisplay .= RCView::SP .
						RCView::span(array('class' => 'redcapGhost'),
							RCView::escape('[' . $p->custom_type . ']'));
				}
				$plist[] = $projDisplay;
			}
			$ajaxData .= RCView::div(array('class' => 'redcapSimple'),
				RCView::font(array('style' => 'font-size: larger; font-weight: bold;'),
				RCView::escape($article->title)) .
				RCView::br() .
				RCView::escape($article->AuthorList) .
				RCView::br() .
				implode(' ', $htmlCitation) . RCView::br() .
				RCView::font(array('style' => 'font-size: 24px;'), '&darr;' . RCView::SP) .
				RCView::span(array('style' => 'color:#777;'), RCL::matchedToProjects()) . RCView::br() .
				RCView::simpleList($plist, false, array('class' => 'redcapCompact', 'style' => 'margin-top: 7px;'))
			);
		}
		$ajaxData .= RCView::p(array(), str_replace('TPL_DOM_ID', 'matchExport_bottom', $exportTemplate));
	}
	else {
		$ajaxData = RCL::pubMatchedNone();
	}
}
elseif ($_GET['action'] == 'getMatchExport') {
	$rows = array();
	$rows[] = array('PubMed ID', 'Title', 'Authors', 'Citation');
	$articleId2Matched = $db->getPubMatchesForStats();
	foreach ($articleId2Matched as $articleId => $projects) {
		// use the first element to build the article citation
		reset($projects);
		$article = current($projects);
		$row = array();
		$row[] = $article->pub_id;
		$row[] = $article->title;
		$row[] = $article->AuthorList;
		$citation = array();
		if (!empty($article->journal_abbrev))
			$citation[] = $article->journal_abbrev;
		if (!empty($article->volume))
			$citation[] = $article->volume;
		if (!empty($article->issue))
			$citation[] = '(' . $article->issue . ')';
		if (!empty($article->pages))
			$citation[] = $article->pages;
		if (!empty($article->ConsensusDate))
			$citation[] = '(' . substr($article->ConsensusDate, 0, 4) . ')';
		$c = implode(' ', $citation);
		// if we only have the year, then that imples an Epub
		if (preg_match('/^\(\d+\)$/', $c)) $c = "$c [Epub ahead of print]";
		$row[] = $c;
		$rows[] = $row;
	}
	// assemble the content
	$content = '';
	foreach ($rows as $i => $row) {
		// "escape" the fields for excel
		foreach ($row as $j => $val) $row[$j] = '"' . str_replace('"', '""', $val) . '"';
		$content .= implode(',', $row) . "\n";
	}
	$date = date('Ymd');
	RCView::exportFile("redcap_pubs_$date.csv", $content, 'application/csv');
}

exit($ajaxData);