/**
 * creates an xForm item list for the set of terms passed in.
 *
 * @param        string [$termIDTree] json string representing the tree of term ids for this term field
 * @param        string [$disabledTermIDsList] a comma separated list of term ids to be markered as headers, can be empty
 * @param        array [$termLocalLookup] a lookup array of term structures
 * @param        object [$ti] term structure field name to index mapping for term definition
 * @return       string representing an xForm select item list
 * @see          getTermOffspringList
 * @todo         expand this function to xForm cascaded selects auto completion select
 */
function createTermSelect($termIDTree, $disabledTermIDsList, $termLocalLookup, $ti)
{
    $res = "";
    $termIDTree = preg_replace("/[\\}\\{\\:\"]/", "", $termIDTree);
    //remove unused structure characters
    $termIDTree = explode(",", $termIDTree);
    if (count($termIDTree) == 1) {
        //term set parent term, so expand to direct children
        $childTerms = getTermOffspringList($termIDTree[0], false);
        if (count($childTerms) > 0) {
            $termIDTree = $childTerms;
        }
    }
    // sort($termIDTree);
    $disabledTerms = explode(",", $disabledTermIDsList);
    foreach ($termIDTree as $index => $idTerm) {
        if (array_key_exists($idTerm, $disabledTerms)) {
            continue;
        }
        if (array_key_exists($idTerm, $termLocalLookup)) {
            $termName = $termLocalLookup[$idTerm][$ti['trm_Label']];
            $termCode = $termLocalLookup[$idTerm][$ti['trm_ConceptID']];
            if (!$termCode) {
                $termCode = (HEURIST_DBID ? HEURIST_DBID : HEURIST_DBNAME) . "-" . $idTerm;
            }
        } else {
            continue;
        }
        $res = $res . "<item>\n" . "<label>\"{$termName}\"</label>\n" . "<value>{$termCode}</value>\n" . "</item>\n";
    }
    return $res;
}
/**
 * returns array list of all terms under a given term
 * @param     int $termID
 * @param     boolean $getAllDescentTerms determines whether to recurse and retrieve children of children (default = true)
 * @return    array  of term IDs
 */
