<?php

require_once('Simpla.php');

class Services extends Simpla
{
    public $menu_id = 3;
    public $root_id = 28;

    public $services_brands = array(
        //1 => array('id' => 1, 'name' => 'Alfa Romeo','url' => 'alfa-romeo', 'image' => ''),
        2 => array('id' => 2, 'name' => 'Audi', 'url' => 'audi', 'image' => 'audi.png'),
        3 => array('id' => 3, 'name' => 'Bentley', 'url' => 'bentley', 'image' => 'bentley.png'),
        4 => array('id' => 4, 'name' => 'BMW', 'url' => 'bmw', 'image' => 'bmw.png'),
        5 => array('id' => 5, 'name' => 'Cadillac', 'url' => 'cadillac', 'image' => 'cadillac.png'),
		55 => array('id' => 55, 'name' => 'Changan', 'url' => 'changan', 'image' => 'changan.png'),
        6 => array('id' => 6, 'name' => 'Chery','url' => 'chery', 'image' => 'chery.png'),
        7 => array('id' => 7, 'name' => 'Chevrolet', 'url' => 'chevrolet', 'image' => 'chevrolet.png'),
        8 => array('id' => 8, 'name' => 'Chrysler', 'url' => 'chrysler', 'image' => 'chrysler.png'),
        9 => array('id' => 9, 'name' => 'Citroen', 'url' => 'citroen', 'image' => 'citroen.png'),
        //10 => array('id' => 10, 'name' => 'Daewoo','url' => 'daewoo', 'image' => ''),
        11 => array('id' => 11, 'name' => 'Dodge', 'url' => 'dodge', 'image' => 'dodge.png'),
		56 => array('id' => 56, 'name' => 'Dongfeng', 'url' => 'Dongfeng', 'image' => 'dongfeng.png'),
        54 => array('id' => 54, 'name' => 'Exeed', 'url' => 'exeed', 'image' => 'exeed.png'),
        12 => array('id' => 12, 'name' => 'Ferrari', 'url' => 'ferrari', 'image' => 'ferrari.png'),
        13 => array('id' => 13, 'name' => 'Fiat', 'url' => 'fiat', 'image' => 'fiat.png'),
        53 => array('id' => 53, 'name' => 'Ford', 'url' => 'ford', 'image' => 'ford.png'),
		57 => array('id' => 57, 'name' => 'GAC', 'url' => 'gac', 'image' => 'gac.png'),
        14 => array('id' => 14, 'name' => 'Geely', 'url' => 'geely', 'image' => 'geely.png'),
        //15 => array('id' => 15, 'name' => 'GMC','url' => 'gmc', 'image' => ''),
        16 => array('id' => 16, 'name' => 'Great Wall','url' => 'great-wall', 'image' => 'great-wall.png'),
        17 => array('id' => 17, 'name' => 'Haval', 'url' => 'haval', 'image' => 'haval.png'),
        18 => array('id' => 18, 'name' => 'Honda', 'url' => 'honda', 'image' => 'honda.png'),
        19 => array('id' => 19, 'name' => 'Hummer', 'url' => 'hummer', 'image' => 'hummer.png'),
        20 => array('id' => 20, 'name' => 'Hyundai', 'url' => 'hyundai', 'image' => 'hyundai.png'),
		58 => array('id' => 58, 'name' => 'Haima', 'url' => 'haima', 'image' => 'haima.png'),	
        21 => array('id' => 21, 'name' => 'Infiniti', 'url' => 'infiniti', 'image' => 'infiniti.png'),
        22 => array('id' => 22, 'name' => 'Jaguar', 'url' => 'jaguar', 'image' => 'jaguar.png'),
		59 => array('id' => 59, 'name' => 'JAC', 'url' => 'jac', 'image' => 'jac.png'),
		60 => array('id' => 60, 'name' => 'Jaecoo', 'url' => 'jaecoo', 'image' => 'jaecoo.png'),
		61 => array('id' => 61, 'name' => 'Jetour', 'url' => 'jetour', 'image' => 'jetour.png'),
		62 => array('id' => 62, 'name' => 'Jetta', 'url' => 'jetta', 'image' => 'jetta.png'),		
        23 => array('id' => 23, 'name' => 'Jeep', 'url' => 'jeep', 'image' => 'jeep.png'),
		63 => array('id' => 63, 'name' => 'JMC', 'url' => 'jmc', 'image' => 'jmc.png'),
		64 => array('id' => 64, 'name' => 'Kaiyi', 'url' => 'kaiyi', 'image' => 'kaiyi.png'),
        24 => array('id' => 24, 'name' => 'Kia', 'url' => 'kia', 'image' => 'kia.png'),
        25 => array('id' => 25, 'name' => 'Land Rover', 'url' => 'land-rover', 'image' => 'land-rover.png'),
        26 => array('id' => 26, 'name' => 'Lexus', 'url' => 'lexus', 'image' => 'lexus.png'),
        27 => array('id' => 27, 'name' => 'LiXiang','url' => 'lixiang', 'image' => 'LiXiang.png'),
		65 => array('id' => 65, 'name' => 'Livan', 'url' => 'livan', 'image' => 'livan.png'),
        28 => array('id' => 28, 'name' => 'Mazda', 'url' => 'mazda', 'image' => 'mazda.png'),
        29 => array('id' => 29, 'name' => 'Mercedes-Benz', 'url' => 'mercedes-benz', 'image' => 'mercedes-benz.png'),
        30 => array('id' => 30, 'name' => 'Mini', 'url' => 'mini', 'image' => 'mini.png'),
        31 => array('id' => 31, 'name' => 'Mitsubishi', 'url' => 'mitsubishi', 'image' => 'mitsubishi.png'),
        32 => array('id' => 32, 'name' => 'Nissan', 'url' => 'nissan', 'image' => 'nissan.png'),
		66 => array('id' => 66, 'name' => 'OMODA', 'url' => 'omoda', 'image' => 'omoda.png'),
        33 => array('id' => 33, 'name' => 'Opel', 'url' => 'opel', 'image' => 'opel.png'),
        34 => array('id' => 34, 'name' => 'Peugeot', 'url' => 'peugeot', 'image' => 'peugeot.png'),
        35 => array('id' => 35, 'name' => 'Porsche', 'url' => 'porsche', 'image' => 'porsche.png'),
        36 => array('id' => 36, 'name' => 'Renault', 'url' => 'renault', 'image' => 'renault.png'),
        //37 => array('id' => 37, 'name' => 'Saab','url' => 'saab', 'image' => 'saab.png'),
        38 => array('id' => 38, 'name' => 'Scania', 'url' => 'scania', 'image' => 'scania.png'),
        //39 => array('id' => 39, 'name' => 'Seat','url' => 'seat', 'image' => ''),
        40 => array('id' => 40, 'name' => 'Skoda', 'url' => 'skoda', 'image' => 'skoda.png'),
        41 => array('id' => 41, 'name' => 'Smart', 'url' => 'smart', 'image' => 'smart.png'),
        //42 => array('id' => 42, 'name' => 'SsangYong','url' => 'ssangyong', 'image' => 'ssangyong.png'),
        43 => array('id' => 43, 'name' => 'Subaru', 'url' => 'subaru', 'image' => 'subaru.png'),
        44 => array('id' => 44, 'name' => 'Suzuki', 'url' => 'suzuki', 'image' => 'suzuki.png'),
		67 => array('id' => 67, 'name' => 'Tank', 'url' => 'tank', 'image' => 'tank.png'),
        45 => array('id' => 45, 'name' => 'Tesla', 'url' => 'tesla', 'image' => 'tesla.png'),
        46 => array('id' => 46, 'name' => 'Toyota', 'url' => 'toyota', 'image' => 'toyota.png'),
        47 => array('id' => 47, 'name' => 'Volkswagen', 'url' => 'volkswagen', 'image' => 'volkswagen.png'),
        48 => array('id' => 48, 'name' => 'Volvo', 'url' => 'volvo', 'image' => 'volvo.png'),
		68 => array('id' => 68, 'name' => 'VOYAH', 'url' => 'voyah', 'image' => 'voyah.png'),
        49 => array('id' => 49, 'name' => 'Zeekr','url' => 'zeekr', 'image' => 'Zeekr.png'),
        50 => array('id' => 50, 'name' => 'ГАЗ', 'url' => 'gaz', 'image' => 'gaz.png'),
        51 => array('id' => 51, 'name' => 'Лада (ВАЗ)', 'url' => 'lada-vaz', 'image' => 'lada-vaz.png'),
        52 => array('id' => 52, 'name' => 'Мототехника', 'url' => 'mototehnika', 'image' => 'moto.png'),
        //53 => array('id' => 53, 'name' => 'УАЗ','url' => 'uaz', 'image' => ''),
    );

