<?php
/**
 * class.pagedTable.php
 *
 * @package gulliver.system
 *
 * ProcessMaker Open Source Edition
 * Copyright (C) 2004 - 2011 Colosa Inc.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program 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 Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 *
 * For more information, contact Colosa Inc, 2566 Le Jeune Rd.,
 * Coral Gables, FL, 33134, USA, or email info@colosa.com.
 *
 */


/**
 * Class pagedTable
 *
 * @author David S. Callizaya S. <davidsantos@colosa.com>
 * @package gulliver.system
 * @access public
 */
class pagedTable
{
    public $xmlFormFile;
    public $currentPage;
    public $orderBy = '';
    public $filter = array();
    public $filterType = array();
    public $searchBy = '';
    public $fastSearch = '';
    public $order = '';
    public $template = 'templates/paged-table.html';
    public $tpl;
    public $style = array();
    public $rowsPerPage = 25;
    public $ownerPage;
    public $popupPage;
    public $popupSubmit;
    public $popupWidth = 450;
    public $popupHeight = 200;
    public $ajaxServer;
    public $fields;
    public $query;
    public $totpages;

    //SQL QUERIES
    public $sql = '';
    public $sqlWhere = '';
    public $sqlGroupBy = '';
    public $sqlSelect = 'SELECT 1';
    public $sqlDelete = '';
    public $sqlInsert = '';
    public $sqlUpdate = '';
    public $fieldDataList = '';

    //Configuration
    public $xmlPopup = '';
    public $addRow = false;
    public $deleteRow = false;
    public $editRow = false;
    public $notFields = '  title button linknew begingrid2 endgrid2 '; // These are not considered to build the sql queries (update,insert,delete)


    //JavaScript Object attributes
    public $onUpdateField = "";
    public $onDeleteField = "";
    public $afterDeleteField = "";
    public $onInsertField = "";

    //New gulliver
    public $xmlForm;
    public $menu = '';
    public $filterForm = '';
    public $filterForm_Id = '';
    public $name = 'pagedTable';
    public $id = 'A1';
    public $disableFooter = false;
    //This attribute is used to set STYLES to groups of TD, using the field type "cellMark" (see XmlFormFieldCellMark)
    public $tdStyle = '';
    public $tdClass = '';
    //Config Save definition
    public $__Configuration = 'orderBy,filter,fastSearch,style/*/showInTable'; //order,rowsPerPage,disableFooter';


    /**
     * Function analizeSql
     * You can to distribute the component of the query like: Select, Where, Group by and order by
     *
     * @author David S. Callizaya S. <davidsantos@colosa.com>
     * @access public
     * @return string
     */
    public function analizeSql()
    {
        if (1 === preg_match('/^\s*SELECT\s+(.+?)(?:\s+FROM\s+(.+?))(?:\s+WHERE\s+(.+?))?(?:\s+GROUP\s+BY\s+(.+?))?(?:\s+ORDER\s+BY\s+(.+?))?(?:\s+BETWEEN\s+(.+?)\s+AND\s+(.+?))?\s*$/im', $this->sqlSelect, $matches)) {
            $this->sqlSelect = 'SELECT ' . $matches[1] . (($matches[2] != '') ? ' FROM ' . $matches[2] : '');
            $this->sqlSelect = 'SELECT ' . $matches[1] . (($matches[2] != '') ? ' FROM ' . $matches[2] : '');
        } else {
            //echo('Warning: SQL Query is not well formed.');
            return;
        }
        $this->sqlFrom = isset($matches[2]) ? $matches[2] : '';
        $this->sqlWhere = isset($matches[3]) ? $matches[3] : '';
        $this->sqlGroupBy = isset($matches[4]) ? $matches[4] : '';
        $this->sqlOrderBy = isset($matches[5]) ? $matches[5] : '';
        $this->order = '';
        if ($this->sqlOrderBy != '') {
            if ($n = preg_match_all('/\b([\w\.]+)\b(?:\s+(ASC|DESC))?,?/im', $this->sqlOrderBy, $matches, PREG_SET_ORDER)) {
                for ($r = 0; $r < $n; $r++) {
                    if (!isset($matches[$r][2])) {
                        $matches[$r][2] = '';
                    }
                    if ($matches[$r][2] == '') {
                        $matches[$r][2] = 'ASC';
                    }
                    $ord = G::createUID('', $matches[$r][1]) . '=' . urlencode($matches[$r][2]);
                    if ($this->order == '') {
                        $this->order = $ord;
                    } else {
                        $this->order .= '&' . $ord;
                    }
                }
                //Orden ascendente
                if ($n == 1) {
                    $this->order = G::createUID('', $matches[0][1]) . '=' . $matches[0][2];
                }
            }
        }
        //Generate: $uniqueWhere=Identify a row bys its data content
        //$this->fieldDataList=url text that dentify a row bys its data content
        $uniqueWhere = '';
        $this->fieldDataList = '';
        foreach ($this->fields as $r => $field) {
            if ((strpos($this->notFields, ' ' . $this->fields[$r]['Type'] . ' ') === false)) {
                if ($uniqueWhere == '') {
                    $uniqueWhere = (($this->sqlWhere != '') ? ('(' . $this->sqlWhere . ') AND (') : '(');
                } else {
                    $uniqueWhere .= ' AND ';
                }
                $uniqueWhere .= $this->fields[$r]['Name'] . '=' . '@@' . $this->fields[$r]['Name'];
                if ($this->fieldDataList == '') {
                    $this->fieldDataList = '';
                } else {
                    $this->fieldDataList .= '&';
                }
                $this->fieldDataList .= $this->fields[$r]['Name'] . '=' . '@@_' . $this->fields[$r]['Name'];
            }
        }
        if ($uniqueWhere != '') {
            $uniqueWhere .= ')';
        }
    }

