<?php 
/**
 * Common Library for Sphinx single index query
 */
require_once 'Sphinx.php';
class sphinxLib extends sphinx
{
    const SPHINX_INDEX = "connexity_feed";
    const PAGE_OFFSET = 0;
    const PAGE_LIMIT = 20;
    
    private $_faceted = ["prices", "brand", "category","availability","min_price","max_price"];
    private $_match_faceted = ["brand", "category","master_category"];
    private $_faceted_map = array('prices' => 'prices', 'brand' => 'brand', 'category' => 'category','availability'=>'availability');
    private $_faceted_expr = array(
        "price" => "FACET INTERVAL(price,0,10,100,1000,10000,100000) as prices ORDER BY price DESC",
        "brand[]" => "FACET brand ORDER BY COUNT(*) DESC LIMIT 20",
        "category[]" => "FACET category,category_display as cat ORDER BY count(*) DESC LIMIT 20",
        "availability" => "FACET availability ORDER BY count(*) DESC LIMIT 2"
    );

    private $_faceted_name = array(
        "prices" => "Price",
        "brand" => "Brand",
        "category" => "Category",
        "availability" => "Availability"
    );
    
    public function __construct($config=array()) {
        parent::__construct($config);
    }

    /**
     * Sorting condition
     * @param type $sort
     * @return string
     */
    private function _sortCondition($sort) {
        $condition = " ";
        if($sort == "price"){
            $condition = " ORDER BY price asc";
        }elseif($sort == "price-desc") {
            $condition = " ORDER BY price desc";
        }
        else{
            $condition = " ORDER BY id desc";
        }
        return $condition;
    }
    
    private function _createWhere($param) {        
        $filters = [];
        $minStr = "";
        foreach ($this->_faceted as $f) {
            if(in_array($f, $this->_match_faceted))
                continue;
            if (isset($param[$f]) && !empty($param[$f])) {
                switch ($f) {
                    case 'prices':
                        $start = ($param[$f]==1) ? 0 : (pow(10,$param[$f]-1));
                        $filters[] = "price BETWEEN " . $start . ' AND ' . (pow(10,$param[$f])-1);
                        break;
                    case 'min_price':
                        $minStr = "price BETWEEN " . $param[$f] . ' AND ';
                        break;
                    case 'max_price':
                        if(!empty($minStr))
                            $filters[] = $minStr.$param[$f];
                        break;
                    default:
                        $filters[] = "$f = " . $this->getQuote($param[$f]);
                }
            }
        }
        return $filters;
    }
    /**
     * create where match
     * @param type $param
     * @return type
     */
    private function _createMatchWhere($param) {
        $filters = [];
        foreach ($this->_match_faceted as $f) {
            if (isset($param[$f]) && !empty($param[$f])) {
                $filters[] = " @$f(\"$param[$f]\") ";
            }
        }
        return $filters;
    }
    
