function SetPeriod($relation, $DateConcept, $srcAtom, $Period)
{
    emitLog("SetPeriod({$relation},{$DateConcept},{$srcAtom},{$Period})");
    // Insert the pair ($srcAtom,$srcAtom + $period) into $relation
    if (($dt1 = strtotime($srcAtom)) === false) {
        ExecEngineSHOUTS("SetPeriod: Illegal date {$dt1} specified in srcAtom (3rd arg): {$srcAtom}");
    }
    if (($dt3 = strtotime($srcAtom . $Period)) === false) {
        ExecEngineSHOUTS("SetPeriod: Illegal period {$dt3} specified as period (4th arg): {$Period}");
    }
    $tgtAtom = date('d-m-Y', $dt3);
    global $execEngineWhispers;
    // Defined in 'pluginsettings.php'
    $execEngineWhispers = false;
    // ExecEngineWhispers("SetPeriod: InsPair($relation,$DateConcept,$srcAtom,$DateConcept,$tgtAtom)");
    // Als '$tgtAtom' nog niet in de database bestaat als een instantie van $DateConcept, dan moet die nog wel worden toegevoegd:
    if (!isAtomInConcept($tgtAtom, $DateConcept)) {
        addAtomToConcept($tgtAtom, $DateConcept);
    }
    InsPair($relation, $DateConcept, $srcAtom, $DateConcept, $tgtAtom);
    return;
}
                 echo '<button class="Button SaveButton" onclick="commitEditing()">Save</button>';
                 echo '<button class="Button CancelButton" onclick="cancelEditing()">Cancel</button>';
             }
             // If the atom is not in the concept, this means that a new atom was be created (and $atom is a time-based unique name).
             // We cannot use a url-encoded command for Create new, since such a url causes problems in the browser history. (pressing back
             // could cause the creation of another atom) With the current method, going back or refreshing the url simply shows the new atom.
             // TODO: Once navigation is not done with urls anymore, we can employ a more elegant solution here.
             //
             // We add the atom to its concept in a temporary transaction, so we can generate the interface in the normal way (by querying
             // the database). When the interface is done, the transaction is rolled back. On save, the atom is added to the concept table
             // again.
             // TODO: with multiple users, this mechanism may lead to non-unique new atom names, until we enocode a session number
             //       in the unique atom name. But since the atom names are based on microseconds, the chances of a problem are pretty slim.
             if ($isNew) {
                 DB_doquer('START TRANSACTION');
                 addAtomToConcept($atom, $concept);
             }
             // we need an extra ScrollPane div because the log windows need to be outside scroll area but inside ampersand root
             // (since their css depends on the 'editing' attribute)
             echo '<div id=ScrollPane>';
             echo generateAtomInterfaces($allInterfaceObjects[$interface], $atom, true);
             echo '</div>';
             echo '</div>';
             echo '<div id=Rollback></div>';
             // needs to be outside AmpersandRoot, so it's easy to address all interface elements not in the Rollback
             if ($isNew) {
                 DB_doquer('ROLLBACK');
             }
         }
     }
 }
