<?php
/**
 * Created by PhpStorm.
 * User: crose
 * Date: 3/13/17
 * Time: 9:29 PM
 */

namespace IMATHUZH\Qfq\Core\Form;


use IMATHUZH\Qfq\Core\Database\Database;
use IMATHUZH\Qfq\Core\Helper\Ldap;
use IMATHUZH\Qfq\Core\Helper\OnString;
use IMATHUZH\Qfq\Core\Store\Session;
use IMATHUZH\Qfq\Core\Store\Sip;


/**
 * Class TypeAhead
 * @package qfq
 */
class TypeAhead {

    /**
     * @var Database
     */
    private $db = null;

    /**
     * @var array
     */
    private $vars = array();

    /**
     * @param bool $phpUnit
     * @throws \CodeException
     */
    public function __construct($phpUnit = false) {

        $this->vars[TYPEAHEAD_API_QUERY] = isset($_GET[TYPEAHEAD_API_QUERY]) ? $_GET[TYPEAHEAD_API_QUERY] : '';
        $this->vars[TYPEAHEAD_API_PREFETCH] = isset($_GET[TYPEAHEAD_API_PREFETCH]) ? $_GET[TYPEAHEAD_API_PREFETCH] : '';
        $this->vars[TYPEAHEAD_API_SIP] = isset($_GET[TYPEAHEAD_API_SIP]) ? $_GET[TYPEAHEAD_API_SIP] : '';

        if ($this->vars[TYPEAHEAD_API_SIP] == '') {
            throw new \CodeException('Missing GET parameter "' . TYPEAHEAD_API_SIP);
        }

        if ($this->vars[TYPEAHEAD_API_QUERY] == '' && $this->vars[TYPEAHEAD_API_PREFETCH] == '') {
            throw new \CodeException('Missing GET parameter "' . TYPEAHEAD_API_QUERY . '" or "' . TYPEAHEAD_API_PREFETCH . '"');
        }

        $session = Session::getInstance($phpUnit);
    }

    /**
     * @return array|int
     * @throws \CodeException
     * @throws \DbException
     * @throws \UserFormException
     * @throws \UserReportException
     */
    public function process() {

        $arr = array();

        $sipClass = new Sip();

        $sipVars = $sipClass->getVarsFromSip($this->vars[TYPEAHEAD_API_SIP]);
        $dbIndex = $sipVars[PARAM_DB_INDEX_DATA] ?? DB_INDEX_DEFAULT;

        // Check for an optional given dbIndex: '[<int>]SELECT ...'
        $sql = $sipVars[FE_TYPEAHEAD_SQL] ?? '';
        if (($sql[0] ?? '') === '[') {
            $pos = strpos($sql, ']');
            $dbIndex = substr($sql, 1, $pos - 1);
            $sipVars[FE_TYPEAHEAD_SQL] = substr($sql, $pos + 1);
        }

        $this->db = new Database($dbIndex);

        if (isset($sipVars[FE_TYPEAHEAD_SQL])) {
            if ($this->vars[TYPEAHEAD_API_PREFETCH] == '') {
                $arr = $this->typeAheadSql($sipVars, $this->vars[TYPEAHEAD_API_QUERY]);
            } else {
                $arr = $this->typeAheadSqlPrefetch($sipVars, $this->vars[TYPEAHEAD_API_PREFETCH], $this->db);
            }
        } elseif (isset($sipVars[FE_LDAP_SERVER])) {
            $ldap = new Ldap();

            if ($this->vars[TYPEAHEAD_API_PREFETCH] == '') {
                $mode = MODE_LDAP_MULTI;
                $key = $this->vars[TYPEAHEAD_API_QUERY];
            } else {
                $mode = MODE_LDAP_PREFETCH;
                $key = $this->vars[TYPEAHEAD_API_PREFETCH];
            }

            $arr = $ldap->process($sipVars, $key, $mode);
        }

        return $arr;
    }

    /**
     * Do a wildcard search on the prepared statement $config[FE_TYPEAHEAD_SQL].
     * All '?' will be replaced by '%$value%'.
     * If there is no 'LIMIT x' defined, append it.
     * Returns an dict array [ API_TYPEAHEAD_KEY => key, API_TYPEAHEAD_VALUE => value ]
     *
     * @param array $config
     * @param string $value
     *
     * @return array
     * @throws \CodeException
     * @throws \DbException
     * @throws \UserFormException
     */
    private function typeAheadSql(array $config, $value) {
        $values = array();

        $sql = $config[FE_TYPEAHEAD_SQL];
        $value = OnString::generateWildcardPattern($value);
        $cnt = substr_count($sql, '?');

        if ($cnt == 0) {
            throw new \UserFormException("Missing at least one '?' in " . FE_TYPEAHEAD_SQL);
        }

        for ($ii = 0; $ii < $cnt; $ii++) {
            $values[] = $value;
        }

        if (!$this->db->hasLimit($sql)) {
            $sql .= ' LIMIT ' . $config[FE_TYPEAHEAD_LIMIT];
        }

        $arr = $this->db->sql($sql, ROW_REGULAR, $values);
        if ($arr == false || count($arr) == 0) {
            return array();
        }

        return $this->db->makeArrayDict($arr, TYPEAHEAD_SQL_KEY_NAME, API_TYPEAHEAD_VALUE, API_TYPEAHEAD_KEY, API_TYPEAHEAD_VALUE);
    }

    /**
     * Returns a dict array [ API_TYPEAHEAD_KEY => key, API_TYPEAHEAD_VALUE => value ] with the prefetch result
     *
     * @param array $config
     * @param string $key
     *
     * @return array
     * @throws \CodeException
     * @throws \DbException
     * @throws \UserFormException
     */

    public static function typeAheadSqlPrefetch(array $config, $key, $db) {
        $keys = array();

        $sql = $config[FE_TYPEAHEAD_SQL_PREFETCH];
        if ($config[FE_TYPEAHEAD_SQL_PREFETCH] == '') {
            throw new \UserFormException("Missing definition for `" . FE_TYPEAHEAD_SQL_PREFETCH . "`", ERROR_MISSING_TYPE_AHEAD_SQL_PREFETCH);
        }

        $cnt = substr_count($sql, '?');
        if ($cnt == 0) {
            throw new \UserFormException("Missing at least one '?' in " . FE_TYPEAHEAD_SQL_PREFETCH);
        }

        for ($ii = 0; $ii < $cnt; $ii++) {
            $keys[] = $key;
        }

        $arr = $db->sql($sql, ROW_REGULAR, $keys);
        if ($arr == false || count($arr) == 0) {
            return array();
        }

        // return first result as key-value pair (concatenate columns)
        $value = '';
        foreach ($arr[0] as $name => $column) {
            $value .= $column;
        }
        return [[API_TYPEAHEAD_KEY => $key, API_TYPEAHEAD_VALUE => $value]];
    }

}