    /**
     * Get search data from given params
     * @param type $params array
        $params["keyword"] = keyword for which against you wanna search
        $params["master_category"] = master category for which against you wanna search
        $params["category"] = catgory for which against you wanna search
        $params["brand"] = Brand for which against you wanna search
        $params["prices"] = Price Number (0-5) which indicates price range 1=>0 - 9,2=>10 -99,3=>100 - 999,4=>1000 - 9999,5=>10000-99999 and so on 
        $params["availability"] = catgory for which against you wanna search
        $params["page"] = page for which you wanna search, by default there is 20 product on 1 page
        $params["sort"] = Sort type like price ace and desc
        $params["debugSql"] = For debug sql statement
        $params["debugSqlResponse"] = For debug sql statement response
        $params["debugMatchSqlCond"] = For debug sql statement for matching words 
        $params["debugFinalResponse"] = For debug Final response send by function
     * @return type
     */
    public function getSearchData($params) {
        $whereCond = $this->_createWhere($params);
        $offset = (isset($params['limit'])) ? $params['limit'] : self::PAGE_LIMIT;
        $start = (empty($params['page']) || $params['page'] == 1) ? self::PAGE_OFFSET : (($params['page']-1) * $offset);
        $sortCondition = $this->_sortCondition($params['sort']);
        $matchWhere = $this->_createMatchWhere($params);
        if(!empty($matchWhere)){
            if(empty($params['keyword'])){
                $match = $this->getQuote(implode(" ",$matchWhere));
            }else{
                $match = $this->getQuote($params['keyword'].implode(" ",$matchWhere));
            }
        }else{
            $match = (empty($params['keyword'])) ? "" : $this->getQuote($params['keyword']);
        }
        $facet_string = implode(' ', $this->_faceted_expr);
        $condition = "";
        if(!empty($match)){
            $condition = " WHERE MATCH($match) ";
        }
        if(count($whereCond) > 0){
           $w_cond =   (empty($condition)) ? ' WHERE ' . implode(' AND ', $whereCond) : ' AND ' . implode(' AND ', $whereCond);
           $condition .= $w_cond;
        }
        $sql = "SELECT * FROM ".self::SPHINX_INDEX.$condition.$sortCondition." LIMIT $start,$offset OPTION max_query_time=2000,max_matches=9999,ranker=sph04,field_weights=(category=100,merchant=90,title=50,description=1) " . $facet_string;
        
        $response = $this->getDataWithFacet($sql, $this->_faceted);
        
        if(empty($response['result']) && $response['metaInfo']['total_found'] <=0){
            $meta = $response['metaData'];
            $words = []; 
            foreach ($meta as $m) {
                if (preg_match('/keyword\[\d+]/', $m['Variable_name'])) {
                    preg_match('/\d+/', $m['Variable_name'], $key);
                    $key = $key[0];
                    $words[$key]['keyword'] = $m['Value'];
                }
                if (preg_match('/docs\[\d+]/', $m['Variable_name'])) {
                    preg_match('/\d+/', $m['Variable_name'], $key);
                    $key = $key[0];
                    $words[$key]['docs'] = $m['Value'];
                }
            }
            $didyoumean = false;
            $didyoumeanquery = [];
            foreach ($words as $i => $keyword) {
                if ($keyword['docs'] == 0) {
                    $indexes = self::SPHINX_INDEX;
                    $rows = $this->getArray("CALL SUGGEST('{$keyword['keyword']}','$indexes')");
                    if (is_array($rows) && count($rows) > 0) {
                        $keywords[$i]['keyword'] = $rows[0]['suggest'];
                        $didyoumeanquery[] = $rows[0]['suggest'];
                        $didyoumean = true;
                        break;
                    }
                }
            }
            $oldKeyword = $params['keyword'];
            $params['keyword'] = (isset($didyoumeanquery[0])) ? $didyoumeanquery[0] : $oldKeyword;
            $whereCond = $this->_createWhere($params);
            $offset = self::PAGE_LIMIT;
            $start = (empty($params['page']) || $params['page'] == 1) ? self::PAGE_OFFSET : (($params['page']-1) * self::PAGE_LIMIT);
            $sortCondition = $this->_sortCondition($params['sort']);
            $matchWhere = $this->_createMatchWhere($params);
            if(!empty($matchWhere)){
                if(empty($params['keyword'])){
                    $match = $this->getQuote(implode(" ",$matchWhere));
                }else{
                    $match = $this->getQuote($params['keyword'].implode(" ",$matchWhere));
                }
            }else{
                $match = (empty($params['keyword'])) ? "" : $this->getQuote($params['keyword']);
            }
            $facet_string = implode(' ', $this->_faceted_expr);
            $condition = "";
            if(!empty($match)){
                $condition = " WHERE MATCH($match) ";
            }
            if(count($whereCond) > 0){
               $w_cond =   (empty($condition)) ? ' WHERE ' . implode(' AND ', $whereCond) : ' AND ' . implode(' AND ', $whereCond);
               $condition .= $w_cond;
            }
            $sql = "SELECT * FROM ".self::SPHINX_INDEX.$condition.$sortCondition." LIMIT $start,$offset OPTION  max_query_time=2000,max_matches=9999,ranker=sph04,field_weights=(category=100,merchant=90,title=50,description=1) " . $facet_string;
            
            $response = $this->getDataWithFacet($sql, $this->_faceted);
            $response['actual_result']=0;
            $response['old_keyword']=$oldKeyword;
            $response['new_keyword']=$params['keyword'];
        }
        
        if(!empty($response['result']) && empty($response['metaInfo'])){
            $response['metaInfo']['total_found'] = empty($response['facet']['availability'][0][1]) ? 20 : $response['facet']['availability'][0][1];
        }
        return $response;
    }
    
    public function getRelatedData($keyword) {
        $responseData = [];
        $sphinixIndex = self::SPHINX_INDEX;
        $keyword = preg_replace("/[^0-9a-zA-Z ]/","", $keyword);
        $keyword = preg_replace("/\s+/"," ", $keyword);
        $keywords = explode(" ",$keyword);
        $keywords = array_chunk($keywords,3)[0];        
        foreach ($keywords as $key => $word) {
            $sql = "CALL SUGGEST('$word','$sphinixIndex', 9 as limit)";
            $response = $this->getArray($sql);
            if(!empty($response)){
                foreach ($response as $data) {
                    if($data['distance']>0 && $data['docs'] > 10){
                        $responseData[] = $data['suggest'];
                        if(count($responseData)>7)
                            break 2;
                    }
                }
            }
        }
        return $responseData;
    }
    /**
     * Get product details by its sku id
     * @param type $id sku id of product
     * @return boolean false OR array
     */
    public function getDetail($id) {
        $data = $this->getRow("select * from ".self::SPHINX_INDEX." WHERE MATCH('@sku(\"$id\")')");
        if(!empty($data)){
            return $data;
        }else{
            return false;
        }
    }
}