<?php
define('idDiGIR_getContent','$Id: DiGIR_getContent.php,v 1.6 2004/05/14 23:57:34 rdg Exp $');
if (defined('idDIGIR_VERSION_REQUEST'))
    return;
/**
* $Id: DiGIR_getContent.php,v 1.6 2004/05/14 23:57:34 rdg Exp $
*
* implements the DiGIR getContent method
*/

require_once('DiGIR_globals.php');
require_once('DiGIR_flt.php');
require_once('DiGIR_config.php');
require_once('adodb/adodb.inc.php');  //adodb generic db library
require_once('DiGIR_recStr.php');

function getContent($params)
{
    global $g_LOG;

    if (_DEBUG)
    {
        echo "<record>\n";
        echo "<d>Dumping the request parameters...</d>";
        echo maketag("resource",$params["resource"]);
        echo maketag("filter",$params["filter"]);
        echo maketag("operation",$params["operation"]);
        echo maketag("startrec",$params["startrec"]);
        echo maketag("maxrecs",$params["maxrecs"]);
        echo maketag("clientkey",$params["clientkey"]);
        echo maketag("recordstruct",$params["recordstruct"]);
        echo maketag("sort",$params["sort"][0].','.$params['sort'][1]);
        echo "</record>\n";
    }

    /*
    Check that something actually being asked for- otherwise just bail.
    */
    if (($params['getrecords'] == false) &&
        ($params['countrecs'] == false))
    {
        echo '<content />';
        appendError(DC_NOCONTENT,
            'Request does not ask for match count or any records',
            DIAG_WARN);
    	echo DiGIRErrors($params['clientkey']);
        return;
    }


    $filterString = trim($params['filter']);
    if (strlen($filterString) < 6)
    {
        echo '<content />';
        appendError(DC_FILTERTOOSHORT,
            "The supplied filter was to short to be valid..",
            DIAG_WARN);
    	echo DiGIRErrors($params['clientkey']);
        return;
    }
    $flt = new filter();
    $flt->parse($filterString,$params['requestnamespaces']);
    if (!$flt->validQuery())
    {
        echo '<content />';
        appendError(DC_INVALIDQUERY,
            "The filter (query) provided (".$filterString.") is invalid.",
            DIAG_ERROR);
    	echo DiGIRErrors($params['clientkey']);
        return;
    }
    
    if (ErrorCountA(array(DIAG_ERROR,DIAG_FATAL)) > 0)
    {
        echo '<content />';
        appendError(DC_TOOMANYERRORS,
            "Too many errors.",
            DIAG_ERROR);
    	echo DiGIRErrors($params['clientkey']);
        return;
    }

    DebugMsg("Loading database configuration data");
    $tmp = new ConfigBuilder($params['resourceconfigfile']);
    $Config = $tmp->Config;
    if ($Config == NULL)
    {
        appendError("DC_CONFIGURATION_FAILURE",
          "Failed to load resource configuration.",
          DIAG_FATAL);
        echo '<content />';
    	echo DiGIRErrors($params['clientkey']);
        return;
    }
    DebugMsg("Config loaded.");
    
    //limit the max number of records to retrieve to the resoruce specified
    //limit.  If the parameter maxrecords <0, then it was not defined by the
    //request, so set it to the default for the resource.
    if (($params['maxrecs'] > $Config->maxResponseRecords) ||
        ($params['maxrecs'] < 0))
    {
        $params['maxrecs'] = $Config->maxResponseRecords;
    }
    
    if ($params['recordstruct'] == '')
    {
        if (!empty($Config->defaultFormats['search']))
        {
            $params['recordstruct'] = $Config->defaultFormats['search'];
        }
        else
        {
            appendError(DC_FORMATLOADFAILED,"Missing record format
              definition",DIAG_ERROR);
        }
    }
        
    //create the record builder
    $RDef = new DiGIRRecord();
    $RDef->nameSpaces = $params['requestnamespaces'];
        
    //construct the record schema
    $xopt = array(XML_OPTION_CASE_FOLDING => FALSE);
    $xp = new XPath("",$xopt);
    if (isURL($params['recordstruct']))
//        $xp->importFromFile($params['recordStruct']);
    {
        //load the structure from the cache
        if ($params['cache'])
        {
            require_once('Cache/HTTP_Request.php');
            $cacheParams = array('cache_dir'=>DIGIR_CACHE_DIRECTORY);
            $requestParams = array('method'=>'GET','http'=>'1.1');
            $cache = &new Cache_HTTP_Request($params['recordstruct'],
                            $requestParams,
                            'file',
                            $cacheParams,
                            DIGIR_FORMAT_CACHE_LIFE_SECS,
                            CACHE_HTTP_REQUEST_RETURN_FALSE);
            $cacheOK = $cache->sendRequest();
            if ($cacheOK)
            {
                $remoteFileBody = $cache->getResponseBody();
                $cacheOK = $xp->importFromString($remoteFileBody);
                
            }
            if (!$cacheOK)
            {
                appendError(DC_FORMATLOADFAILED,"The remote record format "
                    ."definition could not be loaded from the specified URL ("
                    .$params['recordStruct'].")",DIAG_ERROR);
            }
        }
        else
        {
            $xp->importFromFile($params['recordstruct']);
        }
    }
    else
        $xp->importFromString($params['recordstruct']);
        
    //construct the record output template from the xmlschema document
    $RDef->buildTemplate($xp);
    
    if (ErrorCountA(array(DIAG_ERROR,DIAG_FATAL)) > 0)
    {
        echo '<content />';
        appendError(DC_TOOMANYERRORS,
            "Too many errors.",
            DIAG_ERROR);
    	echo DiGIRErrors($params['clientkey']);
        return;
    }


    //add the record namespace(s) to the content element
	$contenttag = '<content'.$RDef->listNamespaces().'>';
	echo $contenttag;

    //load the data source table map
    $RDef->fillStructureTablesFromConfig($Config);

    if ($Config->connectionType == 'z3950')
    {
        $res = getContentZ3950($params,$flt,$Config,$RDef);
    }
    else
    {
        $res = getContentSQL($params,$flt,$Config,$RDef);
    }
    if (!$res)
        return;


	//echo the errors here so the output is captured by the caching mechanism.
	echo DiGIRErrors($params['clientkey']);
}

/**
* Retrieve content from a Z39.50 resource using the ADODB z3950 driver.
*/
function getContentZ3950(&$params,&$flt,&$Config,&$RDef)
{
    global $ADODB_FETCH_MODE;
    
    $qry = $flt->toRPN($Config);

    $cn = &ADONewConnection($Config->connectionType);
    if (!is_object($cn))
    {
        echo '</content>';
        appendError(DC_INTERNALDATABASEERROR,
            'A connection to the database could not be created.',
            DIAG_ERROR);
      	echo DiGIRErrors($params['clientkey']);
        return false;
    }

    $cn->PConnect($Config->connectionString,
                  $Config->connectionUID,
                  $Config->connectionPWD,
                  $Config->connectionDB);
                  
    //load results to associative array
    $ADODB_FETCH_MODE = ADODB_FETCH_ASSOC;
    $rs = &$cn->Execute($qry);
    appendError(DC_MATCH_COUNT,$rs->RecordCount(),DIAG_INFO);
    
    if ($params['getrecords'])
    {
        $nrecs = 0;
        while ((!$RS->EOF) && ($nrecs < $params['maxrecs']))
        {
            $nrecs ++;

            echo $RDef->generateRecord($Config,$cn,$RS,$params['clientkey']);
        }
        
        appendError(DC_ROW_COUNT,$nrecs,DIAG_INFO);
        if ($RS->EOF)
            appendError(DC_END_OF_RECORDS,'true',DIAG_INFO);
        else
            appendError(DC_END_OF_RECORDS,'false',DIAG_INFO);
    }
    $cn->Close();
	echo "</content>\n";
	return true;
}

/**
* Retrieve content from an SQL database.
*/
function getContentSQL(&$params,&$flt,&$Config,&$RDef)
{
    global $ADODB_FETCH_MODE;
    global $g_LOG;

    //create a log entry
    $cLog = new DiGIRLog_search($params['resource'],
                                   $params['filter'],
                                   $params['startrec'],
                                   $params['maxrecs'],
                                   0,
                                   $params['recordstruct']);


    //TODO: the selected fields could be dependent on the requested record schema
    $sqlSELECT = 'SELECT '.$Config->SELECTfields();
    $sqlFROM = $Config->FROMclause();
    $sqlWHERE = ' WHERE '.$flt->toSQL($Config);

    $localFilter = $Config->localFilter();

    if ($localFilter)
    {
        $sqlWHERE .= ' AND '.$localFilter;
    }

    if (ErrorCountA(array(DIAG_ERROR,DIAG_FATAL)) > 0)
    {
        echo '</content>';
        appendError(DC_TOOMANYERRORS,
            "Too many errors.",
            DIAG_ERROR);
       	echo DiGIRErrors($params['clientkey']);
        $g_LOG->log(str_replace("\n"," ",
            "Get content exiting because too many errors encountered"),
             PEAR_LOG_ERROR);
        $cLog->writeLog($g_LOG);
        return false;
    }


    if (_DEBUG)
    {
        //Debug stuff
        echo "<record>\n";
        $Config->Dump();
        echo "</record>\n";
    }

    $cn = &ADONewConnection($Config->connectionType);
    if (!is_object($cn))
    {
        echo '</content>';
        appendError(DC_INTERNALDATABASEERROR,
            'A connection to the database could not be created.',
            DIAG_FATAL);
       	echo DiGIRErrors($params['clientkey']);
        $g_LOG->log(str_replace("\n"," ",
            "Failed to load database driver for type (".$Config->connectionType.")"),
            PEAR_LOG_ERR);
        $cLog->writeLog($g_LOG);
        return false;
    }

    //Set the charPage attribute of the connection.
    //This only works for OLEDB based connections, but will not hurt
    //other types of connections
    $charPage = encodingToCodePage($Config->connectionEncoding);
    if (!is_null($charPage))
        $cn->charPage = $charPage;
    $cn->fmtDate = $cn->fmtTimeStamp;


    $nrecs = 0;
    $res = $cn->PConnect($Config->connectionString,
                  $Config->connectionUID,
                  $Config->connectionPWD,
                  $Config->connectionDB);
    if (!$res)
    {
        echo '</content>';
        appendError(DC_INTERNALDATABASEERROR,
            'A connection to the database could not be created.',
            DIAG_FATAL);
       	echo DiGIRErrors($params['clientkey']);
        $g_LOG->log(str_replace("\n"," ",
            "Failed to connect to database.  Params=".
            serialize(array('cn'=>$Config->connectionString,
                                'uid'=>$Config->connectionUID,
                                'pwd'=>$Config->connectionPWD,
                                'db'=>$Config->connectionDB))),
                PEAR_LOG_ERR);
        $cLog->writeLog($g_LOG);
        return false;
    }
    
    if ($params['countrecs'] == true)
    {
        //user has requested a count of the total number of matches
        $sql = 'SELECT Count(*) AS cnt '.$sqlFROM.$sqlWHERE;
        if (_DEBUG)
        {
            echo "<record>\n";
            echo maketag("sql_count",$sql);
            echo "</record>\n";
        }
        $g_LOG->log(str_replace("\n"," ","SQL_COUNT := ".$sql),PEAR_LOG_DEBUG);

        $encodedSQL = encodeSQL($sql, $Config->connectionEncoding);

        $RS = &$cn->Execute($encodedSQL);
        if (!is_object($RS))
        {
            $err = $cn->ErrorMsg();
            appendError(DC_DATABASE_ERROR,htmlentities($err),DIAG_ERROR);
            appendError(DC_DEBUG_SQL,htmlentities($sql),DIAG_DEBUG);
            $g_LOG->log(str_replace("\n"," ",
                "Error generating record count result set.  SQL=".$sql),
                PEAR_LOG_ERR);
        }
        else
        {
            $totalRecs = $RS->fields[0];
            appendError(DC_MATCH_COUNT,$totalRecs,DIAG_INFO);
        }
        $RS->Close();
    }
    if (ErrorCountA(array(DIAG_ERROR,DIAG_FATAL)) > 0)
    {
        $cn->Close();
        echo '</content>';
        appendError(DC_TOOMANYERRORS,
            "Too many errors.",
            DIAG_ERROR);
       	echo DiGIRErrors($params['clientkey']);
        $g_LOG->log(str_replace("\n"," ",
            "Get content exiting because too many errors encountered"),
             PEAR_LOG_ERR);
        $cLog->writeLog($g_LOG);
        return false;
    }

    if ($params['getrecords'] == true)
    {
        //load results to associative array
        $ADODB_FETCH_MODE = ADODB_FETCH_ASSOC;

        $sqlORDERBY = $Config->ORDERBYclause($Config,
                        $params['sort'][0],
                        $params['sort'][1]);
        $sql = $sqlSELECT.$sqlFROM.$sqlWHERE.$sqlORDERBY;

        if (_DEBUG)
        {
            echo "<record>\n";
            echo maketag("sql_records",$sql);
            echo "</record>\n";
        }
        
        $g_LOG->log(str_replace("\n"," ","SQL_SELECT := ".$sql),PEAR_LOG_DEBUG);

        $encodedSQL = encodeSQL($sql, $Config->connectionEncoding);

        $RS = &$cn->SelectLimit($encodedSQL,
                    $params['maxrecs']+1,
                    $params['startrec']);
        if (!is_object($RS))
        {
            echo '</content>';
            appendError(DC_QUERYPRODUCEDNORESULTS,
                'The query generated a null resultset.',
                DIAG_WARN);
            $err = $cn->ErrorMsg();
            $cn->Close();
            appendError(DC_DATABASE_ERROR,htmlentities($err),DIAG_ERROR);
            appendError(DC_DEBUG_SQL,
                htmlentities($sqlSELECT.$sqlFROM.$sqlWHERE),
                DIAG_DEBUG);
        	echo DiGIRErrors($params['clientkey']);
            $g_LOG->log(str_replace("\n"," ",
                "No resultset generated when getting records.  SQL=".$sql),
                 PEAR_LOG_ERR);
            $cLog->writeLog($g_LOG);
            return false;
        }
        while ((!$RS->EOF) && ($nrecs < $params['maxrecs']))
        {
            $nrecs ++;

            echo $RDef->generateRecord($Config,$cn,$RS,$params['clientkey']);
        }
        appendError(DC_ROW_COUNT,$nrecs,DIAG_INFO);
        if ($RS->EOF)
            appendError(DC_END_OF_RECORDS,'true',DIAG_INFO);
        else
            appendError(DC_END_OF_RECORDS,'false',DIAG_INFO);
        $RS->Close();
        $cn->Close();
    }
	echo "</content>\n";

    $cLog->setparam('returnedrecs',$nrecs);
    $cLog->setparam('status',true);
    $cLog->writeLog($g_LOG);

	return true;
}

?>
