/**
 * Main method that parses POST and update details for given record ID
 *
 * @param int $recID
 */
function updateRecord($recID, $rtyID = null)
{
    // Update the given record.
    // This is non-trivial: so that the versioning stuff (achive_*) works properly
    // we need to separate this into updates, inserts and deletes.
    // We get the currect record details and compare them against the post
    // if the details id is in the post[dtyID][dtlID] then compare the values
    $recID = intval($recID);
    // Check that the user has permissions to edit it.
    $res = mysql_query("select * from Records" . " left join sysUsrGrpLinks on ugl_GroupID=rec_OwnerUGrpID" . " left join defRecTypes on rty_ID=rec_RecTypeID" . " where rec_ID={$recID} and (! rec_OwnerUGrpID or rec_OwnerUGrpID=" . get_user_id() . " or ugl_UserID=" . get_user_id() . ")");
    if (mysql_num_rows($res) == 0) {
        $res = mysql_query("select grp.ugr_Name from Records, " . USERS_DATABASE . ".sysUGrps grp where rec_ID={$recID} and grp.ugr_ID=rec_OwnerUGrpID");
        $grpName = mysql_fetch_row($res);
        $grpName = $grpName[0];
        print '({ error: "\\nSorry - you can\'t edit this record.\\nYou aren\'t in the ' . slash($grpName) . ' workgroup" })';
        return;
    }
    $record = mysql_fetch_assoc($res);
    /*****DEBUG****/
    error_log("save record dtls POST " . print_r($_POST, true));
    // Upload any files submitted ... (doesn't have to take place right now, but may as well)
    uploadFiles();
    //Artem: it does not work here - since we uploaded files at once
    // Get the existing records details and compare them to the incoming data
    $recDetails = getRecordDetails($recID);
    // find UPDATES - everything that is in current record and has a post value is treated as an update
    $recDetailUpdates = array();
    /*****DEBUG****/
    //error_log("save record dtls ".print_r($recDetails,true));
    foreach ($recDetails as $dtyID => $dtlIDs) {
        $eltName = "type:" . $dtyID;
        if (!(@$_POST[$eltName] && is_array($_POST[$eltName]))) {
            // element wasn't in POST: ignore it -this could be a non-rectype detail
            unset($recDetails[$dtyID]);
            // remove from details so it's not deleted
            continue;
        }
        if (count($_POST[$eltName]) == 0) {
            // element was in POST but without content: values have been deleted client-side (need to be deleted in DB so leave POST)
            continue;
        }
        $bdInputHandler = getInputHandlerForType($dtyID);
        //returns the particular handler (processor) for given field type
        foreach ($dtlIDs as $dtlID => $val) {
            /*****DEBUG****/
            //error_log(" in saveRecord details loop  $dtyID,  $dtlID, ".print_r($val,true));
            $eltID = "bd:" . $dtlID;
            $val = @$_POST[$eltName][$eltID];
            if (!$bdInputHandler->inputOK($val, $dtyID, $rtyID)) {
                /*****DEBUG****/
                //error_log(" in saveRecord update details value check error  $dtyID,  $dtlID, ".print_r($val,true));
                continue;
                // faulty input ... ignore
            }
            $toadd = $bdInputHandler->convertPostToMysql($val);
            /*****DEBUG****/
            //error_log(" in saveRecord update details value converted from $val to $toadd");
            if ($toadd == null) {
                continue;
            }
            $recDetailUpdates[$dtlID] = $toadd;
            $recDetailUpdates[$dtlID]["dtl_DetailTypeID"] = $dtyID;
            /*
            @TODO Since this function is utilized in (email)import we need to add verification of values according to detail type
            at the first for terms (enumeration field type)
            */
            unset($_POST[$eltName][$eltID]);
            // remove data from post submission
            if (count($_POST[$eltName]) == 0) {
                // if nothing left in post dtyID then remove it also
                unset($_POST[$eltName]);
            }
            unset($recDetails[$dtyID][$dtlID]);
            // remove data from local reflection of the database
        }
    }
    /*****DEBUG****/
    //error_log("save record dtls POST after updates removed ".print_r($_POST,true));
    /*****DEBUG****/
    //error_log("save record dtls after updates removed ".print_r($recDetails,true));
    // find DELETES
    // Anything left in recDetails now represents recDetails rows that need to be deleted
    $bibDetailDeletes = array();
    foreach ($recDetails as $dtyID => $dtlIDs) {
        foreach ($dtlIDs as $dtlID => $val) {
            array_push($bibDetailDeletes, $dtlID);
        }
    }
    // find INSERTS
    // Try to insert anything left in POST as new recDetails rows
    $bibDetailInserts = array();
    /*****DEBUG****/
    error_log(" in saveRecord checking for inserts  _POST =" . print_r($_POST, true));
    foreach ($_POST as $eltName => $bds) {
        // if not properly formatted or empty or an empty array then skip it
        if (!preg_match("/^type:\\d+\$/", $eltName) || !$_POST[$eltName] || count($_POST[$eltName]) == 0) {
            continue;
        }
        $dtyID = substr($eltName, 5);
        $bdInputHandler = getInputHandlerForType($dtyID);
        foreach ($bds as $eltID => $val) {
            if (!$bdInputHandler->inputOK($val, $dtyID, $rtyID)) {
                /*****DEBUG****/
                //error_log(" in saveRecord insert details value check error for $eltName,  $eltID, ".print_r($val,true));
                continue;
                // faulty input ... ignore
            }
            $newBibDetail = $bdInputHandler->convertPostToMysql($val);
            $newBibDetail["dtl_DetailTypeID"] = $dtyID;
            $newBibDetail["dtl_RecID"] = $recID;
            /*****DEBUG****/
            //error_log("new detail ".print_r($newBibDetail,true));
            array_push($bibDetailInserts, $newBibDetail);
            unset($_POST[$eltName][$eltID]);
            // remove data from post submission
        }
    }
    // Anything left in POST now is stuff that we have no intention of inserting ... ignore it
    // We now have:
    //  - $recDetailUpdates: an assoc. array of dtl_ID => column values to be updated in recDetails
    //  - $bibDetailInserts: an array of column values to be inserted into recDetails
    //  - $bibDetailDeletes: an array of dtl_ID values corresponding to rows to be deleted from recDetails
    // Commence versioning ...
    mysql_query("start transaction");
    $recUpdates = array("rec_Modified" => array("now()"), "rec_FlagTemporary" => 0);
    $recUpdates["rec_ScratchPad"] = $_POST["notes"];
    if (intval(@$_POST["rectype"])) {
        $recUpdates["rec_RecTypeID"] = intval($_POST["rectype"]);
    }
    if (array_key_exists("rec_url", $_POST)) {
        $recUpdates["rec_URL"] = $_POST["rec_url"];
    }
    $owner = $record['rec_OwnerUGrpID'];
    if (is_admin() || is_admin('group', $owner) || $owner == get_user_id()) {
        // must be grpAdmin or record owner to changes ownership or visibility
        if (array_key_exists("rec_owner", $_POST)) {
            $recUpdates["rec_OwnerUGrpID"] = $_POST["rec_owner"];
        }
        if (array_key_exists("rec_visibility", $_POST)) {
            $recUpdates["rec_NonOwnerVisibility"] = $_POST["rec_visibility"];
        } else {
            if ($record['rec_NonOwnerVisibility'] == 'public' && HEURIST_PUBLIC_TO_PENDING) {
                $recUpdates["rec_NonOwnerVisibility"] = 'pending';
            }
        }
    }
    /*****DEBUG****/
    error_log(" in saveRecord update recUpdates = " . print_r($recUpdates, true));
    mysql__update("Records", "rec_ID={$recID}", $recUpdates);
    $biblioUpdated = mysql_affected_rows() > 0 ? true : false;
    if (mysql_error()) {
        error_log("error rec update" . mysql_error());
    }
    $updatedRowCount = 0;
    foreach ($recDetailUpdates as $bdID => $vals) {
        /*****DEBUG****/
        error_log(" in saveRecord update details dtl_ID = {$bdID} value =" . print_r($vals, true));
        mysql__update("recDetails", "dtl_ID={$bdID} and dtl_RecID={$recID}", $vals);
        if (mysql_affected_rows() > 0) {
            ++$updatedRowCount;
        }
    }
    if (mysql_error()) {
        error_log("error detail updates" . mysql_error());
    }
    $insertedRowCount = 0;
    foreach ($bibDetailInserts as $vals) {
        /*****DEBUG****/
        error_log(" in saveRecord insert details detail =" . print_r($vals, true));
        mysql__insert("recDetails", $vals);
        if (mysql_affected_rows() > 0) {
            ++$insertedRowCount;
        }
    }
    if (mysql_error()) {
        error_log("error detail inserts" . mysql_error());
    }
    $deletedRowCount = 0;
    if ($bibDetailDeletes) {
        /*****DEBUG****/
        error_log(" in saveRecord delete details " . print_r($bibDetailDeletes, true));
        mysql_query("delete from recDetails where dtl_ID in (" . join($bibDetailDeletes, ",") . ") and dtl_RecID={$recID}");
        if (mysql_affected_rows() > 0) {
            $deletedRowCount = mysql_affected_rows();
        }
    }
    if (mysql_error()) {
        error_log("error detail deletes" . mysql_error());
    }
    // eliminate any duplicated lines
    $notesIn = explode("\n", str_replace("\r", "", $_POST["notes"]));
    $notesOut = "";
    $notesMap = array();
    for ($i = 0; $i < count($notesIn); ++$i) {
        if (!@$notesMap[$notesIn[$i]] || !$notesIn[$i]) {
            // preserve blank lines
            $notesOut .= $notesIn[$i] . "\n";
            $notesMap[$notesIn[$i]] = true;
        }
    }
    $_POST["notes"] = preg_replace("/\n\n+/", "\n", $notesOut);
    if ($updatedRowCount > 0 || $insertedRowCount > 0 || $deletedRowCount > 0 || $biblioUpdated) {
        /* something changed: update the records title and commit all changes */
        $title_check = check_title_mask2($record["rty_TitleMask"], $record["rec_RecTypeID"], true);
        if ($title_check != '') {
            $new_title = "Please go to Designer View > Essentials > Record types/fields and edit the title mask for this record type";
        } else {
            $new_title = fill_title_mask($record["rty_TitleMask"], $record["rec_ID"], $record["rec_RecTypeID"]);
        }
        mysql_query("update Records\n                set rec_Title = '" . addslashes($new_title) . "'\n                where rec_ID = {$recID}");
        mysql_query("commit");
        // Update memcached's copy of record (if it is cached)
        updateCachedRecord($recID);
        return true;
    } else {
        /* nothing changed: rollback the transaction so we don't get false versioning */
        mysql_query("rollback");
        return false;
    }
}
function checkRectypeMask($rtID, $rtName, $mask, $coMask, $recID, $check)
{
    if (!@$mask && @$rtID) {
        $mask = mysql__select_array("defRecTypes", "rty_TitleMask", "rty_ID={$rtID}");
        $mask = $mask[0];
    }
    if (!@$coMask && @$rtID) {
        $coMask = mysql__select_array("defRecTypes", "rty_CanonicalTitleMask", "rty_ID={$rtID}");
        $coMask = $coMask[0];
    }
    //echo print_r($_REQUEST,true);
    if ($check > 0 || !$recID) {
        ?>
			<div>
				<h3>Checking rectype "<b><i><?php 
        echo $rtName;
        ?>
</i></b>"[<?php 
        echo $rtID;
        ?>
]</h3>
			</div>
<?php 
        $retMaskCheck = check_title_mask2($mask, $rtID, true);
        echo "<div class='resultsRow'><div class='statusCell " . ($retMaskCheck == "" ? "valid'>" : "invalid'>in") . "valid</div>";
        echo "<div class='maskCell'>mask = <i>{$mask}</i></div>";
        if ($retMaskCheck != "") {
            echo "<div class='errorCell'>" . $retMaskCheck . "</div>";
        }
        echo "</div>";
        $retCoMaskCheck = check_title_mask2($coMask, $rtID, true);
        echo "<div class='resultsRow'><div class='statusCell " . ($retCoMaskCheck == "" ? "valid'>" : "invalid'>in") . "valid</div>";
        echo "<div class='maskCell'>canonical mask = <i>{$coMask}</i></div>";
        if ($retCoMaskCheck != "") {
            echo "<div class='errorCell'>" . $retCoMaskCheck . "</div>";
        }
        echo "</div>";
        if ($retCoMaskCheck !== "" && $retMaskCheck == "") {
            $coMask = make_canonical_title_mask($mask, $rtID);
            if ($check != 2) {
                echo "<div class='resultsRow'><div class='statusCell'></div><div class='maskCell'>Correct canonical mask = <span class='valid'>{$coMask}</span></div></div>";
            } else {
                // repair canonical
                mysql_query("update defRecTypes set rty_CanonicalTitleMask='{$coMask}' where rty_ID={$rtID}");
                $error = mysql_error();
                echo "<div class='resultsRow'><div class='statusCell " . ($error == "" ? "valid'>Update successful" : "invalid'>Failed to update") . "</div>";
                echo "<div class='maskCell'>Correct canonical mask = <span class='valid'>{$coMask}</span></div>";
                echo ($error ? "<div class='errorCell invalid'> Error : " . $error . "</div>" : "") . "</div>";
            }
        }
        echo "<hr>\n";
    } else {
        echo "checking type mask {$mask} for recType {$rtID} and rec {$recID} <br/>";
        echo fill_title_mask($mask, $recID, $rtID);
    }
}
mysql_connection_select(DATABASE);
$rectypeID = @$_REQUEST['rty_id'];
$mask = @$_REQUEST['mask'];
if (array_key_exists("check", @$_REQUEST)) {
    if ($_REQUEST["check"] == 2) {
        //get coded mask
        $res = titlemask_make($mask, $rectypeID, 1, null, _ERR_REP_MSG);
        print is_array($res) ? $res[0] : $res;
    } else {
        if ($_REQUEST["check"] == 3) {
            //get human readable mask
            $res = titlemask_make($mask, $rectypeID, 2, null, _ERR_REP_MSG);
            print is_array($res) ? $res[0] : $res;
        } else {
            ///verify text title mask
            $check = check_title_mask2($mask, $rectypeID, true);
            if (!empty($check)) {
                print $check;
            } else {
                print "";
            }
        }
    }
} else {
    $recID = @$_REQUEST['rec_id'];
    $res = titlemask_value($mask, $recID);
    //."<br><br>".fill_title_mask_old($mask, $recID, $rectypeID);
    print $res;
    //echo fill_title_mask_old($mask, $recID, $rectypeID);
    /* it works - but beforehand verification is already done on client side
       $check = check_title_mask2($mask, $rectypeID, true);
function check_title_mask($mask, $rt)
{
    return check_title_mask2($mask, $rt, false);
}