<?php
/**
 * i-doit - Documentation and CMDB solution for IT environments
 *
 * This file is part of the i-doit framework. Modify at your own risk.
 *
 * Please visit http://www.i-doit.com/license for a full copyright and license information.
 *
 * @version     1.10
 * @package     i-doit
 * @author      synetics GmbH
 * @copyright   synetics GmbH
 * @url         http://www.i-doit.com
 * @license     http://www.i-doit.com/license
 */
namespace idoit\Component\Table;

use idoit\Component\Table\Pagerfanta\View\IdoitView;
use idoit\Module\Cmdb\Model\Ci\Table\Config;
use Pagerfanta\Adapter\AdapterInterface;
use Pagerfanta\Pagerfanta;

/**
 * i-doit Table Component.
 *
 * @package     i-doit
 * @subpackage  Component
 * @author      Leonard Fischer <lfischer@i-doit.com>
 * @copyright   synetics GmbH
 * @license     http://www.i-doit.com/license
 */
class Table
{
    /**
     * Parameter for current page.
     */
    const CURRENT_PAGE         = 'page';
    const DEFAULT_FILTER_FIELD = 'isys_cmdb_dao_category_g_global__title';

    /**
     * @var array
     */
    protected $header;

    /**
     * @var AdapterInterface
     */
    protected $adapter;

    /**
     * @var Config
     */
    protected $tableConfig;

    /**
     * @var Pagerfanta
     */
    protected $pager;

    /**
     * @var string
     */
    protected $template;

    /**
     * @var array
     */
    protected $options = [
        'enableCheckboxes'    => false,
        'rowClick'            => false,
        'rowClickURL'         => null,
        'keyboardCommands'    => false,
        'tableConfigURL'      => null,
        'dragDrop'            => false,
        'filter'              => false,
        'filterColumns'       => [],
        'resizeColumns'       => false,
        'resizeColumnAjaxURL' => null,
        'columnSizes'         => [],
        'pages'               => 0,
        'rowsPerPage'         => 50
    ];

    protected $unique;

    /**
     * Table factory.
     *
     * @param AdapterInterface $adapter
     * @param array            $header
     * @param array            $options
     *
     * @return static
     */
    public static function factory(AdapterInterface $adapter, array $header, array $options = [])
    {
        return new static($adapter, $header, $options);
    } // function

    /**
     * Table constructor.
     *
     * @param AdapterInterface        $adapter
     * @param Config $tableConfig
     * @param array                   $header
     * @param array                   $options
     */
    public function __construct(AdapterInterface $adapter, Config $tableConfig, array $header, array $options = [])
    {
        global $g_dirs;

        $this->header   = $header;
        $this->adapter  = $adapter;
        $this->tableConfig   = $tableConfig;
        $this->pager    = new Pagerfanta($adapter);
        $this->template = $g_dirs['smarty'] . 'templates/content/bottom/content/component_table.tpl';
        $this->options  = array_replace_recursive($this->options, $options);
        $this->unique   = uniqid('mainTable-');

        $this->initializePager($_GET[self::CURRENT_PAGE], $this->options['rowsPerPage']);
    } // function

    /**
     * @return Pagerfanta
     */
    public function getPager()
    {
        return $this->pager;
    } // function

    /**
     * Returns the unique table ID.
     *
     * @return string
     */
    public function getUnique()
    {
        return $this->unique;
    } // function

    /**
     * Method for configurating the Pager.
     *
     * @param integer $currentPage
     * @param integer $entriesPerPage
     *
     * @return $this
     */
    public function initializePager($currentPage = null, $entriesPerPage = null)
    {
        if ($currentPage === null)
        {
            $currentPage = 1;
        } // if

        if ($entriesPerPage === null)
        {
            $entriesPerPage = isys_glob_get_pagelimit();
        } // if

        // Configurating the Pagerfanta instance.
        $this->pager->setCurrentPage($currentPage)
            ->setMaxPerPage($entriesPerPage);

        return $this;
    } // function