    /**
     * Function prepareQuery
     *
     * @author David S. Callizaya S. <davidsantos@colosa.com>
     * @access public
     * @return string
     */
    public function prepareQuery()
    {
        //DBConnection
        if (!$this->sqlConnection) {
            $this->dbc = new DBConnection();
        } else {
            if (defined('DB_' . $this->sqlConnection . '_USER')) {
                if (defined('DB_' . $this->sqlConnection . '_HOST')) {
                    eval('$res[\'DBC_SERVER\'] = DB_' . $this->sqlConnection . '_HOST;');
                } else {
                    $res['DBC_SERVER'] = DB_HOST;
                }
                if (defined('DB_' . $this->sqlConnection . '_USER')) {
                    eval('$res[\'DBC_USERNAME\'] = DB_' . $this->sqlConnection . '_USER;');
                }
                if (defined('DB_' . $this->sqlConnection . '_PASS')) {
                    eval('$res[\'DBC_PASSWORD\'] = DB_' . $this->sqlConnection . '_PASS;');
                } else {
                    $res['DBC_PASSWORD'] = DB_PASS;
                }
                if (defined('DB_' . $this->sqlConnection . '_NAME')) {
                    eval('$res[\'DBC_DATABASE\'] = DB_' . $this->sqlConnection . '_NAME;');
                } else {
                    $res['DBC_DATABASE'] = DB_NAME;
                }
                if (defined('DB_' . $this->sqlConnection . '_TYPE')) {
                    eval('$res[\'DBC_TYPE\'] = DB_' . $this->sqlConnection . '_TYPE;');
                } else {
                    $res['DBC_TYPE'] = defined('DB_TYPE') ? DB_TYPE : 'mysql';
                }
                $this->dbc = new DBConnection($res['DBC_SERVER'], $res['DBC_USERNAME'], $res['DBC_PASSWORD'], $res['DBC_DATABASE'], $res['DBC_TYPE']);
            } else {
                $dbc = new DBConnection();
                $dbs = new DBSession($dbc);
                $res = $dbs->execute("select * from  DB_CONNECTION WHERE DBC_UID=" . $this->sqlConnection);
                $res = $res->read();
                $this->dbc = new DBConnection($res['DBC_SERVER'], $res['DBC_USERNAME'], $res['DBC_PASSWORD'], $res['DBC_DATABASE']);
            }
        }
        $this->ses = new DBSession($this->dbc);
        //Query
        //Filter
        if (is_array($this->filter)) {
            $filterFields = $this->filter;
        } else {
            parse_str($this->filter, $filterFields);
        }
        $this->aFilter = $filterFields;
        $filter = '';
        foreach ($filterFields as $field => $like) {
            if ($like !== '') {
                if ($filter !== '') {
                    $filter .= ' AND ';
                }
                $like = mysqli_real_escape_string($this->dbc, $like);
                if (isset($this->filterType[$field])) {
                    switch ($this->filterType[$field]) {
                        case '=':
                            $filter .= $field . ' = "' . $like . '"';
                            break;
                        case '<>':
                            $filter .= $field . ' <> "' . $like . '"';
                            break;
                        case 'contains':
                            $filter .= $field . ' LIKE "%' . $like . '%"';
                            break;
                        case 'like':
                            $filter .= $field . ' LIKE "' . $like . '"';
                            break;
                    }
                } else {
                    $filter .= $field . ' = "' . $like . '"';
                }
            }
        }
        /*
        * QuickSearch
        */
        if ($this->searchBy !== '') {
            $aSB = explode('|', $this->searchBy);
            $subFilter = '';
            foreach ($aSB as $sBy) {
                $subFilter .= ($subFilter !== '') ? ' OR ' : '';
                $subFilter .= $sBy . ' LIKE "%' . G::sqlEscape($this->fastSearch, $this->dbc->type) . '%"';
            }
            if ($subFilter !== '') {
                $filter .= ($filter !== '') ? ' AND ' : '';
                $filter .= '(' . $subFilter . ')';
            }
        }
        //Merge sort array defined by USER with the array defined by SQL
        parse_str($this->order, $orderFields);
        parse_str($this->orderBy, $orderFields2);
        //User sort is more important (first in merge).
        $orderFields3 = array_merge($orderFields2, $orderFields);
        //User sort is overwrites XMLs definition.
        $orderFields = array_merge($orderFields3, $orderFields2);
        //Order (BY SQL DEFINITION AND USER'S DEFINITION)
        $this->aOrder = array();
        $order = '';
        foreach ($orderFields as $field => $fieldOrder) {
            $field = G::getUIDName($field, '');
            $fieldOrder = strtoupper($fieldOrder);
            if ($fieldOrder === 'A') {
                $fieldOrder = 'ASC';
            }
            if ($fieldOrder === 'D') {
                $fieldOrder = 'DESC';
            }
            switch ($fieldOrder) {
                case 'ASC':
                case 'DESC':
                    if ($order !== '') {
                        $order .= ', ';
                    }
                    $order .= $field . ' ' . $fieldOrder;
                    $this->aOrder[$field] = $fieldOrder;
            }
        }
        $this->sql = $this->sqlSelect . ((($this->sqlWhere != '') || ($filter != '')) ? ' WHERE ' : '') . (($this->sqlWhere != '') ? '(' . $this->sqlWhere . ')' : '') . ((($this->sqlWhere != '') && ($filter != '')) ? ' AND ' : '') . (($filter != '') ? '(' . $filter . ')' : '') . (($this->sqlGroupBy != '') ? ' GROUP BY ' . $this->sqlGroupBy : '') . (($order != '') ? ' ORDER BY ' . $order : '');
        //$this->query=$this->ses->execute($this->sql);
        //$this->totpages=ceil($this->query->count()/$this->rowsPerPage);
        return;
    }