    private $_root_url = 'tuning-centr/';

    private $_tree;

    /**
     * @var array
     */
    private $_services;

    public function count($filters)
    {
        $filter = $this->_prepare_filters($filters);
        $this->db->query("SELECT COUNT(DISTINCT p.id) as count FROM __pages p" .
            $filter->where);
        return (int)$this->db->result('count');
    }

    public function all($filters)
    {
        $filter = $this->_prepare_filters($filters);
        $this->db->query(
            "SELECT *" .
            " FROM __pages p" .
            $filter->where .
            $filter->order .
            $filter->limit
        );
        return $this->db->results();
    }

    /**
     * Возвращает данные страницы услуг по её id или url
     *
     * @param string|int $id ID или url страницы данные которой необходимо получить
     * @return object
     */
    public function get($id)
    {
        if (empty($id)) {
            //главная страница услуг
            $id = $this->root_id;
            $conditions = '1';
        } else {
            $conditions = 'menu_id=' . $this->menu_id;
        }

        if (is_string($id)) {
            $conditions .= $this->db->placehold(' AND url=?', $id);
        } else {
            $conditions .= $this->db->placehold(' AND id=?', intval($id));
        }
        $query = "SELECT * FROM __pages WHERE $conditions LIMIT 1";

        $this->db->query($query);
        return $this->db->result();
    }