    /**
     * Render method for the table component.
     *
     * @param bool $return
     *
     * @return string
     */
    public function render($return = false)
    {
        global $g_dirs;

        $rowsPerPageOnLastPage = $pagerNextUrl = null;

        $rowPerPage = \isys_usersettings::get('gui.objectlist.rows-per-page', 50);
        $rows = $this->pager->getNbResults();

        $routeGenerator = function ($page)
        {
            $url = [];
            parse_str($_SERVER['QUERY_STRING'], $url);
            $url[self::CURRENT_PAGE] = $page;

            unset($url[C__GET__AJAX]);

            return '?' . http_build_query($url);
        };

        $pagerView = (new IdoitView())->render(
            $this->pager,
            $routeGenerator,
            [
                'proximity'          => 3,
                'previous_message'   => '<img src="' . $g_dirs['images'] . 'icons/silk/resultset_previous.png" alt="<" />',
                'next_message'       => '<img src="' . $g_dirs['images'] . 'icons/silk/resultset_next.png" alt=">" />',
                'container_template' => _L('LC__UNIVERSAL__PAGES') . ' %pages%'
            ]
        );

        $callbacks = [];
        $data = $this->pager->getCurrentPageResults();

        $properties = [];

        foreach ($this->tableConfig->getProperties() as $property)
        {
            $properties[$property->getClass() . '__' . $property->getKey()] = str_replace(' ', '', ucwords(str_replace('_', ' ', $property->getType())));
        } // foreach

        if (is_array($data) && count($data))
        {
            // Check which property has callbacks.
            foreach ($data[0] as $key => $value)
            {
                $callbackClass = '\\idoit\\Module\\Cmdb\\Model\\Ci\\Type\\' . $properties[$key];

                if (class_exists($callbackClass) && is_a($callbackClass, 'idoit\\Module\\Cmdb\\Model\\Ci\\Category\\DynamicCallbackInterface', true))
                {
                    $callbacks[$key] = $callbackClass;
                } // if

                list($class, $property) = explode('__', str_replace('isys_cmdb_dao_category_', '', $key));

                $class = str_replace(' ', '', ucwords(str_replace('_', ' ', $class)));
                $property = str_replace(' ', '', ucwords(str_replace('_', ' ', (($class === 'GCustomFields') ? substr($property, 1, strpos($property, '_c_')) : $property))));

                $callbackClass = '\\idoit\\Module\\Cmdb\\Model\\Ci\\Category\\' . substr($class, 0, 1) . '\\' . substr($class, 1) . '\\' . $property;

                if (
                    !empty($class) &&
                    class_exists($callbackClass) &&
                    is_a($callbackClass, 'idoit\\Module\\Cmdb\\Model\\Ci\\Category\\DynamicCallbackInterface', true)
                ) {
                    $callbacks[$key] = $callbackClass;
                } // if
            } // foreach

            foreach ($data as &$row)
            {
                foreach ($row as $key => &$value)
                {
                    if (strpos($key, '__') === false && strpos($key, '###') === false && $key != '__id__')
                    {
                        unset($row[$key]);
                        continue;
                    } // if

                    $value = _LL($value);

                    // Check if a callback is set and call it!
                    if (isset($callbacks[$key]))
                    {
                        $value = call_user_func($callbacks[$key] . '::render', $value);
                    } // if
                } // foreach
            } // foreach
        }
        else
        {
            $data = [];
        } // if

        $rowsPerPage = array_unique([
            50                => '50',
            100               => '100',
            150               => '150',
            200               => '200',
            250               => '250',
            500               => '500',
            (int) $rowPerPage => $rowPerPage
        ]);

        if (! $this->pager->hasNextPage())
        {
            $rowsPerPageOnLastPage = count($data);
            $rowsPerPage[$rowsPerPageOnLastPage] = $rowsPerPageOnLastPage;

            foreach ($rowsPerPage as $rowCount => $rowName)
            {
                if ($rowsPerPageOnLastPage < $rowCount)
                {
                    unset($rowsPerPage[$rowCount]);
                } // if
            } // foreach
        }
        else
        {
            $pagerNextUrl = $routeGenerator($this->pager->getNextPage());

            // ID-3533 Always limit the "$rowsPerPage" to the maximum rows (for example: a list with 55 rows should not display any options above 50 and "all").
            foreach ($rowsPerPage as $rowCount => $rowName)
            {
                if ($rows < $rowCount)
                {
                    unset($rowsPerPage[$rowCount]);
                } // if
            } // foreach
        } // if

        natsort($rowsPerPage);

        if ($rows <= \isys_tenantsettings::get('cmdb.limits.table-order-threshhold', 20000))
        {
            $rowsPerPage[$rows] = _L('LC__UNIVERSAL__ALL');
        } // if

        $rules = [
            $this->unique . '-filter'       => [
                'disableInputGroup' => true,
                'p_bInfoIconSpacer' => 0,
                'p_strValue'        => $this->options['filterDefaultValue']
            ],
            $this->unique . '-filter-field' => [
                'disableInputGroup' => true,
                'p_bDbFieldNN'      => true,
                'p_bSort'           => false,
                'p_bInfoIconSpacer' => 0,
                'p_arData'          => $this->options['filterColumns'],
                'p_strSelectedID'   => $this->options['filterDefaultColumn']
            ],
            $this->unique . '-rows-per-page' => [
                'disableInputGroup' => true,
                'p_bDbFieldNN'      => true,
                'p_bSort'           => false,
                'p_bInfoIconSpacer' => 0,
                'p_arData'          => $rowsPerPage,
                'p_strSelectedID'   => (int) $rowsPerPageOnLastPage ?: $this->options['rowsPerPage']
            ]
        ];

        if (!isset($this->options['pages']) || !$this->options['pages'])
        {
            $this->options['pages'] = $this->pager->getNbPages();
        } // if

        unset($_GET[C__GET__AJAX], $_GET[C__GET__AJAX_CALL]);

        $tpl = \isys_application::instance()->template->activate_editmode()
            ->assign('unique', $this->unique)
            ->assign('header', $this->header)
            ->assign('data', $data)
            ->assign('pager', $pagerView)
            ->assign('pagerUrl', $routeGenerator('%page%'))
            ->assign('pagerCurrentUrl', $routeGenerator($this->pager->getCurrentPage()))
            ->assign('pagerNextUrl', $pagerNextUrl)
            ->assign('rows', $rows)
            ->assign('options', $this->options)
            ->smarty_tom_add_rules('tom.content.table', $rules);

        if (!$return)
        {
            $tpl->display($this->template);
        } // if

        return $tpl->fetch($this->template);
    } // function
} // class