    /**
     * Function setupFromXmlform
     *
     * @author David S. Callizaya S. <davidsantos@colosa.com>
     * @access public
     * @param string xmlForm
     * @return string
     */
    public function setupFromXmlform($xmlForm)
    {
        $this->xmlForm = $xmlForm;
        //Config
        $this->name = $xmlForm->name;
        $this->id = $xmlForm->id;
        $this->sqlConnection = ((isset($this->xmlForm->sqlConnection)) ? $this->xmlForm->sqlConnection : '');
        if (isset($_GET['page'])) {
            $this->currentPage = $_GET['page'];
        } else {
            $this->currentPage = 1;
        }
        if (isset($_GET['order'])) {
            $this->orderBy = urldecode($_GET['order']);
        } else {
            $this->orderBy = "";
        }
        if (isset($_GET['filter'])) {
            $this->filter = urldecode($_GET['filter']);
        } else {
            $this->filter = "";
        }
        $this->ajaxServer = G::encryptLink('../gulliver/pagedTableAjax');
        $this->ownerPage = G::encryptLink(SYS_CURRENT_URI);
        //Needed for $mysql_real_escape_string
        $auxDbc = new DBConnection();
        if (isset($this->xmlForm->sql)) {
            $this->sqlSelect = G::replaceDataField($this->xmlForm->sql, $this->xmlForm->values);
        } else {
            trigger_Error('Warning: sql query is empty', E_USER_WARNING);
        }
        // Config attributes from XMLFORM file
        $myAttributes = get_class_vars(get_class($this));
        foreach ($this->xmlForm->xmlform->tree->attribute as $atrib => $value) {
            if (is_array($myAttributes) && array_key_exists($atrib, $myAttributes)) {
                eval('settype($value,gettype($this->' . $atrib . '));');
                if ($value !== '') {
                    eval('$this->' . $atrib . '=$value;');
                }
            }
        }
        //Prepare the fields
        $this->style = array();
        $this->gridWidth = "";
        $this->gridFields = "";
        $this->fieldsType = array();
        foreach ($this->xmlForm->fields as $f => $v) {
            $r = $f;
            $this->fields[$r]['Name'] = $this->xmlForm->fields[$f]->name;
            $this->fields[$r]['Type'] = $this->xmlForm->fields[$f]->type;
            if (isset($this->xmlForm->fields[$f]->size)) {
                $this->fields[$r]['Size'] = $this->xmlForm->fields[$f]->size;
            }
            $this->fields[$r]['Label'] = $this->xmlForm->fields[$f]->label;
        }
        //Autocomplete the sql queries
        // Here we can to distribute the component of the query like: Select, Where, Group by and order by
        $this->analizeSql();
        //Set the default settings
        $this->defaultStyle();
        //continue whith the setup
        $this->gridWidth = '';
        $this->gridFields = '';
        foreach ($this->xmlForm->fields as $f => $v) {
            $r = $f;
            //Parse the column properties
            foreach ($this->xmlForm->fields[$f] as $attribute => $value) {
                if (!is_object($value)) {
                    $this->style[$r][$attribute] = $value;
                }
            }
            //Needed for javascript
            //only the visible columns's width and name are stored
            if ($this->style[$r]['showInTable'] != '0') {
                $this->gridWidth .= ',' . $this->style[$r]['colWidth'];
                $this->gridFields .= ',"form[' . $this->fields[$r]['Name'] . ']"';
            }
        }
        $totalWidth = 0;
        foreach ($this->fields as $r => $rval) {
            if ($this->style[$r]['showInTable'] != '0') {
                $totalWidth += $this->style[$r]['colWidth'];
            }
        }
        $this->totalWidth = $totalWidth;
    }

    /**
     * Function setupFromTable
     *
     * @author David S. Callizaya S. <davidsantos@colosa.com>
     * @access public
     * @param eter string table
     * @return string
     */
    //  function setupFromTable($table)
    //  {
    ////  var_dump2($table);
    //    //Config
    //      $this->rowsPerPage=25;
    //      if (isset($_GET['page']))
    //        $this->currentPage = $_GET['page'];
    //      else
    //        $this->currentPage = 1;
    //      if (isset($_GET['order']))
    //        $this->orderBy = urldecode($_GET['order']);
    //      else
    //        $this->orderBy = "";
    //      if (isset($_GET['filter']))
    //        $this->filter = urldecode($_GET['filter']);
    //      else
    //        $this->filter = "";
    //      $xmlPopup='';
    //      $this->xmlFormFile="";
    ///*      if ($table->Action)
    //        $this->ajaxServer=G::encryptLink($table->Action);
    //      else*/
    //      $this->ajaxServer=G::encryptLink('../gulliver/pagedTableAjax');
    //      $this->popupPage = $this->ajaxServer . '?function=printForm&filename=' . urlencode($xmlPopup);
    //      $this->ownerPage=G::encryptLink(SYS_CURRENT_URI);
    //      $this->sqlConnection='';
    //      if (isset($table->_source))
    //        $this->sqlSelect=$table->_source;
    //      if (isset($table->WhereClause)){
    //        if (strpos(strtoupper($table->WhereClause),'GROUP BY')!==FALSE)
    //          preg_match("/(.+)(GROUP BY)(.*)/",$table->WhereClause,$matches);
    //        else{
    //          $matches[1]=$table->WhereClause;$matches[2]='';
    //        }
    //        $this->sqlWhere=$matches[1];
    //        if (strcasecmp($matches[2],'GROUP BY')==0)
    //          $this->sqlGroupBy=' GROUP BY '.$matches[3];
    //      }
    //      if (strpos(strtoupper($this->sqlSelect),'WHERE')!==FALSE){
    //        preg_match("/SELECT(.+)FROM(.+)WHERE(.+)/",$this->sqlSelect,$matches);
    //        $this->sqlSelect='SELECT '.$matches[1].' FROM '.$matches[2];
    //        $this->sqlWhere=$matches[3];
    //      }
    //    // DBConnection
    //    //      $this->prepareQuery();
    //    //Prepare the fields
    //      if ($table->show_nummbers=='YES'){
    //        $r=-1;
    //        $this->fields[$r]['Name']='numberlabel';
    //        $this->fields[$r]['Type']='numberlabel';
    //        $this->fields[$r]['Label']='#';
    //      }
    //      foreach ($table->Columns as $r => $value){
    //        $this->fields[$r]['Name']=$value['Name'];
    //        $this->fields[$r]['Type']=$value['Type'];
    //        $this->fields[$r]['Label']=((isset($table->Labels[$r]))?$table->Labels[$r]:'');
    //        //Default values for Label if it was empty
    //        if ($this->fields[$r]['Label']=='')
    //          switch($table->Columns[$r]['Type']){
    //           case 'image':
    //           case 'image-text':
    //           case 'jslink':
    //             //var_dump2($table->Columns[$r]);
    //            $this->fields[$r]['Label']=$value['Name'];
    //        }
    //        //Print the type of the field
    //        //$this->fields[$r]['Label'].='('.$this->fields[$r]['Type'].')';
    //        $r++;
    //      }
    //    //Add a delete column if sqlDelete is established
    //    /*  if ($this->sqlDelete!='')
    //      {
    //        $this->fields[$r]['Name']='';
    //        $this->fields[$r]['Type']='linknew';
    //        $this->fields[$r]['Label']=G::LoadXml('labels','ID_DELETE');
    //      }*/
    //    //Set the default settings
    //      $this->defaultStyle();
    //    /*  if ($this->sqlDelete!='')
    //      {
    //        $this->style[$r]['href']="#";
    //        $this->style[$r]['onclick']="document.getElementById('pagedTable').outerHTML=ajax_function('{$this->ajaxServer}','delete','".$this->fieldDataList."');";
    //      }*/
    //    //Prepare the columns's properties
    //      if ($table->show_nummbers=='YES'){
    //        $r=-1;
    //        $this->style[$r]['data']='@@_row__';
    //        $this->style[$r]['colWidth']=30;
    //      }
    //      $this->gridWidth='';
    //      $this->gridFields='';
    //      foreach ($table->Columns as $r => $value){
    //        //var_dump($value['Width']);
    //        $this->style[$r]['colWidth']=$value['Width'];
    //        $this->style[$r]['titleAlign']=$value['Align'];
    //        $this->style[$r]['href']=$value['Target'];
    //        // Add the row reference
    //        switch ($this->fields[$r]['Type']){
    //          case 'image-text':
    //          case 'textimage':
    //          case 'image':
    //          case 'link':
    //            //$this->style[$r]['href'].='/@@_row__.html';  // No
    //            if (substr($value['Content'],0,1)=='&')
    //              $this->style[$r]['href'].='/@@_'.substr($value['Content'],1).'.html';
    //        }
    //        // Extra events for each field
    //        $this->style[$r]['event']=$value['Extra'];
    //        if ($this->fields[$r]['Label']==''){
    //          $this->style[$r]['titleVisibility']='0';
    //          $this->fields[$r]['Label']=$this->fields[$r]['Name'];
    //        }
    //        //if ($value['orderByThis']===true) $this->orderBy=$value['Name'];
    //        //Needed for javascript
    //        //only the visible columns's width and name are stored
    //        if ($this->style[$r]['showInTable']!='0'){
    //          $this->gridWidth.=','.$this->style[$r]['colWidth'];
    //          $this->gridFields.=',"form['.$this->fields[$r]['Name'].']"';
    //        }
    //        $r++;
    //      }
    //      echo('<br>');
    ////    var_dump2($this);
    //  }