    public  function  get_root_url() {
        return $this->_root_url;
    }

    /**
     * Возвращает краткие данные "брендовых" страниц услуги
     * @param int $id ID услуги
     * @param array $filter Фильтры получаемых данных, в виде колонка=>значение
     * @return array
     */
    public function get_brands_pages($id, $filter = array())
    {
        $this->_build_tree();
        if (!isset($this->_services[$id]))
            return array();

        $conditions = $this->db->placehold('parent=? AND brand_id>0', intval($id));
        foreach ($filter as $col => $val) {
            $conditions .= $this->db->placehold(" AND $col=?", $val);
        }

        $this->db->query("SELECT `id`, `brand_id`, `url`, `parent`, `visible`, `name` FROM __pages WHERE $conditions ORDER BY `position`");
        return $this->db->results();
    }

    /**
     * Возвращает данные всех предков услуги.
     * Url каждой услуги включает корень.
     * @param int $id ID услуги
     * @return array
     */
    public function get_path_to($id)
    {
        $this->_build_tree();
        $results = array();
        if(array_key_exists($id, $this->_services)) {
            $breadcrumbs = $this->_services[$id]->path;
            foreach ($breadcrumbs as $breadcrumb) {
                $results[] = (object)array(
                    'id' => $breadcrumb->id,
                    'parent' => $breadcrumb->parent,
                    'name' => $breadcrumb->name,
                    'url' => intval($breadcrumb->id) !== $this->root_id ?  $this->_root_url . $breadcrumb->url  : trim($this->_root_url, '/'),
                );
            }
        }
        return $results;
    }

    public function get_all_brands()
    {
        $results = array();
        foreach ($this->services_brands as $brand) {
            $results[] = (object)$brand;
        }
        return $results;
    }

    /**
     * Возвращает дерево всех страниц услуг
     * @return array
     */
    public function get_tree()
    {
        $this->_build_tree();
        return $this->_tree;
    }

