<?php
/*******************************************************************************
 *
 * LEIDEN OPEN VARIATION DATABASE (LOVD)
 *
 * Created     : 2007-03-27
 * Modified    : 2009-02-09
 * For LOVD    : 2.0-16
 *
 * Access      : Curators and up.
 * Purpose     : Import previously downloaded file into the database.
 *
 * Copyright   : 2004-2009 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';
}

require 
ROOT_PATH 'inc-lib-form.php';

// Require curator clearance.
lovd_requireAUTH(LEVEL_CURATOR);

// If no gene selected, present the selection list.
if (!$_SESSION['currdb'] || $_GET['action'] == 'switch_db') {
    
lovd_switchDB();
}

// Needs to be curator for THIS gene.
if (!lovd_isCurator($_SESSION['currdb'])) {
    
// NOTE that this does not unset certain links in the top menu. Links are available.
    
lovd_showInfoTable((GENE_COUNT'You are not allowed access to ' . (GENE_COUNT 1'this gene database' 'the installed gene database') . '. Please contact your manager or the administrator to grant you access.' 'There are currently no databases installed.'), 'stop');
    require 
ROOT_PATH 'inc-bot.php';
    exit;
}





$nMaxSize 2097152// 2 MB.

if (isset($_GET['sent'])) {
    
lovd_errorClean();

    
// No file...
    
if ($_FILES['upload_file']['error'] > && $_FILES['upload_file']['error'] < 4) {
        
lovd_errorAdd('There was a problem with the file transfer. Please try again. The file cannot be larger than ' round($nMaxSize/pow(10242), 1) . ' MB.');

    } else if (
$_FILES['upload_file']['error'] == || !$_FILES['upload_file']['size']) {
        
lovd_errorAdd('Please select a file to upload.');

    } else if (
$_FILES['upload_file']['size'] > $nMaxSize) {
        
lovd_errorAdd('The file cannot be larger than ' round($nMaxSize/pow(10242), 1) . ' MB.');

    } elseif (
$_FILES['upload_file']['error']) {
        
// Various errors available from 4.3.0 or later.
        
lovd_errorAdd('There was an unknown problem with receiving the file properly, possibly because of the current server settings. If the problem persists, contact the database administrator.');
    }

    if (!
lovd_error()) {
        
$fInput = @fopen($_FILES['upload_file']['tmp_name'], 'r');
        if (!
$fInput) {
            
lovd_errorAdd('Cannot open file after it was received by the server.');
        }
    }



    if (!
lovd_error()) {
        
// Start reading out text file and gathering data.
        
$nLine 1;

        
$aLOVDCols      = array('variant_created_date_''variant_edited_date_''patient_created_date_''patient_edited_date_''ID_sort_''ID_allele_''ID_pathogenic_''ID_status_''ID_variantid_''ID_patientid_''ID_submitterid_''ID_variant_created_by_''ID_variant_edited_by_''ID_patient_created_by_''ID_patient_edited_by_');
        
$aColsMandatory = array('ID_patientid_');

        
// Gather column info from database.
        
require ROOT_PATH 'class/currdb.php';
        
$_CURRDB = new CurrDB(true$_SESSION['currdb']);
        
$sMutationCol $_CURRDB->getMutationCol(); // For lovd_sort() and DB-ID suggestion.

        // Read version information or column names from file.
        
$sLine = @fgets($fInput4096);
        
$sLine rtrim($sLine"\r\n");

        
// 2008-12-23; 2.0-15; Check if the first line with LOVD-version etc. is present
        
if (!preg_match('/^### LOVD-version ([0-9]{4}\-[0-9]{2}[a-z0-9]) ###/'ltrim($sLine'"'), $aRegs)) {
            
lovd_errorAdd('The first line of the imported file should contain the LOVD header! (### LOVD-version ... etc.) <A href="' ROOT_PATH 'docs/variant_and_patient_data/importing_text_files.php">More information</A>.');
        } else {
            
// 2008-02-29; 2.0-04; Version number added to download file.
            // Version number.
            
$sFormatVersion $aRegs[1];

            
// 2009-01-27; 2.0-15; Check for data type.
            
if (preg_match('/^### LOVD-version [0-9a-z-]+ ### ([A-Za-z\/]+) ###/'ltrim($sLine'"'), $aRegs)) {
                
// We received a datatype. It should be Variants/Patients or Patients/Variants.
                
$aFormat explode('/'$aRegs[1]);
                
sort($aFormat);
                if (
$aFormat != array('Patients''Variants')) {
                    
lovd_errorAdd('The header of this file indicates it contains "' $aRegs[1] . '". Expected "Variants/Patients".');
                    if (
$aRegs[1] == 'Columns') {
                        
lovd_errorAdd('Maybe you meant to import your file <A href="' ROOT_PATH 'setup_columns_global_import.php">here</A>?');
                    }
                }
            }

            
// Read the next line for the column names.
            
$sLine = @fgets($fInput4096);
            
$sLine rtrim($sLine"\r\n");
        }

        
// Column handling.
        
$aColumns explode("\t"$sLine);
        foreach (
$aColumns as $nCol => $sCol) {
            
$sCol trim($sCol'"{ }');
            
// Unknown cols? Ignore.
            
if (!in_array($sCol$aLOVDCols) && !$_CURRDB->colExists($sCol)) {
                unset(
$aColumns[$nCol]);
            } else {
                
$aColumns[$nCol] = $sCol;
            }
        }

        
// LOVD mandatory columns really *must* be available.
        
foreach ($aColsMandatory as $sCol) {
            if (!
in_array($sCol$aColumns)) {
                
lovd_errorAdd('Cannot import this file, as it lacks the crucial "' $sCol '" columnn.');
            }
        }

        
// Mandatory cols missing?
        // Directly accessing $aColList, since the checkMandatory is not going to help me here.
        
foreach ($_CURRDB->aColList as $sCol => $aCol) {
            if (
$aCol['mandatory'] && !in_array($sCol$aColumns)) {
                
// Mandatory column is missing from the file.
                
lovd_errorAdd('Bluntly refusing to import this file, as it lacks the mandatory "' $sCol '" (' $aCol['head_column'] . ') column.');
            }
        }



        if (!
lovd_error()) {
            
// Loop lines.
            
$nLine 2// Header = line 2.
            
$nMaxErrors 25;
            
// 2008-09-15; 2.0-12; Added increased execution time to script to help import bigger files.
            
if ((int) ini_get('max_execution_time') < 60) {
                
set_time_limit(60);
            }

            
// Save us a lot of queries, by saving this first.
            
$aIDsUsers = array();
            
$aIDsSubs = array();
            
$qUsers mysql_query('SELECT userid FROM ' TABLE_USERS);
            while (
$r mysql_fetch_row($qUsers)) {
                
$aIDsUsers[] = (int) $r[0];
            }
            
// This one needs to be added, because 0 is a valid value for created_by and edited_by fields.
            
$aIDsUsers[] = 0;
            
$qSubs mysql_query('SELECT submitterid FROM ' TABLE_SUBS);
            while (
$r mysql_fetch_row($qSubs)) {
                
$aIDsSubs[] = (int) $r[0];
            }
            
// This one needs to be added, because 0 is a valid value for the submitterid field.
            
$aIDsSubs[] = 0;

            
// This can be a quite intensive process, but we need to check and verify all the data.
            
$aVariants = array();
            
$aPatients = array();
            
$aPat2Var  = array();
            
$nVariants 0;
            
$nPatients 0;
            
$nPat2Var  0;

            
// 2008-02-12; 2.0-04
            // Fixed memory consumption problem of import script occuring in large databases when loading all variant data into the memory.
            // Full variant data will be loaded later on in this script, only when needed, one by one.
            // $qVar = mysql_query('SELECT * FROM ' . TABLE_CURRDB_VARS);
            
$qVar mysql_query('SELECT variantid FROM ' TABLE_CURRDB_VARS);
            while (
$z mysql_fetch_assoc($qVar)) {
                
// Quote data such that it is equal to what we have in the text file.
                
$z['indb'] = true;
                
$aVariants[(int) $z['variantid']] = $z;
            }

            
// 2007-06-14; 2.0-beta-04
            // Fixed problem when importing new entries when already having entries in other gene databases.
            // $qPat = mysql_query('SELECT p.* FROM ' . TABLE_PATIENTS . ' AS p LEFT JOIN ' . TABLE_PAT2VAR . ' AS p2v USING (patientid) WHERE p2v.symbol = "' . $_SESSION['currdb'] . '"');
            // 2007-09-21; 2.0-beta-09
            // Fixed memory consumption problem of import script occuring in large databases when loading all patient data into the memory.
            // Full patient data will be loaded later on in this script, only when needed, one by one.
            // $qPat = mysql_query('SELECT * FROM ' . TABLE_PATIENTS);
            
$qPat mysql_query('SELECT patientid FROM ' TABLE_PATIENTS);
            while (
$z mysql_fetch_assoc($qPat)) {
                
$z['indb'] = true;
                
$aPatients[(int) $z['patientid']] = $z;
            }

            
// 2008-02-12; 2.0-04
            // Fixed memory consumption problem of import script occuring in large databases when loading all patient2variant data into the memory.
            // Full patient2variant data will be loaded later on in this script, only when needed, one by one.
            // $qPat2Var = mysql_query('SELECT * FROM ' . TABLE_PAT2VAR . ' WHERE symbol = "' . $_SESSION['currdb'] . '"');
            
$qPat2Var mysql_query('SELECT variantid, patientid, allele FROM ' TABLE_PAT2VAR ' WHERE symbol = "' $_SESSION['currdb'] . '"');
            while (
$z mysql_fetch_assoc($qPat2Var)) {
                
// Quote data such that it is equal to what we have in the text file.
                
$z['indb'] = true;
                
$aPat2Var[(int) $z['variantid'] . '|' . (int) $z['patientid'] . '|' $z['allele']] = $z;
            }

            
// 2008-02-29; 2.0-04; Changed the whole pathogenicity ID code list.
            
$aTransformPathogenicity = array('0' => '1''1' => '9''9' => '5');

            
// 2008-11-13; 2.0-14 added by Gerard
            // Initiate an array to keep track of assigned Variant/DBID numbers
            // use variants already seen in the upload file as keys when you add the number
            
$aIDAssigned = array();
            
// 2009-01-27; 2.0-15; Keep track of the maximum variantid in use.
            
$nMaxVariantID 0;



            
// Read rest of the file.
            
while (!feof($fInput) && $sLine rtrim(fgets($fInput4096), "\r\n")) {
                
$nLine ++;
                if (!
trim($sLine)) {
                    
// Empty line.
                    
continue;
                }
                
$aLine explode("\t"$sLine);
                
$aLineVar = array();
                
$aLinePat = array();
                
$aLinePat2Var = array();

                
// Clean first.
                
foreach ($aLine as $nKey => $sVal) {
                    
// We need an extra loop, because we're going to access values of $aLine directly, and then all values should be cleaned.
                    
if (substr($sVal01) == '"' && substr($sVal, -1) == '"') {
                        
$aLine[$nKey] = substr($sVal1, -1);
                    }
                }

                foreach (
$aLine as $nKey => $sVal) {
                    
// Loop data, and verify it.
                    
if (!isset($aColumns[$nKey])) {
                        
// We're ignoring this column.
                        
continue;
                    }
                    
$sCol $aColumns[$nKey];

                    
// Check given ID's.
                    
switch ($sCol) {
                        case 
'variant_created_date_':
                            if (
$sVal && !preg_match('/^[0-9]{4}[.\/-][0-9]{2}[.\/-][0-9]{2}( [0-9]{2}\:[0-9]{2}(\:[0-9]{2}))?$/'$sVal)) {
                                
lovd_errorAdd('Error in line ' $nLine ': value "' htmlspecialchars($sVal) . '" in "' $sCol '" column is not a date I understand.');
                            }
                            
$aLinePat2Var['created_date'] = $sVal;
                            break;
                        case 
'patient_created_date_':
                            if (
$sVal && !preg_match('/^[0-9]{4}[.\/-][0-9]{2}[.\/-][0-9]{2}( [0-9]{2}\:[0-9]{2}(\:[0-9]{2}))?$/'$sVal)) {
                                
lovd_errorAdd('Error in line ' $nLine ': value "' htmlspecialchars($sVal) . '" in "' $sCol '" column is not a date I understand.');
                            }
                            
$aLinePat['created_date'] = $sVal;
                            break;
                        case 
'variant_edited_date_':
                            
// FIXME; check for edited id?
                            
if ($sVal && !preg_match('/^[0-9]{4}[.\/-][0-9]{2}[.\/-][0-9]{2}( [0-9]{2}\:[0-9]{2}(\:[0-9]{2}))?$/'$sVal)) {
                                
lovd_errorAdd('Error in line ' $nLine ': value "' htmlspecialchars($sVal) . '" in "' $sCol '" column is not a date I understand.');
                            }
                            
$aLinePat2Var['edited_date'] = $sVal;
                            break;
                        case 
'patient_edited_date_':
                            
// FIXME; check for edited id?
                            
if ($sVal && !preg_match('/^[0-9]{4}[.\/-][0-9]{2}[.\/-][0-9]{2}( [0-9]{2}\:[0-9]{2}(\:[0-9]{2}))?$/'$sVal)) {
                                
lovd_errorAdd('Error in line ' $nLine ': value "' htmlspecialchars($sVal) . '" in "' $sCol '" column is not a date I understand.');
                            }
                            
$aLinePat['edited_date'] = $sVal;
                            break;
                        case 
'ID_sort_':
                            
// If empty, will be determined at the end of this line's run.
                            
$aLineVar['sort'] = $sVal;
                            break;
                        case 
'ID_allele_':
                            if (!
array_key_exists($sVal$_SETT['var_allele'])) {
                                
lovd_errorAdd('Error in line ' $nLine ': value "' htmlspecialchars($sVal) . '" in "' $sCol '" column is not a valid allele ID.');
                            }
                            
$aLinePat2Var['allele'] = $sVal;
                            
$nAllele $sVal;
                            break;
                        case 
'ID_pathogenic_':
                            if (
$sVal !== '') {
                                if (
$sFormatVersion '2000-040' && in_array($sVal, array('00''01''09''10''11''19''90''91''99'))) {
                                    
// 2008-02-29; 2.0-04; Changed the whole pathogenicity ID code list.
                                    
$sVal $aTransformPathogenicity[$sVal{0}] . $aTransformPathogenicity[$sVal{1}];
                                }
                                
// Empty value may not default to '00'!
                                
$sVal str_pad($sVal2'0'STR_PAD_LEFT);
                                if (!
array_key_exists($sVal$_SETT['var_pathogenic_short'])) {
                                    
lovd_errorAdd('Error in line ' $nLine ': value "' htmlspecialchars($sVal) . '" in "' $sCol '" column is not a valid pathogenicity ID.');
                                }
                            }
                            
$aLinePat2Var['pathogenic'] = $sVal;
                            break;
                        case 
'ID_status_':
                            if (
$sVal !== '') {
                                if (!
array_key_exists($sVal$_SETT['var_status'])) {
                                    
lovd_errorAdd('Error in line ' $nLine ': value "' htmlspecialchars($sVal) . '" in "' $sCol '" column is not a valid status ID.');
                                }
                            }
                            
$aLinePat2Var['status'] = $sVal;
                            break;
                        case 
'ID_submitterid_':
                            
settype($sVal'int');
                            if (!
in_array($sVal$aIDsSubs)) {
                                
lovd_errorAdd('Error in line ' $nLine ': value "' htmlspecialchars($sVal) . '" in "' $sCol '" column is not a valid submitter ID.');
                            }
                            
$aLinePat['submitterid'] = $sVal;
                            break;
                        case 
'ID_variant_created_by_':
                            
settype($sVal'int');
                            if (!
in_array($sVal$aIDsUsers)) {
                                
lovd_errorAdd('Error in line ' $nLine ': value "' htmlspecialchars($sVal) . '" in "' $sCol '" column is not a valid user ID.');
                            }
                            
$aLinePat2Var['created_by'] = $sVal;
                            break;
                        case 
'ID_patient_created_by_':
                            
settype($sVal'int');
                            if (!
in_array($sVal$aIDsUsers)) {
                                
lovd_errorAdd('Error in line ' $nLine ': value "' htmlspecialchars($sVal) . '" in "' $sCol '" column is not a valid user ID.');
                            }
                            
$aLinePat['created_by'] = $sVal;
                            break;
                        case 
'ID_variant_edited_by_':
                            
// FIXME; check for edited date?
                            
settype($sVal'int');
                            if (
$sVal && !in_array($sVal$aIDsUsers)) {
                                
lovd_errorAdd('Error in line ' $nLine ': value "' htmlspecialchars($sVal) . '" in "' $sCol '" column is not a valid user ID.');
                            }
                            
$aLinePat2Var['edited_by'] = $sVal;
                        case 
'ID_patient_edited_by_':
                            
// FIXME; check for edited date?
                            
settype($sVal'int');
                            if (
$sVal && !in_array($sVal$aIDsUsers)) {
                                
lovd_errorAdd('Error in line ' $nLine ': value "' htmlspecialchars($sVal) . '" in "' $sCol '" column is not a valid user ID.');
                            }
                            
$aLinePat['edited_by'] = $sVal;
                            break;
                        case 
'ID_variantid_':
                            
// 2008-12-23; 2.0-15; adapted by Gerard to allow for empty ID_variantid_ fields
                            
if ($sVal && (!preg_match('/^[0-9]+$/'$sVal) || $sVal 1)) {
                                
lovd_errorAdd('Error in line ' $nLine ': value "' htmlspecialchars($sVal) . '" in "' $sCol '" column is not an integer.');
                            }
                            
settype($sVal'int');
                            
$aLineVar['variantid'] = $sVal;
                            
$aLinePat2Var['variantid'] = $sVal;
                            
$nVariantID $sVal;
                            break;
                        case 
'ID_patientid_':
                            if (!
preg_match('/^[0-9]+$/'$sVal) || $sVal 1) {
                                
lovd_errorAdd('Error in line ' $nLine ': value "' htmlspecialchars($sVal) . '" in "' $sCol '" column is not an integer.');
                            }
                            
settype($sVal'int');
                            
$aLinePat['patientid'] = $sVal;
                            
$aLinePat2Var['patientid'] = $sVal;
                            
$nPatientID $sVal;
                            break;
                        default:
                            
// Variant or Patient column. Additional checking.
                            // Directly accessing $aColList, since the $_CURRDB methods are not going to help me here.

                            // Mandatory fields.
                            
if ($aLine[array_search('ID_status_'$aColumns)] >= STATUS_MARKED && $_CURRDB->aColList[$sCol]['mandatory'] && !$sVal) {
                                
// Mandatory col not filled in. Did we see this line before? If so, just ignore. Empty values are allowed for repeated data.
                                // 2008-11-05; 2.0-14; && $sCol != 'Variant/DBID' added by Gerard. That column is allowed to be empty and will be generated
                                
if ((substr($sCol08) == 'Variant/' && $sCol != 'Variant/DBID' && !array_key_exists((int) $aLine[array_search('ID_variantid_'$aColumns)], $aVariants)) || (substr($sCol08) == 'Patient/' && !array_key_exists((int) $aLine[array_search('ID_patientid_'$aColumns)], $aPatients))) {
                                    
lovd_errorAdd('Error in line ' $nLine ': missing value in mandatory "' $sCol '" column.');
                                }
                            }

                            
// Field lengths.
                            
$nMaxLength $_CURRDB->getFieldLength($sCol);
                            
$nLength strlen($sVal);
                            if (
$nMaxLength $nLength) {
                                
lovd_errorAdd('Error in line ' $nLine ': value of ' $nLength ' characters is too long for the "' $sCol '" column, which allows ' $nMaxLength ' characters.');
                            }

                            if (
$sVal) {
                                
// Field types.
                                
$sType $_CURRDB->getFieldType($sCol);
                                switch (
$sType) {
                                    case 
'INT':
                                        if (!
preg_match('/^[0-9]+$/'$sVal)) {
                                            
lovd_errorAdd('Error in line ' $nLine ': value "' htmlspecialchars($sVal) . '" in "' $sCol '" column is not an integer.');
                                        }
                                        break;
                                    case 
'DEC':
                                        if (!
is_numeric($sVal)) {
                                            
lovd_errorAdd('Error in line ' $nLine ': value "' htmlspecialchars($sVal) . '" in "' $sCol '" column is not numeric.');
                                        }
                                        break;
                                    case 
'DATETIME':
                                        if (!
preg_match('/^[0-9]{4}[.\/-][0-9]{2}[.\/-][0-9]{2}( [0-9]{2}\:[0-9]{2}\:[0-9]{2})?$/'$sVal)) {
                                            
lovd_errorAdd('Error in line ' $nLine ': value "' htmlspecialchars($sVal) . '" in "' $sCol '" column is not a date I understand.');
                                        }
                                        break;
                                    case 
'DATE':
                                        if (!
lovd_matchDate($sVal)) {
                                            
lovd_errorAdd('Error in line ' $nLine ': value "' htmlspecialchars($sVal) . '" in "' $sCol '" column is not a date I understand.');
                                        }
                                        break;
                                }

                                
// Regular expressions.
                                
if ($_CURRDB->aColList[$sCol]['preg_pattern'] && !preg_match($_CURRDB->aColList[$sCol]['preg_pattern'], $sVal)) {
                                    
lovd_errorAdd('Error in line ' $nLine ': value "' htmlspecialchars($sVal) . '" in "' $sCol '" column does not correspond to the required input pattern.');
                                }
                            }

                            
// Store column value.
                            
if (substr($sCol07) == 'Variant') {
                                
$aLineVar[$sCol] = $sVal;
                            } else {
                                
$aLinePat[$sCol] = $sVal;
                            }
                    }

                    if (
substr_count($_ERROR"\n") >= $nMaxErrors) {
                        
// Too many errors. Quit now.
                        
lovd_errorAdd('Too many errors, stopping file processing.');
                        break 
2;
                    }
                }

                
// 2009-02-09; 2.0-16; Move this up to prevent notices and failure to import variants.
                // 2009-01-27; 2.0-15; Generates a new variantid for each variant with an empty field.
                
if (empty($aLineVar['variantid'])) {
                    
// The ID_variantid_ field in the upload file is empty so we need to generate a variantid.
                    
if (!$nMaxVariantID) {
                        list(
$nMaxVariantID) = mysql_fetch_row(mysql_query('SELECT MAX(variantid) FROM ' TABLE_CURRDB_VARS));
                    }
                    
$nVariantID = ++ $nMaxVariantID;
                    
$aLineVar['variantid'] = $nVariantID;
                    
$aLinePat2Var['variantid'] = $nVariantID;                    
                    
$sPat2VarKey $nVariantID '|' $nPatientID '|' $aLinePat2Var['allele'];
                }

                
// Auto values!
                
$sPat2VarKey $nVariantID '|' $nPatientID '|' $aLinePat2Var['allele'];

                
// 2008-02-12; 2.0-04
                // Now load the variant, if necessary. This will keep the $aVariants array small.
                
if (array_key_exists($nVariantID$aVariants) && $aVariants[$nVariantID]['indb'] && !isset($aVariants[$nVariantID]['sort'])) {
                    
// I could have picked any other standard Variant column basically.
                    // Variant data is in the database, but not fetched yet. Do this now.
                    
$z mysql_fetch_assoc(mysql_query('SELECT * FROM ' TABLE_CURRDB_VARS ' WHERE variantid = "' $nVariantID '"'));
                    
// Quote data such that it is equal to what we have in the text file.
                    
lovd_magicQuote($z);
                    
$z str_replace(array("\r\n""\r""\n"), array('\r\n''\r''\n'), $z);
                    
$z['indb'] = true;
                    
$aVariants[$nVariantID] = $z;
                }

                
// 2007-09-21; 2.0-beta-09
                // Now load the patient, if necessary. This will keep the $aPatients array small.
                
if (array_key_exists($nPatientID$aPatients) && $aPatients[$nPatientID]['indb'] && !isset($aPatients[$nPatientID]['created_by'])) {
                    
// I could have picked any other standard Patient column basically.
                    // Patient data is in the database, but not fetched yet. Do this now.
                    
$z mysql_fetch_assoc(mysql_query('SELECT * FROM ' TABLE_PATIENTS ' WHERE patientid = "' $nPatientID '"'));
                    
// Quote data such that it is equal to what we have in the text file.
                    
lovd_magicQuote($z);
                    
$z str_replace(array("\r\n""\r""\n"), array('\r\n''\r''\n'), $z);
                    
$z['indb'] = true;
                    
$aPatients[$nPatientID] = $z;
                }

                
// 2008-02-12; 2.0-04
                // Now load the patient2variant entry, if necessary. This will keep the $aPat2Var array small.
                
if (array_key_exists($sPat2VarKey$aPat2Var) && $aPat2Var[$sPat2VarKey]['indb'] && !isset($aPat2Var[$sPat2VarKey]['created_by'])) {
                    
// I could have picked any other standard Pat2Var column basically.
                    // Pat2Var data is in the database, but not fetched yet. Do this now.
                    
$z mysql_fetch_assoc(mysql_query('SELECT * FROM ' TABLE_PAT2VAR ' WHERE symbol = "' $_SESSION['currdb'] . '" AND variantid = "' $nVariantID '" AND patientid = "' $nPatientID '" AND allele = "' $aLinePat2Var['allele'] . '"'));
                    
// Quote data such that it is equal to what we have in the text file.
                    
lovd_magicQuote($z);
                    
$z str_replace(array("\r\n""\r""\n"), array('\r\n''\r''\n'), $z);
                    
$z['indb'] = true;
                    
$aPat2Var[$sPat2VarKey] = $z;
                }

                
// If this entry is already in the database, we don't have to do anything 'cause only the first instance
                // will be loaded into the database. The check for consistency (below) will only complain about an
                // unequal value if the second value is not empty.
                // Not in the database? Then auto-fill the value with a useful default!

                // ID_sort_ column (variant).
                
if ($sMutationCol && !empty($aLineVar[$sMutationCol]) && empty($aLineVar['sort'])) {
                    if (!
array_key_exists($nVariantID$aVariants)) {
                        
$aLineVar['sort'] = lovd_sort($aLineVar[$sMutationCol]);
                    }
                }

                
// ID_pathogenic_ column (pat2var).
                
if (!isset($aLinePat2Var['pathogenic']) || $aLinePat2Var['pathogenic'] === '') {
                    if (!
array_key_exists($sPat2VarKey$aPat2Var)) {
                        
// 2008-05-28; 2.0-07; Changed default value from 99 to 55 (unknown).
                        
$aLinePat2Var['pathogenic'] = '55';
                    }
                }

                
// ID_status_ column (pat2var).
                
if (!isset($aLinePat2Var['status']) || $aLinePat2Var['status'] === '') {
                    if (!
array_key_exists($sPat2VarKey$aPat2Var)) {
                        
$aLinePat2Var['status'] = 1;
                    }
                }

                
// variant_created_by_ (pat2var).
                
if (empty($aLinePat2Var['created_by'])) {
                    if (!
array_key_exists($sPat2VarKey$aPat2Var)) {
                        
$aLinePat2Var['created_by'] = (!empty($aLinePat['submitterid'])? $_AUTH['userid']);
                    }
                }

                
// variant_created_date_ (pat2var).
                
if (empty($aLinePat2Var['created_date'])) {
                    if (!
array_key_exists($sPat2VarKey$aPat2Var)) {
                        
$aLinePat2Var['created_date'] = date('Y-m-d H:i:s');
                    }
                }

                
// patient_created_by_ (patient).
                
if (empty($aLinePat['created_by'])) {
                    if (!
array_key_exists($nPatientID$aPatients)) {
                        
$aLinePat['created_by'] = (!empty($aLinePat['submitterid'])? $_AUTH['userid']);
                    }
                }

                
// patient_created_date_ (patient).
                
if (empty($aLinePat['created_date'])) {
                    if (!
array_key_exists($nPatientID$aPatients)) {
                        
$aLinePat['created_date'] = date('Y-m-d H:i:s');
                    }
                }

                
// 2008-11-13; 2.0-14 Added by Gerard. Generates a Variant/DBID.
                
$sVariant str_replace(array('('')''?'), ''$aLineVar[$sMutationCol]);
                if (empty(
$aLineVar['Variant/DBID'])) {
                    
// The Variant/DBID field in the upload file is empty so we need to generate it.
                    
$sIDGenerated lovd_fetchDBID($_SESSION['currdb'], $sVariant$sMutationCol); // Finds an existing number or generates a new one BUT EACH TIME THE SAME

                    // If the variant is already in the database (ID_variantid_), then the other part of the code will check the DBID.
                    
if (!array_key_exists($nVariantID$aVariants)) {
                        
// Not in the database yet.
                        
if (!array_key_exists($sVariant$aIDAssigned)) {
                            
// This variant (DNA level) has not been found earlier in this imported file.
                            
if (!in_array($sIDGenerated$aIDAssigned)) {
                                
// The generated DBID (IDgenerated) was not already used, so we can use it.
                                
$aIDAssigned[$sVariant] = $sIDGenerated;
                            } else {
                                
// The IDgenerated (Variant/DBID number) is already in use by a different variant, so we need a new IDGenerated
                                // This newly generated number is already in use, so add 1 to the highest value
                                
$sIDGenerated max($aIDAssigned);
                                
$sIDGenerated ++;
                                
$aIDAssigned[$sVariant] = $sIDGenerated;
                            }
                        } else {
                            
// We've seen this variant (DNA level) before in the file. Se we know an ID already!
                            
$sIDGenerated $aIDAssigned[$sVariant];
                        }
                        
$aLineVar['Variant/DBID'] = $sIDGenerated;
                    }

                } elseif (isset(
$aLineVar['Variant/DBID']) && preg_match('/^' $_SESSION['currsymb'] . '_[0-9]{5}/'$aLineVar['Variant/DBID'])) {
                    
// User has filled in an own DBID value that is correct. Let's use it.
                    
$aIDAssigned[$sVariant] = substr($aLineVar['Variant/DBID'], 0strlen($_SESSION['currsymb']) + 6);
                }

                
// This information is not taken from the database.
                
$aLineVar['indb'] = false;
                
$aLinePat['indb'] = false;
                
$aLinePat2Var['indb'] = false;
                
$aLinePat2Var['symbol'] = $_SESSION['currdb'];

                
// Save line number.
                
$aLineVar['line'] = $nLine;
                
$aLinePat['line'] = $nLine;
                
$aLinePat2Var['line'] = $nLine;

                
// Seen variant before? Check data.
                
if (array_key_exists($nVariantID$aVariants)) {
                    foreach (
$aLineVar as $sCol => $sVal) {
                        if (!
in_array($sCol, array('indb''line')) && $sVal && $sVal != $aVariants[$nVariantID][$sCol]) {
                            
// Col should not be indb or line; value should not be empty (otherwise, difference allowed); if value is different: throw error!
                            
lovd_errorAdd('Error in line ' $nLine ': value "' htmlspecialchars($sVal) . '" in "' $sCol '" column does not match value "' $aVariants[$nVariantID][$sCol] . '" from same variant entry ' . ($aVariants[$nVariantID]['indb']? 'in the database' 'on line ' $aVariants[$nVariantID]['line']) . '.');
                        }
                    }
                } else {
                    
// Store information.
                    
$aVariants[$nVariantID] = $aLineVar;
                    
$nVariants ++;
                }

                
// Seen patient before? Check data.
                
if (array_key_exists($nPatientID$aPatients)) {
                    foreach (
$aLinePat as $sCol => $sVal) {
                        if (!
in_array($sCol, array('indb''line')) && $sVal && $sVal != $aPatients[$nPatientID][$sCol]) {
                            
// Col should not be indb or line; value should not be empty (otherwise, difference allowed); if value is different: throw error!
                            
lovd_errorAdd('Error in line ' $nLine ': value "' htmlspecialchars($sVal) . '" in "' $sCol '" column does not match value "' $aPatients[$nPatientID][$sCol] . '" from same patient entry ' . ($aPatients[$nPatientID]['indb']? 'in the database' 'on line ' $aPatients[$nPatientID]['line']) . '.');
                        }
                    }
                } else {
                    
// Store information.
                    
$aPatients[$nPatientID] = $aLinePat;
                    
$nPatients ++;
                }

                
// Seen pat2var before? Check data.
                
if (array_key_exists($sPat2VarKey$aPat2Var)) {
                    foreach (
$aLinePat2Var as $sCol => $sVal) {
                        if (!
in_array($sCol, array('indb''line')) && $sVal && $sVal != $aPat2Var[$sPat2VarKey][$sCol]) {
                            
// Col should not be indb or line; value should not be empty (otherwise, difference allowed); if value is different: throw error!
                            
lovd_errorAdd('Error in line ' $nLine ': value "' htmlspecialchars($sVal) . '" in "' $sCol '" column does not match value "' $aPat2Var[$sPat2VarKey][$sCol] . '" from same patients2variants entry ' . ($aPat2Var[$sPat2VarKey]['indb']? 'in the database' 'on line ' $aPat2Var[$sPat2VarKey]['line']) . '.');
                        }
                    }
                } else {
                    
// Store information.
                    
$aPat2Var[(int) $nVariantID '|' . (int) $nPatientID '|' $aLinePat2Var['allele']] = $aLinePat2Var;
                    
$nPat2Var ++;
                }
            }
            
fclose($fInput);

            
// 2008-02-12; 2.0-04
            // Save even more memory. Unset all the unnecessary stuff.
            
reset($aVariants);
            
reset($aPatients);
            
reset($aPat2Var);
            while (list(
$sKey$aVal) = each($aVariants)) {
                if (!isset(
$aVal['sort'])) {
                    unset(
$aVariants[$sKey]);
                }
            }
            while (list(
$sKey$aVal) = each($aPatients)) {
                if (!isset(
$aVal['created_by'])) {
                    unset(
$aPatients[$sKey]);
                }
            }
            while (list(
$sKey$aVal) = each($aPat2Var)) {
                if (!isset(
$aVal['created_by'])) {
                    unset(
$aPat2Var[$sKey]);
                }
            }



            if (!
lovd_error()) {
                
// Start importing from the memory!
                
require ROOT_PATH 'inc-top.php';
                
lovd_printHeader('config''LOVD Configuration area');

                
$nTotal $nVariants $nPatients $nPat2Var;
                if (!
$nTotal) {
                    print(
'      No entries found that need to be imported in the database. Either your uploaded file contains no variants, or all entries are already in the database.<BR>' "\n\n");
                    require 
ROOT_PATH 'inc-bot.php';
                    exit;
                }

                
// Progress bar.
                
print('      Input file verified. Importing entries...<BR><BR>' "\n" .
                      
'      <TABLE border="0" cellpadding="0" cellspacing="0" class="S11" width="250">' "\n" .
                      
'        <TR style="height : 15px;">' "\n" .
                      
'          <TD width="100%" style="border : 1px solid black;">' "\n" .
                      
'            <IMG src="' ROOT_PATH 'gfx/trans.png" alt="" title="" width="0%" height="15" id="lovd_progress_import" style="background : #AFC8FA;"></TD>' "\n" .
                      
'          <TD align="right" width="25"><INPUT type="text" id="lovd_progress_import_value" size="3" value="0%" style="border : 0px; margin : 0px; padding : 0px; text-align : right;"></TD></TR></TABLE><BR>' "\n\n" .
                      
'      <SCRIPT type="text/javascript">var progressImport = document.getElementById(\'lovd_progress_import\'); var progressImportValue = document.getElementById(\'lovd_progress_import_value\');</SCRIPT>' "\n");

                
// Import...
                
$nProgressPrev '0%';
                
$n 0;

                
// If using transactional tables; begin transaction.
                
if ($_INI['database']['engine'] == 'InnoDB') {
                    
// FIXME; It's better to use 'START TRANSACTION', but that's only available from 4.0.11.
                    //   This works from the introduction of InnoDB in 3.23.
                    
@mysql_query('BEGIN WORK');
                }



                
// Variants.
                
foreach ($aVariants as $nKey => $aVal) {
                    if (
$aVal['indb']) {
                        continue;
                    }

                    
$n++;
                    
$sQ 'INSERT INTO ' TABLE_CURRDB_VARS ' (';
                    
$sCols '';
                    
$sVals '';
                    foreach (
$aVal as $sCol => $sVal) {
                        if (
in_array($sCol, array('indb''line'))) {
                            continue;
                        }
                        
$sCols .= ($sCols', ' '') . '`' $sCol '`';
                        
$sVals .= ($sVals', ' '') . '"' $sVal '"';
                    }
                    
$sQ .= $sCols ') VALUES (' $sVals ')';
                    
$q mysql_query($sQ);
                    if (!
$q) {
                        
// Save the mysql_error before it disappears.
                        
$sError mysql_error();
                        if (
$_INI['database']['engine'] == 'InnoDB') {
                            @
mysql_query('ROLLBACK');
                        }
                        
lovd_dbFout('VariantImportA'$sQ$sError);
                    }

                    
$nProgress round(($n*100)/$nTotal) . '%';
                    if (
$nProgress != $nProgressPrev) {
                        print(
'      <SCRIPT type="text/javascript">progressImport.style.width = \'' $nProgress '\'; progressImportValue.value = \'' $nProgress '\';</SCRIPT>' "\n");
                    }

                    
flush();
                    
usleep(1000);
                    
$nProgressPrev $nProgress;
                }



                
// Patients.
                
foreach ($aPatients as $nKey => $aVal) {
                    if (
$aVal['indb']) {
                        continue;
                    }

                    
$n++;
                    
$sQ 'INSERT INTO ' TABLE_PATIENTS ' (';
                    
$sCols '';
                    
$sVals '';
                    foreach (
$aVal as $sCol => $sVal) {
                        if (
in_array($sCol, array('indb''line'))) {
                            continue;
                        }
                        
$sCols .= ($sCols', ' '') . '`' $sCol '`';
                        
// Quick fix; change edited* fields "" to NULL.
                        
$sVals .= ($sVals', ' '') . (substr($sCol07) == 'edited_' && !$sVal'NULL' '"' $sVal '"');
                    }
                    
$sQ .= $sCols ') VALUES (' $sVals ')';
                    
$q mysql_query($sQ);
                    if (!
$q) {
                        
// Save the mysql_error before it disappears.
                        
$sError mysql_error();
                        if (
$_INI['database']['engine'] == 'InnoDB') {
                            @
mysql_query('ROLLBACK');
                        }
                        
lovd_dbFout('VariantImportB'$sQ$sError);
                    }

                    
$nProgress round(($n*100)/$nTotal) . '%';
                    if (
$nProgress != $nProgressPrev) {
                        print(
'      <SCRIPT type="text/javascript">progressImport.style.width = \'' $nProgress '\'; progressImportValue.value = \'' $nProgress '\';</SCRIPT>' "\n");
                    }

                    
flush();
                    
usleep(1000);
                    
$nProgressPrev $nProgress;
                }



                
// Pat2Var data.
                
foreach ($aPat2Var as $nKey => $aVal) {
                    if (
$aVal['indb']) {
                        continue;
                    }

                    
$n++;
                    
$sQ 'INSERT INTO ' TABLE_PAT2VAR ' (';
                    
$sCols '';
                    
$sVals '';
                    foreach (
$aVal as $sCol => $sVal) {
                        if (
in_array($sCol, array('indb''line'))) {
                            continue;
                        }
                        
$sCols .= ($sCols', ' '') . '`' $sCol '`';
                        
// Quick fix; change edited* fields "" to NULL.
                        
$sVals .= ($sVals', ' '') . (substr($sCol07) == 'edited_' && !$sVal'NULL' '"' $sVal '"');
                    }
                    
$sQ .= $sCols ') VALUES (' $sVals ')';
                    
$q mysql_query($sQ);
                    if (!
$q) {
                        
// Save the mysql_error before it disappears.
                        
$sError mysql_error();
                        if (
$_INI['database']['engine'] == 'InnoDB') {
                            @
mysql_query('ROLLBACK');
                        }
                        
lovd_dbFout('VariantImportC'$sQ$sError);
                    }

                    
$nProgress round(($n*100)/$nTotal) . '%';
                    if (
$nProgress != $nProgressPrev) {
                        print(
'      <SCRIPT type="text/javascript">progressImport.style.width = \'' $nProgress '\'; progressImportValue.value = \'' $nProgress '\';</SCRIPT>' "\n");
                    }

                    
flush();
                    
usleep(1000);
                    
$nProgressPrev $nProgress;
                }



                
// If we don't do this, we haven't got anything in the DB... duh!
                
if ($_INI['database']['engine'] == 'InnoDB') {
                    
// Could this actually fail?!!??
                    
@mysql_query('COMMIT');
                }

                
// 2007-12-05; 2.0-02; Fixed bug #20 - Gene's "Last update" field not updated.
                
lovd_setUpdatedDate($_SESSION['currdb']);

                
// Done!!!
                
lovd_writeLog('MySQL:Event''VariantImport'$_AUTH['username'] . ' (' mysql_real_escape_string($_AUTH['name']) . ') successfully imported ' $nVariants ' variant' . ($nVariants == 1'' 's') . ' and ' $nPatients ' patient' . ($nPatients == 1'' 's') . ' (' $_SESSION['currdb'] . ')');
                print(
'      Done importing!<BR>' "\n\n" .
                      
'      <SCRIPT type="text/javascript">' "\n" .
                      
'        <!--' "\n" .
                      
'        setTimeout("window.location.href = \'' PROTOCOL $_SERVER['HTTP_HOST'] . rtrim(dirname($_SERVER['SCRIPT_NAME']), '/') . '/config.php' lovd_showSID() . '\'", 3000);' "\n" .
                      
'        // -->' "\n" .
                      
'      </SCRIPT>' "\n\n");

                require 
ROOT_PATH 'inc-bot.php';
                exit;
            }
        }
        @
fclose($fInput);
    }
}



require 
ROOT_PATH 'inc-top.php';
lovd_printHeader('config''LOVD Configuration area');

if (!isset(
$_GET['sent'])) {
    list(
$nMaxVar) = mysql_fetch_row(mysql_query('SELECT MAX(variantid) FROM ' TABLE_CURRDB_VARS));
    list(
$nMaxPat) = mysql_fetch_row(mysql_query('SELECT MAX(patientid) FROM ' TABLE_PATIENTS));
    if (
$nMaxPat) {
        
lovd_showInfoTable('If you\'re importing new variants or new patients, please note the available IDs:<BR>Variant:' . ($nMaxVar 1) . ' and up<BR>Patient:' . ($nMaxPat 1) . ' and up''information');
    }
}

print(
'      Please select the file containing the variant and patient data, that you wish to import into the ' $_SESSION['currdb'] . ' gene.<BR>' "\n" .
      
'      <SPAN class="S11">(<A href="' ROOT_PATH 'docs/variant_and_patient_data/importing_text_files.php">Important information about the file format</A>)</SPAN><BR>' "\n" .
      
'      <BR>' "\n\n");

lovd_errorPrint();

print(
'      <FORM action="' $_SERVER['SCRIPT_NAME'] . '?sent" method="post" enctype="multipart/form-data">' "\n" .
      
'        <INPUT type="hidden" name="MAX_FILE_SIZE" value="' $nMaxSize '">' "\n" .
      
'        <INPUT type="file" name="upload_file" size="30"><BR>' "\n" .
      
'        <INPUT type="submit" value="Import variants">' "\n" .
      
'      </FORM><BR>' "\n\n");

lovd_showInfoTable('<SPAN class="S11">In some cases importing big files can lead to memory consumption problems. In case these errors are hidden, LOVD would return a blank screen. If this happens, split your import file into smaller chunks or ask your system administrator to allow PHP to use more memory.<BR><A href="http://www.lovd.nl/bugs/?do=details&id=17" target="_blank">More information</A>.</SPAN>''warning');

require 
ROOT_PATH 'inc-bot.php';
?>