<?php
/*******************************************************************************
 *
 * LEIDEN OPEN VARIATION DATABASE (LOVD)
 *
 * Created     : 2009-09-25
 * Modified    : 2011-07-06
 * For LOVD    : 2.0-32
 *
 * Access      : Public
 * Purpose     : RESTful API/Web Service for LOVD.
 *               Supported:
 *  2.0-22       /api/rest.php/variants/{{ GENE }}
 *  2.0-22       /api/rest.php/variants/{{ GENE }}/{{ ID }}
 *  2.0-27       /api/rest.php/variants/{{ GENE }}/unique
 *  2.0-22       /api/rest.php/variants/{{ GENE }}?search_position=c.1234
 *  2.0-23       /api/rest.php/variants/{{ GENE }}?search_position=c.1234+56_2345-67 (c.1234%2B56_2345-67)
 *  2.0-23       /api/rest.php/variants/{{ GENE }}?search_position=g.12345678
 *  2.0-24       /api/rest.php/variants/{{ GENE }}?search_position=g.1234_5678&position_match=exact|exclusive|partial
 *  2.0-22       /api/rest.php/variants/{{ GENE }}?search_Variant%2FDNA=c.1234C>G (c.1234C%3EG)
 *  2.0-22       /api/rest.php/variants/{{ GENE }}?search_Variant%2FDBID=DMD_01234
 *  2.0-23       /api/rest.php/variants/{{ GENE }}?format=text/bed
 *  2.0-23       /api/rest.php/variants/{{ GENE }}?format=text/bed&visibility=2
 *  2.0-32       /api/rest.php/variants/{{ GENE }}?format=text/bed&PMID={{ PMID }}
 *  2.0-32       /api/rest.php/variants/{{ GENE }}?format=text/bed&PMID={{ PMID }}&visibility=2
 *  2.0-23       /api/rest.php/genes
 *  2.0-23       /api/rest.php/genes/{{ GENE }}
 *  2.0-23       /api/rest.php/genes?search_symbol=DMD
 *  2.0-24       /api/rest.php/genes?search_position=chrX
 *  2.0-24       /api/rest.php/genes?search_position=chrX:3200000
 *  2.0-24       /api/rest.php/genes?search_position=chrX:3200000_4000000&position_match=exact|exclusive|partial
 *
 * OUTPUT VARIANTS:
 *  2.0-22       symbol
 *  2.0-22       id
 *               position_mRNA
 *               position_genomic
 *  2.0-22       Variant/DNA
 *  2.0-22       Variant/DBID
 *  2.0-27       Times_reported
 *
 * OUTPUT GENES:
 *  2.0-23       id
 *  2.0-25       entrez_id
 *  2.0-23       symbol
 *  2.0-23       name
 *               chromosome_location
 *  2.0-24       position_start
 *  2.0-24       position_end
 *               refseq_genomic
 *               refseq_mrna
 *               refseq_build
 *
 * Copyright   : 2004-2011 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';

// Will currently only allow GET.
if (!in_array($_SERVER['REQUEST_METHOD'], array('GET'))) {
    header('HTTP/1.0 501 Not Implemented');
}

// Parse URL to see what we need to do.
$aARGS = array(
                'sDataType',
                'sSymbol',
                'nID',
              );
$sDataType = $sSymbol = $nID = '';

$i = 0;
if (!empty($_SERVER['PATH_INFO'])) { // Prevent notice if rest.php is directly accessed.
    $aPATH_INFO = explode('/', $_SERVER['PATH_INFO']);
    foreach ($aPATH_INFO as $sPath) {
        if (!$sPath) {
            continue;
        }
        $$aARGS[$i] = $sPath;
        $i ++;
    }
}
if (!$i) { // No data type given.
    header('HTTP/1.0 400 Bad Request');
    die('Too few parameters.');
} elseif (!in_array($sDataType, array('variants', 'genes'))) { // Wrong data type given.
    header('HTTP/1.0 400 Bad Request');
    die('Requested data type not known.');
} elseif ($sDataType == 'variants' && $i < 2) { // Variants, but no gene selected.
    header('HTTP/1.0 400 Bad Request');
    die('Too few parameters.');
}

// 2010-06-17; 2.0-27; We want to have a good variable available to know the format.
if (!empty($_GET['format']) && in_array($_GET['format'], array('text/bed'))) {
    define('FORMAT', $_GET['format']);
} else {
    define('FORMAT', false); // FIXME; define proper default value for this later, when we need it. text/xml+atom+text/plain?
}
// Now we've got $sDataType, $sSymbol, $nID, FORMAT filled in, if data is available.





// Check if gene exists.
if ($sSymbol && !in_array($sSymbol, lovd_getGeneList())) {
    header('HTTP/1.0 404 Not Found');
    die('This gene does not exist.');
}





// Need some libraries.
require ROOT_PATH . 'inc-lib-api.php';

// Depending on the requested data type, we need to segment the code here.
if ($sDataType == 'variants') {
    // Check if the DNA and DBID fields are actually there (should always be the case except in modified LOVD instances).
    require ROOT_PATH . 'class/currdb.php';
    $_CURRDB = new CurrDB(true, $sSymbol);
    if ((!$_CURRDB->colExists('Variant/DNA') || !$_CURRDB->colExists('Variant/DBID')) && $sDataType == 'variants') {
        header('HTTP/1.0 503 Service Unavailable');
        die('This gene does not have the Variant/DNA or the Variant/DBID fields enabled, crucial for the API.');
    }

    $bUnique = ($nID == 'unique');
    if ($nID && !preg_match('/^[0-9]+$/', $nID)) {
        if ($bUnique) {
            $nID = false;
        } else {
            header('HTTP/1.0 404 Not Found');
            die(ucfirst(substr($sDataType, 0, -1)) . ' ID does not exist.');
        }
    }

    // Get chromosome, reference sequence, and other data.
    // 2011-01-18; 2.0-30; Fixed bug; We need refseq_build also!
    list($sChromosome, $sRefSeq, $sBuild, $nPositionMRNAStart, $nPositionMRNAEnd, $nPositionCDSEnd, $bSense) = mysql_fetch_row(mysql_query('SELECT chrom_location, refseq_mrna, refseq_build, c_position_mrna_start, c_position_mrna_end, c_position_cds_end, (g_position_mrna_start < g_position_mrna_end) AS sense FROM ' . TABLE_DBS . ' WHERE symbol = "' . $sSymbol . '"'));
    $sChromosome = preg_replace('/^([0-9]{1,2}|[MXY])([pqtercen0-9.-]+)?$/', "$1", $sChromosome);  // That regexp is not completely correct (not limiting enough), but we don't need that anyway.

    if (FORMAT == 'text/bed') {
        // We're exporting a BED file for a Genome Browser.
        // 2011-01-18; 2.0-30; Include check on refseq_build; without that properly selected we cannot map!
        if ($sRefSeq && isset($_SETT['human_builds'][$sBuild]) && $sBuild != '----') {
            $sRefSeqAcc = substr($sRefSeq, 0, strpos($sRefSeq, '.'));
            // If requested, show only variants from a certain PMID.
            $bVarRef = $_CURRDB->colExists('Variant/Reference');
            $bPatRef = $_CURRDB->colExists('Patient/Reference');
            $nPMID = (empty($_GET['PMID']) || !ctype_digit($_GET['PMID'])? 0 : $_GET['PMID']);
            $sQ = 'SELECT LEAST(v.g_position_start, v.g_position_end), GREATEST(v.g_position_start, v.g_position_end), v.type, v.`Variant/DNA` FROM ' . TABLEPREFIX . '_' . $sSymbol . '_variants AS v LEFT JOIN ' . TABLE_PAT2VAR . ' AS p2v ON (p2v.symbol = "' . $sSymbol . '" AND v.variantid = p2v.variantid)' . (!$bPatRef? '' : ' LEFT JOIN ' . TABLE_PATIENTS . ' AS p USING (patientid)') . ' WHERE p2v.status >= ' . STATUS_MARKED . ' AND v.g_position_start != 0' . (!$bVarRef && !$bPatRef? '' : ' AND (' . (!$bVarRef? '' : 'v.`Variant/Reference` LIKE "%{PMID' . $nPMID . '%"') . ($bVarRef && $bPatRef? ' OR ' : '') . (!$bPatRef? '' : 'p.`Patient/Reference` LIKE "%{PMID' . $nPMID . '%"') . ')') . ' GROUP BY v.`Variant/DNA`';
        } else {
            // Not mappable!
            header('HTTP/1.0 503 Service Unavailable');
            die('This gene does not have a NM reference sequence associated to it, crucial for mapping variants to the genome.');
        }

    } else {
        // First build query.
        $sQ = 'SELECT v.variantid, v.c_position_start, v.c_position_start_intron, v.c_position_end, v.c_position_end_intron, v.g_position_start, v.g_position_end, v.`Variant/DNA`, v.`Variant/DBID`';
        // 2010-06-30; 2.0-27; Check availability of Times/Reported column; add times reported in output.
        if ($_CURRDB->colExists('Patient/Times_Reported')) {
            $sQ .= ', SUM(p.`Patient/Times_Reported`) AS Times';
        } else {
            $sQ .= ', COUNT(p2v.patientid) AS Times';
        }
        $sQ .= ' FROM ' . TABLEPREFIX . '_' . $sSymbol . '_variants AS v LEFT JOIN ' . TABLE_PAT2VAR . ' AS p2v ON (p2v.symbol = "' . $sSymbol . '" AND v.variantid = p2v.variantid)';
        if ($_CURRDB->colExists('Patient/Times_Reported')) {
            $sQ .= ' LEFT JOIN ' . TABLE_PATIENTS . ' AS p USING (patientid)';
        }
        $sQ .= ' WHERE p2v.status >= ' . STATUS_MARKED;
        $bSearching = false;
        if ($nID) {
            $sFeedType = 'entry';
            $sQ .= ' AND v.variantid = "' . $nID . '"';
        } else {
            $sFeedType = 'feed';
            // Ok, are we searching then?
            $aSearchableFields = array('position', 'Variant/DNA', 'Variant/DBID');
            foreach ($aSearchableFields as $sField) {
                if (!empty($_GET['search_' . $sField])) {
                    $bSearching = true;
                    if ($sField == 'position') {
                        if ($sRefSeq && (preg_match('/^(g)\.([0-9]+)(_([0-9]+))?$/', $_GET['search_' . $sField], $aRegs) || preg_match('/^(c)\.([*-]?[0-9]+([+-][du]?[0-9]+)?)(_([*-]?[0-9]+([+-][du]?[0-9]+)?))?$/', $_GET['search_' . $sField], $aRegs))) {
                            // $aRegs numbering:        1    2       3 4                                                                   1    2           3                  4 5           6
                            // Mapping is only possible if there is a Reference Sequence.
                            if ($aRegs[1] == 'g') {
                                if (empty($aRegs[3])) {
                                    // No range. Absolute location.
                                    $aRegs[4] = $aRegs[2];
                                }
                                // Very important in genomic positions: genes on antisense will have positions like g.5678_1234 in the database!!!
                                $nMin = min($aRegs[2], $aRegs[4]);
                                $nMax = max($aRegs[2], $aRegs[4]);
                                if (!empty($_GET['position_match'])) {
                                    if ($_GET['position_match'] == 'exclusive') {
                                        // Mutation should be completely in the range.
                                        $sQ .= ' AND g_position_start ' . ($bSense? '>= ' . $nMin : '<= ' . $nMax) . ' AND g_position_end ' . ($bSense? '<= ' . $nMax : '>= ' . $nMin);
                                        continue;
                                    } elseif ($_GET['position_match'] == 'partial') {
                                        $sQ .= ' AND (g_position_start BETWEEN ' . $nMin . ' AND ' . $nMax . ' OR g_position_end BETWEEN ' . $nMin . ' AND ' . $nMax . ' OR (g_position_start ' . ($bSense? '<= ' . $nMin : '>= ' . $nMax) . ' AND g_position_end ' . ($bSense? '>= ' . $nMax : '<= ' . $nMin) . '))';
                                        continue;
                                    }
                                }
                                // Exact match, directly requested through $_GET['position_match'] or argument not given/recognized.
                                $sQ .= ' AND ' . $aRegs[1] . '_position_start = "' . ($bSense? $nMin : $nMax) . '" AND ' . $aRegs[1] . '_position_end = "' . ($bSense? $nMax : $nMin) . '"';
                            } else {
                                $aStart = lovd_convertDNAPositionToDB($nPositionMRNAStart, $nPositionMRNAEnd, $nPositionCDSEnd, $aRegs[2]);
                                if (empty($aRegs[4])) {
                                    $aEnd = $aStart;
                                } else {
                                    $aEnd = lovd_convertDNAPositionToDB($nPositionMRNAStart, $nPositionMRNAEnd, $nPositionCDSEnd, $aRegs[5]);
                                }
                                $sQ .= ' AND ' . $aRegs[1] . '_position_start = "' . $aStart[0] . '" AND ' . $aRegs[1] . '_position_start_intron = "' . $aStart[1] . '" AND ' . $aRegs[1] . '_position_end = "' . $aEnd[0] . '" AND ' . $aRegs[1] . '_position_end_intron = "' . $aEnd[1] . '"';
                            }
                        } else {
                            // This does a first match; trying to find the position at the start of the DNA field. Later this match will be made more accurate!
                            $sQ .= ' AND REPLACE(REPLACE(REPLACE(REPLACE(v.`Variant/DNA`, "[", ""), "(", ""), ")", ""), "?", "") LIKE "' . $_GET['search_' . $sField] . '%"';
                        }
                    } elseif ($sField == 'Variant/DNA') {
                        // This matches regardless of the characters (, ) and ?.
                        $sQ .= ' AND REPLACE(REPLACE(REPLACE(v.`' . $sField . '`, "(", ""), ")", ""), "?", "") = "' . str_replace(array('(', ')', '?'), ' ', $_GET['search_' . $sField]) . '"';
                    } elseif ($sField == 'Variant/DBID') {
                        $sQ .= ' AND v.`' . $sField . '` LIKE "' . $_GET['search_' . $sField] . '%"';
                    } else {
                        $sQ .= ' AND v.`' . $sField . '` = "' . $_GET['search_' . $sField] . '"';
                    }
                }
            }
        }
        if ($bUnique) {
            $sQ .= ' GROUP BY v.`Variant/DNA`, v.`Variant/DBID`';
        } else {
            $sQ .= ' GROUP BY variantid';
        }
        $sQ .= ' ORDER BY v.sort, v.`Variant/DNA`';
    }



} elseif ($sDataType == 'genes') {
    // Listing or simple request on gene symbol.
    // First build query.
    $sQ = 'SELECT g.symbol, g.gene, g.chrom_location, g.g_position_mrna_start, g.g_position_mrna_end, g.refseq_genomic, g.refseq_mrna, g.refseq_build, g.id_entrez, g.created_date, g.updated_date, u.name AS created_by FROM ' . TABLE_DBS . ' AS g LEFT JOIN ' . TABLE_USERS . ' AS u ON (g.created_by = u.userid) WHERE 1=1';
    $bSearching = false;
    if ($sSymbol) {
        $sFeedType = 'entry';
        $sQ .= ' AND symbol = "' . $sSymbol . '"';
    } else {
        $sFeedType = 'feed';
        // Ok, are we searching then?
        $aSearchableFields = array('symbol', 'position');
        foreach ($aSearchableFields as $sField) {
            if (!empty($_GET['search_' . $sField])) {
                $bSearching = true;
                if ($sField == 'symbol') {
                    $sQ .= ' AND (symbol = "' . $_GET['search_' . $sField] . '" OR symbol LIKE "' . $_GET['search_' . $sField] . '\_%")';
                } elseif ($sField == 'position' && preg_match('/^chr([0-9]{1,2}|[MXY])(:[0-9]{1,9}(_[0-9]+)?)?$/', $_GET['search_' . $sField], $aRegs)) {
                    // $aRegs numbering:                             1                2           3
                    @list(, $sChromosome, $sPositionStart, $sPositionEnd) = $aRegs;
                    $sPositionStart = @substr($sPositionStart, 1); // Strip off the : at the beginning.
                    $sPositionEnd   = @substr($sPositionEnd, 1); // Strip off the _ at the beginning.
                    $sQ .= ' AND (chrom_location = "' . $sChromosome . '" OR chrom_location LIKE "' . $sChromosome . 'p%" OR chrom_location LIKE "' . $sChromosome . 'q%")';
                    if ($sPositionStart) {
                        if (!$sPositionEnd) {
                            // No range. Absolute location.
                            $sQ .= ' AND LEAST(g_position_mrna_start, g_position_mrna_end) <= ' . $sPositionStart . ' AND GREATEST(g_position_mrna_start, g_position_mrna_end) >= ' . $sPositionStart;
                        } else {
                            // Actually, $sPositionStart still was the range.
                            list($sPositionStart, $sPositionEnd) = explode('_', $sPositionStart);
                            // Very important in genomic positions: genes on antisense will have positions like g.5678_1234 in the database!!!
                            $nPositionMin = min($sPositionStart, $sPositionEnd);
                            $nPositionMax = max($sPositionStart, $sPositionEnd);
                            if (!empty($_GET['position_match'])) {
                                if ($_GET['position_match'] == 'exclusive') {
                                    // Gene should be completely in the range.
                                    $sQ .= ' AND LEAST(g_position_mrna_start, g_position_mrna_end) >= ' . $nPositionMin . ' AND GREATEST(g_position_mrna_start, g_position_mrna_end) <= ' . $nPositionMax;
                                    continue;
                                } elseif ($_GET['position_match'] == 'partial') {
                                    $sQ .= ' AND (g_position_mrna_start BETWEEN ' . $nPositionMin . ' AND ' . $nPositionMax . ' OR g_position_mrna_end BETWEEN ' . $nPositionMin . ' AND ' . $nPositionMax . ' OR (LEAST(g_position_mrna_start, g_position_mrna_end) <= ' . $nPositionMin . ' AND GREATEST(g_position_mrna_start, g_position_mrna_end) >= ' . $nPositionMax . '))';
                                    continue;
                                }
                            }
                            // Exact match, directly requested through $_GET['position_match'] or argument not given/recognized.
                            $sQ .= ' AND LEAST(g_position_mrna_start, g_position_mrna_end) = ' . $nPositionMin . ' AND GREATEST(g_position_mrna_start, g_position_mrna_end) = ' . $nPositionMax;
                        }
                    }
                }
            }
        }
    }
    $sQ .= ' ORDER BY symbol';
}
$q = mysql_query($sQ);
$n = mysql_num_rows($q);

if ($n) {
    header('HTTP/1.0 200 OK');
// 2010-06-17; 2.0-27; Added this "if" condition because we don't want 404s in de text/bed format, ever.
// It should just return a BED file with a header, but no variants. Now the UCSC browser complains...
} elseif (FORMAT != 'text/bed') {
    header('HTTP/1.0 404 Not Found');
    if ($nID) {
        // Really requested a (variant) ID. Goodbye.
        die(ucfirst($sDataType) . ' ID does not exist.');
    }
}

if ($sDataType == 'variants' && FORMAT == 'text/bed') {
    // We're exporting a BED file for a Genome Browser.
    // This code structure is getting pretty bad, by the way.
    $aVariantTypeColors =
             array(
                    'substr' => '204,0,255',
                    '>'      => '204,0,255', // This one can be removed later.
                    'del'    => '0,0,255',
                    'ins'    => '0,153,0',
                    'dup'    => '255,153,0',
                    ''       => '0,0,0', // Backup, for non-matching variants.
                  );

    // Print header.
    header('Content-type: text/plain; charset=ISO-8859-1');
    // 2011-01-18; 2.0-30; Fixed bug; Human Build was hardcoded set to hg19!
    print('track name="Variants in the LOVD ' . $sSymbol . ' database' . (!$nPMID? '' : ' (PMID:' . $nPMID . ')') . '" description="Variants in LOVD ' . $sSymbol . ' db' . (!$nPMID? '' : ' (PMID:' . $nPMID . ')') . '" visibility=' . (!empty($_GET['visibility']) && is_numeric($_GET['visibility'])? $_GET['visibility'] : 3) . ' itemRgb="On" db="' . $sBuild . '" offset=-1 url="' . ($_CONF['location_url']? $_CONF['location_url'] : PROTOCOL . $_SERVER['HTTP_HOST'] . lovd_cleanDirName(dirname($_SERVER['SCRIPT_NAME']) . '/' . ROOT_PATH)) . 'variants.php?select_db=' . $sSymbol . '&action=search_all&trackid=$$' . '"' . "\n\n");

    while ($r = mysql_fetch_row($q)) {
        list($nPositionStart, $nPositionEnd, $sVariantType, $sDNA) = $r;
        if (!isset($aVariantTypeColors[$sVariantType])) {
            $sVariantType = '';
        }
        $sVariantTypeColor = $aVariantTypeColors[$sVariantType];

        // Print the data.
        // 2010-01-27; 2.0-24; Specify on which strand the variant lies ($bSense).
        print('chr' . $sChromosome . "\t" . $nPositionStart . "\t" . ($nPositionEnd+1) . "\t" . $sSymbol . ':' . preg_replace('/\s+/', '', $sDNA) . "\t" . '0' . "\t" . ($bSense? '+' : '-') . "\t" . $nPositionStart . "\t" . ($nPositionEnd+1) . "\t" . $sVariantTypeColor . "\n");
    }
    exit;
}

// Start feed class.
require ROOT_PATH . 'class/feeds.php';
if ($sFeedType == 'feed') {
    if ($sDataType == 'variants') {
        $sTitle = ($bSearching? ($n? 'R' : 'No r') . 'esults for your query of' : 'Listing of all public variants in') . ' the ' . $sSymbol . ' gene database';
    } elseif ($sDataType == 'genes') {
        $sTitle = ($bSearching? ($n? 'R' : 'No r') . 'esults for your query of' : 'Listing of all genes in') . ' the database';
    }
    // 2010-11-29; 2.0-30; Not adding '/unique' broke the "self-link" of the feed.
    $sLink = ($_CONF['location_url']? $_CONF['location_url'] : PROTOCOL . $_SERVER['HTTP_HOST'] . lovd_cleanDirName(dirname($_SERVER['SCRIPT_NAME']) . '/' . ROOT_PATH)) . 'api/rest.php/' . $sDataType . ($sSymbol? '/' . $sSymbol : '') . (empty($bUnique)? '' : '/unique');
    $sID   = 'tag:' . $_SERVER['HTTP_HOST'] . ',' . $_STAT['date_install'] . ':' . $_STAT['signature'] . '/REST_api';
} else {
    $sTitle = $sLink = $sID = '';
}
$_FEED = new Feed($sFeedType, $sTitle, $sLink, $sID, 'atom');

// Now we will create entries in the feed with the fetched data.
if ($sDataType == 'variants') {
    while ($zData = mysql_fetch_assoc($q)) {
        // Prepare other fields to be included.
        $sTitle = substr($sSymbol, 0, strpos($sSymbol . '_', '_')) . ':' . htmlspecialchars($zData['Variant/DNA']);
        if ($sFeedType == 'feed') {
            $sSelfURL = ($_CONF['location_url']? $_CONF['location_url'] : PROTOCOL . $_SERVER['HTTP_HOST'] . lovd_cleanDirName(dirname($_SERVER['SCRIPT_NAME']) . '/' . ROOT_PATH)) . 'api/rest.php/variants/' . $sSymbol . '/' . $zData['variantid'];
        } else {
            $sSelfURL = '';
        }
        // 2010-10-02; 2.0-29; Isolate the DBID by selecting the first so-called word of the Variant/DBID field.
        // We're assuming here that the start of the DBID field will always be the ID, like the column's default RegExp forces.
        $zData['Variant/DBID'] = preg_replace('/^(\w+).*$/', "$1", $zData['Variant/DBID']);
        $sAltURL               = ($_CONF['location_url']? $_CONF['location_url'] : PROTOCOL . $_SERVER['HTTP_HOST'] . lovd_cleanDirName(dirname($_SERVER['SCRIPT_NAME']) . '/' . ROOT_PATH)) . 'variants.php?select_db=' . $sSymbol . '&amp;action=search_unique&amp;search_Variant%2FDBID=' . rawurlencode($zData['Variant/DBID']);
        $zData['created_date'] = '1970-01-01 00:00:00';
        $zData['updated_date'] = '1970-01-01 00:00:00';
        $sID                   = 'tag:' . $_SERVER['HTTP_HOST'] . ',' . substr($zData['created_date'], 0, 10) . ':' . $sSymbol . '/' . $zData['variantid'];
        $zData['created_by']   = 'Unknown'; // We need to get this data from two tables... too much work?
        $sContributors         = 'Unknown'; // We need to get this data from two tables... too much work?
        if ($sRefSeq && $zData['c_position_start']) {
            $sDNAStart = lovd_convertDNAPositionToHR($nPositionMRNAStart, $nPositionMRNAEnd, $nPositionCDSEnd, $zData['c_position_start'], $zData['c_position_start_intron']);
            if ($zData['c_position_start'] == $zData['c_position_end']) {
                $sDNAEnd = $sDNAStart;
            } else {
                $sDNAEnd = lovd_convertDNAPositionToHR($nPositionMRNAStart, $nPositionMRNAEnd, $nPositionCDSEnd, $zData['c_position_end'], $zData['c_position_end_intron']);
            }
            $sPosition_mRNA    = $sRefSeq . ':c.' . $sDNAStart . ($zData['c_position_end'] == $zData['c_position_start']? '' : '_' . $sDNAEnd);
            $sPosition_genomic = 'chr' . $sChromosome . ':' . $zData['g_position_start'] . ($zData['g_position_end'] == $zData['g_position_start']? '' : '_' . $zData['g_position_end']);
        } else {
            $sPosition_mRNA    = lovd_variantToPosition($zData['Variant/DNA']);
            $sPosition_genomic = 'chr' . $sChromosome . ':?';
        }
        // Really not quite the best solution, but it kind of works. $n is decreased and if there are no more matches, it will give a 404 anyway. Still has a misleading Feed title, though!
        // FIXME; do we want to fix that by implementing a $_FEED->setTitle()?
        if (!$sRefSeq && $bSearching && !empty($_GET['search_position']) && $_GET['search_position'] != $sPosition_mRNA) {
            // This was a false positive! (only when there is no Reference Sequence LOVD will try the DNA field to find the position) Partial match that should not have been reported. Byeeeeeeee...
            $n --; // Does not really matter at this point.
            continue;
        }
        $sContent = 'symbol:' . $sSymbol . "\n" .
                    ($bUnique? '' :
                    'id:' . $zData['variantid'] . "\n") .
                    'position_mRNA:' . $sPosition_mRNA . "\n" .
                    'position_genomic:' . $sPosition_genomic . "\n" .
                    'Variant/DNA:' . htmlspecialchars($zData['Variant/DNA']) . "\n" .
                    'Variant/DBID:' . $zData['Variant/DBID'] . "\n" .
                    'Times_reported:' . $zData['Times']; // 2010-06-30; 2.0-27.
        $_FEED->addEntry($sTitle, $sSelfURL, $sAltURL, $sID, $zData['created_by'], $zData['created_date'], $sContributors, $zData['updated_date'], '', 'text', $sContent);
    }



} elseif ($sDataType == 'genes') {
    while ($zData = mysql_fetch_assoc($q)) {
        // Prepare other fields to be included.
        $sTitle = $zData['symbol'];
        if ($sFeedType == 'feed') {
            $sSelfURL = ($_CONF['location_url']? $_CONF['location_url'] : PROTOCOL . $_SERVER['HTTP_HOST'] . lovd_cleanDirName(dirname($_SERVER['SCRIPT_NAME']) . '/' . ROOT_PATH)) . 'api/rest.php/genes/' . $zData['symbol'];
        } else {
            $sSelfURL = '';
        }
        $sChromosome         = preg_replace('/^([0-9]{1,2}|[MXY])([pqtercen0-9.-]+)?$/', "$1", $zData['chrom_location']);  // That regexp is not completely correct (not limiting enough), but we don't need that anyway.
        $sAltURL             = ($_CONF['location_url']? $_CONF['location_url'] : PROTOCOL . $_SERVER['HTTP_HOST'] . lovd_cleanDirName(dirname($_SERVER['SCRIPT_NAME']) . '/' . ROOT_PATH)) . 'home.php?select_db=' . $zData['symbol'];
        $sID                 = 'tag:' . $_SERVER['HTTP_HOST'] . ',' . substr($zData['created_date'], 0, 10) . ':' . $zData['symbol'];
        $sContributors       = '';
        $qCurators = mysql_query('SELECT u.name FROM ' . TABLE_USERS . ' AS u LEFT JOIN ' . TABLE_CURATES . ' AS c USING (userid) WHERE c.symbol = "' . $zData['symbol'] . '"');
        while (list($sName) = mysql_fetch_row($qCurators)) {
            $sContributors .= ($sContributors? ', ' : '') . $sName;
        }
        $sContent = 'id:' . $zData['symbol'] . "\n" .
                    'entrez_id:' . $zData['id_entrez'] . "\n" . // 2010-02-10; 2.0-25.
                    'symbol:' . substr($zData['symbol'], 0, strpos($zData['symbol'] . '_', '_')) . "\n" .
                    'name:' . $zData['gene'] . "\n" .
                    'chromosome_location:' . $zData['chrom_location'] . "\n" .
                    'position_start:chr' . $sChromosome . ':' . $zData['g_position_mrna_start'] . "\n" . // 2.0-24.
                    'position_end:chr' . $sChromosome . ':' . $zData['g_position_mrna_end'] . "\n" .     // 2.0-24.
                    'refseq_genomic:' . $zData['refseq_genomic'] . "\n" .
                    'refseq_mrna:' . $zData['refseq_mrna'] . "\n" .
                    'refseq_build:' . $zData['refseq_build'];
        $_FEED->addEntry($sTitle, $sSelfURL, $sAltURL, $sID, $zData['created_by'], $zData['created_date'], $sContributors, $zData['updated_date'], '', 'text', $sContent);
    }
}

if (!$n) {
    // This happens if searching on position and there is a partial match. MySQL returns a false positive which has been filtered out now.
    header('HTTP/1.0 404 Not Found'); // This will replace the previous 200 OK status!
}

$_FEED->publish();
?>