    /**
     * Function count
     *
     * @author David S. Callizaya S. <davidsantos@colosa.com>
     * @access public
     * @return string
     */
    public function count()
    {
        $this->prepareQuery();
        return $this->query->count();
    }

    /**
     * Function renderTitle
     *
     * @author David S. Callizaya S. <davidsantos@colosa.com>
     * @access public
     * @return string
     */
    public function renderTitle()
    {
        //Render Title
        $thereisnotitle = true;
        foreach ($this->fields as $r => $rval) {
            if ($this->fields[$r]['Type'] === 'title') {
                $this->tpl->assign("title", $this->fields[$r]['Label']);
                $thereisnotitle = false;
            }
        }
        if ($thereisnotitle) {
            $this->tpl->assign("title", '  ');
        }
        //Render headers
        $this->colCount = 0;
        $this->shownFields = '[';
        foreach ($this->fields as $r => $rval) {
            if ($this->style[$r]['showInTable'] != '0') {
                $this->tpl->newBlock("headers");
                $sortOrder = (((isset($this->aOrder[$this->fields[$r]['Name']])) && ($this->aOrder[$this->fields[$r]['Name']] === 'ASC')) ? 'DESC' : 'ASC');
                $sortOrder = (((isset($this->aOrder[$this->fields[$r]['Name']])) && ($this->aOrder[$this->fields[$r]['Name']] === 'DESC')) ? '' : $sortOrder);
                $this->style[$r]['href'] = $this->ownerPage . '?order=' . ($sortOrder !== '' ? urlencode(G::createUID('', $this->fields[$r]['Name']) . '=' . $sortOrder) : '') . '&page=' . $this->currentPage;
                $this->style[$r]['onsort'] = $this->id . '.doSort("' . G::createUID('', $this->fields[$r]['Name']) . '" , "' . $sortOrder . '");return false;';
                if (isset($this->style[$r]['href'])) {
                    $this->tpl->assign("href", $this->style[$r]['href']);
                }
                if (isset($this->style[$r]['onsort'])) {
                    $this->tpl->assign("onclick", htmlentities($this->style[$r]['onsort'], ENT_QUOTES, 'UTF-8'));
                }
                if (isset($this->style[$r]['colWidth'])) {
                    $this->tpl->assign("width", $this->style[$r]['colWidth']);
                }
                if (isset($this->style[$r]['colWidth'])) {
                    $this->tpl->assign("widthPercent", ($this->style[$r]['colWidth'] * 100 / $this->totalWidth) . "%");
                }
                if (isset($this->style[$r]['titleAlign'])) {
                    $this->tpl->assign("align", 'text-align:' . $this->style[$r]['titleAlign'] . ';');
                }
                if ($this->style[$r]['titleVisibility'] != '0') {
                    $sortOrder = (((isset($this->aOrder[$this->fields[$r]['Name']])) && ($this->aOrder[$this->fields[$r]['Name']] === 'ASC')) ? 'b2' : '');
                    $sortOrder = (((isset($this->aOrder[$this->fields[$r]['Name']])) && ($this->aOrder[$this->fields[$r]['Name']] === 'DESC')) ? 'b<' : $sortOrder);
                    $this->tpl->assign("header", $this->fields[$r]['Label'] . $sortOrder);
                    $this->tpl->assign('displaySeparator', (($this->colCount == 0) || (!isset($this->fields[$r]['Label'])) || ($this->fields[$r]['Label'] === '')) ? 'display:none;' : '');
                } else {
                    $this->tpl->assign('displaySeparator', 'display:none;');
                }
                $this->colCount += 2;
                $this->shownFields .= ($this->shownFields !== '[') ? ',' : '';
                $this->shownFields .= '"' . $r . '"';
            }
        }
        $this->shownFields .= ']';
    }