    public function get_all_services()
    {
        $this->_build_tree();
        return $this->_services;
    }

    /**
     * Возвращает услуги привязанные к главной странице.
     * Форматирование возвращаемых данных зависит от параметра $with_roots.
     * @param $visible_only
     * @param bool $with_roots Флаг определяющий будут ли услуги возвращены как дети их корневых услуг или просто списком
     * @return array
     */
    public function get_home_services($visible_only = false, $with_roots = false)
    {
        $results = array();

        $items = $this->services->all(array('show_home' => 1, 'visible' => 1));
        foreach ($items as $item) {
            if ($visible_only && !$this->is_visible($item->id))
                continue;
            if ($with_roots) {
                $root = $this->_services[$item->id]->path[1];
                if (!isset($results[$root->id])) {
                    $results[$root->id] = $this->get(intval($root->id));
                    $results[$root->id]->children = array();
                }
                if(!array_key_exists($item->id, $results))
                    $results[$root->id]->children[] = $item;
            } else
                $results[] = $item;
        }

        return $results;
    }

    /**
     * Возвращает услуги главной страницы услуг (отмеченные как "в услугах").
     * Форматирование возвращаемых данных зависит от параметра $with_roots.
     * @param $visible_only
     * @param bool $with_roots Флаг определяющий будут ли услуги возвращены как дети их корневых услуг или просто списком
     * @return array
     */
    public function get_main_services($visible_only = false, $with_roots = false)
    {
        $results = array();

        $items = $this->services->all(array('show_service' => 1, 'visible' => 1));
        foreach ($items as $item) {
            if ($visible_only && !$this->is_visible($item->id))
                continue;
            if ($with_roots) {
                $root = $this->_services[$item->id]->path[1];
                if (!isset($results[$root->id])) {
                    $results[$root->id] = $this->get(intval($root->id));
                    $results[$root->id]->children = array();
                }
                if(!array_key_exists($item->id, $results))
                    $results[$root->id]->children[] = $item;
            } else
                $results[] = $item;
        }

        return $results;
    }

    public function get_brand($brand_id)
    {
        if (array_key_exists($brand_id, $this->services_brands))
            return (object)$this->services_brands[$brand_id];

        return false;
    }

    /**
     * Возвращает данные брендов привязанных к странице услуги
     * @param int $id ID услуги
     * @return array
     */
    public function get_service_brands($id)
    {
        $conditions = $this->db->placehold('p.parent=? AND p.brand_id>0', intval($id));
        $this->db->query("SELECT * FROM __pages p  WHERE $conditions ");

        $results = array();
        foreach ($this->db->results() as $page) {
            if (array_key_exists($page->brand_id, $this->services_brands)) {
                $brand = (object)$this->services_brands[$page->brand_id];
                $brand->page_id = $page->id;
                $brand->page_url = $page->url;
                $brand->page_visible = $page->visible;
                $results[] = $brand;
            }
        }
        return $results;
    }

    /**
     * Создаёт новые или удаляет существующие "брендовые" страницы услуги.
     * К услуге будут привязаны только бренды ID которых перечислены в $brands.
     * Если массив $brands не содержит элементов, то будут удалены все "брендовые" страницы услуги.
     * @param int $id ID страницы услуги
     * @param array $brands ID брендов, для которых должны быть сгенерированы страницы.
     * @return void
     */
    public function create_brands_pages($id, $brands)
    {
        $delete_conditions = $this->db->placehold('menu_id=? AND parent=? AND brand_id>0', $this->menu_id, intval($id));

        if (is_array($brands) && !empty($brands)) {
            $ids = array();

            foreach ($brands as $brand_id) {
                $ids[] = intval($brand_id);
                $this->create_brand_page($id, intval($brand_id));
            }

            $delete_conditions .= $this->db->placehold(' AND brand_id NOT IN (?@)', $ids);
        }
        //Удаляем все брендовые страницы, которые не были перечислены в $brands
        $this->db->query("DELETE FROM __pages WHERE $delete_conditions");
    }

