<?php 
    # $Id: benchmarkInstances_SEARCH.php,v 1.5 2007/01/16 21:14:15 jarda Exp $

    /* Page that allows to search benchmark instances
    */

    require_once('structuredPage.inc.php');

    class PageClass extends ViewStructuredPage 
    {
        var $displayLimit = 100;
        var $attributesLimit = 5;

        
        /* Initializes constants and auxiliary arrays
        */
        function customInitialization()
        {
            define('AR_LT', 1);
            define('AR_LE', 2);
            define('AR_EQ', 3);
            define('AR_GE', 4);
            define('AR_GT', 5);
            define('AR_NE', 6);

            $this->attributeRelations = array(AR_LT, AR_LE, AR_EQ, AR_GE, AR_GT, AR_NE);
            $this->attributeRelationStrings = array(AR_LT => '<', AR_LE => '<=', AR_EQ => '=', 
                                                    AR_GE => '>=', AR_GT => '>', AR_NE => '<>');
        }
        
        
        function getTitle()
        {
            return 'Search benchmark instance';
        }

        
        function printContents() {
            $db = connect();
            
            $this->insertSearchingCriteria($db);

            if ($this->areCriteriaPrepared())
            {
                $this->insertAggregateDownloadButton();
                $this->insertResults($db);
            }
        }


        /* Finds out whether a search criteria has been entered
        */
        function areCriteriaPrepared()
        {
            return ($_GET['search'] != NULL);
        }


        /* Inserts searching criteria input controls to the page
        */
        function insertSearchingCriteria($db)
        {
            echo "<form action=\"benchmarkInstances_SEARCH.php\" type=\"get\">\n";

            # name, format and benchmark set criteria {{{
            echo "<table>\n";

            echo "<tr><td>Benchmark name:</td><td><input type=\"text\" name=\"name\" value=\"$_GET[name]\"></td></tr>\n";

            echo "<tr><td>Format:</td><td>\n";
            $this->insertFormatSelection($db);
            echo "</td></tr>\n";

            echo "<tr><td>Set:</td><td>\n";
            $this->insertBenchmarkSetSelection($db);
            echo "</td></tr>\n";

            echo "</table>\n";
            # }}}


            # attributes criteria {{{
            echo "<table>\n";
                
            for ($index = 1; $index <= $this->attributesLimit; $index++) {
                $this->insertAttributeCriteria($index);
            }

            echo "</table>\n";
            # }}}

            echo "<br>\n";

            echo "<input type=\"submit\" value=\"Search\" name=\"search\">";

            echo "</form>\n";
        }


        /* Inserts format selection input control to the page
        */
        function insertFormatSelection($db)
        {
            echo "<select name=\"formatId\">\n";
            echo("<option value=\"\"></option>\n");

            $query = "SELECT * FROM format";
            $result = $db->Execute($query);

            while ($row = $result->FetchRow()) {
                echo "<option value=\"$row[id]\"";
                if ($row['id'] == $_GET['formatId'])
                    echo " selected";
                echo ">$row[name]</option>\n";
            }

            echo("</select>");
        }


        /* Inserts benchmark set selection input control to the page
        */
        function insertBenchmarkSetSelection($db)
        {
            echo("<select name=\"benchmarkSetId\">\n");
            echo("<option value=\"\"></option>\n");

            $db = connect();
            $query = "SELECT * FROM benchmarkSet";
            $result = $db->Execute($query);

            while ($row = $result->FetchRow()) {
                echo "<option value=\"$row[id]\"";
                if ($row['id'] == $_GET['benchmarkSetId'])
                    echo " selected";
                echo ">$row[name]</option>\n";
            }

            echo("</select></td></tr>\n");
        }


        /* Inserts one row of attribute criteria controls
        */
        function insertAttributeCriteria($index)
        {
            echo "<tr><td>";

            # attribute {{{
            echo("<select name=\"attribute_$index\">\n");
            echo("<option value=\"\"></option>\n");

            $db = connect();
            $query = "SELECT * FROM attribute";
            $result = $db->Execute($query);

            while ($row = $result->FetchRow()) {
                echo "<option value=\"$row[id]\"";
                if ($row['id'] == $_GET["attribute_$index"])
                    echo " selected";
                echo ">$row[name]</option>\n";
            }

            echo("</select>\n");
            # }}}

            echo "</td><td>";

            # relation {{{
            echo("<select name=\"relation_$index\">\n");
            echo("<option value=\"\"></option>\n");

            foreach ($this->attributeRelations as $relation) {
                
                echo "<option value=\"$relation\"";
                if ($relation == $_GET["relation_$index"])
                    echo " selected";
                echo ">".$this->attributeRelationStrings[$relation]."</option>\n";
            }

            echo("</select>\n");
            # }}}

            echo "</td><td>";

            # value {{{
            $originalValue = $_GET["value_$index"];
            echo "<input type=\"text\" name=\"value_$index\" value=\"$originalValue\">";
            # }}}

            echo "<td></tr>";
        }

        
        /* Inserts a button for aggregate downloading of benchmarks
        */
        function insertAggregateDownloadButton()
        {
            echo "<br>\n";
            echo "<form action=\"benchmarksArchive_DOWNLOAD.php\" method=\"post\">\n";
            
            $query = $this->getQueryString();
            echo "<input type=\"hidden\" name=\"query\" value=\"$query\">\n";

            echo "Archive of the matching benchmarks: <input type=\"submit\" name=\"download\" value=\"Download\">\n";
            echo "</form>\n";
            echo "<br>";
        }


        /* Inserts table of results to the page
        */
        function insertResults($db)
        {
            $count = $this->getCount($db);
            
            $query = $this->getQueryString();

            $offset = $this->getOffset();

            $this->insertNavigationControls($offset, $count);

            $recordSet = $db->SelectLimit($query, $this->displayLimit, $offset);

            echo "<table border=\"1\">\n";

            $canEditDB = $this->userCanEditDB();

            echo "<tr><th>Benchmark</th><th>Set</th><th>Format</th><th>Instance description</th><th>Download</th>";
            
            if ($canEditDB)
            {
                echo "<th>Edit</th>";
                echo "<th>Delete</th>";
            }
                
            echo "</tr>\n";
            
            while ($row = $recordSet->FetchRow()) {
                echo "<tr><td>";
                echo "<a href=\"benchmarkInstance_SHOW.php?id=$row[id]\" title=\"$row[benchmarkdescription]\">$row[name]</a>";
                echo "</td><td>";
                echo "$row[setname]";
                echo "</td><td>";
                echo "$row[formatname]";
                echo "</td><td>";
                
                if ($row['instancedescription'])
                    echo $row['instancedescription'];
                else
                    echo "&nbsp;";
                
                echo "</td><td>";

                if ($row['filename'])
                    echo "<a href=\"benchmarkFile_DOWNLOAD.php?id=$row[id]\">Download</a>";
                else
                    echo "&nbsp;";

                if ($canEditDB)
                {
                    echo "</td><td><a href=\"benchmarkInstance_EDIT.php?id=$row[id]\">Edit</a>";
                    echo "</td><td><a href=\"benchmarkInstance_DELETE.php?id=$row[id]\"><font color=\"red\">Delete</font></a>";
                }
                
                echo "</td></tr>\n";
            }

            echo "</table>\n";
        }


        /* Returns number of search results
        */
        function getCount($db)
        {
            $query = $this->getQueryString(1);

            $recordSet = $db->Execute($query);

            $row = $recordSet->FetchRow();

            return $row['count'];
        }


        /* Inserts navigation controls for page browsing across of pages of
        * results and displaying related information
        */
        function insertNavigationControls($offset, $count)
        {
            $previousPageExists  = $offset > 0;
            $nextPageExists      = $offset + $this->displayLimit < $count ;

            $getParameters = array() + $_GET;

            if ($previousPageExists)
            {
                $getParameters['offset'] = $offset - $this->displayLimit;
                echo "<a href=\"benchmarkInstances_SEARCH.php?" . $this->getGETStringFromArray($getParameters) . "\">&lt; Previous&nbsp;</a>";
            }

            if ($count > 0) {
                $begin = $offset + 1;
                $end = min($offset + $this->displayLimit, $count);

                echo "$begin - $end of $count";
            }
            else
                echo 'No matching instance has been found';

            if ($nextPageExists)
            {
                $getParameters['offset'] = $offset + $this->displayLimit;
                echo "<a href=\"benchmarkInstances_SEARCH.php?" . $this->getGETStringFromArray($getParameters) . "\">&nbsp;Next &gt;</a>";
            }

            echo "<br>\n";
            echo "<br>\n";
        }


        /* Creates GET string from an associative array
        */
        function getGETStringFromArray($getParameters)
        {
            $pairs = array();

            foreach ($getParameters as $key => $value)
            {
                array_push($pairs, "$key=$value");
            }

            return join("&", $pairs);
        }


        /* Calculates and returns offset of the first displayed searching result
        */
        function getOffset()
        {
            $offset = $_GET['offset'];

            settype($offset, 'integer');

            $offset = $offset - ($offset % $this->displayLimit);

            if ($offset <= 0)
                return 0;

            return $offset;
        }


        /* Prepares query string for displayable results or count of displayable results
        */
        function getQueryString($countOnly = 0)
        {
            if ($countOnly)
                $query = "SELECT count(*) ";
            else
            {
                $query = "SELECT benchmark.name AS name, benchmarkInstance.id AS id, " .
                         "benchmarkInstance.fileName AS filename, " .
                         "benchmarkSet.id AS benchmarksetid, " .
                         "benchmark.description AS benchmarkdescription, benchmarkSet.name AS setname, " .
                         "benchmarkInstance.description AS instancedescription, " .
                         "format.name AS formatname, " .
                         "benchmarkInstance.fileName AS filename ";
            }
                     
            $query = $query .
                     "FROM benchmark, benchmarkInstance, benchmarkSet, format " .
                     "WHERE benchmarkInstance.benchmarkId = benchmark.id AND " .
                     "benchmarkInstance.formatId = format.id AND " .
                     "benchmarkInstance.benchmarkSetId = benchmarkSet.id";

            $searchCriteria = $this->getSearchCriteria();

            if ($searchCriteria)
                $query = $query . ' AND ' . $searchCriteria; 

            if (!$countOnly)
                $query = $query . ' ORDER BY benchmark.name';

            return $query; 
        }
        

        /* Returns the part of query string that will contain the search criteria
        */
        function getSearchCriteria()
        {
            $criteriaArray = array();

            if ($_GET['name'])
                array_push($criteriaArray, "benchmark.name LIKE '%$_GET[name]%'");

            if ($_GET['benchmarkSetId'])
                array_push($criteriaArray, "benchmarkSet.id = $_GET[benchmarkSetId]");

            if ($_GET['formatId'])
                array_push($criteriaArray, "format.id = $_GET[formatId]");

            $attributeCriteria = $this->getAttributeCriteria();

            if ($attributeCriteria) {
                array_push($criteriaArray, $attributeCriteria);
            }

            return join(" AND ", $criteriaArray);
        }

        /* Returns the part of query string that will contain the attribute criteria
        */
        function getAttributeCriteria()
        {
            $criteriaArray = array();
            
                        
            for ($index = 1; $index <= $this->attributesLimit; $index++)
            {
                if (!$_GET["attribute_$index"] || !$_GET["relation_$index"] || !strlen($_GET["value_$index"]))
                    continue;

                $attributeId = $_GET["attribute_$index"];
                $relation = $this->attributeRelationStrings[$_GET["relation_$index"]];
                $value = $_GET["value_$index"];
                $value = "'$value'";

                if (($relation == AR_EQ) || ($relation == AR_NE)) {
                    $comparison = "trim(benchmarkInstanceAttribute.value) $relation trim($value)";
                }
                else {
                    $comparison = $this->numerize("benchmarkInstanceAttribute.value") . " $relation " . $this->numerize($value);
                }
                
                $criteria = "benchmarkInstance.id IN (SELECT benchmarkInstance.id FROM benchmarkInstance, " .
                            "benchmarkInstanceAttribute, attribute " .
                            "WHERE benchmarkInstance.id = benchmarkInstanceAttribute.benchmarkInstanceId AND " .
                            "benchmarkInstanceAttribute.attributeId = attribute.id AND " .
                            "(attribute.id = '$attributeId' AND " .
                            "$comparison))";
                
                array_push($criteriaArray, $criteria);
            }

            return join(" AND ", $criteriaArray);
        }

        
        /* Modifies a numeric comparison condition so that it can be applied on a character column data
        */
        function numerize($value)
        {
            return "(CASE WHEN $value similar to ' *(0|1|2|3|4|5|6|7|8|9)+ *' THEN CAST($value AS NUMERIC) END)";
        }
    }
    

    launchPage();

    # vim:enc=iso8859-2:fenc=iso8859-2:
?>