    /**
     * Function renderField
     *
     * @author David S. Callizaya S. <davidsantos@colosa.com>
     * @access public
     * @param eter string row
     * @param eter string r
     * @param eter string result
     * @return string
     */
    public function renderField($row, $r, $result)
    {
        global $G_DATE_FORMAT;
        //BEGIN: Special content: __sqlEdit__,__sqlDelete__
        $result['sqlDelete__'] = "pagedTable.event='Delete';pagedTable_DoIt=true;if (pagedTable.onDeleteField) pagedTable_DoIt=eval(pagedTable.onDeleteField);if (pagedTable_DoIt) document.getElementById('pagedTable').outerHTML=ajax_function('{$this->ajaxServer}','delete','field='+encodeURIComponent('" . ($this->fieldDataList) . "'));if (pagedTable.afterDeleteField) return eval(pagedTable.afterDeleteField); else return false;";
        $result['sqlEdit__'] = "pagedTable.event='Update';pagedTable.field=encodeURIComponent('" . $this->fieldDataList . "');pagedTable.updateField(pagedTable.field);return false;";
        $result['pagedTableField__'] = "'" . $this->fieldDataList . "'";
        $result['row__'] = $row;
        //END: Special content.
        //Merge $result with $xmlForm values (for default valuesSettings)
        $result = array_merge($this->xmlForm->values, $result);
        switch (true) {
            case ($this->style[$r]['data'] != ''):
                $value = ((isset($result[$this->style[$r]['data']])) ? $result[$this->style[$r]['data']] : '');
                break;
            default:
                $value = $this->fields[$r]['Label'];
        }
        switch ($this->fields[$r]['Type']) {
            case 'date':
                /*Accept dates like 20070515 without - or / to separate its parts*/
                if (strlen($value) <= 10 && strlen($value) > 4) {
                    $value = str_replace('/', '-', $value);
                    if (strpos($value, '-') === false) {
                        $value = substr($value, 0, 4) . '-' . substr($value, 4, 2) . '-' . substr($value, 6, 2);
                    }
                }
        }
        $this->tpl->newBlock("field");
        $this->tpl->assign('width', $this->style[$r]['colWidth']);
        $this->tpl->assign('widthPercent', ($this->style[$r]['colWidth'] * 100 / $this->totalWidth) . '%');
        $this->tpl->assign('className', (isset($this->style[$r]['colClassName']) && ($this->style[$r]['colClassName'])) ? $this->style[$r]['colClassName'] : $this->tdClass);
        $this->tpl->assign('style', $this->tdStyle);
        if (isset($this->style[$r]['align'])) {
            $this->tpl->assign("align", $this->style[$r]['align']);
        }
        if (isset($this->style[$r]['colAlign'])) {
            $this->tpl->assign("align", $this->style[$r]['colAlign']);
        }
        /**
         * BEGIN : Reeplace of @@, @%,...
         * in field's attributes like onclick, link,
         * ...
         */
        if (isset($this->xmlForm->fields[$this->fields[$r]['Name']]->onclick)) {
            $this->xmlForm->fields[$this->fields[$r]['Name']]->onclick = G::replaceDataField($this->style[$r]['onclick'], $result);
        }
        if (isset($this->xmlForm->fields[$this->fields[$r]['Name']]->link)) {
            $this->xmlForm->fields[$this->fields[$r]['Name']]->link = G::replaceDataField($this->style[$r]['link'], $result);
        }
        if (isset($this->xmlForm->fields[$this->fields[$r]['Name']]->value)) {
            $this->xmlForm->fields[$this->fields[$r]['Name']]->value = G::replaceDataField($this->style[$r]['value'], $result);
        }
        /**
         * BREAK : Reeplace of @@, @%,...
         */
        /**
         * Rendering of the field
         */
        $this->xmlForm->setDefaultValues();
        $this->xmlForm->setValues($result);
        $this->xmlForm->fields[$this->fields[$r]['Name']]->mode = 'view';
        if ((array_search('rendergrid', get_class_methods(get_class($this->xmlForm->fields[$this->fields[$r]['Name']]))) !== false) || (array_search('renderGrid', get_class_methods(get_class($this->xmlForm->fields[$this->fields[$r]['Name']]))) !== false)) {
            $htmlField = $this->xmlForm->fields[$this->fields[$r]['Name']]->renderGrid(array($value
            ), $this->xmlForm);
            $this->tpl->assign("value", $htmlField[0]);
        } else {
        }
        /**
         * CONTINUE : Reeplace of @@, @%,...
         */
        if (isset($this->xmlForm->fields[$this->fields[$r]['Name']]->onclick)) {
            $this->xmlForm->fields[$this->fields[$r]['Name']]->onclick = $this->style[$r]['onclick'];
        }
        if (isset($this->xmlForm->fields[$this->fields[$r]['Name']]->link)) {
            $this->xmlForm->fields[$this->fields[$r]['Name']]->link = $this->style[$r]['link'];
        }
        if (isset($this->xmlForm->fields[$this->fields[$r]['Name']]->value)) {
            $this->xmlForm->fields[$this->fields[$r]['Name']]->value = $this->style[$r]['value'];
        }
        /**
         * END : Reeplace of @@, @%,...
         */
        return $this->fields[$r]['Type'];
    }