function getTermOffspringList($termID, $getAllDescentTerms = true)
{
    $offspring = array();
    if ($termID) {
        $res = mysql_query("select * from defTerms where trm_ParentTermID = {$termID}");
        if (mysql_num_rows($res)) {
            //child nodes exist
            while ($row = mysql_fetch_assoc($res)) {
                // for each child node
                $subTermID = $row['trm_ID'];
                array_push($offspring, $subTermID);
                if ($row['trm_ChildCount'] > 0 && $getAllDescentTerms) {
                    $offspring = array_merge($offspring, getTermOffspringList($subTermID));
                }
            }
        }
    }
    return $offspring;
}
function isValidID($id, $dtyID, $rtyID = null)
{
    static $rtFieldDefs = null;
    static $dtyIDDefs = null;
    if (!is_numeric($id)) {
        return false;
    }
    if (!$dtyIDDefs) {
        $dtyIDDefs = array();
        $res = mysql_query("select dty_ID, dty_Type, dty_JsonTermIDTree,dty_TermIDTreeNonSelectableIDs,dty_PtrTargetRectypeIDs" . " from defDetailTypes" . " where dty_Type in ('enum','relationtype','resource')");
        while ($res && ($row = mysql_fetch_row($res))) {
            //use first element as index
            if ($row[1] === 'enum' || $row[1] === 'relationtype') {
                //create term Id list and term list.
                $terms = getTermsFromFormat($row[2]);
                if (($cntTrm = count($terms)) > 0) {
                    if ($cntTrm == 1) {
                        $terms = getTermOffspringList($terms[0]);
                    } else {
                        $nonTerms = getTermsFromFormat($row[3]);
                        if (count($nonTerms) > 0) {
                            $terms = array_diff($terms, $nonTerms);
                        }
                    }
                    if (!empty($terms)) {
                        $dtyIDDefs[$row[0]] = $terms;
                    }
                }
            } else {
                if ($row[1] === 'resource') {
                    // create list of valid rectypes
                    if (count($row[4]) > 0 && $row[4] != "") {
                        $temp = explode(",", $row[4]);
                        if (!empty($temp)) {
                            $dtyIDDefs[$row[0]] = $temp;
                        }
                    }
                }
            }
        }
    }
    if ($rtyID && !$rtFieldDefs) {
        $rtFieldDefs = array('max' => array());
        $res = mysql_query("select rst_DetailTypeID, dty_Type, rst_MaxValues," . " if(rst_FilteredJsonTermIDTree is not null and CHAR_LENGTH(rst_FilteredJsonTermIDTree)>0,rst_FilteredJsonTermIDTree,dty_JsonTermIDTree) as rst_FilteredJsonTermIDTree," . " if(rst_TermIDTreeNonSelectableIDs is not null and CHAR_LENGTH(rst_TermIDTreeNonSelectableIDs)>0,rst_TermIDTreeNonSelectableIDs,dty_TermIDTreeNonSelectableIDs) as rst_TermIDTreeNonSelectableIDs," . " if(rst_PtrFilteredIDs is not null and CHAR_LENGTH(rst_PtrFilteredIDs)>0,rst_PtrFilteredIDs,dty_PtrTargetRectypeIDs) as rst_PtrFilteredIDs" . " from defRecStructure" . " left join defDetailTypes on rst_DetailTypeID = dty_ID" . " where rst_RecTypeID=" . $rtyID);
        while ($res && ($row = mysql_fetch_row($res))) {
            //use first element as index
            if (is_numeric($row[2])) {
                $rtFieldDefs['max'][$row[0]] = $row[2];
            }
            if ($row[1] === 'enum' || $row[1] === 'relationtype') {
                //create term Id list and term list.
                $terms = getTermsFromFormat($row[3]);
                if (($cntTrm = count($terms)) > 0) {
                    if ($cntTrm == 1) {
                        $terms = getTermOffspringList($terms[0]);
                    } else {
                        $nonTerms = getTermsFromFormat($row[4]);
                        if (count($nonTerms) > 0) {
                            $terms = array_diff($terms, $nonTerms);
                        }
                    }
                    if (!empty($terms)) {
                        $rtFieldDefs[$row[0]] = $terms;
                    }
                }
            } else {
                if ($row[1] === 'resource') {
                    // create list of valid rectypes
                    if (count($row[5]) > 0 && $row[5] != "") {
                        $temp = explode(",", $row[5]);
                        if (!empty($temp)) {
                            $rtFieldDefs[$row[0]] = $temp;
                        }
                    } else {
                        $rtFieldDefs[$row[0]] = "all";
                    }
                }
            }
        }
    }
    /*****DEBUG****/
    //error_log("save record isValidID rtFields = ".print_r($rtFieldDefs,true));
    /*****DEBUG****/
    //error_log("save record isValidID rdtyDefs = ".print_r($dtyIDDefs,true));
    if ($rtyID && array_key_exists($dtyID, $rtFieldDefs)) {
        return $rtFieldDefs[$dtyID] === "all" || in_array($id, $rtFieldDefs[$dtyID]);
    } else {
        if (array_key_exists($dtyID, $dtyIDDefs)) {
            return $dtyIDDefs[$dtyID] === "all" || in_array($id, $dtyIDDefs[$dtyID]);
        }
    }
    return false;
}
function getTermListAll($termDomain)
{
    $terms = array();
    $res = mysql_query('SELECT * FROM defTerms
            where (trm_Domain="' . $termDomain . '") and (trm_ParentTermId=0 or trm_ParentTermId is NULL)');
    if ($res && mysql_num_rows($res)) {
        //child nodes exist
        while ($row = mysql_fetch_assoc($res)) {
            // for each child node
            array_push($terms, $row['trm_ID']);
            if (true) {
                //ARTEM: trm_ChildCount is not reliable   }$row['trm_ChildCount'] > 0 && $getAllDescentTerms) {
                $terms = array_merge($terms, getTermOffspringList($row['trm_ID']));
            }
        }
    } else {
    }
    return $terms;
}
                     array_push($row[4], $trmSet);
                 }
             }
         }
     }
     break;
 case "relationtype":
     //calculate the list of terms for this detail type
     if (!$row[6]) {
         $row[4] = array(array("0", "No Terms for {$row['1']}"));
     } else {
         preg_match_all("/\\d+/", $row[6], $matches);
         $trmIDs = $matches[0];
         if (count($trmIDs) == 1) {
             //term set parent term, so expand to direct children
             $childTerms = getTermOffspringList($trmIDs[0], false);
             if (count($childTerms) > 0) {
                 $trmIDs = $childTerms;
             }
         } else {
             if ($row[7]) {
                 preg_match_all("/\\d+/", $row[7], $hdrTermIDs);
                 if ($hdrTermIDs[0] && is_array($hdrTermIDs[0])) {
                     $trmIDS = array_diff($trmIDs, $hdrTermIDs[0]);
                     //remove disabled Terms
                 }
             }
         }
         $trmCnt = count($trmIDs);
         $trmIDs = join(",", $trmIDs);
         if ($trmIDs) {
/**
* Verify rectype pointer value or term id
*
* @param mixed $id  - rectype id (for resource) or term id (for enum reltype)
* @param mixed $dtyID - field type id
* @param mixed $rtyID - rectype id
*/
function isValidID($id, $dtyID, $rtyID = null)
{
    if (!is_numeric($id) || !is_numeric($dtyID)) {
        return false;
    }
    if (!@$dtyIDDefs) {
        $dtyIDDefs = array();
    }
    if (!@$dtyIDDefs[$dtyID]) {
        $res = mysql_query("select dty_ID, dty_Type, dty_JsonTermIDTree,dty_TermIDTreeNonSelectableIDs,dty_PtrTargetRectypeIDs" . " from defDetailTypes" . " where dty_ID={$dtyID} and dty_Type in ('enum','relationtype','resource')");
        while ($res && ($row = mysql_fetch_row($res))) {
            //use first element as index
            if (defined('DT_RELATION_TYPE') && $dtyID == DT_RELATION_TYPE) {
                //$row[1] === 'relationtype' ){
                $dtyIDDefs[$dtyID] = getTermListAll('relation');
            } else {
                if ($row[1] === 'enum') {
                    //create term Id list and term list.
                    $terms = getTermsFromFormat($row[2]);
                    if (($cntTrm = count($terms)) > 0) {
                        if ($cntTrm == 1) {
                            //vocabulary
                            $terms = getTermOffspringList($terms[0]);
                        } else {
                            $nonTerms = getTermsFromFormat($row[3]);
                            if (count($nonTerms) > 0) {
                                $terms = array_diff($terms, $nonTerms);
                            }
                        }
                        if (count($terms) < 1) {
                            $dtyIDDefs[$row[0]] = "all";
                        } else {
                            $dtyIDDefs[$row[0]] = $terms;
                        }
                    }
                } else {
                    if ($row[1] === 'resource') {
                        // create list of valid rectypes
                        $dtyIDDefs[$row[0]] = "all";
                        if ($row[4] != "") {
                            $temp = explode(",", $row[4]);
                            //get allowed record types
                            if (count($temp) > 0) {
                                $dtyIDDefs[$row[0]] = $temp;
                            }
                        }
                    }
                }
            }
        }
    }
    if (false && $rtyID && !$rtFieldDefs) {
        //this code not used anymore
        $rtFieldDefs = array('max' => array());
        $res = mysql_query("select rst_DetailTypeID, dty_Type, rst_MaxValues," . " if(rst_FilteredJsonTermIDTree is not null and CHAR_LENGTH(rst_FilteredJsonTermIDTree)>0,rst_FilteredJsonTermIDTree,dty_JsonTermIDTree) as rst_FilteredJsonTermIDTree," . " if(rst_TermIDTreeNonSelectableIDs is not null and CHAR_LENGTH(rst_TermIDTreeNonSelectableIDs)>0,rst_TermIDTreeNonSelectableIDs,dty_TermIDTreeNonSelectableIDs) as rst_TermIDTreeNonSelectableIDs," . " if(rst_PtrFilteredIDs is not null and CHAR_LENGTH(rst_PtrFilteredIDs)>0,rst_PtrFilteredIDs,dty_PtrTargetRectypeIDs) as rst_PtrFilteredIDs" . " from defRecStructure" . " left join defDetailTypes on rst_DetailTypeID = dty_ID" . " where rst_RecTypeID=" . $rtyID);
        while ($res && ($row = mysql_fetch_row($res))) {
            //use first element as index
            if (is_numeric($row[2])) {
                $rtFieldDefs['max'][$row[0]] = $row[2];
            }
            /*
            These fields are never defined in UI. Thus, they should aleays be null. It was for overwrite of base field constraints by further contraints within the recstructure,
            which is one step too many and has been removed from design by Ian in approx 2011
            
            if ( $row[1] === 'enum' || $row[1] === 'relationtype') {
            //create term Id list and term list.
            $terms = getTermsFromFormat($row[3]);
            if (($cntTrm = count($terms)) > 0) {
            if ($cntTrm == 1) {
            $terms = getTermOffspringList($terms[0]);
            }else{
            $nonTerms = getTermsFromFormat($row[4]);
            if (count($nonTerms) > 0) {
            $terms = array_diff($terms,$nonTerms);
            }
            }
            if (!empty($terms)) {
            $rtFieldDefs[$row[0]] = $terms;
            }
            }
            } else if ($row[1] === 'resource') {
            // create list of valid rectypes
            if (count($row[5])>0 && $row[5] != "") {
            $temp = explode(",",$row[5]);
            if (!empty($temp)) {
            $rtFieldDefs[$row[0]] = $temp;
            }
            }else{
            $rtFieldDefs[$row[0]] = "all";
            }
            }
            */
        }
    }
    // not used
    // if ($rtFieldDefs && $rtyID && array_key_exists($dtyID, $rtFieldDefs)) {
    //    $res = $rtFieldDefs[$dtyID] === "all" || in_array($id, $rtFieldDefs[$dtyID]);
    //}
    if ($dtyIDDefs && @$dtyIDDefs[$dtyID]) {
        return $dtyIDDefs[$dtyID] === "all" || in_array($id, $dtyIDDefs[$dtyID]);
    }
    return false;
}
function isInvalidTerm($defs, $defs_nonsel, $id, $dtyID)
{
    global $dtyIDDefs;
    if (!@$dtyIDDefs[$dtyID]) {
        $terms = getTermsFromFormat($defs);
        if (($cntTrm = count($terms)) > 0) {
            if ($cntTrm == 1) {
                //vocabulary
                $terms = getTermOffspringList($terms[0]);
            } else {
                $nonTerms = getTermsFromFormat($defs_nonsel);
                if (count($nonTerms) > 0) {
                    $terms = array_diff($terms, $nonTerms);
                }
            }
            if (count($terms) < 1) {
                $dtyIDDefs[$dtyID] = "all";
            } else {
                $dtyIDDefs[$dtyID] = $terms;
            }
        }
    }
    if (!@$dtyIDDefs[$dtyID]) {
        return true;
        //terms not found
    }
    return !($dtyIDDefs[$dtyID] === "all" || in_array($id, $dtyIDDefs[$dtyID]));
}