    public function create_brand_page($id, $brand_id)
    {
        // страница услуги
        if (!($page = $this->services->get(intval($id))))
            return;

        //проверяем существует ли "брендовая" страница услуги
        $conditions = $this->db->placehold('parent=? AND brand_id=?', intval($id), intval($brand_id));
        if ($this->count(array('where' => $conditions)) === 0) {// страницы не существует
            if (array_key_exists($brand_id, $this->services_brands)) {
                $brand = (object)$this->services_brands[$brand_id];
                $service = array(
                    'parent' => $id,
                    'brand_id' => $brand_id,
                    'menu_id' => $this->menu_id,
                    'url' => $page->url . '/' . $brand->url,
                    'name' => $brand->name,
                    'header' => $page->name . ' ' . $brand->name,
                    'meta_title' => $page->name . ' ' . $brand->name . ' в Санкт-Петербурге | Тюнинг центр'
                );
                $this->pages->add_page($service);
            }
        }
    }

    public function update($id, $service)
    {
        $old_service = $this->get(intval($id));

        $query = $this->db->placehold("UPDATE __pages SET ?% WHERE id=? LIMIT 1", $service, intval($id));
        $this->db->query($query);

        $service = (object)$service;
        //был изменён родитель или позиция
        if((isset($service->parent) && intval($old_service->parent) !== intval($service->parent))
            || (isset($service->position)) && intval($old_service->position) !== intval($service->position))
            $this->fix_positions();

        //была изменен статус видимости
        if(isset($service->visible) && intval($old_service->visible) !== intval($service->visible))
            $this->set_visible($id, $service->visible);

        return $id;
    }

    /**
     * Удаляет все услуги с указанными id, а также всех их потомков
     * @param $ids
     * @param bool $recursive Разрешено ли удалять узлы имеющие детей (по умолчанию - запрещено)
     * @return void
     */
    public function delete($ids, $recursive = false)
    {
        $ids = (array)$ids;
        foreach ($ids as $id) {
            $service = $this->get(intval($id));
            if (!empty($service)) {
                // получаем ID детей
                $this->db->query('SELECT id FROM __pages WHERE parent=' . $service->id);
                $children = $this->db->results('id');
                $has_children = count($children) > 0;

                // если есть дети и удаление не рекурсивное - пропускаем узел
                if (!$recursive && $has_children)
                    continue;

                if ($has_children) {
                    // рекурсивно удаляем потомков
                    $this->delete($children, $recursive);
                } else {
                    // узел без детей - удаляем
                    $this->_delete_internal(intval($id));
                    $this->_unset_tree();
                }
            }
        }
    }

    public function move($id, $options)
    {
        $this->_build_tree();

        $id = intval($id);
        $new_parent = intval($options['parent']);
        $relative_position = intval($options['position']);

        if (isset($id, $this->_services) && isset($id, $this->_services[$new_parent])) {
            $service = $this->_services[$id];
            // новый родитель
            $parent = $this->_services[$new_parent];

            // нод место которого должен занять перемещаемый
            if (isset($parent->children[$relative_position])) {
                $target_node = $parent->children[$relative_position];
                $insert_position = intval($target_node->position);
            } else {
                // добавление в самую нижнюю позицию
                $target_node = null;
                $insert_position = $parent->position + (isset($parent->descendants) ? count($parent->descendants) : 1);
            }

            if (intval($service->parent) !== $new_parent) {
                // у нода будет другой родитель
                $conditions = $this->db->placehold('parent=?, position=? WHERE id=?', $new_parent, $insert_position, intval($service->id));
                $this->db->query('UPDATE __pages SET ' . $conditions);
                if ($target_node)
                    $this->db->query('UPDATE __pages SET position=' . $insert_position + 1 . ' WHERE id=' . intval($target_node->id));
            } else {
                // родитель не меняется
                $i = 0;
                foreach ($parent->children as $node) {
                    //$this->db->query('UPDATE __pages SET position=position+? WHERE id=?');
                    if ($node->id !== $service->id) {
                        $i = ($i === $relative_position) ? $relative_position + 1 : $i;
                        $this->db->query('UPDATE __pages SET position=? WHERE id=?', $i, intval($node->id));
                        ++$i;
                    } else {
                        $this->db->query('UPDATE __pages SET position=? WHERE id=?', $relative_position, intval($node->id));
                    }
                }
            }
            $this->fix_positions();
            $this->_unset_tree();

            return true;
        }

        return false;
    }