    /**
     * Function defaultStyle
     *
     * @author David S. Callizaya S. <davidsantos@colosa.com>
     * @access public
     * @return string
     */
    public function defaultStyle()
    {
        //    for($r=1;$r<=sizeof($this->fields);$r++)
        foreach ($this->fields as $r => $rval) {
            $this->style[$r] = array('showInTable' => '1', 'titleVisibility' => '1', 'colWidth' => '150', 'onclick' => '', 'event' => ''
            );
            //Some widths
            if (!(strpos('  date linknew ', ' ' . $this->fields[$r]['Type'] . ' ') === false)) {
                $this->style[$r]['colWidth'] = '70';
                //Data source:
            }
            if (!(strpos('  title button linknew image-text jslink ', ' ' . $this->fields[$r]['Type'] . ' ') === false)) {
                $this->style[$r]['data'] = ''; //If the control is a link it shows the label
            } else {
                $this->style[$r]['data'] = $this->fields[$r]['Name']; //ELSE: The data value for that field
            }
            //Hidden fields
            if (!isset($this->style[$r]['showInTable'])) {
                if (!(strpos('  title button endgrid2 submit password ', ' ' . $this->fields[$r]['Type'] . ' ') === false)) {
                    $this->style[$r]['showInTable'] = '0';
                } else {
                    $this->style[$r]['showInTable'] = '1';
                }
            }
            //Hidden titles
            if (!(strpos('  linknew button endgrid2 ', ' ' . $this->fields[$r]['Type'] . ' ') === false)) {
                $this->style[$r]['titleVisibility'] = '0';
            }
            //Align titles
            $this->style[$r]['titleAlign'] = 'center';
            //Align fields
            if (isset($_SESSION['SET_DIRECTION']) && (strcasecmp($_SESSION['SET_DIRECTION'], 'rtl') === 0)) {
                $this->style[$r]['align'] = 'right';
            } else {
                $this->style[$r]['align'] = 'left';
            }
            if (!(strpos(' linknew date ', ' ' . $this->fields[$r]['Type'] . ' ') === false)) {
                $this->style[$r]['align'] = 'center';
            }
        }
        // Adjust the columns width to prevent overflow the page width
        //Render headers
        $totalWidth = 0;
        foreach ($this->fields as $r => $rval) {
            if ($this->style[$r]['showInTable'] != '0') {
                $totalWidth += $this->style[$r]['colWidth'];
            }
        }
        $this->totalWidth = $totalWidth;
        $maxWidth = 1800;
        $proportion = $totalWidth / $maxWidth;
        if ($proportion > 1) {
            $this->totalWidth = 1800;
        }
        if ($proportion > 1) {
            foreach ($this->fields as $r => $rval) {
                if ($this->style[$r]['showInTable'] != '0') {
                    $this->style[$r]['colWidth'] = $this->style[$r]['colWidth'] / $proportion;
                }
            }
        }
    }

