<?php
/*******************************************************************************
 *
 * LEIDEN OPEN VARIATION DATABASE (LOVD)
 *
 * Created     : 2006-08-08
 * Modified    : 2010-04-12
 * For LOVD    : 2.0-26
 *
 * Access      : Public
 * Purpose     : View & search selected gene's variants.
 *
 * Copyright   : 2004-2010 Leiden University Medical Center; http://www.LUMC.nl/
 * Programmers : Ing. Ivo F.A.C. Fokkema <I.F.A.C.Fokkema@LUMC.nl>
 *               Ir. Gerard C.P. Schaafsma <G.C.P.Schaafsma@LUMC.nl>
 * Last edited : Ing. Ivo F.A.C. Fokkema <I.F.A.C.Fokkema@LUMC.nl>
 *
 *
 * This file is part of LOVD.
 *
 * LOVD is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * LOVD is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with LOVD; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 *************/

define('ROOT_PATH', './');
require ROOT_PATH . 'inc-init.php';

if (HAS_AUTH) {
    // If authorized, check for updates.
    require ROOT_PATH . 'inc-upgrade.php';
}

// If no gene selected, forward to the select list.
if (!$_SESSION['currdb']) {
    header('Location: ' . PROTOCOL . $_SERVER['HTTP_HOST'] . rtrim(dirname($_SERVER['PHP_SELF']), '/') . '/home.php' . lovd_showSID());
    exit;
}