function InsAtom($concept)
{
    // call function from DatabaseUtils.php
    $atom = mkUniqueAtomByTime($concept);
    // create new atom name
    addAtomToConcept($atom, $concept);
    // insert new atom in databse
    // log
    ExecEngineWhispers("New atom {$atom} ({$concept}) created");
    emitLog("addAtomToConcept({$atom}, {$concept})");
    // return created atom identifier
    return $atom;
}
function createNewAtom($concept)
{
    $newAtom = mkUniqueAtomByTime($concept);
    addAtomToConcept($newAtom, $concept);
    return $newAtom;
}
function editUpdate($rel, $isFlipped, $parentAtom, $childAtom, $parentOrChild, $originalAtom)
{
    global $relationTableInfo;
    global $tableColumnInfo;
    emitLog("editUpdate({$rel}, " . ($isFlipped ? 'true' : 'false') . ", {$parentAtom}, {$childAtom}, {$parentOrChild}, {$originalAtom})");
    /* There seems to be a bug in 'editUpdate', nl. when a $relation occurs multiple times as KEY in the relationTableInfo (which we have seen happening when you overload an (Ampersand) relation (name). The following code may be used to find the right entry in the relationTableInfo, but that is not used by 'editUpdate'.
      // check if $relation appears in $relationTableInfo
      if (array_key_exists($relation, $relationTableInfo))
      { foreach($relationTableInfo as $key => $arr)
         if($key == $relation)
         { if($arr['srcConcept'] == $srcConcept && $arr['tgtConcept'] == $tgtConcept)
            { $table = $arr['table'];
            $srcCol = $arr['srcCol'];
               $tgtCol = $arr['tgtCol'];
               echo "<br>[FOUND: table=$table, srcCol=$srcCol, tgtCol=$tgtCol]";
           }
         }
      } else
      { echo "ERROR: Relation $relation does not exist (in table info)";
      }
    */
    $table = $relationTableInfo[$rel]['table'];
    $srcCol = $relationTableInfo[$rel]['srcCol'];
    $tgtCol = $relationTableInfo[$rel]['tgtCol'];
    $parentCol = $isFlipped ? $tgtCol : $srcCol;
    $childCol = $isFlipped ? $srcCol : $tgtCol;
    $modifiedCol = $parentOrChild == 'parent' ? $parentCol : $childCol;
    $modifiedAtom = $parentOrChild == 'parent' ? $parentAtom : $childAtom;
    $stableCol = $parentOrChild == 'parent' ? $childCol : $parentCol;
    $stableAtom = $parentOrChild == 'parent' ? $childAtom : $parentAtom;
    $tableEsc = escapeSQL($table);
    $modifiedColEsc = escapeSQL($modifiedCol);
    $stableColEsc = escapeSQL($stableCol);
    $modifiedAtomEsc = escapeSQL($modifiedAtom);
    $stableAtomEsc = escapeSQL($stableAtom);
    $originalAtomEsc = escapeSQL($originalAtom);
    // only if the stable column is unique, we do an update
    // TODO: maybe we can do updates also in non-unique columns
    if ($tableColumnInfo[$table][$stableCol]['unique']) {
        $query = "UPDATE `{$tableEsc}` SET `{$modifiedColEsc}`='{$modifiedAtomEsc}' WHERE `{$stableColEsc}`='{$stableAtomEsc}'";
        emitLog($query);
        queryDb($query);
    } else {
        /* if ($tableColumnInfo[$table][$modifiedCol]['unique'])
           { // todo: is this ok? no, we'd also have to delete stableAtom originalAtom and check if modified atom even exists, otherwise we need an insert, not an update.
             $query = "UPDATE `$tableEsc` SET `$stableColEsc`='$stableAtomEsc' WHERE `$modifiedColEsc`='$modifiedAtomEsc'";
             emitLog ($query);
             queryDb($query);
           }
           else { */
        // delete only if there was an $originalAtom
        if ($originalAtom != '') {
            $query = "DELETE FROM `{$tableEsc}` WHERE `{$stableColEsc}`='{$stableAtomEsc}' AND `{$modifiedColEsc}`='{$originalAtomEsc}';";
            emitLog($query);
            queryDb($query);
        }
        $query = "INSERT INTO `{$tableEsc}` (`{$stableColEsc}`, `{$modifiedColEsc}`) VALUES ('{$stableAtomEsc}', '{$modifiedAtomEsc}')";
        emitLog($query);
        queryDb($query);
    }
    // ensure that the $modifiedAtom is in the concept tables for $modifiedConcept
    $childConcept = $isFlipped ? $relationTableInfo[$rel]['srcConcept'] : $relationTableInfo[$rel]['tgtConcept'];
    $parentConcept = $isFlipped ? $relationTableInfo[$rel]['tgtConcept'] : $relationTableInfo[$rel]['srcConcept'];
    $modifiedConcept = $parentOrChild == 'parent' ? $parentConcept : $childConcept;
    emitLog("adding to concept tables: {$modifiedAtom} : {$modifiedConcept}");
    addAtomToConcept($modifiedAtom, $modifiedConcept);
    // TODO: errors here are not reported correctly
}