    /**
     * Function renderTable
     *
     * @author David S. Callizaya S. <davidsantos@colosa.com>
     * @param $block : = 'content'(Prints contentBlock only)
     * @access public
     * @return string
     */
    public function renderTable($block = '')
    {
        $filter = new InputFilter();
        $this->orderBy = $filter->xssFilterHard($this->orderBy);
        $this->currentPage = $filter->xssFilterHard($this->currentPage);
        $this->id = $filter->xssFilterHard($this->id);
        $this->name = $filter->xssFilterHard($this->name);
        $this->ownerPage = $filter->xssFilterHard($this->ownerPage);
        // DBConnection
        $this->prepareQuery();
        //Query for get the number of rows
        $this->query = $this->ses->execute($this->sql);
        $this->totRows = $this->query->count();
        $this->totpages = ceil($this->query->count() / $this->rowsPerPage);
        //Query for obtain the records
        $this->query = $this->ses->execute($this->sql . ' LIMIT ' . (($this->currentPage - 1) * $this->rowsPerPage) . ', ' . $this->rowsPerPage);
        // Prepare the template
        $this->tpl = new TemplatePower(PATH_CORE . $this->template);
        $this->tpl->prepare();
        /**
         * ******** HEAD BLOCK **************
         */
        if (($block === '') || ($block === 'head')) {
            $this->tpl->newBlock('headBlock');
            $this->tpl->assign('pagedTable_Id', $this->id);
            $this->tpl->assign('pagedTable_Name', $this->name);
            $this->tpl->assign('pagedTable_Height', $this->xmlForm->height);
            $this->xmlForm->home = $filter->xssFilterHard($this->xmlForm->home);
            $this->filterForm = $filter->xssFilterHard($this->filterForm);
            $this->menu = $filter->xssFilterHard($this->menu);
            if (file_exists($this->xmlForm->home . $this->filterForm . '.xml')) {
                $filterForm = new filterForm($this->filterForm, $this->xmlForm->home);
                if ($this->menu === '') {
                    $this->menu = 'gulliver/pagedTable_Options';
                }
            }
            if (file_exists($this->xmlForm->home . $this->menu . '.xml')) {
                $menu = new xmlMenu($this->menu, $this->xmlForm->home);
                $this->tpl->newBlock('headerBlock');
                $template = PATH_CORE . 'templates' . PATH_SEP . $menu->type . '.html';
                $menu->setValues($this->xmlForm->values);
                $menu->setValues(array('PAGED_TABLE_ID' => $this->id
                ));
                $menu->setValues(array('PAGED_TABLE_FAST_SEARCH' => $this->fastSearch
                ));
                if (isset($filterForm->name)) {
                    $menu->setValues(array('SEARCH_FILTER_FORM' => $filterForm->name
                    ));
                }
                $this->tpl->assign('content', $menu->render($template, $scriptCode));
                $oHeadPublisher = headPublisher::getSingleton();
                $oHeadPublisher->addScriptFile($menu->scriptURL);
                $oHeadPublisher->addScriptCode($scriptCode);
            }
            if (file_exists($this->xmlForm->home . $this->filterForm . '.xml')) {
                $this->tpl->newBlock('headerBlock');
                $this->filterForm_Id = $filterForm->id;
                $filterForm->type = 'filterform';
                $filterForm->ajaxServer = '../gulliver/defaultAjax';
                $template = PATH_CORE . 'templates/' . $filterForm->type . '.html';
                $filterForm->setValues($this->xmlForm->values);
                $filterForm->setValues(array('PAGED_TABLE_ID' => $this->id
                ));
                $filterForm->setValues(array('PAGED_TABLE_FAST_SEARCH' => $this->fastSearch
                ));
                $this->tpl->assign('content', $filterForm->render($template, $scriptCode));
                $oHeadPublisher = headPublisher::getSingleton();
                $oHeadPublisher->addScriptFile($filterForm->scriptURL);
                $oHeadPublisher->addScriptCode($scriptCode);
                if (isset($_SESSION)) {
                    $_SESSION[$filterForm->id] = $filterForm->values;
                }
            }
        }
        /**
         * ******** CONTENT BLOCK **************
         */
        if (($block === '') || ($block === 'content')) {
            $this->tpl->newBlock('contentBlock');
            $this->tpl->assign('gridWidth', '=[' . substr($this->gridWidth, 1) . ']');
            $this->tpl->assign('fieldNames', '=[' . substr($this->gridFields, 1) . ']');
            $this->tpl->assign('ajaxUri', '="' . addslashes($this->ajaxServer) . '"');
            $this->tpl->assign('currentUri', '="' . addslashes($this->ownerPage) . '"');
            $this->tpl->assign('currentOrder', '="' . addslashes($this->orderBy) . '"');
            $this->tpl->assign('currentPage', '=' . $this->currentPage);
            $this->tpl->assign('currentFilter', '="' . '"');
            $this->tpl->assign('totalRows', '=' . $this->query->count());
            $this->tpl->assign('rowsPerPage', '=' . $this->rowsPerPage);
            $this->tpl->assign('popupPage', '="' . addslashes($this->popupPage) . '"');
            $this->tpl->assign('popupWidth', '=' . $this->popupWidth);
            $this->tpl->assign('popupHeight', '=' . $this->popupHeight);
            $this->tpl->assign('pagedTable_Id', $this->id);
            $this->tpl->assign('pagedTable_Name', $this->name);
            $this->tpl->assign("pagedTable_JS", "{$this->id}.element=document.getElementById('pagedtable[{$this->id}]');");
            $this->renderTitle();
            //Render rows
            $gridRows = 0;
            for ($j = 0; $j < $this->query->count(); $j++) {
                $result = $this->query->read();
                //if (($j>=(($this->currentPage-1)*$this->rowsPerPage))&&($j<(($this->currentPage)*$this->rowsPerPage)))
                //{
                $gridRows++;
                $this->tpl->newBlock("row");
                $this->tpl->assign("class", "Row" . (($j % 2) + 1));
                $this->tdStyle = '';
                $this->tdClass = '';
                foreach ($this->fields as $r => $rval) {
                    if (strcasecmp($this->fields[$r]['Type'], 'cellMark') == 0) {
                        $result1 = $result;
                        $result1['row__'] = $j + 1;
                        $this->xmlForm->setDefaultValues();
                        $this->xmlForm->setValues($result1);
                        $result1 = array_merge($this->xmlForm->values, $result1);
                        $this->tdStyle = $this->xmlForm->fields[$this->fields[$r]['Name']]->tdStyle($result1, $this->xmlForm);
                        $this->tdClass = $this->xmlForm->fields[$this->fields[$r]['Name']]->tdClass($result1, $this->xmlForm);
                    } elseif ($this->style[$r]['showInTable'] != '0') {
                        $this->renderField($j + 1, $r, $result);
                    }
                }
                //}
            }
            $this->tpl->assign('_ROOT.gridRows', '=' . $gridRows); //number of rows in the current page
            $this->tpl->newBlock('rowTag');
            $this->tpl->assign('rowId', 'insertAtLast');
            if ($this->currentPage > 1) {
                $firstUrl = $this->ownerPage . '?order=' . $this->orderBy . '&page=1';
                $firstUrl = $filter->xssFilterHard($firstUrl);
                $firstAjax = $this->id . ".doGoToPage(1);return false;";
                $firstAjax = $filter->xssFilterHard($firstAjax);
                $prevpage = $this->currentPage - 1;
                $prevUrl = $this->ownerPage . '?order=' . $this->orderBy . '&page=' . $prevpage;
                $prevUrl = $filter->xssFilterHard($prevUrl);
                $prevAjax = $this->id . ".doGoToPage(" . $prevpage . ");return false;";
                $prevAjax = $filter->xssFilterHard($prevAjax);
                $first = "<a href=\"" . htmlentities($firstUrl, ENT_QUOTES, 'utf-8') . "\" onclick=\"" . $firstAjax . "\" class='firstPage'>&nbsp;</a>";
                $prev = "<a href=\"" . htmlentities($prevUrl, ENT_QUOTES, 'utf-8') . "\"  onclick=\"" . $prevAjax . "\" class='previousPage'>&nbsp;</a>";
            } else {
                $first = "<a class='noFirstPage'>&nbsp;</a>";
                $prev = "<a class='noPreviousPage'>&nbsp;</a>";
            }
            if ($this->currentPage < $this->totpages) {
                $lastUrl = $this->ownerPage . '?order=' . $this->orderBy . '&page=' . $this->totpages;
                $lastUrl = $filter->xssFilterHard($lastUrl);
                $lastAjax = $this->id . ".doGoToPage(" . $this->totpages . ");return false;";
                $lastAjax = $filter->xssFilterHard($lastAjax);
                $nextpage = $this->currentPage + 1;
                $nextUrl = $this->ownerPage . '?order=' . $this->orderBy . '&page=' . $nextpage;
                $nextUrl = $filter->xssFilterHard($nextUrl);
                $nextAjax = $this->id . ".doGoToPage(" . $nextpage . ");return false;";
                $nextAjax = $filter->xssFilterHard($nextAjax);
                $next = "<a href=\"" . htmlentities($nextUrl, ENT_QUOTES, 'utf-8') . "\" onclick=\"" . $nextAjax . "\" class='nextPage'>&nbsp;</a>";
                $last = "<a href=\"" . htmlentities($lastUrl, ENT_QUOTES, 'utf-8') . "\" onclick=\"" . $lastAjax . "\" class='lastPage'>&nbsp;</a>";
            } else {
                $next = "<a class='noNextPage'>&nbsp;</a>";
                $last = "<a class='noLastPage'>&nbsp;</a>";
            }
            $pagesEnum = '';
            for ($r = 1; $r <= $this->totpages; $r++) {
                if (($r >= ($this->currentPage - 5)) && ($r <= ($this->currentPage + 5))) {
                    $pageAjax = $this->id . ".doGoToPage(" . $r . ");return false;";
                    if ($r != $this->currentPage) {
                        $pageAjax = $filter->xssFilterHard($pageAjax);
                        $pagesEnum .= "&nbsp;<a href=\"" . htmlentities($this->ownerPage . '?order=' . $this->orderBy . '&page=' . $r, ENT_QUOTES, 'utf-8') . "\" onclick=\"" . $pageAjax . "\">" . $r . "</a>";
                    } else {
                        $pagesEnum .= "&nbsp;<a>" . $r . "</a>";
                    }
                }
            }
            if ($this->query->count() === 0) {
                $this->tpl->newBlock('norecords');
                $this->tpl->assign("columnCount", $this->colCount);
                $noRecordsFound = 'ID_NO_RECORDS_FOUND';
                if (G::LoadTranslation($noRecordsFound)) {
                    $noRecordsFound = G::LoadTranslation($noRecordsFound);
                }
                $this->tpl->assign("noRecordsFound", $noRecordsFound);
            }
            if (!$this->disableFooter) {
                $this->tpl->newBlock("bottomFooter");
                $this->tpl->assign("columnCount", $this->colCount);
                $this->tpl->assign("pagedTableId", $this->id);
                if (($this->query->count() !== 0)) {
                    if ($this->totpages > 1) {
                        $this->tpl->assign("first", $first);
                        $this->tpl->assign("prev", $prev);
                        $this->tpl->assign("next", $next);
                        $this->tpl->assign("last", $last);
                    }
                    $this->tpl->assign("currentPage", $this->currentPage);
                    $this->tpl->assign("totalPages", $this->totpages);
                    $firstRow = ($this->currentPage - 1) * $this->rowsPerPage + 1;
                    $lastRow = $firstRow + $this->query->count() - 1;
                    $this->tpl->assign("firstRow", $firstRow);
                    $this->tpl->assign("lastRow", $lastRow);
                    $this->tpl->assign("totalRows", $this->totRows);
                } else {
                    $this->tpl->assign("indexStyle", 'visibility:hidden;');
                }
                if ($this->searchBy) {
                    $this->tpl->assign("fastSearchValue", $this->fastSearch);
                } else {
                    $this->tpl->assign("fastSearchStyle", 'visibility:hidden;');
                }
                if ($this->addRow) {
                    if ($this->sqlInsert != '') {
                        $this->tpl->assign("insert", '<a href="#" onclick="pagedTable.event=\'Insert\';popup(\'' . $this->popupPage . '\');return false;">' ./*G::LoadXml('labels','ID_ADD_NEW')*/
                            'ID_ADD_NEW' . '</a>');
                    }
                }
                $this->tpl->assign("pagesEnum", $pagesEnum);
            } ?>
            <script language='JavaScript'>
                var <?php echo $this->id?><?php echo($this->name != '' ? '=' . $this->name : '')?>=
                new G_PagedTable();
                <?php echo $this->id?>.id<?php echo '="' . addslashes($this->id) . '"'?>;
                <?php echo $this->id?>.name<?php echo '="' . addslashes($this->name) . '"'?>;
                <?php echo $this->id?>.ajaxUri<?php echo '="' . addslashes($this->ajaxServer) . '?ptID=' . $this->id . '"'?>;
                <?php echo $this->id?>.currentOrder<?php echo '="' . addslashes($this->orderBy) . '"'?>;
                <?php echo $this->id?>.currentFilter;
                <?php echo $this->id?>.currentPage<?php echo '=' . $this->currentPage?>;
                <?php echo $this->id?>.totalRows<?php echo '=' . $this->query->count()?>;
                <?php echo $this->id?>.rowsPerPage<?php echo '=' . $this->rowsPerPage?>;
                <?php echo $this->id?>.popupPage<?php echo '="' . addslashes($this->popupPage) . '?ptID=' . $this->id . '"'?>;
                <?php echo $this->id?>.onUpdateField<?php echo '="' . addslashes($this->onUpdateField) . '"'?>;
                <?php echo $this->id?>.shownFields<?php echo '=' . $this->shownFields ?>;

                var panelPopup;
                var popupWidth<?php echo '=' . $this->popupWidth?>;
                var popupHeight<?php echo '=' . $this->popupHeight?>;
            </script>
            <?php
        }
        /**
         * ******** CLOSE BLOCK **************
         */
        if (($block === '') || ($block === 'close')) {
            $this->tpl->newBlock("closeBlock");
        }
        $this->tpl->printToScreen();
        unset($this->tpl);
        unset($this->dbc);
        unset($this->ses);
        $_SESSION['pagedTable[' . $this->id . ']'] = base64_encode(serialize($this));
        return;
    }

    /**
     * Function printForm
     *
     * @access public
     * @param string $filename
     * @param array $data
     * @return void
     */
    public function printForm($filename, $data = array())
    {
        //    $G_FORM = new Form($filename, PATH_XMLFORM);
        //    echo $G_FORM->render(PATH_TPL . 'xmlform.html', $scriptContent);
        global $G_PUBLISH;
        $G_PUBLISH = new Publisher();
        $G_PUBLISH->AddContent('xmlform', 'xmlform', $filename, '', $data, $this->popupSubmit);
        G::RenderPage("publish", "blank");
    }
}

/**
 * Function var_dump2
 *
 * @access public
 * @param string $o
 * @return void
 */
function var_dump2($o)
{
    if (is_object($o) || is_array($o)) {
        foreach ($o as $key => $value) {
            echo('<b>');
            var_dump($key);
            echo('</b>');
            print_r($value);
            echo('<br>');
        }
    } else {
        var_dump($o);
    }
}