if (in_array($_GET['action'], array('view_all', 'search_all', 'view_unique', 'search_unique'))) {
    // View all / search variants in this gene.

    // 2009-11-06; 2.0-23; Move this part up because we need to support hide_col = all.
    // Whether or not a user can see non-public data.
    define('IS_CURATOR', lovd_isCurator($_SESSION['currdb']));

    require ROOT_PATH . 'inc-lib-list.php';
    require ROOT_PATH . 'class/currdb.php';
    $_CURRDB = new CurrDB();
    $_CURRDB->hideCols('public', IS_CURATOR);
    $_CURRDB->hideColsByTable((substr($_GET['action'], -6) == 'unique'? 'Variant' : ''));

    // Array which will make up the table (header and data).
    if (substr($_GET['action'], -3) == 'all') {
        $aTable = array('pathogenic_' => array('Path.', 50));
    } else {
        $aTable = array();
    }
    $aTable = array_merge($aTable, $_CURRDB->buildTable('list'));

    // Additional columns for authorized users.
    if (substr($_GET['action'], -3) == 'all' && IS_CURATOR) {
        $aTable['submitterid'] = array('Submitterid', 100);
        $aTable['status_'] = array('Status', 75);
    }

    // 2008-02-15; 2.0-04; Allow others to hide columns for this session only.
    // 2008-09-17; 2.0-12; Store this information in a cookie, so that it will be remembered after your session ends.
    if (isset($_COOKIE[$_SETT['cookie_id'] . '_hidden_cols'])) {
        $aHiddenColumns = preg_split('/[;,]+/', $_COOKIE[$_SETT['cookie_id'] . '_hidden_cols']); // Support both , and ; as a separator for backwards compatibility to LOVD 2.0-22 and before.
    } else {
        $aHiddenColumns = array();
    }
    if (!empty($_GET['hide_col'])) {
        // 2009-11-06; 2.0-23; Received strings are now converted into arrays to be prosessed the same way.
        if (is_string($_GET['hide_col'])) {
            $_GET['hide_col'] = explode(',', $_GET['hide_col']);
        }
        foreach ($_GET['hide_col'] as $sCol) {
            // We don't check the availability of the column here, because some other gene may have it.
            if ($sCol == 'all') {
                foreach ($aTable as $key => $value) {
                    if (!in_array($key, $aHiddenColumns)) {
                        $aHiddenColumns[] = $key;
                    }
                }
            } elseif (!in_array($sCol, $aHiddenColumns)) {
                $aHiddenColumns[] = $sCol;
            }
        }
    }
    if (!empty($_GET['show_col'])) {
        // 2009-11-06; 2.0-23; Received strings are now converted into arrays to be prosessed the same way.
        if (is_string($_GET['show_col'])) {
            $_GET['show_col'] = explode(',', $_GET['show_col']);
        }
        foreach ($_GET['show_col'] as $sCol) {
            if ($sCol == 'all') {
                $aHiddenColumns = array();
            } else {
                $nKey = array_search($sCol, $aHiddenColumns);
                if ($nKey !== false) {
                    unset($aHiddenColumns[$nKey]);
                }
            }
        }
    }

    // Now, store the settings in the cookie.
    if ((!isset($_COOKIE[$_SETT['cookie_id'] . '_hidden_cols']) && count($aHiddenColumns)) || (isset($_COOKIE[$_SETT['cookie_id'] . '_hidden_cols']) && $_COOKIE[$_SETT['cookie_id'] . '_hidden_cols'] != implode(',', $aHiddenColumns))) {
        setcookie($_SETT['cookie_id'] . '_hidden_cols', implode(',', $aHiddenColumns), time() + 60*60*24*31);
    }

    // Then, clean $aHiddenCols so that it will only contain columns that are actually going to be on the screen. This is for counting purposes, to see how much has been hidden.
    foreach ($aHiddenColumns as $nKey => $sCol) {
        if (!isset($aTable[$sCol])) {
            unset($aHiddenColumns[$nKey]);
        }
    }

    require ROOT_PATH . 'inc-top.php';
    lovd_printGeneHeader();
    lovd_printHeader('variant_listings', 'LOVD - Variant listings for ' . $_SESSION['currdb']);

    // 2007-03-20; 2.0-alpha-09; Isn't *not* joining to TABLE_PATIENTS much faster? Joining prevents orphaned entries to show up.
    //list($nTotal) = mysql_fetch_row(mysql_query('SELECT COUNT(*) FROM ' . TABLE_PAT2VAR . ' AS t1 LEFT JOIN ' . TABLE_PATIENTS . ' AS t2 USING (patientid) WHERE t1.symbol = "' . $_SESSION['currdb'] . '" AND ' . (IS_CURATOR? '1=1' : 't1.status >= ' . STATUS_MARKED)));
    list($nTotal) = mysql_fetch_row(mysql_query('SELECT COUNT(*) FROM ' . TABLE_PAT2VAR . ' AS t1 WHERE t1.symbol = "' . $_SESSION['currdb'] . '" AND ' . (IS_CURATOR? '1=1' : 't1.status >= ' . STATUS_MARKED)));
    if (!$nTotal) {
        print('      There are currently no ' . (IS_CURATOR? '' : 'public ') . 'variants in this gene.<BR>' . "\n");
        lovd_printGeneFooter();
        require ROOT_PATH . 'inc-bot.php';
        exit;
    }

    // Standard query, will be extended later on.
    if (substr($_GET['action'], -6) == 'unique') {
        // View unique. View all variants, exclude non public entries depending on $_CONF['hide_nonpublic'].
        $sQ = 'SELECT v.*, COUNT(p2v.variantid) AS mutations FROM ' . TABLE_CURRDB_VARS . ' AS v LEFT JOIN ' . TABLE_PAT2VAR . ' AS p2v ON (p2v.symbol = "' . $_SESSION['currdb'] . '" AND v.variantid = p2v.variantid) LEFT OUTER JOIN ' . TABLE_PATHOGENIC . ' AS path USING (pathogenic) WHERE ' . (!IS_CURATOR && $_CONF['hide_nonpublic']? 'p2v.status >= ' . STATUS_MARKED : '1=1');
    } else {
        // View all.
        // 2010-03-30; 2.0-26; 'mutations' was not calculated correctly because homozygous mutations are hidden; the total number of mutations was calculated for both and then summed up. Include a division by the count of the DNA field to adjust the value.
        $sQ = 'SELECT v.*, p.*, p2v.allele, p2v.status' . (IS_CURATOR? ', stat.status_text AS status_' : '') . ', path.pathogenic_text AS pathogenic_, (COUNT(p2v_2.variantid)/COUNT(DISTINCT v.`Variant/DNA`, p2v.allele)) AS mutations, s.reference AS subs_reference FROM ' . TABLE_CURRDB_VARS . ' AS v LEFT JOIN ' . TABLE_PAT2VAR . ' AS p2v ON (p2v.symbol = "' . $_SESSION['currdb'] . '" AND v.variantid = p2v.variantid) LEFT JOIN ' . TABLE_PATIENTS . ' AS p USING (patientid) LEFT OUTER JOIN ' . TABLE_PAT2VAR . ' AS p2v_2 ON (p.patientid = p2v_2.patientid' . (IS_CURATOR? '' : ' AND p2v_2.status >= ' . STATUS_MARKED) . ')' . (IS_CURATOR? ' LEFT OUTER JOIN ' . TABLE_VAR_STATUS . ' AS stat ON (p2v.status = stat.status)' : '') . ' LEFT OUTER JOIN ' . TABLE_PATHOGENIC . ' AS path ON (p2v.pathogenic = path.pathogenic) LEFT OUTER JOIN ' . TABLE_SUBS . ' AS s ON (p.submitterid = s.submitterid) WHERE ' . (IS_CURATOR? '1=1' : 'p2v.status >= ' . STATUS_MARKED . ' AND p2v_2.status >= ' . STATUS_MARKED);
        if (!empty($_GET['view']) && !empty($_SESSION['variant_statistics'][$_SESSION['currdb']][$_GET['view']])) {
            // 2009-09-03; 2.0-21; add variantid's
            $sQ .= ' AND v.variantid IN ( ' . implode($_SESSION['variant_statistics'][$_SESSION['currdb']][$_GET['view']], ', ') . ')';
            // 2009-09-03; 2.0-21; added notification
            $aVariantType =
                     array(
                            'DNA_unknown' => 'unknown variants at DNA',
                            'DNA_twovars' => 'variants with 2 changes in 1 allele at DNA',
                            'DNA_delins' => 'insertion/deletion variants at DNA',
                            'DNA_inv' => 'inversion variants at DNA',
                            'DNA_ins' => 'insertion variants at DNA',
                            'DNA_dup' => 'duplication variants at DNA',
                            'DNA_del' => 'deletion variants at DNA',
                            'DNA_sub' => 'substitution variants at DNA',
                            'DNA_complex' => 'complex variants at DNA',
                            'RNA_unknown' => 'unknown variants at RNA',
                            'RNA_twovars' => 'variants with 2 changes in 1 allele at RNA',
                            'RNA_spl' => 'splice variants at RNA',
                            'RNA_complex' => 'complex variants at RNA',
                            'RNA_delins' => 'insertion/deletion variants at RNA',
                            'RNA_inv' => 'inversion variants at RNA',
                            'RNA_ins' => 'insertion variants at RNA',
                            'RNA_del' => 'deletion variants at RNA',
                            'RNA_dup' => 'duplication variants at RNA',
                            'RNA_sub' => 'substitution variants at RNA',
                            'RNA_no effect' => 'variants with no effect at RNA',
                            'RNA_r.0' => 'variants with no RNA produced',
                            'Prot_twovars' => 'variants with 2 changes in 1 allele at protein',
                            'Prot_complex' => 'complex variants at protein',
                            'Prot_unknown' => 'unknown variants at protein',
                            'Prot_fs' => 'frame shift variants at protein',
                            'Prot_p.X' => 'nonstop variants at protein',
                            'Prot_X' => 'nonsense variants at protein',
                            'Prot_delins' => 'insertion/deletion variants at protein',
                            'Prot_del' => 'deletion variants at protein',
                            'Prot_dup' => 'duplication variants at protein',
                            'Prot_ins' => 'insertion variants at protein',
                            'Prot_no protein' => 'variants with no protein produced',
                            'Prot_p.Met' => 'translation initiation variants at protein',
                            'Prot_sub' => 'substitution variants at protein',
                            'Prot_=' => 'silent variants at protein',
                          );
            lovd_showInfoTable('Please note that only ' . $aVariantType[$_GET['view']] . (stristr($aVariantType[$_GET['view']], 'produced') ? '' : ' level') . ' are shown.', 'warning');
        }
    }

    // Guess the column used to describe the mutation.
    $sMutationCol = $_CURRDB->getMutationCol();

    if (substr($_GET['action'], 0, 6) == 'search') {
        // Here starts the actual building of the query.

        // 2009-11-20; 2.0-23; added option when coming from the UCSC browser.
        if (isset($_GET['trackid'])) {
            $_GET['search_Variant/DNA'] = substr($_GET['trackid'], (strpos($_GET['trackid'], ':') + 1));
        }

        // 2008-07-31; 2.0-10; Implement XSS check on search terms.
        foreach ($_GET as $key => $val) {
            if (!is_array($val) && $val != strip_tags($val)) {
                $_GET[$key] = '';
            }
        }

        // SEARCH: Exception for $_GET['search_MutCol'].
        if (!empty($_GET['search_MutCol'])) {
            if (!empty($_GET['search_' . $sMutationCol])) {
                $_GET['search_' . $sMutationCol] .= ' ' . $_GET['search_MutCol'];
            } else {
                $_GET['search_' . $sMutationCol] = $_GET['search_MutCol'];
            }
        }

        // SEARCH: Advanced text search.
        $aSearchText = array_merge(
                 array('search_pathogenic_' => 'path.pathogenic_text'),
                 $_CURRDB->buildSearchList());
        if (IS_CURATOR) {
            // Add status.
            $aSearchText['search_submitterid'] = 'p.submitterid';
            $aSearchText['search_status_'] = 'stat.status_text';
        }
        foreach ($aSearchText as $key => $val) {
            if (isset($_GET[$key]) && trim($_GET[$key])) {
                $a = explode(' ', trim($_GET[$key]));
                foreach ($a as $sTerm) {
                    if ($sTerm) {
                        if (substr_count($sTerm, '|') && preg_match('/^[^|]+(\|[^|]+)+$/', $sTerm)) {
                            // OR.
                            $aOR = explode('|', $sTerm);
                            $sQ .= ' AND (';
                            foreach ($aOR as $nTerm => $sTerm) {
                                // 2009-03-03; 2.0-17; Advanced searching did not allow to combine NOT and OR searches.
                                if (substr($sTerm, 0, 1) == '!') {
                                    // NOT.
                                    $sQ .= ($nTerm? ' OR ' : '') . $val . ' NOT LIKE "%' . lovd_escapeSearchTerm(substr($sTerm, 1)) . '%"';
                                } else {
                                    // Common search term.
                                    $sQ .= ($nTerm? ' OR ' : '') . $val . ' LIKE "%' . lovd_escapeSearchTerm($sTerm) . '%"';
                                }
                            }
                            $sQ .= ')';
                        } elseif (substr($sTerm, 0, 1) == '!') {
                            // NOT.
                            $sQ .= ' AND ' . $val . ' NOT LIKE "%' . lovd_escapeSearchTerm(substr($sTerm, 1)) . '%"';
                        } else {
                            // Common search term.
                            $sQ .= ' AND ' . $val . ' LIKE "%' . lovd_escapeSearchTerm($sTerm) . '%"';
                        }
                    }
                }
            }
        }
    }

    if (substr($_GET['action'], -6) == 'unique') {
        $sQ .= ' GROUP BY v.`' . $sMutationCol . '`';
    } else {
        // Add p2v.allele here to show homozygous mutations twice in the list.
        $sQ .= ' GROUP BY v.variantid, p.patientid';
    }

    $nResults = mysql_num_rows(mysql_query($sQ));

    // SORT: Current settings.
    if (!empty($_GET['order'])) {
        $aOrder = explode(',', $_GET['order']);
    } else {
        $aOrder = array('', '');
    }

    // SORT: Column data.
    $aOrderList = array_merge(
             array('pathogenic_' => array('path.pathogenic', 'ASC')),
             array('sort' => array('v.sort', 'ASC')),
             $_CURRDB->buildOrderList());
    if (substr($_GET['action'], -3) == 'all' && IS_CURATOR) {
        // Add submitterid & status.
        $aOrderList['submitterid'] = array('p.submitterid', 'ASC');
        $aOrderList['status_'] = array('p2v.status', 'ASC');
    }
    if (!array_key_exists($aOrder[0], $aOrderList)) {
        // 2007-10-10; 2.0-beta-10; Changed default sorting column from Exon to Variant/DNA.
        $aOrder[0] = $sMutationCol;
    }
    if ($aOrder[1] != 'ASC' && $aOrder[1] != 'DESC') {
        $aOrder[1] = $aOrderList[$aOrder[0]][1];
    }

    // 2007-10-19; 2.0-01; Fixed bug #18 - Variants do not sort correctly when selecting DNA column to sort on.
    // 2009-06-12; 2.0-19; Changed again, since the sort column now also contains the Exon information.
    // SORT: Additional sort columns (faking a perfect sort).
    $sOrderPre = '';
    $sOrderPost = '';
    if ($aOrder[0] == 'Variant/DNA') {
        // 1) In case of the mutation column, sort FIRST on sort.
        $sOrderPre .= 'v.sort ' . $aOrder[1] . ', ';
    } else {
        // 2) In case of anything else, sort on sort AFTER.
        $sOrderPost .= ', v.sort ' . $aOrder[1];
    }

    $_GET['limit'] = (isset($_GET['limit']) && in_array($_GET['limit'], $_SETT['variant_listsizes'])? $_GET['limit'] : (HAS_AUTH? $_AUTH['list_size'] : 100));
    $sQueryLimit = lovd_pagesplitInit(($nResults > 0? $nResults : $nTotal), $_GET['limit']);
    $sQ .= ' ORDER BY ' . $sOrderPre . $aOrderList[$aOrder[0]][0] . ' ' . $aOrder[1] . $sOrderPost . (substr($_GET['action'], -6) == 'unique'? '' : ', p.patientid') . ' ' . $sQueryLimit;



    // Show form; required for sorting and searching.
    // 2008-02-15; 2.0-04; Allow form to store info for hiding/showing columns.
    // 2009-07-22; 2.0-21; Fix issue with loosing the pathogenicity search term when sorting, searching or changing the limit setting.
    print('      <FORM action="' . $_SERVER['PHP_SELF'] . '" method="get" style="margin : 0px;">' . "\n" .
          '        <INPUT type="hidden" name="select_db" value="' . $_SESSION['currdb'] . '">' . "\n" .
          '        <INPUT type="hidden" name="action" value="' . $_GET['action'] . '">' . "\n" .
          ($_GET['action'] == 'search_unique' && !empty($_GET['search_pathogenic_']) && $_GET['search_pathogenic_'] == '-'?
          '        <INPUT type="hidden" name="search_pathogenic_" value="' . $_GET['search_pathogenic_'] . '">' . "\n" : '') .
          '        <INPUT type="hidden" name="order" value="' . implode(',', $aOrder) . '">' . "\n" .
          '        <INPUT type="hidden" name="hide_col" value="">' . "\n" .
          '        <INPUT type="hidden" name="show_col" value="">' . "\n\n");

    if (!$nResults) {
        // FIXME; this is not how it should be done. There's supposed to be some link here, showing all variants again.
        //     What about returning to the previous search results? Store in $_SESSION?
        // Searched, but no results.
        print('      No results have been found that match your criteria.<BR><BR>' . "\n\n");
        if (!IS_CURATOR && !empty($_GET['search_' . $sMutationCol])) {
            // Possibly, visitor is searching for variant that is not public. Isolate basepair and actually check.
            $sBase = preg_replace('/^(c\.|g\.)?([[(?]*)/', "$1", $_GET['search_' . $sMutationCol]);
            $sBase = preg_replace('/^((c\.|g\.)?\*?\-?[0-9]+([-+][0-9]+)?(_[0-9]+([-+][0-9]+)?)?).*/', "$1", $sBase);

            $sQ = 'SELECT COUNT(*) FROM ' . TABLE_CURRDB_VARS . ' AS v LEFT JOIN ' . TABLE_PAT2VAR . ' AS p2v ON (p2v.symbol = "' . $_SESSION['currdb'] . '" AND v.variantid = p2v.variantid) WHERE v.`' . $sMutationCol . '` LIKE "' . $sBase . '%" AND p2v.status < ' . STATUS_MARKED;
            list($nResults) = mysql_fetch_row(mysql_query($sQ));
            if ($nResults) {
                print('      A variant for ' . $sBase . ' is present in our database but it is not yet public. When you want more information, please contact the curator, specifying the variant you are looking for. When you have identified this variant in a sample, please submit it right away; only a complete and fully up-to-date database is most useful for those interested.<BR><BR>' . "\n\n");
            } else {
                print('      Possibly, you\'re looking for an entry that is not yet public. If so, contact the curator for information about the variant you\'re looking for.<BR><BR>' . "\n\n");
            }
        }
        lovd_printGeneFooter();
        require ROOT_PATH . 'inc-bot.php';
        exit;
    }

    $q = mysql_query($sQ);
    if (!$q) {
        lovd_dbFout('Variants' . ucfirst($_GET['action']), $sQ, mysql_error());
    }

    if ($_GET['action'] == 'search_unique' && !empty($_GET['search_pathogenic_']) && $_GET['search_pathogenic_'] == '-') {
        // 'Polymorphism' table.
        lovd_showInfoTable('Please note that this overview may not be complete, as variants with unknown effect to the phenotype are left out.', 'warning');
    }

    // 2009-09-24; 2.0-23; Show link at all times. Simply activate only when needed.
    $sNavigation = '';
    // "Unhide all columns".
    if (count($aHiddenColumns)) {
        $sNavigation = '<A href="#" onclick="document.forms[0].show_col.value=\'all\';document.forms[0].submit();">';
    } else {
        $sNavigation = '<A style="color : #999999;">';
    }
    $sNavigation .= 'Unhide all columns</A>';
    // 2009-09-24; 2.0-23; Added "Hide specific columns" and "Hide all columns" links.
    // "Hide specific columns".
    // "Hide all columns".
    if (count($aHiddenColumns) < count($aTable)-1) {
        $sNavigation .= ' | <A href="#" onclick="lovd_openWindow(\'views_columns.php' . '?action=' . $_GET['action'] . '&amp;hide=true' . lovd_showSID(true, true) . '\', \'HideColumns\', 300, 500); return false;">Hide Specific Columns</A>' .
                        ' | <A href="#" onclick="document.forms[0].hide_col.value=\'all\';document.forms[0].submit();">Hide all columns</A>';
    } else {
        $sNavigation .= ' | <A style="color : #999999;">Hide Specific Columns</A>' .
                        ' | <A style="color : #999999;">Hide all columns</A>';
    }

    // 2009-11-27; 2.0-23; Added information table that explains the current view.
    lovd_includeJS(ROOT_PATH . 'inc-js-toggle-visibility.js');
    if (substr($_GET['action'], -6) == 'unique') {
        $sInfoText = 'The variants below are all in the ' . $_SESSION['currdb'] . ' database' . (substr($_GET['action'], 0, 6) == 'search'? ', matching your query' : '') . '. In this view only variant fields are shown. Variants are listed only once, a number is present in the ' . $aTable['Variant/DNA'][0] . ' field when a variant has been reported more than once (in such cases fields other than the ' . $aTable['Variant/DNA'][0] . ' just belong to one entry and may differ for other entries). <BR>Selecting and clicking a specific line will open a detailed view showing all variant entries, including patient and pathogenicity information.';
    } else {
        $sInfoText = 'The variants below are all in the ' . $_SESSION['currdb'] . ' database' . (substr($_GET['action'], 0, 6) == 'search'? ', matching your query' : '') . '. All fields are shown, including patient and pathogenicity information. A \'+\' in the ' . $aTable['Variant/DNA'][0] . ' field indicates that more variants were found in this patient. Variants reported in a gene database other than ' . $_SESSION['currdb'] . ', are reported as the gene symbol with the number of reported variants between parenthesis.<BR>Selecting and clicking a specific line will open a detailed view showing all details per patient.';
    }

    print('      <TABLE border="0" cellpadding="0" cellspacing="0" width="960">' . "\n" .
          '        <TR>' . "\n" .
          '          <TD valign="top">' . "\n");
    lovd_viewNavigation($sNavigation, 6);
    print('          </TD>' . "\n" .
          '          <TD align="right">' . "\n" .
          '            <TABLE border="0" cellpadding="2" cellspacing="0" width="525" class="info" style="font-size : 11px;">' . "\n" .
          '              <TR>' . "\n" .
          '                <TH>About this overview [<A href="#" id="moreinfo_link" onClick="lovd_toggleVisibility(\'moreinfo\'); return false;">Show</A>]</TH>' . "\n" .
          '              <TR id="moreinfo" style="display : none;">' . "\n" .
          '                <TD>' . $sInfoText . '</TD></TR></TABLE></TD></TR></TABLE><BR>' . "\n\n");

    $n = (isset($nResults)? $nResults : $nTotal);
    print('      <SPAN class="S11">' . $n . (substr($_GET['action'], -6) == 'unique' || IS_CURATOR? '' : ' public') . ' entr' . ($n == 1? 'y' : 'ies') . '</SPAN><BR>' . "\n");

    // Stretch it up, cause we're adding data to it...
    if ($aTable[$sMutationCol][1] < 200) {
        $aTable[$sMutationCol][1] = 200;
    }

    // Total width.
    $nTotalWidth = 2;
    $nHiddenColWidth = 5;
    $bPrevHidden = false; // 2009-10-27; 2.0-23; To remember if the previous column was hidden. We now group hidden columns into one.
    foreach ($aTable as $sCol => $aCol) {
        // 2008-02-15; 2.0-04; Hidden columns are smaller!
        if (in_array($sCol, $aHiddenColumns) && $sCol != $sMutationCol) {
            // We don't allow the MutationCol to be hidden!
            // 2009-11-09; 2.0-23; We now group hidden columns into one.
            if (!$bPrevHidden) {
                $nTotalWidth += $nHiddenColWidth + 8;
                $bPrevHidden = true;
            }
        } else {
            $nTotalWidth += $aCol[1] + 8;
            $bPrevHidden = false;
        }
    }



    // Print selection list to choose number of results per page.
    print('      <SPAN class="S11"><SELECT name="limit" class="S11" onchange="document.forms[0].submit();">');
    foreach ($_SETT['variant_listsizes'] as $nSize) {
        print("\n" . 
              '        <OPTION value="' . $nSize . '"' . ($_GET['limit'] == $nSize? ' selected' : '') . '>' . $nSize . '</OPTION>');
    }
    print('</SELECT> entries per page</SPAN><BR>' . "\n\n");

    // Stretch table up, to respect column widths.
    print('      <IMG src="' . ROOT_PATH . 'gfx/trans.png" alt="" width="' . $nTotalWidth . '" height="1"><BR>' . "\n\n");

    // Table.
    print('      <TABLE border="0" cellpadding="0" cellspacing="1" class="data">' . "\n" .
          '        <TR>');

    $bPrevHidden = false; // 2009-10-27; 2.0-23; To remember if the previous column was hidden. We now group hidden columns into one.
    // Print the column headers.
    foreach ($aTable as $sField => $aCol) {
        // 2008-02-15; 2.0-04; Hide columns!
        if (in_array($sField, $aHiddenColumns) && $sField != $sMutationCol) {
            // We don't allow the MutationCol to be hidden!
            // 2009-10-01; 2.0-23; We now group hidden columns into one.
            if (!$bPrevHidden) {
                print("\n" . '          <TH width="' . $nHiddenColWidth . '"><A href="#" onclick="lovd_openWindow(\'views_columns.php?action=' . $_GET['action'] . lovd_showSID(true, true) . '\', \'ShowColumns\', 300, 500);"><IMG src="' . ROOT_PATH . 'gfx/order_arrow_show.png" alt="Unhide specific columns" title="Unhide specific columns" width="5" height="13" border="0"></A></TH>');
                $bPrevHidden = true;
            }
            continue;
        } else {
            $bPrevHidden = false;
        }

        // Location onclick changed because of the search fields within the same <TH>. Clicking on the field triggers a sort.
        print("\n" . '          <TH valign="top"' . (!empty($aCol[2])? ' ' . $aCol[2] : '') . (is_numeric($aCol[1])? ' width="' . $aCol[1] . '"' : '') . (array_key_exists($sField, $aOrderList)? ' class="order' . ($aOrder[0] == $sField? 'ed' : '') . '"' : '') . '>' .
              (array_key_exists($sField, $aOrderList)? "\n" .
                                                           '            <TABLE border="0" cellpadding="0" cellspacing="0" width="100%" class="S11">' . "\n" .
                                                           '              <TR' . (array_key_exists($sField, $aOrderList)? ' onclick="document.forms[0].order.value=\'' . $sField . ',' . ($aOrder[0] == $sField? ($aOrder[1] == 'ASC'? 'DESC' : 'ASC') : $aOrderList[$sField][1]) . '\';document.forms[0].submit();"' : '') . '>' . "\n" .
                                                           '                <TH>' . str_replace(' ', '&nbsp;', $aCol[0]) . '</TH>' . "\n" .
                                                           '                <TD align="right" width="13">' . ($sField == $sMutationCol? '&nbsp;' : '<IMG src="' . ROOT_PATH . 'gfx/order_arrow_hide.png" alt="Hide ' . $aCol[0] . ' column" title="Hide ' . $aCol[0] . ' column" width="11" height="11" onclick="document.forms[0].hide_col.value=\'' . $sField . '\';document.forms[0].submit();" style="margin : 1px;">') . '</TD>' . "\n" .
                                                           '                <TD align="right" width="13"><IMG src="' . ROOT_PATH . 'gfx/order_arrow_desc' . ($aOrder[0] == $sField && $aOrder[1] == 'DESC'? '_sel' : '') . '.png" alt="Descending" title="Descending" width="13" height="6"><BR><IMG src="' . ROOT_PATH . 'gfx/order_arrow_asc' . ($aOrder[0] == $sField && $aOrder[1] == 'ASC'? '_sel' : '') . '.png" alt="Ascending" title="Ascending" width="13" height="6"></TD></TR>' .
                                                           (substr($_GET['action'], 0, 6) == 'search'? "\n" .
                                                                                         '              <TR>' . "\n" .
                                                                                         // 2009-09-22; 2.0-22; #43; Added onkeydown with check for "Enter/Return" key to submit the form anyway like Firefox does, too.
                                                                                         '                <TD colspan="3"><INPUT type="text" name="search_' . $sField . '" value="' . (isset($_GET['search_' . $sField])? htmlspecialchars(stripslashes($_GET['search_' . $sField])) : '') . '" title="' . $aCol[0] . ' field should contain..." style="width : ' . ($aCol[1] - 8) . 'px; font-weight : normal;" onchange="document.forms[0].submit();" onkeydown="if (event.keyCode == 13) { document.forms[0].submit(); }"></TD></TR>' : '') .
                                                           '</TABLE>' : $aCol[0]) . '</TH>');
    }
    print('</TR>');

    $i = 0;
    $nRepeat = 25;
    while ($zData = mysql_fetch_assoc($q)) {
        // Print header repeatedly.
        $i ++;
        if (!($i%($nRepeat+1))) {
            print("\n" .
                  '        <TR>');
            $bPrevHidden = false; // 2009-10-27; 2.0-23; To remember if the previous column was hidden. We now group hidden columns into one.
            // Print the repeated column headers.
            foreach ($aTable as $sField => $aCol) {
                // 2008-02-15; 2.0-04; Hide columns!
                if (in_array($sField, $aHiddenColumns) && $sField != $sMutationCol) {
                    // We don't allow the MutationCol to be hidden!
                    // 2009-10-01; 2.0-23; We now group hidden columns into one.
                    if (!$bPrevHidden) {
                        print("\n" . '          <TH width="' . $nHiddenColWidth . '"><A href="#" onclick="lovd_openWindow(\'views_columns.php?action=' . $_GET['action'] . lovd_showSID(true, true) . '\', \'ShowColumns\', 300, 500);"><IMG src="' . ROOT_PATH . 'gfx/order_arrow_show.png" alt="Unhide specific columns" title="Unhide specific columns" width="5" height="13" border="0"></A></TH>');
                        $bPrevHidden = true;
                    }
                    continue;
                } else {
                   $bPrevHidden = false;
                }

                print("\n" . '          <TH valign="top"' . (!empty($aCol[2])? ' ' . $aCol[2] : '') . (is_numeric($aCol[1])? ' width="' . $aCol[1] . '"' : '') . (array_key_exists($sField, $aOrderList)? ' class="order' . ($aOrder[0] == $sField? 'ed' : '') . '"' : '') . '>' .
                      (array_key_exists($sField, $aOrderList)? "\n" .
                                                                   '            <TABLE border="0" cellpadding="0" cellspacing="0" width="100%" class="S11">' . "\n" .
                                                                   '              <TR' . (array_key_exists($sField, $aOrderList)? ' onclick="document.forms[0].order.value=\'' . $sField . ',' . ($aOrder[0] == $sField? ($aOrder[1] == 'ASC'? 'DESC' : 'ASC') : $aOrderList[$sField][1]) . '\';document.forms[0].submit();"' : '') . '>' . "\n" .
                                                                   '                <TH>' . str_replace(' ', '&nbsp;', $aCol[0]) . '</TH>' . "\n" .
                                                                   '                <TD align="right" width="13">' . ($sField == $sMutationCol? '&nbsp;' : '<IMG src="' . ROOT_PATH . 'gfx/order_arrow_hide.png" alt="Hide ' . $aCol[0] . ' column" title="Hide ' . $aCol[0] . ' column" width="11" height="11" onclick="document.forms[0].hide_col.value=\'' . $sField . '\';document.forms[0].submit();" style="margin : 1px;">') . '</TD>' . "\n" .
                                                                   '                <TD align="right" width="13"><IMG src="' . ROOT_PATH . 'gfx/order_arrow_desc' . ($aOrder[0] == $sField && $aOrder[1] == 'DESC'? '_sel' : '') . '.png" alt="Descending" title="Descending" width="13" height="6"><BR><IMG src="' . ROOT_PATH . 'gfx/order_arrow_asc' . ($aOrder[0] == $sField && $aOrder[1] == 'ASC'? '_sel' : '') . '.png" alt="Ascending" title="Ascending" width="13" height="6"></TD></TR>' .
                                                                   '</TABLE>' : $aCol[0]) . '</TH>');
            }
            print('</TR>');
            $i = 1;
        }

        if (substr($_GET['action'], -6) == 'unique') {
            // Unique list is slightly simpler.
            print("\n" .
                  '        <TR valign="top" style="cursor : pointer; cursor : hand;" onmouseover="this.className = \'hover\';" onmouseout="this.className = \'\';" onclick="window.location.href = \'' . $_SERVER['PHP_SELF'] . '?select_db=' . $_SESSION['currdb'] . '&amp;action=search_all&amp;search_' . rawurlencode($sMutationCol) . '=' . rawurlencode($zData[$sMutationCol]) . lovd_showSID(true, true) . '\';">');
        } else {
            print("\n" .
                  '        <TR valign="top"' . (IS_CURATOR && $zData['status'] < STATUS_OK? ' class="' . ($zData['status'] < STATUS_MARKED? 'del' : 'marked') . '"' : '') . ' style="cursor : pointer; cursor : hand;" onmouseover="this.className = \'' . (IS_CURATOR && $zData['status'] < STATUS_OK? ($zData['status'] < STATUS_MARKED? 'del_' : 'marked_') : '') . 'hover\';" onmouseout="this.className = \'' . (IS_CURATOR && $zData['status'] < STATUS_OK? ($zData['status'] < STATUS_MARKED? 'del' : 'marked') : '') . '\';" onclick="window.location.href = \'' . $_SERVER['PHP_SELF'] . '?select_db=' . $_SESSION['currdb'] . '&amp;action=view&amp;view=' . $zData['patientid'] . '%2C' . $zData['variantid'] . '%2C' . $zData['allele'] . lovd_showSID(true, true) . '\';">');
        }

        // Create normal anchor link as well.
        if (substr($_GET['action'], -6) == 'unique') {
            $sLink = '<A href="' . $_SERVER['PHP_SELF'] . '?select_db=' . $_SESSION['currdb'] . '&amp;action=search_all&amp;search_' . rawurlencode($sMutationCol) . '=' . rawurlencode($zData[$sMutationCol]) . lovd_showSID(true, true) . '" class="data">';
        } else {
            $sLink = '<A href="' . $_SERVER['PHP_SELF'] . '?select_db=' . $_SESSION['currdb'] . '&amp;action=view&amp;view=' . $zData['patientid'] . '%2C' . $zData['variantid'] . '%2C' . $zData['allele'] . lovd_showSID(true, true) . '" class="data"' . ($zData['status'] < STATUS_MARKED? ' style="color : #AAAAAA;"' : '') . '>';
        }
        if ($sMutationCol) {
            $zData[$sMutationCol] = $sLink . $zData[$sMutationCol] . '</A>';
        }

        // Very unlikely not to function; only if none of the HGVS standard DNA, RNA or Protein fields are enabled, this will fail.
        if ($zData['mutations'] > 1) {
            if (substr($_GET['action'], -3) == 'all') {
                // 2008-03-27; 2.0-05; Show only a maximum number of other mutations associated with this patient. Otherwise, hide them all.
                if ($zData['mutations'] > 10) {
                    // Too many to fetch; wouldn't look good.
                    // FIXME; make a setting out of this.
                    $zData[$sMutationCol] .= '<BR>&nbsp;&nbsp;&nbsp;&nbsp;+ ' . ($zData['mutations'] - 1) . ' others';
                } else {
                    // Fetch info on other mutations.
                    // FIXME; this may be quite a performance lag with a high $_GET['limit'] value and lots of associated mutations.
                    // Backwards compatible with MySQL 4.0 and earlier; if we rely on MySQL 4.1, we could do a GROUP_CONCAT in top mutation fetch query that save us these queries.
                    $sQOther = 'SELECT p2v.*, v.`' . $sMutationCol . '` FROM ' . TABLE_PAT2VAR . ' AS p2v LEFT OUTER JOIN ' . TABLE_CURRDB_VARS . ' AS v ON (p2v.symbol = "' . $_SESSION['currdb'] . '" AND v.variantid = p2v.variantid) WHERE ' . (IS_CURATOR? '' : 'p2v.status >= ' . STATUS_MARKED . ' AND ') . 'p2v.patientid = "' . $zData['patientid'] . '" AND !(p2v.symbol = "' . $_SESSION['currdb'] . '" AND p2v.variantid = "' . $zData['variantid'] . '" AND p2v.allele = "' . $zData['allele'] . '") ORDER BY v.sort ASC';

                    $qOther = mysql_query($sQOther);
                    $sOther = '';
                    $aOther = array();

                    // Loop other variants found in the same patient.
                    while ($zOther = mysql_fetch_assoc($qOther)) {
                        if ($zOther['symbol'] == $_SESSION['currdb']) {
                            // Other variant in same gene.
                            $sOther .= ($sOther? ', ' : '') . $zOther[$sMutationCol];
                        } else {
                            // Other variant in different gene.
                            if (!isset($aOther[$zOther['symbol']])) {
                                $aOther[$zOther['symbol']] = 0;
                            }
                            $aOther[$zOther['symbol']] ++;
                        }
                    }

                    if (count($aOther)) {
                        foreach ($aOther as $sGene => $nOther) {
                            $sOther .= ($sOther? ', ' : '') . $sGene . ' (' . $nOther . ')';
                        }
                    }

                    $zData[$sMutationCol] .= '<BR>&nbsp;&nbsp;&nbsp;&nbsp;+ ' . $sOther;
                }

            } else {
                // Unique variant list, found more than once.
                $zData[$sMutationCol] .= '<BR>&nbsp;&nbsp;(Reported ' . $zData['mutations'] . ' times)';
            }
        }

        // Parse and build Custom Links.
        lovd_buildLinks($zData);

        // Transform select lists' values.
        $_CURRDB->transformSelectValues($zData);

        // FIXME;
        // Shorten strings for TEXT that surely doesn't contain HTML tags... HOW?

        // Submitter reference...
        if ($_CURRDB->colExists('Patient/Reference') && $zData['subs_reference']) {
            // 2008-03-28; 2.0-05; Show full submitter information directly from this link.
            $zData['Patient/Reference'] .= (!empty($zData['Patient/Reference'])? ', ' : '') . '<A href="#" onclick="lovd_openWindow(\'' . ROOT_PATH . 'submitters.php?action=view&amp;view=' . $zData['submitterid'] . lovd_showSID(true, true) . '\', \'SubmitterView\', 400, 175, event.screenX - 50, event.screenY - 50); return false;">' . $zData['subs_reference'] . '</A>';
        }

        // SubmitterID, don't show the '00000' entries.
        if (array_key_exists('submitterid', $aTable) && (int) $zData['submitterid'] == 0) {
            $zData['submitterid'] = 0;
        }

        $bPrevHidden = false; // 2009-10-27; 2.0-23; To remember if the previous column was hidden. We now group hidden columns into one.
        // Print the data.
        foreach ($aTable as $sField => $aCol) {
            // 2008-02-15; 2.0-04; Hidden columns are smaller!
            if (in_array($sField, $aHiddenColumns) && $sField != $sMutationCol) {
                // We don't allow the MutationCol to be hidden!
                // 2009-10-01; 2.0-23; We now group hidden columns into one.
                if (!$bPrevHidden) {
                    print("\n" . '          <TD width="' . $nHiddenColWidth . '">&nbsp;</TD>');
                    $bPrevHidden = true;
                }
                continue;
            } else {
               $bPrevHidden = false;
            }
            print("\n" . '          <TD' . (!empty($aCol[2])? ' ' . $aCol[2] : '') . (is_numeric($aCol[1])? ' width="' . $aCol[1] . '"' : '') . ($aOrder[0] == $sField? ' class="ordered"' : '') . '>' . (!$zData[$sField]? '-' : $zData[$sField]) . '</TD>');
        }
        print('</TR>');
    }
    print('</TABLE>' . "\n" .
          '</FORM>' . "\n\n");



    // URL pagelink.
    $sPageLink = 'order=' . rawurlencode(implode(',', $aOrder));

    // 2009-10-29; 2.0-23; Added $_GET['view'] to $sPageLink to stay in a variants type overview when coming from variant_statistics.php.
    if (isset($_GET['view'])) {
        $sPageLink .= '&amp;view=' . $_GET['view'];
    }

    // 2009-04-23; 2.0-19; by Gerard: added link(s) for the searched column(s)
    $sSearchLink = '';
    if (substr($_GET['action'], 0, 6) == 'search') {
        // SEARCH: Simple text search.
        foreach ($aSearchText as $key => $val) {
            if (isset($_GET[$key]) && $_GET[$key]) {
                // 2009-04-23; 2.0-18; Added stripslashes to allow search terms to include quotes.
                $sSearchLink .= '&amp;' . $key . '=' . rawurlencode(stripslashes($_GET[$key]));
            }
        }
    }

    $sPageLink .= $sSearchLink;
    lovd_pagesplitShowNav($sPageLink);

    if ($_SETT['currdb']['allow_download'] || IS_CURATOR) {
        lovd_showInfoTable('Click here to save this list in a tab-delimited text file.', 'save', '500', 'download.php?select_db=' . $_SESSION['currdb'] . '&amp;action=' . $_GET['action'] . '&amp;' . $sPageLink . '');
    }

    // 2009-04-23; 2.0-19; by Gerard, link to config_free_edit.php added for Free edit functionality
    // Should only be available for curators or higher.
    if (substr($_GET['action'], 0, 6) == 'search' && IS_CURATOR) {
        // "Find & replace" and "Copy column" buttons.
        print('            <TABLE border="0" cellpadding="2" cellspacing="0" class="setup" width="500">' . "\n" .
              '              <TR>' . "\n" .
              '                <TD colspan="2"><B>Apply advanced edit features on these search results:</B></TD></TR>' . "\n" .
              '              <TR class="setup" onclick="window.location.href=\'' . ROOT_PATH . 'config_free_edit.php?action=fnr' . $sSearchLink . lovd_showSID(true, true) . '\';">' . "\n" .
              '                <TD align="center" width="40"><IMG src="' . ROOT_PATH . 'gfx/lovd_free_edit_fnr.png" alt="Find & Replace" width="32" height="32"></TD>' . "\n" .
              '                <TD>Find &amp; Replace: Find a certain value in a specific column and replace it with a different value.</TD></TR>' . "\n" .
              '              <TR class="setup" onclick="window.location.href=\'' . ROOT_PATH . 'config_free_edit.php?action=copy' . $sSearchLink . lovd_showSID(true, true) . '\';">' . "\n" .
              '                <TD align="center" width="40"><IMG src="' . ROOT_PATH . 'gfx/lovd_free_edit_copy.png" alt="Copy column" width="32" height="32"></TD>' . "\n" .
              '                <TD>Copy column: Copy or move certain values from one specific column to another.</TD></TR></TABLE><BR>' . "\n");
    }

    // Notes for the variant listings...
    if ($_SETT['currdb']['note_listing']) {
        print(str_replace(array("\r\n", "\r", "\n"), '<BR>', $_SETT['currdb']['note_listing']) . '<BR><BR>' . "\n\n");
    }

    // Short legend...
    print('      <SPAN class="S15"><B>Legend:</B></SPAN> [ <A href="variants_legend.php?select_db=' . $_SESSION['currdb'] . '" target="_blank">' . $_SESSION['currdb'] . ' full legend</A> ]<BR>' . "\n\n" .
          '      <SPAN class="S11">' . "\n" .
          '        Sequence variations are described basically as recommended by the Ad-Hoc Committee for Mutation Nomenclature (AHCMN), with the recently suggested additions (den Dunnen JT and Antonarakis SE [2000], Hum.Mut. 15:7-12); for a summary see <A href="http://www.HGVS.org/mutnomen/"><B>Nomenclature</B></A>.' . "\n" .
          '        ' . ($_SETT['currdb']['refseq']? '<A href="' . $_SETT['currdb']['refseq_url'] . '">' . ($_SETT['currdb']['refseq'] == 'c'? 'Coding DNA ' : ($_SETT['currdb']['refseq'] == 'g'? 'Genomic ' : '')) . 'Reference Sequence</A>' . ($_SETT['currdb']['refseq'] == 'c'? ', with the first base of the Met-codon counted as position 1' : '') . '.' : '') . '<BR>' . "\n" .
          '        ' . (substr($_GET['action'], -6) == 'unique'? '' : '<B>Path.</B>: Variant pathogenicity, in the format Reported/Concluded; \'+\' indicating the variant is pathogenic, \'+?\' probably pathogenic, \'-\' no known pathogenicity, \'-?\' probably no pathogenicity, \'?\' effect unknown. ') . $_CURRDB->buildLegend('short') .
          (substr($_GET['action'], -3) == 'all' && IS_CURATOR? ' <B>Status</B>: Status of this variant entry.' : '') .
          '</SPAN><BR><BR>' . "\n\n");

    lovd_printGeneFooter();
    require ROOT_PATH . 'inc-bot.php';
    exit;





} elseif ($_GET['action'] == 'view' && ((preg_match('/^([0-9]{1,7})\,([0-9]{1,7})(\,([0-9]{1,2}))?$/', $_GET['view'], $aRegs) && list(, $_GET['patientid'], $_GET['variantid']) = $aRegs) || (preg_match('/^([0-9]{1,7})$/', $_GET['view'], $aRegs) && list(, $_GET['patientid']) = $aRegs))) {
    // View specific patient/mutation.

    // 2010-03-11; 2.0-25; Largely redone; IS_CURATOR and $bEditable are now determined at the same time, because we need to know the difference between them sooner.
    // Also split the rights on patient and variants, and fixed *several* problems with the rights of curators.
    // Also, because having both constants (IS_CURATOR) and variables ($bEditable) for the same thing is illogical, renamed them all to variables.
    // IS_CURATOR -> $bAuthPat/$bAuthVar; $bEditable -> $bEditablePat/$bEditableVar.
    // Whether or not a user can see non-public data && check if user is allowed to edit patients/assign submitters, or edit/delete variants.
    if (HAS_SUBS) {
        // Submitters: if the patient is theirs, they can see all data of the patient and of the containing variants.
        // When "My Submissions" has been enabled, they can edit all data as well. They can't change the submitter related to the patient, though.
        $bAuthPat = $bAuthVar = (bool) mysql_num_rows(mysql_query('SELECT p.submitterid FROM ' . TABLE_PATIENTS . ' AS p WHERE p.patientid = "' . $_GET['patientid'] . '" AND p.submitterid = "' . $_SUBS['submitterid'] . '"'));
        $bEditablePat = $bEditableVar = ($_CONF['my_submissions'] && $bAuthPat);
    } elseif (HAS_AUTH) {
        if ($_AUTH['level'] >= LEVEL_MANAGER) {
            $bAuthPat = $bEditablePat = $bAuthVar = $bEditableVar = true;
        } else {
            // 2010-03-11; 2.0-25; Oops... Curators could just select their gene and view all hidden data of any patient... Don't use $_SESSION['currdb']!!!
            // Curators can see hidden data of patient when they own *any* of the genes associated with the patient.
            $bAuthPat = (bool) mysql_num_rows(mysql_query('SELECT symbol FROM ' . TABLE_PAT2VAR . ' WHERE patientid = "' . $_GET['patientid'] . '" AND symbol IN ("' . implode('", "', $_AUTH['curates']) . '") GROUP BY symbol'));
            // But curators can only edit the patient when they own *all* of the genes associated with the patient.
            $bEditablePat = !mysql_num_rows(mysql_query('SELECT symbol FROM ' . TABLE_PAT2VAR . ' WHERE patientid = "' . $_GET['patientid'] . '" AND symbol NOT IN ("' . implode('", "', $_AUTH['curates']) . '") GROUP BY symbol'));
            $bAuthVar = $bEditableVar = lovd_isCurator($_SESSION['currdb']);
        }
    } else {
        $bAuthPat = $bEditablePat = $bAuthVar = $bEditableVar = false;
    }

    // If given, allele.
    if (isset($aRegs[4])) {
        $_GET['allele'] = $aRegs[4];
    }

    // 2009-11-09; 2.0-23; Hide hidden columns in this overview, too.
    if (isset($_COOKIE[$_SETT['cookie_id'] . '_hidden_cols'])) {
        $aHiddenColumns = preg_split('/[;,]+/', $_COOKIE[$_SETT['cookie_id'] . '_hidden_cols']); // Support both , and ; as a separator for backwards compatibility to LOVD 2.0-22 and before.
    } else {
        $aHiddenColumns = array();
    }

    require ROOT_PATH . 'class/currdb.php';
    $_CURRDB = new CurrDB();
    $_CURRDB->hideCols('public', $bAuthPat);
    require ROOT_PATH . 'inc-top.php';
    lovd_printGeneHeader();
    lovd_printHeader('variant_listings', 'LOVD - Variant listings for ' . $_SESSION['currdb']);

    // 2009-11-27; 2.0-23; Added information table that explains the current view.
    lovd_includeJS(ROOT_PATH . 'inc-js-toggle-visibility.js');
    $sInfoText = 'This detailed view shows all details of the selected patient, including all variants reported in this patient. At the bottom of the page, all variants reported in this patient are listed, with the one you are looking at in bold. The link to the UCSC Genome Browser will show the browser zoomed in to the location of the selected variant.' . (!$bAuthPat? '' : '<BR>Below the patient data table and the selected variant\'s data table, links are provided for authorized users to edit or delete entries, or to add new data.');
    print('      <TABLE border="0" cellpadding="2" cellspacing="0" width="600" class="info" style="font-size : 11px;">' . "\n" .
          '        <TR>' . "\n" .
          '          <TH>About this overview [<A href="#" id="moreinfo_link" onClick="lovd_toggleVisibility(\'moreinfo\'); return false;">Show</A>]</TH>' . "\n" .
          '          <TR id="moreinfo" style="display : none;">' . "\n" .
          '            <TD>' . $sInfoText . '</TD></TR></TABLE><BR>' . "\n\n");

    if (!empty($_GET['variantid'])) {
        // Fetch patient data, patient must be associated with mentioned variantid.
        $zData = @mysql_fetch_assoc(mysql_query('SELECT p.*, p2v.status, p2v.variantid, CONCAT(s.firstname, " ", s.lastname) AS submitterid_, s.reference AS subs_reference FROM ' . TABLE_PATIENTS . ' AS p LEFT JOIN ' . TABLE_PAT2VAR . ' AS p2v ON (p.patientid = p2v.patientid) LEFT OUTER JOIN ' . TABLE_SUBS . ' AS s ON (p.submitterid = s.submitterid) WHERE p2v.symbol = "' . $_SESSION['currdb'] . '" AND p2v.variantid = "' . $_GET['variantid'] . '" AND p.patientid = "' . $_GET['patientid'] . '"' . ($bAuthVar? '' : ' AND p2v.status >= "' . STATUS_MARKED . '"')));
    } else {
        // 2007-08-09; 2.0-beta-07; View patient information without considering any variants is now possible.
        // 2010-04-12; 2.0-26; But of course, patients are only public if any of the containing variants is public!!!
        $zData = @mysql_fetch_assoc(mysql_query('SELECT p.*, CONCAT(s.firstname, " ", s.lastname) AS submitterid_, s.reference AS subs_reference FROM ' . TABLE_PATIENTS . ' AS p LEFT JOIN ' . TABLE_PAT2VAR . ' AS p2v ON (p.patientid = p2v.patientid) LEFT OUTER JOIN ' . TABLE_SUBS . ' AS s ON (p.submitterid = s.submitterid) WHERE p.patientid = "' . $_GET['patientid'] . '"' . ($bAuthPat? '' : ' AND p2v.status >= "' . STATUS_MARKED . '"')));
    }

    if (!$zData) {
        // Wrong ID, apparently.
        lovd_showInfoTable('No such ID!', 'stop');
        lovd_printGeneFooter();
        require ROOT_PATH . 'inc-bot.php';
        exit;
    }

    // 2008-10-01; 2.0-13; Show "Unhide all columns" button.
    if (count($aHiddenColumns) && !isset($_GET['show_all_cols'])) {
        lovd_showInfoTable('Columns that you normally have hidden from view, will not be displayed here, either. Do you wish to <A href="' . $_SERVER['PHP_SELF'] . '?select_db=' . $_SESSION['currdb'] . '&amp;action=view&amp;view=' . rawurlencode($_GET['view']) . '&amp;show_all_cols">show all fields</A>?<BR><I>This will not influence your configured display settings.</I>', 'warning', 600);
    }

    // Array which will make up the table (header and data).
    $aTable = $_CURRDB->buildTable('detail');

    // Submitter column.
    if ($zData['submitterid_'] || $bAuthPat) {
        $aTable = array_merge(
                $aTable,
                 array(
                        'submitterid_' => 'Submitter',
                      ));
    }

    // Additional columns for authorized users.
    if ($bAuthPat) {
        $aTable = array_merge(
                $aTable,
                 array(
                        'created_by' => 'Created by',
                        'created_date' => 'Date created',
                        'edited_by' => 'Edited by',
                        'edited_date' => 'Date edited',
                      ));

        // Remove unnecessary columns.
        if ($zData['edited_by'] == NULL) {
            // Never been edited.
            unset($aTable['edited_by'], $aTable['edited_date']);
        }
    }

    // Table.
    print('      <TABLE border="0" cellpadding="0" cellspacing="1" width="600" class="gene">');

    // Patient table header.
    print("\n" .
          '        <TR>' . "\n" .
          '          <TH colspan="2" class="S15">Patient data (#' . $zData['patientid'] . ')</TH>');

    // Parse and build Custom Links.
    lovd_buildLinks($zData);

    // Transform select lists' values.
    $_CURRDB->transformSelectValues($zData);

    // Submitter reference...
    if ($zData['subs_reference'] && $_CURRDB->colExists('Patient/Reference')) {
        // 2008-03-28; 2.0-05; Show full submitter information directly from this link.
        $zData['Patient/Reference'] .= (!empty($zData['Patient/Reference'])? ', ' : '') . '<A href="#" onclick="lovd_openWindow(\'' . ROOT_PATH . 'submitters.php?action=view&amp;view=' . $zData['submitterid'] . lovd_showSID(true, true) . '\', \'SubmitterView\', 400, 175, event.screenX - 50, event.screenY - 50); return false;">' . $zData['subs_reference'] . '</A>';
    }

    // 2007-08-17; 2.0-beta-07; Add link to assign submitter to this patient.
    // 2008-10-02; 2.0-13; Remove this link for submitters; they have no use for it.
    // 2010-03-12; 2.0-25; Also curators sometimes don't have use for it, therefore use $bEditablePat. You must be able to *edit* the patient to see this link.
    if (HAS_AUTH && $bEditablePat) {
        $zData['submitterid_'] .= ' (<A href="#" onclick="lovd_openWindow(\'' . ROOT_PATH . 'submit_patients.php?action=assign_submitter&amp;patientid=' . $zData['patientid'] . lovd_showSID(true, true) . '\', \'AssignSubmitter\', 700, 150); return false;">' . (!(int) $zData['submitterid']? 'Assign' : 'Change') . '</A>)';
    }

    // Additional columns for authorized users.
    if ($bAuthPat) {
        // Not very efficient, but I'm thinking mostly this page is viewed by
        // non-curators, so incorporating these into the main query is not very
        // efficient, either.
        if ($zData['created_by']) {
            list($sCreatedBy) = mysql_fetch_row(mysql_query('SELECT name FROM ' . TABLE_USERS . ' WHERE userid = "' . $zData['created_by'] . '"'));
            $zData['created_by'] = $sCreatedBy;
        } else {
            $zData['created_by'] = 'Submitter';
        }
        
        if (isset($aTable['edited_by'])) {
            if ($zData['edited_by']) {
                list($sEditedBy) = mysql_fetch_row(mysql_query('SELECT name FROM ' . TABLE_USERS . ' WHERE userid = "' . $zData['edited_by'] . '"'));
                $zData['edited_by'] = $sEditedBy;
            } else {
                $zData['edited_by'] = 'Submitter';
            }
        }
    }

    foreach ($aTable as $sField => $sHeader) {
        // 2009-11-03; 2.0-23; Also hide columns here, unless overridden. The rtrim($sField, '_') is to make sure 'submitterid_' is handled like 'submitterid'.
        if (substr($sField, 0, 8) == 'Variant/' || (in_array(rtrim($sField, '_'), $aHiddenColumns) && !isset($_GET['show_all_cols']))) {
            continue;
        }

        // Textarea's can be anywhere...
        $zData[$sField] = str_replace(array("\r\n", "\r", "\n"), '<BR>', $zData[$sField]);

        print("\n" .
              '        <TR>' . "\n" .
              '          <TH valign="top">' . str_replace(' ', '&nbsp;', $sHeader) . '</TH>' . "\n" .
              '          <TD>' . (!$zData[$sField]? '-' : $zData[$sField]) . '</TD></TR>');
    }
    print('</TABLE>' . "\n\n");

    $sNavigation = '';
    $nSubmitterID = $zData['submitterid'];
    // 2010-03-12; 2.0-25; Only curators with actual rights on the patient can add variants to it this way!!! (through submit.php it's possible)
    if ($bAuthPat) {
        // Curator, or owning submitter.
        $sNavigation .= '<A href="submit.php?action=submit&amp;add_pat=' . $zData['patientid'] . '">Add new variant to patient</A>';

        if ($bEditablePat) {
            // Authorized user (admin, manager or curator with rights) is logged in. Provide tools.
            $sNavigation .= ($sNavigation? ' | ' : '') . '<A href="submit_patients.php?action=edit&amp;edit=' . $zData['patientid'] . '">Edit patient</A>';
            if (HAS_AUTH) {
                // Just for the allowed curators and up, not for submitters.
                $sNavigation .= ' | <A href="submit_patients.php?action=drop&amp;drop=' . $zData['patientid'] . '">Delete complete submission</A>';
            }
        } else {
            $sNavigation .= ($sNavigation? ' | ' : '') . '<B style="color : #CCCCCC;">Edit patient</B>';
            if (HAS_AUTH) {
                // Just for the allowed curators and up, not for submitters.
                $sNavigation .= ' | <B style="color : #CCCCCC;">Delete complete submission</B>';
            }
        }
    }

    if ($sNavigation) {
        print('      <IMG src="gfx/trans.png" alt="" width="1" height="5"><BR>' . "\n");
        lovd_viewNavigation($sNavigation);
    }

    print('      <BR>' . "\n\n");

    // 2008-05-30; 2.0-07; Add agree to submitter's changes option.
    // 2009-04-06; 2.0-17; Added HAS_AUTH prerequisite.
    // 2010-03-12; 2.0-25; Not for curators who can't edit this patient!
    if (HAS_AUTH && $bEditablePat && $zData['edited_by'] == 'Submitter') {
        lovd_showInfoTable('This patient entry has last been edited by a submitter. If you agree to the changes, please click here to clear this message.', 'question', 600, 'submit_patients.php?action=edit&amp;edit=' . $zData['patientid'] . '&amp;agree=true');
    }





    if (!empty($_GET['variantid'])) {
        // Fetch variant data, variant must be associated with mentioned patientid and, if given, the allele must match.
        $zData = @mysql_fetch_assoc(mysql_query('SELECT v.*, p2v.* FROM ' . TABLE_CURRDB_VARS . ' AS v LEFT JOIN ' . TABLE_PAT2VAR . ' AS p2v ON (v.variantid = p2v.variantid) WHERE p2v.symbol = "' . $_SESSION['currdb'] . '" AND v.variantid = "' . $_GET['variantid'] . '" AND p2v.patientid = "' . $_GET['patientid'] . '"' . (empty($_GET['allele'])? '' : ' AND p2v.allele = "' . $_GET['allele'] . '"') . ($bAuthVar? '' : ' AND p2v.status >= "' . STATUS_MARKED . '"')));
        if (!$zData) {
            // Wrong ID, apparently.
            lovd_showInfoTable('No such ID!', 'stop');
            lovd_printGeneFooter();
            require ROOT_PATH . 'inc-bot.php';
            exit;
        }

        // Array which will make up the table (header and data).
        $aTable = $_CURRDB->buildTable('detail');

        // Additional columns for authorized users.
        if ($bAuthVar) {
            $aTable = array_merge(
                    $aTable,
                     array(
                            'status_' => 'Status',
                            'created_by' => 'Created by',
                            'created_date' => 'Date created',
                            'edited_by' => 'Edited by',
                            'edited_date' => 'Date edited',
                          ));

            // Remove unnecessary columns.
            if ($zData['edited_by'] == NULL) {
                // Never been edited.
                unset($aTable['edited_by'], $aTable['edited_date']);
            }
        }

        // Additional columns.
        $aTable = array_merge(
                 array(
                        'allele_' => 'Allele',
                        'pathogenic_reported' => 'Reported pathogenicity',
                        'pathogenic_concluded' => 'Concluded pathogenicity',
                      ),
                $aTable);

        // Table.
        print('      <TABLE border="0" cellpadding="0" cellspacing="1" width="600" class="gene">');

        // Variant table header.
        print("\n" .
              '        <TR>' . "\n" .
              '          <TH colspan="2" class="S15">Variant data</TH>');

        // Parse and build Custom Links.
        lovd_buildLinks($zData);

        // Transform select lists' values.
        $_CURRDB->transformSelectValues($zData);

        // Additional columns for authorized users.
        if ($bAuthVar) {
            $zData['status_'] = $_SETT['var_status'][$zData['status']];

            // Not very efficient, but I'm thinking mostly this page is viewed by
            // non-curators, so incorporating these into the main query is not very
            // efficient, either.
            if ($zData['created_by']) {
                list($sCreatedBy) = mysql_fetch_row(mysql_query('SELECT name FROM ' . TABLE_USERS . ' WHERE userid = "' . $zData['created_by'] . '"'));
                $zData['created_by'] = $sCreatedBy;
            } else {
                $zData['created_by'] = 'Submitter';
            }

            // 2008-12-04; 2.0-15; Added this if statement to prevent false positive "Variant entry last edited by a submitter" messages.
            if (isset($aTable['edited_by'])) {
                if ($zData['edited_by']) {
                    list($sEditedBy) = mysql_fetch_row(mysql_query('SELECT name FROM ' . TABLE_USERS . ' WHERE userid = "' . $zData['edited_by'] . '"'));
                    $zData['edited_by'] = $sEditedBy;
                } else {
                    $zData['edited_by'] = 'Submitter';
                }
            }
        }

        $zData['allele_'] = $_SETT['var_allele'][$zData['allele']];
        $zData['pathogenic_reported'] = $_SETT['var_pathogenic'][$zData['pathogenic']{0}];
        $zData['pathogenic_concluded'] = $_SETT['var_pathogenic'][$zData['pathogenic']{1}];

        // For pathogenicity, we'll have to add a trick.
        if (in_array('pathogenic_', $aHiddenColumns)) {
            $aHiddenColumns[] = 'pathogenic_reported';
            $aHiddenColumns[] = 'pathogenic_concluded';
        }

        if ($zData['g_position_start']) {
            // 2009-12-02; 2.0-23; Added link to UCSC Genome Browser.
            $sChromosome = preg_replace('/^([0-9]+|[XY])[pq0-9.-]+$/', "$1", $_SETT['currdb']['chrom_location']);  // That regexp is not completely correct (not limiting enough), but we don't need that anyway.
            $lVariant = abs($zData['g_position_end'] - $zData['g_position_start']);
            $lMargin = ($lVariant > 20? 5 : round((30 - $lVariant)/2));
            // 2010-01-20; 2.0-24; The UCSC can't handle BED files through SSL! So BED files will be delivered without SSL.
            $zData['Variant/DNA'] .= ' &nbsp; <SPAN class="S11">(<A href="http://genome.ucsc.edu/cgi-bin/hgTracks?clade=mammal&amp;org=Human&amp;db=' . $_SETT['currdb']['refseq_build'] . '&amp;position=chr' . $sChromosome . ':' . ($zData['g_position_start'] - $lMargin) . '-' . ($zData['g_position_end'] + $lMargin) . '&amp;width=800&amp;ruler=full&amp;ccdsGene=full&amp;hgt.customText=' . rawurlencode(($_CONF['location_url']? str_replace('https://', 'http://', $_CONF['location_url']) : 'http://' . $_SERVER['HTTP_HOST'] . lovd_cleanDirName(dirname($_SERVER['SCRIPT_NAME']) . '/' . ROOT_PATH)) . 'api/rest.php/variants/' . $_SESSION['currdb'] . '?format=text/bed') . '" target="_blank">View in UCSC Genome Browser</A>)</SPAN>';
        }

        foreach ($aTable as $sField => $sHeader) {
            // 2009-11-03; 2.0-23; Also hide columns here, unless overridden.
            if (substr($sField, 0, 8) == 'Patient/' || (in_array($sField, $aHiddenColumns) && !isset($_GET['show_all_cols']))) {
                continue;
            }

            // Textarea's can be anywhere...
            $zData[$sField] = str_replace(array("\r\n", "\r", "\n"), '<BR>', $zData[$sField]);

            print("\n" .
                  '        <TR>' . "\n" .
                  '          <TH valign="top">' . str_replace(' ', '&nbsp;', $sHeader) . '</TH>' . "\n" .
                  '          <TD>' . (!$zData[$sField]? '-' : $zData[$sField]) . '</TD></TR>');
        }
        print('</TABLE>' . "\n\n");

        $sNavigation = '';
        if ($bAuthVar) {
            // Authorized user (admin, manager or curator with rights on this gene) is logged in. Provide tools.
            // 2008-04-22; 2.0-06; Submitters can now also edit variants when My Submissions is activated.
            // 2010-03-12; 2.0-25; Optimize this with the new variable names.
            if ($bEditableVar) {
                if (HAS_AUTH && $zData['status'] < 9) {
                    $sNavigation = '<A href="submit_variants.php?select_db=' . $_SESSION['currdb'] . '&amp;action=edit&amp;edit=' . $zData['patientid'] . '%2C' . $zData['variantid'] . '%2C' . $zData['allele'] . '&amp;curate=true">Curate variant</A>';
                } else {
                    $sNavigation = '<A style="color : #CCCCCC;">Curate variant</A>';
                }
                $sNavigation .= ($sNavigation? ' | ' : '') . '<A href="submit_variants.php?select_db=' . $_SESSION['currdb'] . '&amp;action=edit&amp;edit=' . $zData['patientid'] . '%2C' . $zData['variantid'] . '%2C' . $zData['allele'] . '">Edit variant</A>';
                if (HAS_AUTH) {
                    $sNavigation .= ' | <A href="submit_variants.php?select_db=' . $_SESSION['currdb'] . '&amp;action=drop&amp;drop=' . $zData['patientid'] . '%2C' . $zData['variantid'] . '%2C' . $zData['allele'] . '">Delete variant from submission</A>';
                }
            } else {
                $sNavigation = '<A style="color : #CCCCCC;">Curate variant</A> | <B style="color : #CCCCCC;">Edit variant</B>';
            }
        }

        if ($sNavigation) {
            print('      <IMG src="gfx/trans.png" alt="" width="1" height="5"><BR>' . "\n");
            lovd_viewNavigation($sNavigation);
        }

        print('      <BR>' . "\n\n");

        // 2008-10-16; 2.0-13; Add agree to submitter's changes option.
        // 2009-04-06; 2.0-17; Added HAS_AUTH prerequisite.
        // 2010-03-12; 2.0-25; Not for curators who can't edit this variant!
        if (HAS_AUTH && $bEditableVar && $zData['edited_by'] == 'Submitter') {
            lovd_showInfoTable('This variant entry has last been edited by a submitter. If you agree to the changes, please click here to clear this message.', 'question', 600, 'submit_variants.php?select_db=' . $_SESSION['currdb'] . '&amp;action=edit&amp;edit=' . $zData['patientid'] . '%2C' . $zData['variantid'] . '%2C' . $zData['allele'] . '&amp;agree=true');
        }
    }





    // On a per-gene basis, we'll list the different mutations found.
    // The tables don't have to be union compatible, so UNION is just not an option.
    $aCURRDBs = array($_SESSION['currdb'] => & $_CURRDB);

    // Get list of genes.
    // 2010-03-12; 2.0-25; Used $bAuthPat here, but that means possible variants are shown that are not supposed to be shown. I will filter those out later, but it may generate a header without data.
    $qGenes = mysql_query('SELECT DISTINCT symbol FROM ' . TABLE_PAT2VAR . ' WHERE patientid = "' . $_GET['patientid'] . '"' . ($bAuthPat? '' : ' AND status >= ' . STATUS_MARKED) . ' ORDER BY symbol');
    while (list($sSymbol) = mysql_fetch_row($qGenes)) {
        // Per gene... list variants.

        // 2010-03-15; 2.0-25; Reset authorization rules.
        $bAuthVar = (lovd_isCurator($sSymbol) || (HAS_SUBS && $bAuthPat));
        $bEditableVar = ((HAS_SUBS && $bAuthVar && $_CONF['my_submissions']) || (HAS_AUTH && $bAuthVar));

        // We need to have the CURRDB object.
        if (!isset($aCURRDBs[$sSymbol])) {
            $aCURRDBs[$sSymbol] = new CurrDB(true, $sSymbol);
            // 2010-03-12; 2.0-25; Submitters who own the patient should also see all columns!
            $aCURRDBs[$sSymbol]->hideCols('public', $bAuthVar);
        }

        // Guess the column used to describe the mutation.
        $sMutationCol = $_CURRDB->getMutationCol();

        // Standard query, will be extended later on.
        // 2010-03-12; 2.0-25; Don't allow curators of other genes to see hidden entries for this patient!!!
        $sQ = 'SELECT p2v.symbol, p2v.patientid, p2v.pathogenic, p2v.allele, v.*, p2v.status FROM ' . TABLEPREFIX . '_' . $sSymbol . '_variants AS v LEFT JOIN ' . TABLE_PAT2VAR . ' AS p2v ON (v.variantid = p2v.variantid) WHERE p2v.patientid = "' . $_GET['patientid'] . '" AND p2v.symbol = "' . $sSymbol . '"' . ($bAuthVar? '' : ' AND p2v.status >= ' . STATUS_MARKED);

        // SORT: Current settings.
        if (isset($_GET['order']) && $_GET['order']) {
            $aOrder = explode(',', $_GET['order']);
        } else {
            $aOrder = array('', '');
        }

        // SORT: Column data.
        $aOrderList = array_merge(
                 array('sort' => array('v.sort', 'ASC')),
                 $aCURRDBs[$sSymbol]->buildOrderList());
        if ($bAuthVar) {
            // Add status.
            $aOrderList['status'] = array('p2v.status', 'ASC');
        }
        if (!array_key_exists($aOrder[0], $aOrderList)) {
            // 2007-10-19; 2.0-01; Changed default sorting column from Exon to Variant/DNA.
            $aOrder[0] = $sMutationCol;
        }
        if ($aOrder[1] != 'ASC' && $aOrder[1] != 'DESC') {
            $aOrder[1] = $aOrderList[$aOrder[0]][1];
        }

        // 2007-10-19; 2.0-01; Fixed bug #18 - Variants do not sort correctly when selecting DNA column to sort on.
        // 2009-06-12; 2.0-19; Changed again, since the sort column now also contains the Exon information.
        // SORT: Additional sort columns (faking a perfect sort).
        $sOrderPre = '';
        $sOrderPost = '';
        if ($aOrder[0] == 'Variant/DNA') {
            // 1) In case of the mutation column, sort FIRST on sort.
            $sOrderPre .= 'v.sort ' . $aOrder[1] . ', ';
        } else {
            // 2) In case of anything else, sort on sort AFTER.
            $sOrderPost .= ', v.sort ' . $aOrder[1];
        }

        $sQ .= ' ORDER BY ' . $sOrderPre . $aOrderList[$aOrder[0]][0] . ' ' . $aOrder[1] . $sOrderPost;



// FIXME; move up? document.forms[0], right?
        // Show form; required for sorting and searching.
        print('      <FORM action="' . $_SERVER['PHP_SELF'] . '" method="get" style="margin : 0px;">' . "\n" .
              '        <INPUT type="hidden" name="select_db" value="' . $_SESSION['currdb'] . '">' . "\n" .
              '        <INPUT type="hidden" name="action" value="' . $_GET['action'] . '">' . "\n" .
              '        <INPUT type="hidden" name="view" value="' . $_GET['view'] . '">' . "\n" .
              '        <INPUT type="hidden" name="order" value="' . implode(',', $aOrder) . '">' . "\n\n");

        $q = mysql_query($sQ);
        if (!$q) {
            lovd_dbFout('Variants' . ucfirst($_GET['action']), $sQ, mysql_error());
        }

        $n = mysql_num_rows($q);
        print('      <SPAN class="S13"><B>' . $n . ' entr' . ($n == 1? 'y' : 'ies') . ' in ' . $sSymbol . '</B></SPAN><BR>' . "\n");

        // Array which will make up the table (header and data).
        $aTable = $aCURRDBs[$sSymbol]->buildTable('list');

        // Guess the column used to describe the mutation.
        $sMutationCol = $aCURRDBs[$sSymbol]->getMutationCol();

        // Unset patient columns...
        foreach ($aTable as $sCol => $val) {
            if (substr($sCol, 0, 8) == 'Patient/') {
                unset($aTable[$sCol]);
            }
        }

        // Additional columns for authorized users.
        if ($bAuthVar) {
            $aTable['status'] = array('Status', 75);
        }

        // Additional columns.
        $aTable = array_merge(
                 array(
                        'pathogenic_' => array('Path.', 40),
                        'allele_' => array('Allele', 130),
                      ),
                $aTable);

        // Total width.
        $nTotalWidth = 2;
        $nHiddenColWidth = 5;
        $bPrevHidden = false; // 2009-10-27; 2.0-23; To remember if the previous column was hidden. We now group hidden columns into one.
        foreach ($aTable as $sCol => $aCol) {
            // 2008-02-15; 2.0-04; Hidden columns are smaller!
            if (in_array($sCol, $aHiddenColumns) && $sCol != $sMutationCol) {
                // We don't allow the MutationCol to be hidden!
                // 2009-11-09; 2.0-23; We now group hidden columns into one.
                if (!$bPrevHidden) {
                    $nTotalWidth += $nHiddenColWidth + 8;
                    $bPrevHidden = true;
                }
            } else {
                $nTotalWidth += $aCol[1] + 8;
                $bPrevHidden = false;
            }
        }



        // Stretch table up, to respect column widths.
        print('      <IMG src="' . ROOT_PATH . 'gfx/trans.png" alt="" width="' . $nTotalWidth . '" height="1"><BR>' . "\n\n");

        // Table.
        print('      <TABLE border="0" cellpadding="0" cellspacing="1" class="data">' . "\n" .
              '        <TR>');

        $bPrevHidden = false; // 2009-10-27; 2.0-23; To remember if the previous column was hidden. We now group hidden columns into one.
        // Print the column headers.
        foreach ($aTable as $sField => $aCol) {
            // 2008-02-15; 2.0-04; Hide columns!
            if (in_array($sField, $aHiddenColumns) && $sField != $sMutationCol && !isset($_GET['show_all_cols'])) {
                // We don't allow the MutationCol to be hidden!
                    // 2009-10-01; 2.0-23; We now group hidden columns into one.
                if (!$bPrevHidden) {
                    print("\n" . '          <TH width="' . $nHiddenColWidth . '"><A href="' . $_SERVER['PHP_SELF'] . '?select_db=' . $_SESSION['currdb'] . '&amp;action=view&amp;view=' . rawurlencode($_GET['view']) . '&amp;show_all_cols"><IMG src="' . ROOT_PATH . 'gfx/order_arrow_show.png" alt="Unhide all columns" title="Unhide all columns" width="5" height="13" border="0"></A></TH>');
                    $bPrevHidden = true;
                }
                continue;
            } else {
                $bPrevHidden = false;
            }
            print("\n" . '          <TH' . (!empty($aCol[2])? ' ' . $aCol[2] : '') . (is_numeric($aCol[1])? ' width="' . $aCol[1] . '"' : '') . (array_key_exists($sField, $aOrderList)? ' class="order' . ($aOrder[0] == $sField? 'ed' : '') . '" onclick="document.forms[0].order.value=\'' . $sField . ',' . ($aOrder[0] == $sField? ($aOrder[1] == 'ASC'? 'DESC' : 'ASC') : $aOrderList[$sField][1]) . '\';document.forms[0].submit();"' : '') . '>' .
                  (array_key_exists($sField, $aOrderList)? "\n" .
                                                               '            <TABLE border="0" cellpadding="0" cellspacing="0" width="100%" class="S11">' . "\n" .
                                                               '              <TR>' . "\n" .
                                                               '                <TH>' . str_replace(' ', '&nbsp;', $aCol[0]) . '</TH>' . "\n" .
                                                               '                <TD align="right"><IMG src="gfx/order_arrow_desc' . ($aOrder[0] == $sField && $aOrder[1] == 'DESC'? '_sel' : '') . '.png" alt="Descending" title="Descending" width="13" height="6"><BR><IMG src="gfx/order_arrow_asc' . ($aOrder[0] == $sField && $aOrder[1] == 'ASC'? '_sel' : '') . '.png" alt="Ascending" title="Ascending" width="13" height="6"></TD></TR></TABLE>' : $aCol[0]) . '</TH>');
        }
        print('</TR>');

        while ($zData = mysql_fetch_assoc($q)) {
            print("\n" .
                  '        <TR valign="top"' . ($bAuthVar && $zData['status'] < STATUS_OK? ' class="' . ($zData['status'] < STATUS_MARKED? 'del' : 'marked') . '"' : '') . ' style="cursor : pointer; cursor : hand;' . (!empty($_GET['variantid']) && $zData['variantid'] == $_GET['variantid'] && $zData['symbol'] == $_SESSION['currdb'] && (!isset($_GET['allele']) || $zData['allele'] == $_GET['allele'])? ' font-weight : bold;' : '') . '" onmouseover="this.className = \'' . ($bAuthVar && $zData['status'] < STATUS_OK? ($zData['status'] < STATUS_MARKED? 'del_' : 'marked_') : '') . 'hover\';" onmouseout="this.className = \'' . ($bAuthVar && $zData['status'] < STATUS_OK? ($zData['status'] < STATUS_MARKED? 'del' : 'marked') : '') . '\';" onclick="window.location.href = \'' . $_SERVER['PHP_SELF'] . '?select_db=' . $zData['symbol'] . '&amp;action=view&amp;view=' . $zData['patientid'] . '%2C' . $zData['variantid'] . '%2C' . $zData['allele'] . lovd_showSID(true, true) . '\';">');

            $zData['pathogenic_'] = $_SETT['var_pathogenic_short'][$zData['pathogenic']];
            $zData['allele_']     = $_SETT['var_allele'][$zData['allele']];
            // Create normal anchor link as well.
            $sLink = '<A href="' . $_SERVER['PHP_SELF'] . '?select_db=' . $zData['symbol'] . '&amp;action=view&amp;view=' . $zData['patientid'] . '%2C' . $zData['variantid'] . '%2C' . $zData['allele'] . '" style="color : #' . ($zData['status'] < STATUS_MARKED? 'AAAAAA' : '000000') . '; text-decoration : none;">';
            if ($sMutationCol) {
                $zData[$sMutationCol] = $sLink . $zData[$sMutationCol] . '</A>';
            }

            // Parse and build Custom Links.
            lovd_buildLinks($zData);

            // 2008-10-10; 2.0-13; Oops, forgot to transform the selection lists's values here.
            // Transform select lists' values.
            $aCURRDBs[$sSymbol]->transformSelectValues($zData);

            // Additional columns for authorized users.
            if ($bAuthVar) {
                $zData['status'] = $_SETT['var_status'][$zData['status']];
            }

            // FIXME;
            // Shorten strings for TEXT that surely doesn't contain HTML tags... HOW?

            $bPrevHidden = false; // 2009-10-27; 2.0-23; To remember if the previous column was hidden. We now group hidden columns into one.
            foreach ($aTable as $sField => $aCol) {
                if (in_array($sField, $aHiddenColumns) && $sField != $sMutationCol && !isset($_GET['show_all_cols'])) {
                    // We don't allow the MutationCol to be hidden!
                    // 2009-10-01; 2.0-23; We now group hidden columns into one.
                    if (!$bPrevHidden) {
                        print("\n" . '          <TD width="' . $nHiddenColWidth . '">&nbsp;</TD>');
                        $bPrevHidden = true;
                    }
                    continue;
                } else {
                    $bPrevHidden = false;
                }
                print("\n" . '          <TD' . (!empty($aCol[2])? ' ' . $aCol[2] : '') . (is_numeric($aCol[1])? ' width="' . $aCol[1] . '"' : '') . ($aOrder[0] == $sField? ' class="ordered"' : '') . '>' . (!$zData[$sField]? '-' : $zData[$sField]) . '</TD>');
            }
            print('</TR>');
        }
        print('</TABLE>' . "\n");
        print('</FORM>' . "\n\n");
        print('      <BR>' . "\n\n");
    }

    lovd_printGeneFooter();
    require ROOT_PATH . 'inc-bot.php';
    exit;





} else {
    // Default action:
    // 2009-10-29; 2.0-23; We have been requested to enable the search fields by default.
    header('Location: ' . PROTOCOL . $_SERVER['HTTP_HOST'] . $_SERVER['PHP_SELF'] . '?action=search_unique' . lovd_showSID(true));
    exit;
}
?>