    /**
     * Возвращает реальный статус видимости услуги, в зависимости от статуса её родителей
     * @param $id
     * @return bool
     */
    public function is_visible($id)
    {
        $this->_build_tree();
        if (!array_key_exists($id, $this->_services) || !$this->_services[$id]->visible)
            return false;

        foreach ($this->_services[intval($id)]->path as $serv) {
            if (!$serv->visible)
                return false;
        }

        return true;
    }

    /**
     * Есть ли дети у указанной услуги
     * @param int $id
     * @return bool
     */
    public function has_children($id)
    {
        $this->_build_tree();
        return array_key_exists($id, $this->_services) && !empty($this->_services[$id]->children);
    }

    /**
     * Включает и отключает услугу
     * @param $id
     * @param $status
     * @return void
     */
    public function set_visible($id, $status) {
        $this->_build_tree();
        $visible = intval(boolval($status));

        $service = $this->get(intval($id));
        if($service) {
            $query = 'UPDATE __pages SET visible=' . $visible . ' WHERE id=';

            //если услуга не брендовая, включаем/отключаем всех её родителей/потомков
            if(!$service->brand_id) {
                $target_id = intval($service->id);
                if ($visible) { //включение услуги
                    foreach ($this->_services[$target_id]->path as $serv)
                        $this->db->query($query . $serv->id);
                } else { //отключение услуги
                    foreach ($this->_services[$target_id]->descendants as $s_id)
                        $this->db->query($query . $s_id);
                }
            } else { //брендовая услуга
                $target_id = intval($service->parent);
                if ($visible) { //включение предков родителя
                    foreach ($this->_services[$target_id]->path as $serv)
                        $this->db->query($query . $serv->id);
                    //включение самого родителя
                    $this->db->query($query . $target_id);
                }
            }

            // обновляем статус самой услуги
            $this->db->query( $query . $service->id);
        }
        $this->_unset_tree();
    }

    public function fix_positions($tree = null, &$pos = 0, $level=1)
    {
        if ($tree === null) {
            $this->_unset_tree();
            $tree = $this->_build_tree();
            $pos = 0;
            $level = 1;
        }
        foreach ($tree as $node) {
            $this->db->query('UPDATE __pages SET level='. $level .', position=' . ++$pos . ' WHERE id=' . intval($node->id));
            if ($node->children) {
                $this->fix_positions($node->children, $pos, $level+1);
            }
        }
    }

    private function _delete_internal($id)
    {
        //удаляем связанные объекты
        $this->db->query('DELETE FROM __pages_objects WHERE page_id=' . $id);
        //удаляем саму страницу
        $this->db->query('DELETE FROM __pages WHERE id=' . $id);
    }


