<?php
/*******************************************************************************
 *
 * LEIDEN OPEN VARIATION DATABASE (LOVD)
 *
 * Created     : 2007-01-18
 * Modified    : 2010-07-29
 * For LOVD    : 2.0-28
 *
 * Access      : Public
 * Purpose     : Provide search forms for public. Actual searching is performed
 *               by variants.php. Also provides, if enabled, the possibility to
 *               count how many entries are in the database that match certain
 *               search terms.
 *
 * Copyright   : 2004-2010 Leiden University Medical Center; http://www.LUMC.nl/
 * Programmer  : Ing. Ivo F.A.C. Fokkema <I.F.A.C.Fokkema@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;
}

// Whether or not a user can see non-public data.
if (lovd_isCurator($_SESSION['currdb'])) {
    define('IS_CURATOR', true);
} else {
    define('IS_CURATOR', false);
}





if (isset($_GET['show']) && in_array($_GET['show'], array('type', 'quick', 'full'))) {
    // Provide search forms; search by variant type, simple search and advanced search.

    // Require form functions.
    require ROOT_PATH . 'inc-lib-form.php';

    require ROOT_PATH . 'class/currdb.php';
    $_CURRDB = new CurrDB();
    $_CURRDB->hideCols('public', IS_CURATOR);
    require ROOT_PATH . 'inc-top.php';
    lovd_printGeneHeader();
    lovd_printHeader('variant_search', 'LOVD - Search variants');

    // Table.
    print('      <FORM action="variants.php" method="get">' . "\n" .
          '        <INPUT type="hidden" name="select_db" value="' . $_SESSION['currdb'] . '">' . "\n" .
          '        <INPUT type="hidden" name="action" value="search_all">' . "\n" .
          '        <TABLE border="0" cellpadding="0" cellspacing="1" width="760">');

    // Array which will make up the form table.
    $aForm = array(
                    array('POST', '', '', '50%', '50%'),
                  );

    if ($_GET['show'] != 'type' && $_CURRDB->colExists('Variant/Exon')) {
        // Retrieve exon numbers.
        $aExons = array();
        // FIXME; No join to PAT2VAR, and therefore no status check...
        //     To speed things up a little, but might cause weirdness with an exon nr being in the selection list but not found when searched.
        $qExon = mysql_query('SELECT DISTINCT `Variant/Exon` FROM ' . TABLE_CURRDB_VARS . ' ORDER BY `Variant/Exon`');
        while (list($nExon) = mysql_fetch_row($qExon)) {
            $aExons[$nExon] = $nExon;
        }
        $aForm[] = array('Exon number', 'select', 'search_Variant/Exon', 1, $aExons, '-- all --', false, false);
    }

    // Retrieve variant types.
    if ($_CURRDB->colExists('Variant/Type')) {
        // Determine type of variant according to this column's contents.
        $a = $_CURRDB->buildFormTable('Variant', 'Variant/Type');
        $a[0][2] = 'search_' . $a[0][2];
        $aForm = array_merge($aForm, $a);

    } else {
        // Use the Mutation Column.
        $sMutationCol = $_CURRDB->getMutationCol();
        $aTypes = array();
        // FIXME; This may not be the best solution. Could we maybe get the DISTINCT Variant/DNA, loop that, and then check for ourselves?
        // FIXME; No join to PAT2VAR, and therefore no status check...
        //     To speed things up a little, but might cause weirdness with a mutation type being in the selection list but not found when searched.
        list($nSub)     = @mysql_fetch_row(mysql_query('SELECT COUNT(*) FROM ' . TABLE_CURRDB_VARS . ' WHERE `' . $sMutationCol . '` LIKE "%>%"'));
        list($nIns)     = @mysql_fetch_row(mysql_query('SELECT COUNT(*) FROM ' . TABLE_CURRDB_VARS . ' WHERE `' . $sMutationCol . '` LIKE "%ins%"'));
        list($nDel)     = @mysql_fetch_row(mysql_query('SELECT COUNT(*) FROM ' . TABLE_CURRDB_VARS . ' WHERE `' . $sMutationCol . '` LIKE "%del%"'));
        list($nDup)     = @mysql_fetch_row(mysql_query('SELECT COUNT(*) FROM ' . TABLE_CURRDB_VARS . ' WHERE `' . $sMutationCol . '` LIKE "%dup%"'));
        list($nDelIns)  = @mysql_fetch_row(mysql_query('SELECT COUNT(*) FROM ' . TABLE_CURRDB_VARS . ' WHERE `' . $sMutationCol . '` LIKE "%delins%"'));
        list($nInv)     = @mysql_fetch_row(mysql_query('SELECT COUNT(*) FROM ' . TABLE_CURRDB_VARS . ' WHERE `' . $sMutationCol . '` LIKE "%inv%"'));
        list($nTrans)   = @mysql_fetch_row(mysql_query('SELECT COUNT(*) FROM ' . TABLE_CURRDB_VARS . ' WHERE `' . $sMutationCol . '` LIKE "%t(%)%"'));

        if ($nSub > 0) {
            $aTypes['>'] = 'Substitution';
        } if ($nIns > 0) {
            $aTypes['ins'] = 'Insertion';
        } if ($nDel > 0) {
            $aTypes['del'] = 'Deletion';
        } if ($nDup > 0) {
            $aTypes['dup'] = 'Duplication';
        } if ($nDelIns > 0) {
            $aTypes['delins'] = 'Insertion/Deletion';
        } if ($nInv > 0) {
            $aTypes['inv'] = 'Inversion';
        } if ($nTrans > 0) {
            $aTypes['t(%)'] = 'Translocation';
        }
        $aForm[] = array('Type of sequence variant', 'select', 'search_MutCol', 1, $aTypes, '-- all --', false, false);
    }

    // DNA, RNA, Protein fields.
    if ($_GET['show'] == 'full') {
        // FIXME; check if these exist?
        $aForm[] = array('(Part of) Sequence variation description', 'text', 'search_Variant/DNA', 20);
        $aForm[] = array('', 'print', '<SPAN class="form_note">According to nomenclature by den Dunnen JT and Antonarakis SE [2000] <A href="http://www3.interscience.wiley.com/cgi-bin/abstract?ID=68503056" target="_blank">Hum.Mut. 15:7-12</A>, <A href="http://www.HGVS.org/mutnomen/examplesDNA.html" target="_blank">Examples</A></SPAN>');
        $aForm[] = array('(Part of) Sequence variation on RNA level', 'text', 'search_Variant/RNA', 20);
        $aForm[] = array('(Part of) Protein change description', 'text', 'search_Variant/Protein', 20);
    }

    // Disease list.
    if ($_GET['show'] != 'type') {
        // Let CURRDB solve this one.
        // FIXME; LOVD 1.1.0 detected a list of used diseases itself. Should we do that, too?
        $a = $_CURRDB->buildFormTable('Patient', 'Patient/Phenotype/Disease');
        $a[0][2] = 'search_Patient/Phenotype/Disease';
        if ($a[0][1] == 'select') {
            // CURRDB has decided this is a selection list. Modify it.
            $a[0][3] = 1; // Field size.
            $a[0][5] = '-- all --'; // Select?
            $a[0][6] = false; // Multiple?
        }
        $aForm = array_merge($aForm, $a);
    }

    // Reference, Template, Detection technique.
    if ($_GET['show'] == 'full') {
        $aForm[] = array('Reference (author, pubmed ID, etc.)', 'text', 'search_Patient/Reference', 20);

        // Let CURRDB solve this one.
        // FIXME; LOVD 1.1.0 detected a list of used detection templates itself. Should we do that, too?
        $a = $_CURRDB->buildFormTable('Patient', 'Patient/Detection/Template');
        $a[0][2] = 'search_Patient/Detection/Template';
        if ($a[0][1] == 'select') {
            // CURRDB has decided this is a selection list. Modify it.
            $a[0][3] = 1; // Field size.
            $a[0][5] = '-- all --'; // Select?
            $a[0][6] = false; // Multiple?
        }
        $aForm = array_merge($aForm, $a);
    
        // Let CURRDB solve this one.
        // FIXME; LOVD 1.1.0 detected a list of used detection techniques itself. Should we do that, too?
        $a = $_CURRDB->buildFormTable('Patient', 'Patient/Detection/Technique');
        $a[0][2] = 'search_Patient/Detection/Technique';
        if ($a[0][1] == 'select') {
            // CURRDB has decided this is a selection list. Modify it.
            $a[0][3] = 1; // Field size.
            $a[0][5] = '-- all --'; // Select?
            $a[0][6] = false; // Multiple?
        }
        $aForm = array_merge($aForm, $a);
    }

    $aForm[] = 'skip';
    $aForm[] = array('', 'submit', 'Search sequence variants');
    $_MODULES->processForm('VariantsSearch', $aForm);
    lovd_viewForm($aForm);

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

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





} elseif ($_GET['action'] == 'count_all') {
    // Search through all entries, including hidden entries and hidden cols.

    // Require form functions.
    require ROOT_PATH . 'inc-lib-form.php';
    require ROOT_PATH . 'inc-lib-list.php';
    require ROOT_PATH . 'class/currdb.php';
    $_CURRDB = new CurrDB();
    $_CURRDB->hideCols('allow_count_all', IS_CURATOR);
    require ROOT_PATH . 'inc-top.php';
    lovd_printGeneHeader();
    lovd_printHeader('variant_search', 'LOVD - Search variants');

    // Deny access if not authorized and feature is turned off.
    if (!HAS_AUTH && !$_CONF['search_count_entries']) {
        lovd_showInfoTable('This feature is currently disabled by the LOVD settings. Please ask the LOVD manager to enable this feature.', 'stop');
        require ROOT_PATH . 'inc-bot.php';
        exit;
    }




    // Check if it's sent.
    $nSent = 0;
    foreach ($_GET as $key => $val) {
        if (substr($key, 0, 7) == 'search_') {
            // Implement XSS check on search terms.
            if (!is_array($val) && $val != strip_tags($val)) {
                $_GET[$key] = '';
                $val = '';
            }

            if ($val) {
                // Apparently, something has been filled in.
                $nSent ++;
            }
        }
    }

    if ($nSent) {
        // Standard query, will be extended later on.
        $sQ = 'SELECT v.variantid 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) WHERE 1=1';

        // Here starts the actual building of the query.

        // SEARCH: Advanced text search.
        $aSearchText = array_merge(
            $_CURRDB->buildSearchList('text'),
            $_CURRDB->buildSearchList('textarea'),
            $_CURRDB->buildSearchList('checkbox'));
        foreach ($aSearchText as $key => $val) {
            if (isset($_GET[$key]) && trim($_GET[$key])) {
                // 2010; 2.0-28; Allow for searches where the order of words is forced by enclosing the values with double quotes; ["Fokkema et al 2005"] will only
                // return hits with these words in exactly this order while [Fokkema et al 2005] will return hits with all of these words, in whatever order.
                $sSearch = preg_replace_callback('/\\\"([^"]+)\\\"/', create_function('$aRegs', 'return str_replace(\' \', \'{{SPACE}}\', $aRegs[1]);'), trim($_GET[$key]));
                $a = explode(' ', $sSearch);
                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) . '%"';
                        }
                    }
                }
            }
        }

        // SEARCH: List search.
        $aSearchSelect = array_merge(
                 array(
                        'search_allele' => 'p2v.allele',
                        'search_pathogenic' => 'p2v.pathogenic',
                        'search_status' => 'p2v.status',
                      ),
            $_CURRDB->buildSearchList('select'));
        foreach ($aSearchSelect as $key => $val) {
            if (!empty($_GET[$key])) {
                if (!is_array($_GET[$key])) {
                    // Single select.
                    $sQ .= ' AND CONCAT(";", ' . $val . ', ";") LIKE "%;' . $_GET[$key] . ';%"';
                } else {
                    // Multiple select.
                    $sQ .= ' AND CONCAT(";", ' . $val . ', ";") LIKE "%;' . implode('" AND CONCAT(";", ' . $val . ', ";") LIKE "%', $_GET[$key]) . ';%"';
                }
            }
        }

        // 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));

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

        lovd_showInfoTable('Your search term' . ($nSent == 1? '' : 's') . ' matched ' . $nResults . ' variant entr' . ($nResults == 1? 'y.' : 'ies.'), 'information');

    } else {

        lovd_showInfoTable('Fill in at least one value in the form below to return the number of entries in the database matching your search terms, including non-public entries.', 'information');
    }





    // Show form; required for sorting and searching.
    print('      <FORM action="' . $_SERVER['PHP_SELF'] . '" method="get" style="margin : 0px;">' . "\n" .
          '        <INPUT type="hidden" name="action" value="' . $_GET['action'] . '">' . "\n" .
          '        <INPUT type="hidden" name="select_db" value="' . $_SESSION['currdb'] . '">');

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

    // Manipulate data; remove nonsense or difficult value.
    unset($_SETT['var_allele'][0]);
    unset($_SETT['var_allele'][3]);

    // Array which will make up the form table.
    $aForm = array_merge(
                         array(
                                array('GET', '', '', '40%', '60%'),
                                array('', 'print', '<B>Sequence variant data search terms</B>'),
                              ),
                         $_CURRDB->buildFormTable('Variant'),
                         array(
                                'skip',
                                array('', 'print', '<B>Variant settings search terms</B>'),
                                array('Variant allele', 'select', 'allele', 1, $_SETT['var_allele'], true, false, false),
                                array('Pathogenicity', 'select', 'pathogenic', 1, $_SETT['var_pathogenic_short'], true, false, false),
                                array('Variant status', 'select', 'status', 1, $_SETT['var_status'], true, false, false),
                                'skip',
                                array('', 'print', '<B>Patient data search terms</B>'),
                              ),
                         $_CURRDB->buildFormTable('Patient'),
                         array(
                                'skip',
                                array('', 'submit', 'Show number of matching entries'),
                              ));

    foreach ($aForm as $key => $val) {
        // Remove comments and custom link info... we don't need it here. Chose not to modify CurrDB for this, but to do this here.
        if ($key && is_array($val)) {
            if ($val[1] == 'print') {
                if (substr($val[2], 0, 3) != '<B>') {
                    unset($aForm[$key]);
                }
            } elseif ($val[1] != 'submit') {
                // Prepend 'search_' to the field name, so the search code tracks it down.
                $aForm[$key][2] = 'search_' . $val[2];
            }
        }
    }

    $_MODULES->processForm('VariantsSearchCountAll', $aForm);
    lovd_viewForm($aForm);

    print('</TABLE></FORM>' . "\n\n");

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





} else {
    // Default action:
    header('Location: ' . PROTOCOL . $_SERVER['HTTP_HOST'] . $_SERVER['PHP_SELF'] . '?show=full' . lovd_showSID(true));
    exit;
}
?>
