<?php
define('idDiGIR_scan','$Id: DiGIR_scan.php,v 1.8 2004/06/09 17:45:32 rdg Exp $');
if (defined('idDIGIR_VERSION_REQUEST'))
    return;
/**
* DiGIR_scan.php
*
* Implements SCAN operation

SCAN essentially performs a
SELECT field,count(field) FROM table GROUP BY field ORDER BY field

and returns zero or more of the resulting rows.
*/

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

function scanColumn($params)
{
    global $g_LOG;

    //create a log entry
    //$resource,$strfilter,$startrec,$maxrecs,$returnedrecs,$column
    $cLog = new DiGIRLog_inventory($params['resource'],
                                   $params['filter'],
                                   $params['startrec'],
                                   $params['maxrecs'],
                                   0,
                                   '');

    //if no filter is supplied, just use the column name in the record structure
    $filterString = trim($params['filter']);
    $flt = new filter();
    $flt->parse($filterString,$params['requestnamespaces']);
    
    // just check for a valid filter if it was supplied
    if (strlen($filterString) >= 6)
    {
        if (!$flt->validQuery())
        {
            appendError(DC_INVALIDQUERY,
                "The filter (query) provided (".$filterString.") is invalid.",
                DIAG_WARN);
        }
    }

    $tmp = new ConfigBuilder($params['resourceconfigfile']);
    $Config = $tmp->Config;

    //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->maxInventoryRecords) ||
        ($params['maxrecs'] < 0))
    {
        $params['maxrecs'] = $Config->maxInventoryRecords;
    }


    if ($params['recordstruct'] == '')
    {
        if (!empty($Config->defaultFormats['scan']))
        {
            $params['recordstruct'] = $Config->defaultFormats['scan'];
        }
        else
        {
            appendError(DC_FORMATLOADFAILED,"Missing record format
              definition",DIAG_ERROR);
        }
    }
    
    if (_DEBUG)
    {
        foreach ($params as $k=>$v)
        {
            DebugMsg("params[".$k."]=]".$v);
        }
    }

    //create the record builder
    $RDef = new DiGIRScanRecord();
    $RDef->nameSpaces = $params['requestnamespaces'];

    $xopt = array(XML_OPTION_CASE_FOLDING => FALSE);
    $xp = new XPath("",$xopt);

    if (isURL($params['recordstruct']))
    {
        if ($params['cache'])
        {
            //load the structure from the 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);
            $res = $cache->sendRequest();
            if ($res)
            {
                $remoteFileBody = $cache->getResponseBody();
                $xp->importFromString($remoteFileBody);
            }
            else
            {
                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']);
            //echo "<d>".$xp->exportAsHTML()."</d>";
        }
    }
    elseif (strpos(trim($params['recordstruct']),"<") !== FALSE)
    {
        $xp->importFromString($params['recordstruct']);
    }
    else
    {
        $xmltmp = '<records>';
        $xmltmp .= '<structure><xsd:element name="record">';
        $xmltmp .= '<xsd:complexType><xsd:all>';
        $xmltmp .= '<xsd:element ref="'.$params['recordstruct'].'" />';
        $xmltmp .= '</xsd:all></xsd:complexType>';
        $xmltmp .= '</xsd:element>';
        $xmltmp .= '</structure></records>';
        $xp->importFromString($xmltmp);
    }

    $RDef->buildTemplate($xp);

    //get the column being scanned from the RDef
    $cLog->setparam('column',$RDef->root[0][7]);
    

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

    //load the data source table map
    $RDef->fillStructureTablesFromConfig($Config);
    
    $requestedConcept = $RDef->getRequestNode();
    
    $colSource = $requestedConcept['table'].".".$requestedConcept['field'];

    if (_DEBUG)
        DebugMsg("request Concept = ".$colSource);

    $sqlFROM = $Config->FROMclause();
    $sqlWHERE = ' ';
    $requestFilter = '';
    if ($flt->validQuery())
    {
        $requestFilter = $flt->toSQL($Config);
        $sqlWHERE = ' WHERE '.$requestFilter;
    }

    $sqlSELECT = "SELECT ".$colSource.", count(".$colSource.") as cnt";

    $localFilter = $Config->localFilter();

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

        $sqlWHERE .= $localFilter;
    }

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

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

    $res = $cn->Connect($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"," ",
            "(inventory) 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;
    }

    $nrecs = 0;
    if ($params['countrecs'] == true)
    {
        //user has requested a count of the total number of matches
        $sql = $sqlSELECT.$sqlFROM.$sqlWHERE;
        $sql.= " GROUP BY ".$colSource;
        if (_DEBUG)
        {
            echo "<d>\n";
            echo maketag("sql_count",$sql);
            echo "</d>\n";
        }
        $g_LOG->log(str_replace("\n"," ","SQL_COUNT := ".$sql),PEAR_LOG_DEBUG);
        $RS = &$cn->Execute($sql);
        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"," ",
                "(inventory) Error generating record count result set. SQL=".$sql),
                PEAR_LOG_ERR);
        }
        else
        {
            $totalRecs = $RS->RecordCount();
            appendError(DC_MATCH_COUNT,$totalRecs,DIAG_INFO);
            $RS->Close();
        }
    }
    if ($params['getrecords'] == true)
    {
        $sql = $sqlSELECT.$sqlFROM.$sqlWHERE;
        $sql.= " GROUP BY ".$colSource;
        $sql.= " ORDER BY ".$colSource;

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

        $RS = &$cn->SelectLimit($sql,
                                $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();
            appendError(DC_DATABASE_ERROR,htmlentities($err),DIAG_ERROR);
            appendError(DC_DEBUG_SQL,
                htmlentities($sqlSELECT.$sqlFROM.$sqlWHERE),
                DIAG_DEBUG);
            $cn->Close();
            echo DiGIRErrors($params['clientkey']);

            $g_LOG->log(str_replace("\n"," ",
                "(inventory) No resultset generated when getting records.  SQL=".$sql),
                 PEAR_LOG_ERR);
            $cLog->writeLog($g_LOG);
            return;
        }
        while ((!$RS->EOF) && ($nrecs < $params['maxrecs']))
        {
            $nrecs ++;
            echo $RDef->generateRecord($Config,$cn,$RS,$params['clientkey']);
            if (!$params['cache'])
                flush();
        }
        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);
    }
    echo "</content>\n";
    $cn->Close();

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

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

?>