    private function _build_tree()
    {
        if (!is_null($this->_tree))
            return $this->_tree;

        $this->db->query(
            "SELECT p.id, p.parent, p.brand_id, p.name, p.url, p.visible, p.position" .
            " FROM __pages p" .
            " WHERE (menu_id=" . $this->menu_id . " OR p.id=" . $this->root_id . ") AND p.brand_id=0" .
            " ORDER BY p.parent, p.position"
        );
        $services = $this->db->results();

        if (empty($services)) {
            return array();
        }

        // Дерево категорий
        $tree = $services[0];
        unset($services[0]);
        $tree->children = array();
        $pointers = array();
        $pointers[$this->root_id] = &$tree;
        $pointers[$this->root_id]->path = array($tree);

        $finish = false;
        // строим дерево
        while (!empty($services) && !$finish) {
            $flag = false;
            foreach ($services as $k => $service) {
                if (isset($pointers[$service->parent])) {
                    $pointers[$service->parent]->children[] = ($pointers[$service->id] = $service);
                    $curr = $pointers[$service->id];
                    $pointers[$service->id]->path = array_merge((array)$pointers[$service->parent]->path, array($curr));
                    unset($services[$k]);
                    $flag = true;
                }
            }
            if (!$flag) $finish = true;
        }

        // добавляем ID всех потомков к нодам
        $ids = array_reverse(array_keys($pointers));
        foreach ($ids as $id) {
            if ($id != $this->root_id) {
                $pointers[$id]->descendants[] = $id;
                if (isset($pointers[$pointers[$id]->parent]->descendants))
                    $pointers[$pointers[$id]->parent]->descendants = array_merge($pointers[$id]->descendants, $pointers[$pointers[$id]->parent]->descendants);
                else
                    $pointers[$pointers[$id]->parent]->descendants = $pointers[$id]->descendants;
            }
        }
        unset($ids);

        // получаем полный url к каждой странице попутно подчищая лишние ID и устанавливая реальный статус видимости элемента
        foreach ($pointers as $service) {
            if (!isset($service->children))
                unset($service->descendants);

            /*
            $current_url = $service->url;
            foreach ($service->path as $serv) {
                if (substr($serv->url, -1) !== '/') {
                    $current_url .= $serv->url . '/';
                } else {
                    $current_url = $serv->url;
                }
            }
            $service->url = $current_url;*/
        }

        $this->_tree = $tree->children;
        $this->_services = $pointers;

        return $this->_tree;
    }

    private function _unset_tree()
    {
        unset($this->_tree);
        unset($this->_services);
    }

    private function _prepare_filters($filter)
    {
        $filters = new stdClass();

        $where = 'menu_id=' . $this->menu_id;

        if (array_key_exists('where', $filter)) {
            $where = $filter['where'];
        } else {
            if (array_key_exists('ids', $filter)) {
                if (is_array($filter['ids']) && !empty($filter['ids']))
                    $where .= $this->db->placehold(' AND p.id IN (?@)', $filter['ids']);
                else
                    $where .= $this->db->placehold(' AND p.id IN (NULL)');
            }
            if (array_key_exists('visible', $filter)) {// активные/архивные контракты
                $where .= $this->db->placehold(' AND p.visible=?', intval($filter['visible']));
            }
            if (array_key_exists('branded', $filter)) {
                $where .= ' AND p.brand_id>0';
            }
            if (array_key_exists('show_service', $filter)) {
                $where .= ' AND p.show_service=' . intval($filter['show_service']);
            }
            if (array_key_exists('show_home', $filter)) {
                $where .= ' AND p.show_home=' . intval($filter['show_home']);
            }
            if (array_key_exists('parent', $filter)) {
                $where .= $this->db->placehold(' AND p.parent=?', intval($filter['parent']));
            }
            if (array_key_exists('brand_id', $filter)) {
                $where .= $this->db->placehold(' AND p.brand_id=?', intval($filter['brand_id']));
            }

            // поисковый запрос
            if (isset($filter['keyword'])) {
                $keywords = explode(' ', $filter['keyword']);
                foreach ($keywords as $keyword) {
                    $escaped_keyword = $this->db->escape(trim($keyword));
                    if (!empty($escaped_keyword)) {
                        $where .= ' AND (p.name LIKE "%' . $escaped_keyword . '%" OR p.header LIKE "%' . $escaped_keyword . '%")';
                    }
                }
            }
        }
        $filters->where = ' WHERE ' . $where;

        if (isset($filter['order']) && is_string($filter['order'])) {
            $order = $filter['order'];
        } else{
            // сортировка по-умолчанию
            $order = 'level, position';
        }
        $filters->order = !empty($order) ? ' ORDER BY ' . $order : '';

        // навигация
        $filters->limit = '';
        if (isset($filter['limit'])) {
            $limit = max(1, intval($filter['limit']));
            if (isset($filter['page'])) {
                $page = max(1, intval($filter['page']));
                $limit = $this->db->placehold('?, ? ', ($page - 1) * $limit, $limit);
            }
            $filters->limit = ' LIMIT ' . $limit;
        }

        return $filters;
    }

}