<?
//===============================================================================================================================================
// класс, базовый для создания систем БЕЗ ДЕРЕВА КАТАЛОГА
//===============================================================================================================================================

class c_system
{ public $table_name ;
  public $table_view ;
  public $tkey ;
  public $url_field ; // поле, на основе которого будет формироваться путь к объекта
  public $pages_info ;
  public $patch_mode ;
  public $cur_list_size ;
  public $cur_sort_type ;
  public $cur_sort_mode ;
  public $tree ;
  public $name ;
  public $system_name ;
  public $system_title ;
  public $root_dir ;
  public $section_page_name ;
  public $item_page_name ;
  public $last_reboot ;
  public $no_fs_info=0 ;  // блокировка автодобавления значка редактирования при выборке данных из базы
  public $path_to_level=0 ;  // до какого уровня выводить путь
  public $clss_items ;  // до какого уровня выводить путь

  public $subscriptions=array() ; // // параметры подсистемы, овечасющие за подписку и рассылку


  function	__construct($create_options=array())
  { $this->name=$create_options['system_kod'] ;
	$this->system_name=$create_options['system_name'] ;
    //damp_array($create_options) ;
    if ($create_options['debug']) { echo '<div class="black bold">Опции для конструктора '.$this->system_name.':' ; damp_array($create_options,1,0) ; echo '</div>';}
    // устанавливаем значение согласно переданных опций, если значения не были установлены ранее в конструкторе родительского класса
    if ($create_options['table_name'] 	  and !$this->table_name) 		$this->table_name		=$create_options['table_name'];
    if ($create_options['table_view'] 	  and !$this->table_view) 		$this->table_view		=$create_options['table_view'];
	if ($create_options['section_page_name']  	and !$this->section_page_name) 	$this->section_page_name	=$create_options['section_page_name'];
	if ($create_options['item_page_name']  	  	and !$this->item_page_name)		$this->item_page_name		=$create_options['item_page_name'];
	if ($create_options['root_dir']	  	  and !$this->root_dir) 		$this->root_dir			=$create_options['root_dir'];
 	if ($create_options['item_table'] 	  and !$this->item_table) 		$this->item_table		=$create_options['item_table'];
 	if ($create_options['usl_show_items'] and !$this->usl_show_items) 	$this->usl_show_items	=$create_options['usl_show_items'];
 	if ($create_options['path_to_level'] and !$this->path_to_level) 	$this->path_to_level	=$create_options['path_to_level'];
 	if ($create_options['clss_items'] and !$this->clss_items) 	$this->clss_items	=$create_options['clss_items'];

 	//if ($create_options['def_items_order_by'] and !$this->def_items_order_by) $this->def_items_order_by	=$create_options['def_items_order_by'];

	// значения для заголовка, которые показывать в шаблоне главной страницы
	if ($create_options['system_title'] and !$this->system_title) 	$this->system_title	=$create_options['system_title'];
	if ($create_options['system_href'] and !$this->system_href) 	$this->system_href	=$create_options['system_href'];

	// значения по умолчанию
	//if (!$this->root_dir)			$this->root_dir=$this->name;  // по умолчанию корневой каталог совпадает с названием подсистемы
    //if (!$this->section_page_name)	$this->section_page_name=$this->root_dir ; // название страниц каталога по умолчанию
    //if (!$this->item_page_name)	    $this->item_page_name=$this->root_dir ; // название страниц элементов по умолчанию
	if (!$this->tkey) 				$this->tkey=$_SESSION['pkey_by_table'][$this->table_name] ;
    //if (!$this->item_table)			$this->item_table=$this->table_name ;
    //if (!$this->tkey_items) 		$this->tkey_items=$_SESSION['pkey_by_table'][$this->item_table] ;
    //if (!$this->usl_show_items)     $this->usl_show_items='enabled=1' ;
    //if ($this->clss_items)          $this->usl_show_items.=' and clss in ('.$this->clss_items.')' ;
    // новая система  - прописываем параметры страниц для конкретной подсистемы, если их нет - берем из настроек по умолчанию
    $this->pages_info=$_SESSION['init_options']['default']['pages'] ;

    if (_sizeof($create_options['pages'])) foreach($create_options['pages'] as $indx=>$rec)
        if ($indx=='options')
        { if (!is_array($this->pages_info['options'])) $this->pages_info['options']=$rec ;
          else                                         $this->pages_info['options']=array_merge($this->pages_info['options'],$rec) ; // опции - добавляем, остальное - переписываем
        }
        else                   $this->pages_info[$indx]=$rec ;

    //damp_array($this->pages_info) ;

    // устанавливаем текущение значения
    if (_sizeof($this->pages_info['size'])) 		list($this->cur_list_size,$temp)=each($this->pages_info['size']) ;
    if (_sizeof($this->pages_info['sort_type'])) list($this->cur_sort_type,$temp)=each($this->pages_info['sort_type']) ;  // по умолчанию используем код первого значения
    if (_sizeof($this->pages_info['sort_mode'])) list($this->cur_sort_mode,$temp)=each($this->pages_info['sort_mode']) ;  // по умолчанию используем код первого значения

    //echo $this->table_name.'<br>' ; damp_array($this->pages_info) ;
    //if ($this->table_name=='obj_site_news') damp_array($this) ;
    if ($create_options['debug']) echo '<div class=green>Объект успешно создан</div>' ;
    //damp_array($create_options) ;
    //$this->last_reboot=date('d.m.Y H:i:s',time()) ;
    //trace() ;

    set_time_point('Создание объекта <strong>'.$this->name.'</strong>') ;
	// инициализируем подсистему
  	if (!$create_options['no_init']) $this->init($create_options) ;
  }

  function init($create_options=array()) {}

  // анализ данных, переданных формой перед отправкой заголовков
  function on_send_header_before() {}

  // коррекция ссылки на объект с учетом текущего домена
  function check_href_by_domain($obj)
  {
    return ($obj->href) ;
  }

  // получение из БД информации по объекту системы
  function select_db_obj_info($id)
  { $arr=explode('.',$id) ;
    $rec=select_db_obj_info($this->tkey,$arr[0]) ;
    return($rec) ;
  }


 function get_items($usl,$options=array())
  { //damp_array($options);
    if (!$options['limit']) $options['limit']=($options['count'])? 'limit '.$options['count']:'' ;
    if ($options['order']) 	$options['order_by']=$options['order'] ;
 	$options['no_group_clss']=1 ;
    $options['no_slave_table']=1 ;
    //$root=($options['use_root'])? $options['use_root']:'root' ;
    if ($options['use_table']) $options['use_tkey']=$_SESSION['pkey_by_table'][$options['use_table']] ;
    if ($options['only_clss']) $options['use_tkey']=_DOT($this->tkey)->list_clss[$options['only_clss']] ;
    //damp_array($options);

    // 13.02.2010 - элемены могут находиться не в основной таблице, которую надо указать в init.php:  $_SESSION['init_options']['yyy']['item_table']=$TM_xxx ;
    $tkey=($options['use_tkey'])? $options['use_tkey']:$this->tkey_items ;
    //echo 'tkey='.$tkey_items.'<br>' ;

    $_usl[]=$usl ;

    if ($options['only_active_rasdel']) { $list_active_rasdel=$this->tree['root']->get_list_child() ;
    								      $_usl[]='parent in ('.$list_active_rasdel.')' ;
    								    }


    //$_usl[]=$this->usl_show_items ; //goods_show_usl ; это условие должно быть уже задано ранее, т.к. должно учитываться при подсчете страниц

    $usl_items=implode(' and ',$_usl) ;
    if (isset($options['props']) and is_object($_SESSION['category_system'])) $usl_items.=$_SESSION['category_system']->get_usl_to_props($options['props']);
    // заменить в будущем на execSQL()
    $list_rec=select_objs($tkey,'',$usl_items,$options) ;
    if (_sizeof($list_rec[$tkey])) foreach($list_rec[$tkey] as $id=>$rec) $this->prepare_public_info($list_rec[$tkey][$id],$options) ;
    //damp_array($list_rec[$tkey]) ;
    return($list_rec[$tkey]) ;
  }

  // показ произвольного шаблона
  // передается либо ($rec,$func_name,$options=array())
  // либо ($func_name,$options=array())
  function print_template($rec,$func_name,$options=array())
  { $options['system']=$this ;
    if (!is_array($rec) and !is_object($rec)) { $options=$func_name ; $func_name=$rec ; $rec='-' ; }
    $res=print_template($rec,$func_name,$options) ;
    return($res);
  }

  function show_item($rec,$func_name,$options=array())
  { if (!is_array($rec)) $rec=get_obj_info($rec.'.'.$this->tkey_items) ;
    else $this->prepare_public_info($rec) ; //- перенесено в print_template
    $res=$this->print_template($rec,$func_name,$options) ;
    return($res) ;
  }

  // формируем условие отбора объектов
  // $_params - или объект - элемент дерева каталога
  //            или код - код элемент дерева каталога
  //            или условие выборки

  function create_usl_select_obj($_params,&$options)
  {   $obj='' ;

      if ($_params) // если что-то передано в параметрме $_params
      { if (is_object($_params)) $obj=$_params ; // если $_params - объект, то работаем дальше с ним
        else
        { $obj=$this->tree[$_params] ; // пытаемся найти объект в дереве по коду
          if (!is_object($obj)) $usl[]=$_params ; // если объект в дереве не найден, значит $_params - условие выборки
        }
      }
      //echo '_params='.$_params.'<br>' ;

      if ($options['count']=='all') { $options['limit']='' ; $options['count']='' ;}
      if (is_object($obj))
      {  $parent_ids=($options['show_items_from_child'])? $obj->get_list_child():$obj->pkey ;
         $id_by_link='' ;
         if (TM_LINK) $id_by_link=get_str_link_ids($parent_ids,$this->tkey,array('debug'=>0,'clss'=>200)) ;
         $usl[]=(!$id_by_link)? 'parent in('.$parent_ids.')':'(parent in('.$parent_ids.') or pkey in ('.$id_by_link.'))' ;
      }
      if ($options['only_clss']) 		$usl[]='clss='.$options['only_clss'] ;
      else if($this->usl_show_items)	$usl[]=$this->usl_show_items ;
      if ($options['use_usl']) 		if (is_array($options['use_usl'])) $usl=array_merge($usl,$options['use_usl']) ; else $usl[]=$options['use_usl'] ;
      if (_sizeof($usl)) $usl_items=implode(' and ',$usl) ;
      //if ($options['debug']) echo 'usl='.$usl_items.'<br>' ;
      return($usl_items) ;
  }

  // показ элементов раздела по указанному шаблону
  // obj 	- объект дерева, будут выбраны все дочерние элементы, если передана опция 'show_items_from_child' будут показываны и все дочерние элементы всех дочерних подразделов
  //		- либо код объекта дерева
  //		- либо условие выборки, например parent=3
  function show_list_items($_params,$func_name,$options=array())
  { //echo 'params=' ; print_r($_params) ; echo '<br>' ;
    //echo 'func_name=' ; print_r($func_name) ; echo '<br>' ;
    //echo 'options=' ; print_r($options) ; echo '<br>' ;
    //$options['debug']=1 ;
    if ($this->no_fs_info) $options['no_fs_info']=1 ;
    // сохраняем текущие параметры, переданные в GET
    if ($_GET['size'])  $this->cur_list_size=$_GET['size'] ;
    if ($_POST['size'])  $this->cur_list_size=$_POST['size'] ;
    if ($_GET['sort'])  $this->cur_sort_type=$_GET['sort'] ; // код типа сортировки
    if ($_POST['sort'])  $this->cur_sort_type=$_POST['sort'] ; // код типа сортировки
    if ($_GET['smode'])  $this->cur_sort_mode=$_GET['smode'] ; // код направления сортировки
    if ($_POST['smode'])  $this->cur_sort_mode=$_POST['smode'] ; // код направления сортировки

    if (is_array($_params)) { $list_recs=$_params ; $count_obj=_sizeof($list_recs) ; } // если $_params - массив, то выборку не делаем
    else
    {   // при поиске условия выборки объектов формируются в отдельной функции
        // так как там для полнотекстового поиска идет свой отдельный запрос
        $usl_items=$this->create_usl_select_obj($_params,$options) ;// echo '$usl_items='.$usl_items.'<br>' ;
        // если в $this->cur_sort_type и $this->cur_sort_mode задан тип и направление сортировки по применяем его
        if ($this->cur_sort_type and !$options['order_by'] and !$options['no_order'])
        { $options['order_by']=$this->pages_info['sort_type'][$this->cur_sort_type]['order_by'] ;
          if ($this->cur_sort_mode)  $options['order_by'].=' '.$this->pages_info['sort_mode'][$this->cur_sort_mode] ;
        }

        //damp_array($this->pages_info) ;
        // новый способ получения записей - позволяет ускорить выборку при получении записей в 6 раз при использовании rand()
        if ($options['get_pkeys_before_exec'] or $options['order_by']=='rand()')
        { $tkey=($options['only_clss'])? _DOT($this->tkey)->list_clss[$options['only_clss']]:$this->tkey_items ;
          list($count_obj,$pkeys)=get_pkeys($tkey,$usl_items,$options) ;
          if ($pkeys) $usl_items='pkey in ('.$pkeys.')' ;
          $options['count']='' ;
          $options['limit']='' ;
          $options['order_by']='' ;
        }
        // иначе используетм стандартный способ получения количества записей
        else if (!$options['count'] and !$options['limit']) // добавлено 10.06.12 - если задано число позиций для показа, не делать запрос в базу на обзее количество
        {   $count_obj=$this->get_cnt_items($usl_items,$options) ;  // по умолчанию - get_cnt_items
            if ($options['debug']) echo 'Получено всего записей по данному условию:'.$count_obj.'<br>';
        } else $count_obj=1 ;

        if ($options['save_last_select_pkeys']) $_SESSION['saved_last_select_pkeys'][$this->name]=$this->get_pkeys_items($usl_items,$options) ;
        $cur_page=($options['cur_page'])? $options['cur_page']:_CUR_PAGE_NUMBER ; //$_GET['page'] ;
        if (!$options['count'] and !$options['limit'] and $options['panel_select_pages']) $this->prepare_pages_info($count_obj,$cur_page,$this->cur_list_size,$options) ;
        if ($count_obj) { $list_recs=$this->get_items($usl_items,$options) ;   $count_obj=_sizeof($list_recs) ; }
        //echo 'Получено записей:'._sizeof($list_recs).'<br>' ;
        $options['usl_all_obj']=$usl_items ;
        $options['count_recs']=_sizeof($list_recs) ;

        // отключено для "букеты из изрушек"
        if (_sizeof($list_recs)==1) 		$options['panel_select_usl']=0 ; // если всего один элемент - не показываем панель сортировки и размера страниц
        // отключено для airmed.ru
        if ($options['count_page']==1)  $options['panel_select_pages']=0 ; // если всего одна страница - не показываем панель выбора страниц
        if ($options['group_by'])		$list_recs=group_by_field($options['group_by'],$list_recs) ; // группируем товар по полю, если поле указано
        // показывает массив элементов указанной функцией вывода
    }


    if ($count_obj and !$options['no_any_panels'] and !$options['no_top_panels'])
    { 	// показываем верхнюю панель
        $options_panel_top=(_sizeof($this->pages_info['panel_top']['options']))? array_merge($options,$this->pages_info['panel_top']['options']):$options ;
        $options_panel_top['panel_position']='top' ;
        //damp_array($this->pages_info) ;
        $func_name_panel_top=($this->pages_info['panel_top']['func_name'])? $this->pages_info['panel_top']['func_name']:'' ;
        //echo '$func_name_panel_top='.$func_name_panel_top.'<br>' ;
        //if ($func_name_panel_top and method_exists($this,$func_name_panel_top)) $this->$func_name_panel_top($options_panel_top) ;
        //else
        if ($func_name_panel_top and function_exists($func_name_panel_top)) $func_name_panel_top($this,$options_panel_top) ;
    }
    	// показываем список

    if ($options['debug_sort']) echo 'sort='.$options['order_by'].'<br>' ;

    if (!_sizeof($list_recs)) $list_recs=array() ;
    $this->print_template($list_recs,$func_name,$options) ; // $func_name($this,$list_recs,$options) ;

    if ($count_obj and !$options['no_any_panels'] and !$options['no_bottom_panels'])
    {	// показываем нижнюю панель
        $options_panel_bottom=(_sizeof($this->pages_info['panel_bottom']['options']))? array_merge($options,$this->pages_info['panel_bottom']['options']):$options ;
        $options_panel_bottom['panel_position']='bottom' ;
        $func_name_panel_bottom=($this->pages_info['panel_bottom']['func_name'])? $this->pages_info['panel_bottom']['func_name']:'' ;
        // пока не пошло, потом разобраться почему
        //if ($func_name_panel_bottom and method_exists($this,$func_name_panel_bottom)) $this->$func_name_panel_bottom($options_panel_bottom) ;
        //else
        if ($func_name_panel_bottom and function_exists($func_name_panel_bottom)) $func_name_panel_bottom($this,$options_panel_bottom) ;

    	//$this->panel_list_items_bottom_navigat($options) ;
    }
    if (!_sizeof($list_recs)) $count_obj=0 ;
    //$result=array('from'=>$from_pos+1,'to'=>$to_pos,'all'=>$count_obj,'','next_page'=>$next_page) ;
    return($count_obj) ;
  }



  // показ последних добавленых элементов, по умполчнию 5
  function show_last_items($func_name,$options=array())
  {
    if (!$options['order_by']) 	$options['order_by']='c_data desc' ;
    if (!$options['count']) 	$options['count']=5 ;
    $this->show_list_items('',$func_name,$options);
  }

  // функции вывода элементов страницы -------------------------------------------------------------------------------------------------------------------------------

    // функция для подготовки вывода страниц
    // $table_name 	- 	таблица где объекты
    // $usl 		-	условие показв выводитых объектов
    // $page		- 	текущая страница
    // $list_size	- 	число объектов на страницу
    //
    // вписывает в массив options значения:
    // count_page	-	число страниц
    // limit		-	параметр для $options['limit'] для выборки объектов в нужном интервале
    // current_page -   текущая страница
    // list_size    -   текущий размер страницы

  function prepare_pages_info($count_obj_all,$page,$list_size,&$options=array())
       {   if ($page=='all') $list_size='all' ;
           $count=($list_size!='all' and $list_size)? ceil($count_obj_all/$list_size):1 ; // $list_size - число элементов на лист, = 6,9,12,all
           if ($page=='last' or $page>$count) $page=$count ;
           $page=$page/1 ; if (!$page) $page=1 ; // Приводим значение $page к 1
           $first_obj=($page-1)*$list_size ; // с какого элемента начинаем вывод 0...$list_size
           $options['first_obj']=$first_obj+1 ;
           $options['last_obj']=$first_obj+$list_size ;
           if ($options['last_obj']>$count_obj_all) $options['last_obj']=$count_obj_all ;
		   $options['limit']=($list_size=='all' or !$list_size)? '':'limit '.$first_obj.','.$list_size ; // лимит для выборки из базы
		   $options['list_size']=$list_size ;
           $options['current_page']=$page ;
           $options['count_page']=$count ;
           $options['count_obj']=$count_obj_all ;
	   }


  function get_childs_id($id)
  { if (isset($this->tree[$id])) return($this->tree[$id]->get_list_child()) ;
    else                         return(0) ;
  }

  function get_cnt_items($usl,$options=array())
  { $table_name=($options['use_table'])? $options['use_table']:$this->item_table ;
  	if ($options['only_clss'] and !$options['use_table']) $table_name=_DOT(_DOT($this->tkey)->list_clss[$options['only_clss']])->table_name ;
    if (isset($options['props']) and is_object($_SESSION['category_system'])) $usl.=$_SESSION['category_system']->get_usl_to_props($options['props']);
  	$res=execSQL_van('select count(pkey) as cnt from '.$table_name.' where '.$usl,$options) ;
  	return($res['cnt']) ;
  }

  function get_pkeys_items($usl,$options=array())
  { $table_name=($options['use_table'])? $options['use_table']:$this->item_table ;
  	if ($options['only_clss'] and !$options['use_table']) $table_name=_DOT(_DOT($this->tkey)->list_clss[$options['only_clss']])->table_name ;
    if (isset($options['props']) and is_object($_SESSION['category_system'])) $usl.=$_SESSION['category_system']->get_usl_to_props($options['props']);
  	$res=execSQL_line('select pkey from '.$table_name.' where '.$usl,$options) ;
  	return($res) ;
  }



  // подготовка данных для показа панели номеров страниц
  // ['options']['page_mode']
  // два режима показа страниц
  // 0: показывается только номера страниц, кнопки вперед и назад только при превышении числа показываемых страниц заданного лимита. Кнопки перелистывают группу страниц
  // 1: показываются номера страниц и кнопки вперед - назад. Кнопки перелистывают на одну страница. Все номера страниц.
  // 2: показываются номера страниц и кнопки вперед - назад. Кнопки перелистывают на одну страница. Номера страниц - в заданом лимите.

  function prepare_panel_select_pages($options=array())
  {  $pages_num_format=$this->pages_info['options']['pages_num_format'] ;
     $page_max_number_count=$this->pages_info['options']['page_max_number_count'] ;
     $page_image_prev=$this->pages_info['options']['page_image_prev'] ;
     $page_image_next=$this->pages_info['options']['page_image_next'] ;
     $page_mode=$this->pages_info['options']['page_mode'] ; // 0 или 1 или 2
     if ($page_mode==1) $page_max_number_count=10000000 ;
     $page=$options['current_page'] ; 		// $page			-	текущая страница
     $count_page=$options['count_page'] ; 	// $count_page	-	всего страниц
     //$list_size=$options['list_size'] ; 	// $list_size	- 	число объектов на страницу
     //damp_array($options) ;
     $start_page=ceil($page/$page_max_number_count) ;

     $res_pages=array() ;
     $res_prev=array() ;
     $res_last=array() ;
     $res_all=array() ;
   	 if ($count_page>=1)
		       { switch($page_mode)
                 {  case 0: if ($start_page>1)
                            {  $to_page=($start_page-1)*$page_max_number_count ;
                 		       $href=$this->generate_page_url($to_page,$options) ;
                               $res_prev=array('href'=>$href,'img_src'=>$page_image_prev)  ;
                            }
                            break ;
                    case 1:
                    case 2: $to_page=$page-1 ;
                            $href=$this->generate_page_url($to_page,$options) ;
                            if ($page==1) $res_prev=array('img_src'=>$page_image_prev)  ;
                            else          $res_prev=array('href'=>$href,'img_src'=>$page_image_prev,'value'=>$page-1)  ;
                            break ;
                 }

		         for ($i=($start_page-1)*$page_max_number_count+1; $i<=$count_page and $i<=$start_page*($page_max_number_count); $i++)
		           {  $href=$this->generate_page_url($i,$options) ;
		              $res_pages[]=array('href'=>$href,'value'=>sprintf($pages_num_format,$i),'selected'=>(($i==$page)? 1:0)) ;
		           }

                 switch($page_mode)
                 {  case 0: if ($i<=$count_page)
                            { $to_page=$start_page*$page_max_number_count+1 ;
                              $href=$this->generate_page_url($to_page,$options) ;
                              $res_last=array('href'=>$href,'img_src'=>$page_image_next) ;
                            }
                            break ;
                    case 1:
                    case 2:
                            $href=$this->generate_page_url($page+1,$options) ;
                            if ($page>=$count_page) $res_last=array('img_src'=>$page_image_next) ;
                            else                    $res_last=array('href'=>$href,'img_src'=>$page_image_next,'value'=>$page+1) ;
                            break ;
                 }

                 $res_all=array('href'=>$this->generate_page_url('all',$options)) ;
		       }
	 return(array($res_pages,$res_prev,$res_last,$res_all)) ;
   }


  function generate_page_url($page,$options=array())
  { // номер страницы передается в виде /page_2.html
    if (_PAGE_NUMBER_SOURCE=='in_name')
    { if ($options['pages_base_url']) $url=$options['pages_base_url'] ;
      else                            $url=_CUR_PAGE_PATH ;

      list($from_page,$url)=extract_page_number_from_path($url) ;
      $page_info=parse_url_path($url) ;
      //echo 'page='.$page.'<br>url='.$url.'<br>' ; damp_array($page_info,1,-1) ;
      $new_url=$page_info['_CUR_PAGE_DIR'] ;
      if ($page>1)                    $new_url.='page_'.$page.'.html' ;
      if ($page_info['_CUR_PAGE_QUERY'])   $new_url.='?'.$page_info['_CUR_PAGE_QUERY'] ;
      //echo '$new_url='.$new_url.'<br>' ;
    }
    // номер страницы передается в виде /?page=2
    else
    { if ($options['pages_base_url']) $new_url=$this->generate_url(array('page'=>$page),$options['pages_base_url']) ;
      else                            $new_url=$this->generate_url(array('page'=>$page)) ;

    }

    $new_url=str_replace('/ua','',$new_url) ;
    return($new_url) ;
  }


  // создаем ссылку, аналогочиную текущей странице $_SERVER('REQUEST_URI'), но
  // со значение параметров par=value, переданных через $in
  // параметр page=1 не отображается, >1 отображается как page_xxx.html
  function generate_url($in=array(),$pages_base_url='')
    { if (!$pages_base_url)
       if (_PAGE_NUMBER_SOURCE=='in_name') $pages_base_url=_CUR_PAGE_DIR ;
       else                                $pages_base_url=_CUR_PAGE_PATH._CUR_PAGE_QUERY ;
      //echo 'SF_REQUEST_URI='.$GLOBALS['SF_REQUEST_URI'].'<br>' ;
      //echo 'REQUEST_URI='.$_SERVER['REQUEST_URI'].'<br>' ;
      $arr_url=parse_url($pages_base_url) ;
      //damp_array($arr_url) ;
      parse_str($arr_url['query'],$out);
      //damp_array($in) ;
      //damp_array($out) ;
      $page_name='' ;
      if (isset($out['page']) and $in['page']==1) unset($out['page']) ;
      if ($in['page']==1)                         unset($in['page']) ;
      if ($in['page']) if (_PAGE_NUMBER_SOURCE=='in_name') { $page_name='page_'.$in['page'].'.html' ; unset($in['page']) ; }

      $out=array_merge($out,$in) ;

      $str_par=(_sizeof($out))? '?'.rawurldecode(http_build_query($out)):'' ;
      if ($page_name)  $href=$arr_url['path'].$page_name.$str_par ; else $href=$arr_url['path'].$str_par ;
      //echo 'href='.$href.'<br>' ;
      return($href) ;
    }


  function prepare_panel_page_size($options=array())
   {  $res_arr=array() ;
      if (_sizeof($this->pages_info['size'])>1) foreach ($this->pages_info['size'] as $key=>$value)
          $res_arr[]=array('value'=>$key,'title'=>$value,'selected'=>(($this->cur_list_size==$key)? 1:0)) ;
      return($res_arr) ;
   }

  function prepare_panel_sort_usl($options=array())
   {  $res_arr=array() ;
      if (_sizeof($this->pages_info['sort_type'])>1) foreach ($this->pages_info['sort_type'] as $key=>$value)
          $res_arr[]=array('value'=>$key,'title'=>$value['name'],'selected'=>(($this->cur_sort_type==$key)? 1:0)) ;
      return($res_arr);
  }

  // готовим информацию по объекту - эта функция должны быть перекрыта в кажом классе
  function _public(&$rec,$options=array()) {$this->prepare_public_info($rec,$options);}


  function prepare_public_info_for_arr(&$arr,$options=array())
  {
    if (_sizeof($arr))  foreach($arr as $i=>$rec) $this->prepare_public_info($arr[$i],$options) ;
  }

  function prepare_public_info(&$rec,$options=array())
  { if (!$rec['__href']) $rec['__href']=$this->get_url_item($rec) ;
    if (!$rec['__name']) $rec['__name']=$this->get_name_obj($rec) ;
  	if (!$rec['__data']) $rec['__data']=date("d.m.y",$rec['c_data']) ;
    if (!$rec['__level']) $rec['__level']=$this->tree[$rec['parent']]->level+1 ;
  	if ($rec['_image_name']) $rec['__img_alt']=strip_tags($rec['__name']) ;
  }

 // возвращаем адрес для объекта системы на основе пути родительского подраздела и режима вывода пути
  function get_patch_item(&$rec) {return($this->get_url_item($rec)) ; }
  // функция перекрывается в catalog_system
  function get_url_item(&$rec)
  { $res='/'.$this->item_page_name.'_'.$rec['pkey'].'.html' ;
    return($res) ;
  }

  function get_name_obj(&$rec) { return($rec['obj_name']) ; }

  /*
    // возвращает результаты поиска по стандартному алгоритму в обычных полях товара
    // в принице может вернуть только условие поиска, а выборка может бытб сделана в рамках функции show_list_items
    function get_items_search($usl,$options=array())
    { $text=($options['search_text'])? $options['search_text']:$usl ; // текст для поиска передается либо в первом параметре либо через опции
      if (!$options['search_text']) $usl=$this->usl_show_items ;      // если текст поиска передан через первый пареметр, то обязательное условие отбора берем из
      if (!$text) return ;
      // подготовливает условие для поиска по стандартным полям товара
      $_usl=$this->get_array_search_usl($text) ;
      $res_usl='('.implode(' or ',$_usl).') and '.$this->usl_show_items ;
      if ($usl) $res_usl.=' and '.$usl ;
      if ($options['get_only_usl']) return($res_usl) ; // echo $res_usl.'<br>' ;
      $list_obj=$this->get_items($res_usl,$options) ;
      return($list_obj) ;
    }

    function get_array_search_usl($text)
    { $_usl=array() ;
      $_usl[]=$this->prepare_search_usl('obj_name','like%%',$text) ;
      $_usl[]=$this->prepare_search_usl('pkey','=',$text) ;
      return($_usl) ;
    }

    function get_cnt_items_search($usl,$options=array())
    { $options['get_only_usl']=1 ;  // чтобы не дублировать формирование условий поиска
      $usl=$this->get_items_search($usl,$options) ;
      $cnt=$this->get_cnt_items($usl,$options) ;
      return($cnt) ;
    }
   */
    // подготовка условия для выборки данных
    // возвращает условие для подстановки его в запрос SQL
    // перектрытие данной функиии не требуется
   function prepare_search_usl($fname,$operand,$worlds)
   { if (!is_array($worlds))
     { $temp=str_replace(',',' ',$worlds) ;
       $worlds=explode(' ',$temp) ;
     }
     $usl="" ;  $res_usl=array() ;
       if (_sizeof($worlds)) foreach($worlds as $word) if(trim($word))
        switch ($operand)
        { case '=':        $res_usl[] = $fname.'="'.$word.'"' ; break;
          case 'like%%':   $res_usl[] = $fname.' like "%'.$word.'%"' ; break;
          case 'like%':    $res_usl[] = $fname.' like "%'.$word.'"' ; break;
        }

       if (_sizeof($res_usl)) $usl='('.implode(' and ',$res_usl).')' ;
       return($usl) ;
   }
    /*
  // полнотекстовый поиск по каталогу
  // внимание!!! полнотекстовый поиск работет корректно только на больных наборах данных
  // для оптимизации поиска по текущему каталогу необходимо переопределить эту фуккцию
  function get_items_search_fulltext($usl,$options=array())
  {  //$text=($options['search_text'])? $options['search_text']:$usl ; // текст для поиска передается либо в первом параметре либо через опции
     //if (!$options['search_text']) $usl=$this->usl_show_items ;      // если текст поиска передан через первый пареметр, то обязательное условие отбора берем из
     //if (!$text) return ;
     // подготовливает условия для полнотекстовго поиска
     //$mode=' in boolean mode' ;
     //$fields='obj_name,annot,value,obj_name_ua,annot_ua,value_ua' ;
     //$list_recs=execSQL('select pkey,obj_name,match('.$fields.') against (\''.$text.'\''.$mode.') as score from obj_site_news where match('.$fields.') against (\''.$text.'\''.$mode.') and clss=9 order by score desc',2) ;
     //$list_recs=execSQL('select pkey,obj_name,match('.$fields.') against (\''.$text.'\') as score from obj_site_news where match('.$fields.') against (\''.$text.'\') and clss=9 order by score desc',2) ;
     //$list_recs=execSQL('select pkey,obj_name,match('.$fields.') against (\''.$text.'\') as score from obj_site_news where clss=9',2) ;

  }

  function get_cnt_items_search_fulltext($usl,$options=array())
  {

  }
   */

  function get_cur_page_path($sect_id=0,$obj_id=0)
  { if (!$sect_id) $sect_id=$GLOBALS['section_id'] ;
    if (!$obj_id)  $obj_id=$GLOBALS['obj_info']['pkey'] ;
    if ($sect_id and isset($this->tree[$sect_id]))   $path=$this->tree[$sect_id]->get_path(array('include_index'=>1,'to_level'=>$this->path_to_level,'cur_obj_pkey'=>$obj_id)) ; // потом - у текущей системы
    else
    {  $path['/']=_INDEX_PAGE_NAME ;
       if ($this->system_title) $path['/'.$this->root_dir.'/']=$this->system_title ;
    }
    return($path) ;
  }

  function get_cur_page_title()
  {
    return($this->system_title);
  }


 function show_result_message($result) {$this->show_message($result);}
 function show_message($result)
 { $result_data=parse_result($result) ;
//   damp_array($result_data) ;
   $func_name=$this->name.'_show_messages' ;
   //echo $func_name.'<br>' ;
   if (function_exists($func_name)) { $res=$func_name($result_data['type'],$result_data['code'],$result_data['text'],$result_data['rec']) ; return($res) ; }


   $mess_func_name=$this->name.'_message_'.$result_data['code'] ;
   //echo '$mess_code='.$result_data['code'].'<br>' ; echo '$mess_func_name='.$mess_func_name ;
   $res=0 ;
   // 01.10.13 - более не используется
   // подключаем файл шаблонов
   //if (isset($this->template_script_name) and $this->template_script_name!="") include_once(_DIR_TO_TEMPLATES.'/'.$this->template_script_name) ;
   // выполняем функцию из файла шаблонов
   if (function_exists($mess_func_name)) $res=$mess_func_name($result_data['rec']) ;
   else
   {  if ($result_data['type']=='error') echo '<div class=alert>'.$result_data['code'].'</div>' ;
      else                               echo '<div class=alert_info>'.$result_data['code'].'</div>' ;
   }
   return($res) ;
 }

 function save_form_values_to_session($options)
 { if (_sizeof($options)) foreach($options as $id=>$value)
     if (!is_array($value)) $_SESSION['form_values'][$id]=stripslashes($value) ;
     else foreach($value as $id2=>$value2) $_SESSION['form_values'][$id][$id2]=stripslashes($value2) ;
  //   damp_array($_SESSION['form_values']) ;

 }

// верхняя панель навигации
  function panel_list_items_top_navigat(&$options=array())
  { damp_array($options) ;
    if ($options['no_any_panel']) return ;
    if ((!$options['panel_select_pages'] or $options['panel_select_pages']=='bottom') and (!$options['panel_select_usl'] or $options['panel_select_usl']=='bottom')/* and !$options['panel_diapazon_page']*/) return ;
	?><div id=panel_navigat class="top isCorner"><?
	  if ($options['panel_select_pages'] and $options['panel_select_pages']!='bottom') 	$this->panel_select_pages($options);
	  if ($options['panel_select_usl'] and $options['panel_select_usl']!='bottom') 		$this->panel_select_usl($options,1);
	  if ($options['panel_diapazon_page'] and $options['panel_diapazon_page']!='bottom')$this->panel_diapazon_page($options) ;
	?><div class=clear></div></div><?
  }

  // нижняя панель навигации
  function panel_list_items_bottom_navigat(&$options=array())
  { //damp_array($options);
    if ($options['no_any_panel']) return ;
    if ((!$options['panel_select_pages'] or $options['panel_select_pages']=='top') and (!$options['panel_select_usl'] or $options['panel_select_usl']=='top')/* and !$options['panel_diapazon_page']*/) return ;
	?><div id=panel_navigat class=bottom><?
	  if ($options['panel_select_pages'] and $options['panel_select_pages']!='top') 	$this->panel_select_pages($options);
	  if ($options['panel_select_usl'] and $options['panel_select_usl']!='top') 		$this->panel_select_usl($options,1);
	  if ($options['panel_diapazon_page'] and $options['panel_diapazon_page']!='top') $this->panel_diapazon_page($options) ;
	?><div class=clear></div></div><?
  }

  function panel_select_pages(&$options=array()) // show_page_panel
  {  global $search_text ;
     //damp_array($this->pages_info) ;
     $text=array() ;
     $page_number_rasdel=$this->pages_info['options']['page_number_rasdel'] ;
     $cur_page=$options['current_page'] ;
     list($arr_pages,$to_prev,$to_next)=$this->prepare_panel_select_pages($options) ;
     //damp_array($arr_pages) ; damp_array($to_prev) ; damp_array($to_next) ;

     ?><div class=list_pages>Страницы: <?

     if (_sizeof($to_prev))  if ($to_prev['href']) echo '<a href="'.htmlspecialchars($to_prev['href']).'"><img src="'.$to_prev['img_src'].'" alt="" border="0"></a>' ;
                            else                  echo '<img src="'.$to_prev['img_src'].'" alt="" border="0">' ;

     if (_sizeof($arr_pages)) { foreach($arr_pages as $rec) $text[]=($rec['selected'])? "<span class=cur_page>".$rec['value'].'</span>':'<a href="'.htmlspecialchars($rec['href']).'" >'.$rec['value'].'</a>' ;
     						   echo implode(' ',$text) ;
     						 }
     if (_sizeof($to_next))  if ($to_next['href']) echo '<a href="'.htmlspecialchars($to_next['href']).'"><img src="'.$to_next['img_src'].'" alt="" border="0"></a>' ;
                            else                  echo '<img src="'.$to_next['img_src'].'" alt="" border="0">' ;

     ?></div><?
   }

   function panel_select_usl(&$options=array(),$num=1)
   {  global $search_text ;
      //damp_array($this->pages_info['size']) ;
      //damp_array($this->pages_info['sort_type']) ;
      ?><div class=select_usl>
         <form name="sort_size<?echo $num?>" method="GET">
         <input name="page" type="hidden" value="1">
         <? $arr=$this->prepare_panel_page_size($options) ; //damp_array($arr) ;
            if (_sizeof($arr))
	          { ?><div class=panel_select_size>выводить
					<select name="size" onchange="document.forms.sort_size<?echo $num?>.submit();return(false);">
						 <? foreach ($arr as $rec)  {?><option value="<?echo $rec['value']?>"  <? if ($rec['selected']) echo 'selected'?>><?echo $rec['title']?></option><?}?>
					</select>
		         </div>
		        <?
		      }
			$arr=$this->prepare_panel_sort_usl($options) ;  //damp_array($arr) ;
            if (_sizeof($arr))
		      { ?><div class=panel_select_sort>сортировать по
					<select name="sort" onchange="document.forms.sort_size<?echo $num?>.submit();return(false);">
							 <? foreach ($arr as $rec)  {?><option value="<?echo $rec['value']?>"  <? if ($rec['selected']) echo 'selected'?>><?echo $rec['title']?></option><?}?>
					</select>
		         </div><?
		      }
	     if ($search_text) {?><input name="search_text" type="hidden" value="<?echo $search_text?>"><?}?>
		</form>
		</div>
	<?
   }

    // информация о текущей выборке при постраничной  HTML выборке
       function panel_info_select($options=array())
       { $_str2=array() ; $info2=array() ;
         //damp_array($options,1,-1) ;
         if ($options['count_obj'])                             $info2['всего строк']=$options['count_obj'];
         if ($options['first_obj'] and $options['last_obj'])    $info2['показаны строки']=$options['first_obj'].' по '.$options['last_obj'];
         //damp_array($info,1,-1) ;
         if (_sizeof($info2)) foreach($info2 as $title=>$value) $_str2[]=$title.': <strong>'.$value.'</strong>' ;
         if (_sizeof($_str2)) echo '<div class=float_left>'.implode(', ',$_str2).'</div>' ;
       }






}

//===============================================================================================================================================
// класс, базовый для создания систем С ДЕРОВОМ КАТАЛОГА
//===============================================================================================================================================

class c_system_catalog extends c_system
{
  public $tree = array() ;
  public $patch_mode ;
  //public $list_subdomain ;
  public $url_type ;
  // $url_type: = href - используется значение поля href, если не задано, используется pkey
  //            = lat   - выводим транслитом имя объекта, если задано href - выводим href (для совместимости со старыми сайтами)
  //            = rus   - выводим на русском имя объекта, если задано href - выводим href  (для совместимости со старыми сайтами)

  public $function_check_filter='' ;

  // 13.02.2010 - item_table,tkey_items: элемены могут находиться не в основной таблице, которую надо указать в init.php:  $_SESSION['init_options']['yyy']['item_table']=$TM_xxx ;
  // класса - каталог, т.е. простые элементы образуют дерево, сответствеено добавляется описание section
  // $create_options в подсистему передается как объединение init_options[xxx], options в _xxx_site_boot и опций по умолчанию в конструкторе подсистемы
  function	__construct($create_options=array())
  { // совместимость со старыми параметрами для url
    if ($create_options['patch_mode']=='tree_rus' or $create_options['patch_mode']=='tree_lat') $create_options['patch_mode']='TREE_NAME' ;
    if ($create_options['patch_mode']=='tree') $create_options['patch_mode']='TREE_ID' ;

    if (isset($create_options['tree_fields'])) {$create_options['tree']['fields']=$create_options['tree_fields'] ; unset($create_options['tree_fields']) ; }

    $this->id_root			=$create_options['id_root'];
    $this->patch_mode		=($create_options['patch_mode'])? 		$create_options['patch_mode']		:_URL_MODE;
    // внимание!!! при использовании мультиязычность не ограничивать выборку по полям для модели
    $this->tree_fields		=($create_options['tree']['fields'])? 	$create_options['tree']['fields']	:'*';//'pkey,parent,clss,indx,enabled,obj_name,href' ;
    $this->tree_clss        =($create_options['tree']['clss'])? 	$create_options['tree']['clss']		:'1,10';
    $this->tree_usl_select =(_ENGINE_MODE=='admin')? 'clss in ('.$this->tree_clss.')':'clss in ('.$this->tree_clss.') and enabled=1 and _enabled=1' ;
   //damp_array($this) ;
    if ($create_options['tree']['usl_include']) $this->tree_usl_select =$create_options['tree']['usl_include'];

    $this->no_root_dir		=($create_options['no_root_dir'])? 		1:0;//'pkey,parent,clss,indx,enabled,obj_name,href' ;


    if (!$create_options['tree']['order_by'])	                    $create_options['tree']['order_by']='indx' ;
    if (!$create_options['tree']['get_count_by_clss'])	            $create_options['tree']['get_count_by_clss']=1 ;

    if ($create_options['function_check_filter']) $this->function_check_filter=$create_options['function_check_filter'] ;

    parent::__construct($create_options) ;

	if (!$create_options['no_create_model'])
        $this->create_model($create_options['tree']) ;
  }

  // создать объектныю модель, если до этого модель уже была создана, то она уничтожиться и будет создана занова
  // для модели будут действительны все опции, заданные в массиве [tree]
  function create_model($options=array())
  { $debug=$options['debug'] ;
    if ($debug) set_time_point('create_model - start') ;
    if ($options['get_count']) $options['get_count_by_usl']=$options['get_count'] ;
    if ($debug==1) { echo '<strong>Параметры создания модели:</strong>' ; damp_array($options,1,-1) ; }

	if ($debug) echo '<div class="black bold">Создаем модель каталога</div>' ;
    if (!$this->tkey) { echo '<span class="red">Не указано имя таблицы для create_model или таблица не существует('.$this->table_name.')</span><br>' ; return ; }
    if (!isset($options['include_space_section']) or _ENGINE_MODE=='admin') $options['include_space_section']=1 ; // по умолчанию включаем в дерево все подразделы
    if ($debug==2) { echo '<strong>Параметры создания модели:</strong>' ; damp_array($options) ; }

    // очищаем массив от старых объектов
    if (_sizeof($this->tree)) foreach ($this->tree as $i=>$rec) if (isset($this->tree[$i])) unset($this->tree[$i]) ;
    if ($debug) set_time_point('create_model - очистка старой модели') ;

    $order_by='parent,'.(($options['order_by'])?  $options['order_by']:'indx,pkey')  ;
    //$options['no_cur_lag_correct']=1 ;  // запрет автокорректии полей рабочего языка страницы на основе _CUR_LANG
    //$options['no_group_clss']=1 ;
    //$options['no_out_table']=1  ;
    //$debug=2 ;

    //$db_options=$options ;
    //$db_options['debug']=$options['db_debug']  ;

    if ($debug) echo 'Поля, используемые в модели: '.$this->tree_fields.'<br>' ;
    if ($debug) echo 'Условие выборки разделов каталога: '.$this->tree_usl_select.'<br>' ;

    //пока просто получаем все записи, отвечающие условиям отбора объектов
    // используем более простую и  быстрою функции выборки
    //damp_array(_DOT($this->tkey));
    //if (_IS_SYSTEM_IP) $debug=1 ;
    $sql='select '.$this->tree_fields.' from '.$this->table_name.' where '.$this->tree_usl_select.' order by '.$order_by ;
    $list_obj=execSQL($sql,$options) ;

    if (isset(_DOT($this->tkey)->list_clss[3]) and _DOT($this->tkey)->setting['set_image_name']!='sql') fill_field_image_name($list_obj) ;

    if ($debug) set_time_point('create_model - получение записей разделов каталога') ;

    if ($debug) echo 'Получено элементов дерева: '._sizeof($list_obj).'<br>' ;
    // первый проход массива записей по объектам - просто создаем объекты и помещаем их в массив this->tree
    $obj_class_name=($options['class_name'])? $options['class_name']:'c_obj';
    if (_sizeof($list_obj)) foreach($list_obj as $rec)
    { // по новой системе в конструктор передается вся запись по объекту, а он уже сам сохраняет необходимые ему поля
      $this->tree[$rec['pkey']] = new $obj_class_name($rec,$this) ;
      if (!$this->id_root and !$rec['parent']) $this->id_root=$rec['pkey'] ; // если корень дерева не указан, берем за начало объект, у которого parent=0
    }
    if ($debug) set_time_point('create_model - первый проход - создание объектов ('._sizeof($list_obj).')') ;


    //if ($debug) { echo '<div class=red>414: Итоговый каталог: '._sizeof($this->tree).' элементов<br></div>' ; }
    if ($debug) echo 'Определен корень каталога: '.$this->id_root.' - '.$this->tree[$this->id_root]->name.'<br>' ;

    // второй проход массива записей по объектам - проставляем список потомоков у объектов
    if (_sizeof($list_obj)) foreach($list_obj as $rec)  if (isset($this->tree[$rec['parent']])) $this->tree[$rec['parent']]->list_obj[]=$rec['pkey'] ;
    if ($debug) set_time_point('create_model - второй проход - назначение списка потомков ('._sizeof($list_obj).')') ;

    //damp_array($this->tree[1]->list_obj);
    //damp_array($this) ;

    // даем команду корневому элементу дерева проставить номера уровней и отметить используемые элементы каталога
    if (isset($this->tree[$this->id_root])) {   $this->tree['root']=&$this->tree[$this->id_root] ;
    											$this->tree['root']->update_child_level() ;
    										}
    else  { echo 'Не найден корень каталога: '.$this->name.' - '.$this->id_root.'<br>' ; trace() ;}
    if ($debug) set_time_point('create_model - третий проход - назначаем номера уровней') ;


    //echo 'Полный каталог:<br>' ; if (_sizeof($this->tree)) foreach($this->tree as $obj) { echo $obj->pkey.' '.$obj->name.' '.$obj->level.' '.$obj->is_used ; print_r($obj->list_obj) ; echo '<br>' ;}

    // третий проход - заполняем информацией используемые элементы каталога, неиспользуемые - удяляем
    //if (_sizeof($this->tree)) foreach ($this->tree as $pkey=>$obj) if ($this->tree[$pkey]->is_used) $this->tree[$pkey]->save_info($list_obj[$this->tkey][$pkey],$options) ; else unset($this->tree[$pkey]) ;
    if (_sizeof($this->tree)) foreach ($this->tree as $pkey=>$obj) if (!$this->tree[$pkey]->is_used) unset($this->tree[$pkey]) ;
    if ($debug) set_time_point('create_model - четвертый проход - удаляем неисползуемые элементы каталога') ;


    // подситыаем число объектов, не являющихся элементами каталога и удаляем пустые разделы
    // 13.02.2010 - добавлена опция  'item_table' - если объекты находятся не в основной таблице
    /*
    if ($options['usl_count_obj'])
    {   $count_table_name=($options['item_table'])? $options['item_table']:$this->table_name ;
        $arr_cnt=execSQL('select parent,count(pkey) as cnt from '.$count_table_name.' where '.$options['usl_count_obj'].' group by parent order by parent',$debug) ;
	    if (_sizeof($arr_cnt)) foreach($arr_cnt as $rec) if (isset($this->tree[$rec['parent']])) $this->tree[$rec['parent']]->_cnt=$rec['cnt'] ;
	    if ($debug==1) $this->tree['root']->show_tree() ;
	    $this->tree['root']->update_cnt_value() ;
	    //if ($debug==1) $this->tree['root']->show_tree() ;
	    if (!$options['include_space_section']) $this->tree['root']->delete_space_obj($debug) ;
    }
     */

    // делаем запросы - сколько каких объектов по заданному условию - обычно комбинация из нескольких условий по полям
    if (_sizeof($options['get_count_by_usl'])) foreach($options['get_count_by_usl'] as $arr_usl) if (is_array($arr_usl))
        { if ($debug) echo 'Делаем подсчет количества объектов по условию: '.$arr_usl['usl'].'<br>' ;
          $this->get_cnt_by_usl($arr_usl['usl'],$arr_usl['flag_name'],$arr_usl);
          if ($debug) set_time_point('create_model - Выполнен подсчет количества объектов по условию: '.$arr_usl['usl']) ;
        }


    //damp_array($options);
    if (_sizeof($options['get_count_by_fname'])) foreach($options['get_count_by_fname'] as $arr_usl) if (is_array($arr_usl))
        { if ($debug) echo 'Делаем подсчет количества объектов по полю: '.$arr_usl['fname'].'<br>' ;
          $this->get_cnt_by_fname($arr_usl['fname'],$arr_usl['cur_flag'],$arr_usl['all_flag'],$arr_usl['usl_select'],$arr_usl['options']) ;
          if ($debug) set_time_point('create_model - Выполнен подсчет количества объектов по полю: '.$arr_usl['fname']) ;
        }


    // 26.06.2011 - использована более новая функция  get_cnt_by_fname($fname,$flag_name,$usl,$options=array()) - по времени примерно так же , но один запрос вместо отдельгл запроса по каждому классу
    // но, внимание - данная таблица не считает кол-во элементов в out таблицах, что необходимо обсуждать, но в приницпе правильно
    // 05.08.2011 - неправильно для galerey - не считает кол-во фото в дочерних таблицах
    // 15.08.2013 - в get_cnt_by_fname добавлен подсчет кол-ва в слинкованных объектах
    if ($options['get_count_by_clss'])
    { if ($debug) echo 'Делаем подсчет количества объектов по классам<br>' ;
      $options_select=(is_array($options['get_count_by_clss']))? $options['get_count_by_clss']:array('debug'=>$options['get_count_by_clss']-1) ;
      $this->get_cnt_by_fname('clss','cur_cnt_clss','all_cnt_clss','enabled>0',$options_select) ;
      if ($debug) set_time_point('create_model - Выполнен подсчет количества объектов по классам') ;
      if (!$options['include_space_section']) $this->tree['root']->delete_space_obj($debug) ;
    }

     //if ($debug) echo '11' ;

    if ($debug) { echo '<div class=red>Итоговый каталог: '._sizeof($this->tree).' элементов<br></div>' ; }

 	if ($this->tree['root'])	{ 	//if ($debug) echo ''
                                    if (!$options['no_auto_generate_page_patch']) { $this->tree['root']->update_page_patch() ; // автораздачу можно отключить
                                                                                    if ($debug) set_time_point('create_model - update_page_patch') ;
                                                                                  }
      								$this->list_enabled_section=$this->tree['root']->get_list_child() ;
                                    if ($debug) set_time_point('create_model - get_list_child') ;
      								$this->on_create_tree() ;
                                    if ($debug) set_time_point('create_model - on_create_tree') ;
      								//echo 'debug='.$debug.'<br>' ;
      								if ($debug==2) $this->tree['root']->show_tree(array('href','level','cnt','_cnt')) ;
    							}


    //if ($options['dop_func'])  $options['dop_func']($options['dop_func_options']) ; // вызов дополниельной функции обработки данных



   //$this->tree['root']->usl_include_section=$usl_otb ;
   //$this->tree['root']->usl_count_obj=$options['usl_count_obj'] ;
    //damp_array($options) ;
    //echo 'options='.$debug.'<br>' ;
    /*
    if ($debug=='show_model')
    { echo '<div class=red>Итоговый каталог: '.$this->name._sizeof($this->tree).' элементов<br></div>' ;
       ?><table><?
       if (_sizeof($this->tree)) foreach($this->tree as $obj)
       { ?><tr><td><? echo $obj->pkey?></td>
               <td><? echo $obj->href ?></td>
               <td><? echo $obj->name?></td>
               <td><? $obj->level?></td>
               <td><? $obj->is_used?></td>
               <td><? print_r($obj->cur_cnt_clss) ; ?></td>
               <td><?print_r($obj->all_cnt_clss) ;?></td>
           </tr><? ;
       }
       ?></table><?
    }
     */



    //if ($debug) print_r(array_keys($this->tree));

   set_time_point('Создание модели <strong>'.$this->root_dir.'</strong>') ;
  }

  // отрабатываем событие создания дерева
  function on_create_tree()  {}


    // функция для подстета числа объектов в каждом разделе дерева
    // согласно переданному условию
    // $usl - условие или массив условий (будеьт объдинено через and)
    // $options['table'] - использовать для подсчета объектов указанную таблицу
    // $options['only_clss'] - подсчитывать только объекты указанного класса, соотвественно будет использована необходимая таблица объектов
    // $options['parent_field'] - поле parent
    // $options['dop_usl'] - добавлять условие dop_usl
    // условие, на основании которго делался подсчет, сохраняется в usl_cnt_objects[$flag_name]

  function get_cnt_objects($usl,$flag_name,$options=array()) {$this->get_cnt_by_usl($usl,$flag_name,$options);}

  function get_cnt_by_usl($usl,$flag_name,$options=array())
  {   if (!$flag_name) return ;
      if (!is_array($usl)) { if ($usl) $arr_usl[]=$usl ; } else $arr_usl=$usl ;
      $table_name=($options['table_name'])? $options['table_name']:$this->table_name ;
      $parent_field=($options['parent_field'])? $options['parent_field']:'parent' ;
      if ($options['only_clss']) { $arr_usl[]='clss='.$options['only_clss'] ; $table_name=_DOT(_DOT($this->tkey)->list_clss[$options['only_clss']])->table_name ;}
      if (!$table_name) { print_error('Не удалось определить таблицу для выборки cnt_objects')  ; return ; }
      //15.11.11 - отключено, т.к. не позволяем в дальшейнем сравнивать условие сохраненное в usl_cnt_objects с текущим условием фильтра
      //$arr_usl[]='enabled=1' ;
	  if ($options['debug']) damp_array($arr_usl) ;
      $res_usl=implode(' and ',$arr_usl) ;
      if ($options['return_only_usl']) return($res_usl) ;
      //echo '$arr_usl' ; print_r($arr_usl) ; echo '<br>';
      $where_usl=(_sizeof($arr_usl))? 'where '.$res_usl:'' ;
      // Обнуляем все флаги во всех подразделах
      $this->clear_cnt_objects($flag_name) ;
      // получаем список разделов и количество объектов
      $list_parent=execSQL('select '.$parent_field.',count(pkey) as cnt from '.$table_name.' '.$where_usl.' group by '.$parent_field.' order by '.$parent_field,$options) ;
      // проставляем флаги только в тех подразделах, которые включают в себя текущий бренд
      if (_sizeof($list_parent)) foreach($list_parent as $rec) if (isset($this->tree[$rec[$parent_field]])) $this->tree[$rec[$parent_field]]->$flag_name=$rec['cnt'] ;
      // рекурсивно переносим флаги с детей на родителей
      $this->tree['root']->update_field_value($flag_name) ;
      // сохраняем условие, по которому был сделан подсчет
      if ($options['debug']) echo 'сохраняем условие, по которому был сделан подсчет: '.$res_usl.'<br>' ;
      $this->tree['root']->usl_cnt_objects[$flag_name]=$res_usl ;
  }

  // позволяет получить для каждого элемента дерева каталога массив с числом объектов для каждого значения $fname
  // обычно используется для получения сводной информации, сколько каких брендов в каждом разделе каталога
  // $fname - поле, данные по которму надо получить
  // $cur_flag_name - массив, в который будут помещены данные по текущему разделу
  // $all_flag_name - массв, в котором будут данные по текущему и дочерним разделам
  // $usl - дополнительное условие для выборки объектов
  // $options[only_clss] - выборка будет происходить только из объектов одного класса, в таблице имеено этого класса
  // !!! внимание. Данная функция не считает объекты в out таблицах - из-за их большого объема (напрмер число изображений для товаров 10000), хотя потом данная информация в модели не учитывается
  // необходимо подстчитать объекты, находящиеся в out таблице, необходимо в опции only_clss указать код класса, по которому будем считать
  // !!! внимание необходимо добрабоатть - сейчас не учитываются используются сликованные объекты
  function get_cnt_by_fname($fname,$cur_flag_name,$all_flag_name,$usl,$options=array())
    { $arr_clss_usl=array() ;
      //damp_array($options,1,-1);
      if (!$this->tree['root']->pkey) return ; // если дерева нет, функция не выполняется
      if (!is_array($usl)) { if ($usl) $arr_usl[]=$usl ; else $arr_usl=array() ; } else $arr_usl=$usl ;
      $table_name=($options['table_name'])? $options['table_name']:$this->table_name ;
      $parent_field='parent,'.$fname ;

       if ($options['only_clss'])
       { $arr_clss=explode(',',$options['only_clss']) ;
         foreach($arr_clss as $clss)
         { $tkey=_DOT($this->tkey)->list_clss[$clss] ;
           $arr_clss_usl[$tkey]='clss='.$clss ; // формуруем условия для конкретного класса
           $arr_tables[]=$tkey ;
         }
       }
       else $arr_tables[]=($options['table_name'])? $options['table_name']:$this->table_name ;

       // делаем выборку в OUT таблицах, если необходимо
       if ($options['include_out_tables'] and _sizeof(_DOT($this->tkey)->list_OUT)) foreach(_DOT($this->tkey)->list_OUT as $out_table_name) $arr_tables[]=$out_table_name ;


       if (!_sizeof($arr_tables)) { print_error('Не удалось определить таблицу для выборки cnt_objects')  ; return ; }

       if ($options['debug']) { echo 'table_names:' ; print_r($arr_tables) ; echo '<br>' ; echo 'fname='.$fname.'<br>cur_flag_name='.$cur_flag_name.'<br>all_flag_name='.$all_flag_name.'<br>Условия выборки:' ; print_r($arr_usl) ; echo '<br>' ; }

       $res_usl=implode(' and ',$arr_usl) ;

       if ($options['return_only_usl']) return($res_usl) ; //echo '$arr_usl' ; print_r($arr_usl) ; echo '<br>';
       $where_usl=(_sizeof($arr_usl))? 'where '.$res_usl:'' ;

       // Обнуляем все флаги во всех подразделах
       $this->clear_cnt_objects($cur_flag_name) ;
       //$this->clear_cnt_objects($all_flag_name) ;
       // получаем список разделов и количество объектов
       //damp_array($arr_clss_usl,1,-1);

       foreach($arr_tables as $tkey)
       { $options['no_indx']=1 ;
         $cur_table_usl=_sizeof($arr_clss_usl[$tkey])? $where_usl.' and '.$arr_clss_usl[$tkey]:$where_usl ;
         //$cur_table_usl.=' and parent in (select pkey from '.$table_name.' where '.$this->tree_usl_select.')' ;
         $table_name=(is_object(_DOT($tkey)))? _DOT($tkey)->table_name:$tkey ;
       //$list_parent=execSQL('select parent,count(pkey) as cnt from '.$table_name.' '.$where_usl.' group by '.$parent_field.' order by '.$parent_field,$options['debug']) ;
         $arr=execSQL('select '.$parent_field.',count(pkey) as cnt from '.$table_name.' '.$cur_table_usl.' group by '.$parent_field.' order by '.$parent_field,$options) ;
         $list_parent=group_by_field('parent',$arr,$fname,'cnt') ;
         //print_2x_arr($list_parent) ;


       // проставляем флаги только в тех подразделах, которые включают в себя текущий бренд
       if (_sizeof($list_parent)) foreach($list_parent as $parent=>$recs) if (isset($this->tree[$parent])) $this->tree[$parent]->$cur_flag_name=$recs ; //[$rec[$fname]]=$rec['cnt'] ;
       // рекурсивно переносим флаги с детей на родителей
       if (is_object($this->tree['root'])) $this->tree['root']->update_cnt_fname_value($cur_flag_name,$all_flag_name) ;
       }
       //$this->tree['root']->update_field_value($flag_name) ;
       // сохраняем условие, по которому был сделан подсчет
       //if ($options['debug']) echo 'сохраняем условие, по которому был сделан подсчет: '.$res_usl.'<br>' ;
       $this->tree['root']->usl_cnt_objects[$cur_flag_name]=$res_usl ;
       $this->tree['root']->usl_cnt_objects[$all_flag_name]=$res_usl ;
    }

  // Обнуляем все флаги во всех подразделах
  function clear_cnt_objects($flag_name)
  { if (_sizeof($this->tree)) foreach($this->tree as $obj) unset($obj->$flag_name);
    $this->tree['root']->usl_cnt_objects[$flag_name]='' ;
  }

  // специально переделанные функции для price.kz
  function get_cnt_objects2($usl,$flag_name,$options=array())
  {   if (!$flag_name) return ;
      if (!is_array($usl)) { if ($usl) $arr_usl[]=$usl ; } else $arr_usl=$usl ;
      $table_name=($options['table_name'])? $options['table_name']:$this->table_name ;
      $parent_field=($options['parent_field'])? $options['parent_field']:'parent' ;
      if ($options['only_clss']) { $arr_usl[]='clss='.$options['only_clss'] ; $table_name=_DOT(_DOT($this->tkey)->list_clss[$options['only_clss']])->table_name ;}
      if (!$table_name) { print_error('Не удалось определить таблицу для выборки cnt_objects')  ; return ; }
      $arr_usl[]='enabled=1' ;
	  if ($options['debug']) damp_array($arr_usl) ;
      $res_usl=implode(' and ',$arr_usl) ;
      if ($options['return_only_usl']) return($res_usl) ;
      //echo '$arr_usl' ; print_r($arr_usl) ; echo '<br>';
      $where_usl=(_sizeof($arr_usl))? 'where '.$res_usl:'' ;
      // Обнуляем все флаги во всех подразделах
      $this->clear_cnt_objects($flag_name) ;
      // получаем список разделов и количество объектов
      $list_parent=execSQL('select '.$parent_field.',count(pkey) as cnt from '.$table_name.' '.$where_usl.' group by '.$parent_field.' order by '.$parent_field,$options['debug']) ;
      // проставляем флаги только в тех подразделах, которые включают в себя текущий бренд
      if (_sizeof($list_parent)) foreach($list_parent as $rec) if (isset($this->tree[$rec[$parent_field]])) $this->tree[$rec[$parent_field]]->$flag_name=$rec['cnt'] ;
      // рекурсивно переносим флаги с детей на родителей
      $this->tree['root']->update_field_value($flag_name) ;
      // сохраняем условие, по которому был сделан подсчет
      if ($options['debug']) echo 'сохраняем условие, по которому был сделан подсчет: '.$res_usl.'<br>' ;
      $this->tree['root']->usl_cnt_objects[$flag_name]=$res_usl ;
  }

  // Обнуляем все флаги во всех подразделах
  function clear_cnt_objects2($flag_name)
  { if (_sizeof($this->tree)) foreach($this->tree as $obj) $obj->$flag_name=0 ;
    $this->tree['root']->usl_cnt_objects[$flag_name]='' ;
  }


  // ------------------------------------------------------------------------------------------------------------------------------------------------------
  // функции для работы с адресами страниц элементов каталога
  // ------------------------------------------------------------------------------------------------------------------------------------------------------

  // возвращаем название страницы для записи REC - не весь URL а только фрагмент!!!
  // на основании этих фрагментов далее будет строиться путь объекта
  // функция используетмя только! для разделов каталога
  // внимание! для формирования поля url_name используется функция $url_name=_CLSS($rec['clss'])->prepare_url_obj($rec), формириуется каждый раз при изменении наименования объекта ;
  function get_url_dir_name(&$rec)
  {   $name='' ;
      switch ($this->patch_mode)
          { case 'TREE_NAME':
            case 'TREE_ID':    // href - предопределенное имя для раздела
                               // url_name - генериться автоматически заполняется при изменении имени объекта
                               if ($rec['href'])                        $name=strip_tags(trim($rec['href']))  ;  // значение href имеет приоритет в люббом случае - для сохранения ссылок на старых сайтах
                               else if ($rec['url_name'])               $name=strip_tags(trim($rec['url_name']))  ;  // значение url_name заполяняется автоматически  при создании или изменении объекта
                               else if ($this->patch_mode=='TREE_NAME') $name=safe_text_to_url($rec['obj_name'],$rec['tkey']) ; // тут должна быть функция _CLSS($rec['clss'])->prepare_url_obj($rec)  но она потребует режима полной загрузки движка на сайте
                               if (!$name)                             $name=$rec['pkey'] ;
                               if (!$rec['parent'])                    $name='/' ;
                               break ;
            case 'cat_1':      if (!$rec['parent']) $name='' ;
                               else                 $name=$rec['pkey'].'.html' ;
                               break ;
            case 'page':       if (!$rec['parent']) $name=($rec['href'])? $rec['href'].'.html':$this->section_page_name.'.html' ;
                               else                 $name=$this->section_page_name.'_'.$rec['pkey'].'.html' ;
                               break ;
            case 'as_is':      $name=strip_tags(trim($rec['href']))  ;
                               break ;
          }
      return($name) ;
  }

  // возвращаем относительный URL страницы для ЭЛЕМЕНТА ДЕРЕВА КАТАЛОГА - на основе пути родительского подраздела и режима вывода пути
  // используется в obj->update_page_patch
  // $this->href=get_url_section($this) ;
  // // внимание! для формирования поля url_name используется функция $url_name=_CLSS($rec['clss'])->prepare_url_obj($rec) ;
  function get_url_section($obj_section)
  {   $dir_name=$obj_section->url_dir_name ;
      $level=$obj_section->level ;
      $parent=$obj_section->parent ;
      $url='' ;
      switch ($this->patch_mode)
      { // формирование дерева на заданных условиях ---------------------------------------------------------------------
        case 'TREE_NAME':
        case 'TREE_ID':   if (!$this->no_root_dir)
                          { if ($parent) $url=$this->tree[$parent]->href.$dir_name.'/' ; // url по дереву в выделенном каталоге
                            else
                            {  if ($obj_section->subdomain) $url=_MAIN_PROTOCOL.$obj_section->subdomain.'.'._BASE_DOMAIN.'/' ;
                               else                         $url=(_USE_SUBDOMAIN)? _MAIN_PROTOCOL._MAIN_DOMAIN.'/'.$this->root_dir.'/':'/'.$this->root_dir.'/' ;
                            }
                          }
                          else
                          { if ($level>1) $url=$this->tree[$parent]->href.$dir_name.'/' ; // url по дереву в выделенном каталоге
                            else if ($level==1)
                            { if ($obj_section->subdomain) $url=_MAIN_PROTOCOL.$obj_section->subdomain.'.'._BASE_DOMAIN.'/' ;
                              else                         $url=(_USE_SUBDOMAIN)? _MAIN_PROTOCOL._MAIN_DOMAIN.'/'.$dir_name.'/':'/'.$dir_name.'/' ;
                            }
                            else  $url='/' ;
                          }

                          break;
        case 'cat_1':     $url='/'.$this->root_dir.'/'.$dir_name ; break ; // в выделенном каталоге, но без дерева
        case 'page':      $url='/'.$dir_name ; break ; // в корне сайта, используюся префикс, уже в имени
        case 'as_is':     $url=$dir_name ; break ; // = обработанное $rec['href'],  используется только для меню
      }
      return($url) ;
  }

   // возвращаем относительный URL страницы для объекта системы - НЕ ЭЛЕМЕНТА ДЕРЕВА КАТАЛОГА - на основе пути родительского подраздела и режима вывода пути
   // используется в prepare_public_info при подготовке записи к публикации
   // $rec['__href']=get_url_item($rec)
   // внимание! для формирования поля url_name используется функция $url_name=_CLSS($rec['clss'])->prepare_url_obj($rec) ;
   function get_url_item(&$rec)
     { $pkey=$rec['pkey'] ; $parent=$rec['parent'] ;
       switch ($this->patch_mode)
       { case 'TREE_NAME': $res=$this->tree[$parent]->href.(($rec['url_name'])? $rec['url_name']:$pkey).'.html' ; break;   // /catalog/Подарки/Мужские/Одеколон.html  или /catalog/podarki/man/odekolon.html
         case 'TREE_ID':   $res=$this->tree[$parent]->href.$pkey.'.html' ; break;                                          // /catalog/1232/2342/1833.html
         case 'cat_1':     $res=$this->tree['root']->href.$pkey.'.html' ; break;                                           // /catalog/1233.html
         case 'as_is':     $res=$this->tree[$pkey]->href ; break;                                                          // = $rec['href']
         case 'page':
         default:     $res='/'.$this->item_page_name.'_'.$pkey.'.html' ;                                                  // /goods_7273.html
       }
       return($res) ;
     }

    // формирует правильное url_name в зависимости от типа дерева
    // используется при сохранении имени объекта (obj_name) в базу данных - для товаров необходимо сохранить правильное имя в базе
    /*
    function get_url_name($pkey,$obj_name='')
    {  $name=$pkey ;
       if ($this->patch_mode=='TREE_NAME' and $obj_name) $name=safe_text_to_url($obj_name) ;
       return($name) ;
    }
    */

    // создаем url по коду обхекта
    function get_url_by_id($id)
    {  $url='' ;
       if (!isset($this->tree[$id]))
       { $rec=execSQL_van('select * from '.$this->table_name.' where pkey='.$id) ;
         if ($rec['pkey']) $url=_MAIN_DOMAIN.$this->get_url_item($rec) ;
       }
       else $url=_MAIN_DOMAIN.$this->tree[$id]->href ;
       return($url) ;
    }

    // определяем код подраздела по пути
    // должны совпасть все элементы пути
    // получает код объекта входа и путь от этого объекта
    // возвращает id секции, определенный путь, набор фильтра
    function get_id_by_url($root_id,$dir,$debug=0)
    {  $not_found=1 ; $id=0  ;  $use_dir=array() ;   $filter_set=array() ;
       //if (_IS_SYSTEM_IP) $debug=1 ;
       $section_root=$this->tree[$root_id] ;

       $dir=strip_tags(urldecode($dir)) ; // восстановление url, в которые попало форматирование тегами из-за старых версий движка
       $ss=explode('/',$dir) ;// if ($debug)

       //echo '111' ; damp_array($this->list_subdomain,1,-1) ;
       if (!$this->no_root_dir and !$section_root->subdomain) { $use_dir[0]=$ss[1] ; unset($ss[0],$ss[1]) ; } // удаляем /catalog/
       if ($this->no_root_dir and !$section_root->subdomain) { $use_dir[0]=$ss[1] ; unset($ss[0],$ss[1]) ; } // удаляем /catalog/

       //damp_array($ss) ;

       //if ()

       $arr2=parse_url($section_root->href) ;
       //damp_array($arr2) ;
       $root_section_patch=$arr2['path'] ;
       //echo

       /*
        if ($cur_domain==_MAIN_DOMAIN) $section_root=$this->tree['root'] ;
       else
       { $cur_domain_section_id=$this->list_subdomain[$cur_domain] ;
         if (isset($this->tree[$cur_domain_section_id])) $section_root=$this->tree[$cur_domain_section_id] ;
       } */
       //echo 'dir='.$dir.'<br>' ;
       //echo '$section_root->href='.$section_root->href.'<br>' ;
       //echo '$root_section_patch='.$root_section_patch.'<br>' ;
       //echo '$dir='.$dir.'<br>' ;
       // если попали сразу на корень - возвраащаем ответ
       if ($dir==$root_section_patch) return(array('id'=>$section_root->pkey,'dir'=>$section_root->href,'filter_set'=>array())) ;
       $sect=$section_root ;
       if (_sizeof($ss)) foreach($ss as $level=>$sect_patch) if (trim($sect_patch))
       { if ($debug) echo '<div class="bold black">level='.$level.' - ищем - '.$sect_patch.'</div>' ;
         $not_found=1 ;
         if (_sizeof($sect->list_obj)) foreach($sect->list_obj as $pkey)
          {  if ($sect_patch==$this->tree[$pkey]->href or $sect_patch==$this->tree[$pkey]->url_dir_name or $sect_patch==$pkey)
              { $sect=$this->tree[$pkey] ;
                $not_found=0 ;
                $use_dir[$level]=$sect_patch ;
                if ($debug) echo '<span class="bold green">Найдено</span>: $sect='.$sect->name.' (id='.$pkey.')'.'<br>' ;
                break ;

              }
              }
         // может это фильтр?
         if ($not_found and isset($this->function_check_filter) and function_exists($this->function_check_filter))
         { $func_name=$this->function_check_filter ;
           $filter_set=array() ;
           if (function_exists($func_name)) $filter_set=$func_name($sect_patch,$level) ;
           if (_sizeof($filter_set)) { $not_found=0 ; if ($debug) echo 'Найден фильтр: '.print_r($filter_set,true).'<br>' ; }
          }
         if ($not_found) break ;
       }

       //if ($debug)
       //    echo 'not_found='.$not_found.'<br>' ;
       if (!$not_found) $id=$sect->pkey ;
       $result=array() ;
       $result['id']=$id ;
       //$result['dir']='/'.implode('/',$use_dir).'/' ;
       $result['dir']=$sect->href ;
       $result['filter_set']=$filter_set ;
       if ($debug) damp_array($result,1,-1) ;
       return($result) ;
    }


   function check_dir_to_filter($dir,$level)
   {
     $result=parse_url_dir_to_filter_value($dir) ;
     return($result) ;
   }

   function prepare_public_info(&$rec,$options=array())
    { if (!isset($this->tree[$rec['pkey']])) parent::prepare_public_info($rec,$options) ; // товар
      else // раздел
      { if (!$rec['__href']) $rec['__href']=$this->tree[$rec['pkey']]->href ;
        if (!$rec['__name']) $rec['__name']=$this->tree[$rec['pkey']]->name ;
        if (!$rec['__data']) $rec['__data']=date("d.m.y",$this->tree[$rec['pkey']]->rec['c_data']) ;
        if (!$rec['__level']) $rec['__level']=$this->tree[$rec['parent']]->level+1 ;
        if ($rec['_image_name']) $rec['__img_alt']=strip_tags($rec['__name']) ;
      }
    }


  function select_obj_info($_CUR_PAGE_DIR,$_CUR_PAGE_NAME='')
  {  $result=0 ;
     if ($this->patch_mode=='TREE_ID')       $result=$this->select_obj_info_by_tree($_CUR_PAGE_DIR,$_CUR_PAGE_NAME) ;
     elseif ($this->patch_mode=='TREE_NAME') $result=$this->select_obj_info_by_tree($_CUR_PAGE_DIR,$_CUR_PAGE_NAME) ;
     elseif ($this->patch_mode=='page')      $result=$this->select_obj_info_by_page($_CUR_PAGE_DIR,$_CUR_PAGE_NAME) ;
     return($result) ;
  }


  // получаем инфу по текущему объекту - для подсистем работающих через страницы
  function select_obj_info_by_page($_CUR_PAGE_DIR,$_CUR_PAGE_NAME='')
  { global $obj_info,$debug_obj_info,$section_id ;
    /// !!! скрипты, работающие через дерево передают параметры $_CUR_PAGE_DIR - путь объекта,$_CUR_PAGE_NAME - код объекта
    //  !!! скрипты, работающие через имя - передает только параметр $_CUR_PAGE_NAME - это код объекта
    // если в $_CUR_PAGE_DIR передан только путь (путь оканчивается на "/"), то значит у нас раздел каталога
    // если путь не оканчивается на "/", то значит у нас объект каталога - всю информацию берем из кода
    $id=0 ;
    if ($debug_obj_info) echo 'Система каталога - страничная<br>' ;
    if ($debug_obj_info) echo '$_CUR_PAGE_DIR='.$_CUR_PAGE_DIR.'<br>$_CUR_PAGE_NAME='.$_CUR_PAGE_NAME.'<br>' ;
    if (preg_match_all('/'.$this->section_page_name.'_(.+?)\.html/is',$_CUR_PAGE_NAME,$matches,PREG_SET_ORDER)) $id=$matches[0][1];
    if (preg_match_all('/'.$this->item_page_name.'_(.+?)\.html/is',$_CUR_PAGE_NAME,$matches,PREG_SET_ORDER))    $id=$matches[0][1];
    if ($this->tree['root']->url_name==$_CUR_PAGE_NAME) $id=$this->tree['root']->pkey ;
    if (!$id)
    {  $name=str_replace('.html','',$_CUR_PAGE_NAME) ;
       if (_sizeof($this->tree)) foreach($this->tree as $node_id=>$node_obj) if ($node_obj->rec['href'] and $node_obj->rec['href']==$name) $id=$node_id ;
    }
    if ($debug_obj_info) echo 'id='.$id.'<br>' ;


    $section_id=0 ;

    // если передано имя объекта
    //print_r($this->tree[$_CUR_PAGE_NAME]) ;
    if ($id and $this->tree[$id]->pkey)
    				   { // смотрим, есть ли для $id запись в модели дерева каталога
    				   	 $section_id=$this->tree[$id]->pkey ;
    				   	 // получаем информацию по разделу
      				   	 if ($section_id) $obj_info=select_db_obj_info($this->tkey,$section_id,array('get_child_obj'=>'3,5','only_enabled_child'=>1,'add_usl'=>$this->usl_show_section)) ; // damp_array($obj_info) ;
    				     if ($debug_obj_info) echo 'Алгоритм1: section_id='.$section_id.' obj_name='.$obj_info['obj_name'].'<br>' ;
                           $this->adding_info_from_tree_model($obj_info) ;
                           $this->fill_obj_info_to_section_rec($section_id,$obj_info) ;
                           //damp_array($obj_info) ;
    				   }
    // если $id задано, но его нет в в дереве - делаем запрос в базу
    else if ($id)	   { // этот запрос вернет результат только если объект - элемент каталога, НЕ РАЗДЕЛ
					     $obj_info=$this->get_obj_info_by_id($id) ;
					     // по запросу с базы запись должна иметь действующего родителя в дереве каталога
  					     if (isset($this->tree[$obj_info['parent']])) { $section_id=$obj_info['parent'] ;  $this->prepare_public_info($obj_info) ; }
					     else										  $obj_info=array() ; // если не имеет - уничтожаем выборку
					     if ($debug_obj_info) echo 'Алгоритм2: section_id='.$section_id.' obj_name='.$obj_info['obj_name'].' clss='.$obj_info['clss'].'<br>' ;
					   }
	// если ни один из параметров не передан - объект - корень каталога
	/*
	if (!$_CUR_PAGE_DIRselect_obj_info_by_tree and !$id)  { $section_id=$this->tree['root']->pkey ;
                                               $obj_info=select_db_obj_info($this->tkey,$section_id,array('get_child_obj'=>'3,5','add_usl'=>$this->usl_show_section)) ; // damp_array($obj_info) ;
                                               if ($debug_obj_info) echo 'Алгоритм3: section_id='.$section_id.' obj_name='.$obj_info['obj_name'].'<br>' ;
                                             }
    */
	// если раздел по пути не определен - ошибка 404 в заголовок клиенту, но страницу надо выводить
    if (!$section_id or !_sizeof($obj_info))
    {  if ($debug_obj_info) echo '<span class="red bold">Алгоритм 404</span><br>' ;
       _CUR_PAGE()->result=404 ;  // дубляж, не нужно
       $result=404 ;
       unset($section_id) ;
    }
    else
    { // постепенно на удаление - дублируют obj_info
      global $cur_section_obj ; 	$cur_section_obj[$this->name]=$this->tree[$section_id] ; // подраздел объекта //damp_array($cur_section_obj[$this->name]) ;
       global $cur_rasd_obj ; 		$cur_rasd_obj[$this->name]=$this->tree[$cur_section_obj[$this->name]->get_parent_obj(1)] ; // корневой подраздел объекта //damp_array($cur_rasd_obj) ;
   	  global $cur_sections_tree ; $cur_sections_tree[$this->name]=$cur_section_obj[$this->name]->get_arr_parent() ; // получаем массив, в котором индексы - уровни, значения - коды родительких объектов
    }
    return($result) ;
    //damp_array($obj_info) ;
  }


  // получаем инфу по текущему объекту - для подсистем работающих через деверо
  // обозначение раздела каталога /путь/путь/путь/путь/
  // обозначение объекта каталога /путь/путь/путь/путь/имя.html
  // внимание!!! для подсистем, работающих по странице - должна быть отдельная функция разпознования объекта
  // если объект не найден, вписываем в _CUR_PAGE()->result=404
  function select_obj_info_by_tree($_CUR_PAGE_DIR,$_CUR_PAGE_NAME='',$options=array())
  { global $obj_info,$debug_obj_info,$section_id ;
    /// !!! скрипты, работающие через дерево передают параметры $_CUR_PAGE_DIR - путь объекта,$_CUR_PAGE_NAME - код объекта
    //  !!! скрипты, работающие через имя - передает только параметр $_CUR_PAGE_NAME - это код объекта
    // если в $_CUR_PAGE_DIR передан только путь (путь оканчивается на "/"), то значит у нас раздел каталога
    // если путь не оканчивается на "/", то значит у нас объект каталога - всю информацию берем из кода
    if ($debug_obj_info) echo '$_CUR_PAGE_DIR='.$_CUR_PAGE_DIR.'<br>$_CUR_PAGE_NAME='.$_CUR_PAGE_NAME.'<br>mont_obj_id='.$GLOBALS['mont_obj_id'].'<br>' ;
      $cur_url='' ; $true_url='' ; /*if (!$section_id) */ $section_id=$this->tree['root']->pkey ; $result_parse=array() ;

    // ГЛАВНАЯ ПРОВЕРКА - необходимо получить id раздела, в котором находится объект
    // если путь есть, определяем раздел каталога по пути
    // имеем: точку входа в каталог или поддомен
    // они будут опредлять, от какого объекта над распозновать путь объекта







    if ($_CUR_PAGE_DIR){  $result_parse=$this->get_id_by_url($GLOBALS['mont_obj_id'],$_CUR_PAGE_DIR) ; //echo '$section_id='.$section_id.'<br>' ;
                          //damp_array($result_parse) ;
                          $section_id=$result_parse['id'] ; //echo '$section_id='.$section_id.'<br>' ;
                          $cur_url=$result_parse['dir'] ; //echo '$cur_url='.$cur_url.'<br>' ;
                          // делаем редирект на страницу с правильным url - заменяем страницы с кодами на станицы с названиями
                          if ($section_id) $true_url=$this->tree[$section_id]->href ;
                          //else             $true_url=$result_parse['dir'] ; // для случаем когда точка монтирования через поддомен открывается через подкаталог
                          // echo '$true_url='.$true_url.'<br>' ;

                          //damp_array()
    					  if ($debug_obj_info) echo '<span class="blau bold">Алгоритм 2</span>: задан $_CUR_PAGE_DIR: текущий каталог - '.$section_id.'<br>' ;
    					}
    else                { // если пути нет, то значит, мы в корне каталога
                          if ($debug_obj_info) echo '<span class="blau bold">Алгоритм 1</span>: не задан $_CUR_PAGE_DIR: текущий каталог - корень каталога<br>' ;
                        }
    if ($debug_obj_info) echo '<span class="green bold">Результат определения кода раздела section_id=</span> '.$section_id.'<br>' ;
    //damp_array($this) ;

    //else // если страница задана, значит искомый объект - объект в каталоге

    if ($section_id and $_CUR_PAGE_NAME)
    { // этот запрос вернет результат только если объект находится в найденном разделе каталога
	  $list_childs_rasdels=$this->tree[$section_id]->get_list_child() ;
      $obj_name_id=str_replace(array('.html','.php'),'',$_CUR_PAGE_NAME) ;
      $obj_info=$this->get_obj_info_by_id($obj_name_id,' and parent in('.$list_childs_rasdels.')') ;
      if ($debug_obj_info) echo '<span class="blau bold">Алгоритм 3</span>: Определен section_id и задано $_CUR_PAGE_NAME: obj_name='.$obj_info['obj_name'].'<br>' ;

      if ($obj_info['pkey'])
      {  $cur_url=($options['cur_url'])? $options['cur_url']:_CUR_SHEME._CUR_DOMAIN.$_CUR_PAGE_DIR.$_CUR_PAGE_NAME ; //echo '$cur_url='.$cur_url.'<br>' ;
           $this->prepare_public_info($obj_info) ;
           $true_url=$obj_info['__href'] ; //echo '$true_url='.$true_url.'<br>' ;
      }
	}

	// страница не задана - значит получаем информацию по текущему разделу
	if ($section_id and !$_CUR_PAGE_NAME)
    { $obj_info=select_db_obj_info($this->tkey,$section_id,array('get_child_obj'=>'3,5','only_enabled_child'=>1,'add_usl'=>$this->usl_show_section,'debug'=>0)) ; // damp_array($obj_info) ;
      $this->adding_info_from_tree_model($obj_info) ;
      $this->fill_obj_info_to_section_rec($section_id,$obj_info) ;
      if (_sizeof($result_parse['filter_set'])) $obj_info['__filter_set']=$result_parse['filter_set'] ;

	  if ($debug_obj_info) echo '<span class="blau bold">Алгоритм 4</span>: Определен section_id и не задано $_CUR_PAGE_NAME: obj_name='.$obj_info['obj_name'].'<br>' ;
	}

    //if ($debug_obj_info) { echo '<span class="green bold">Результат определения определение информации по объекту:</span>' ; damp_array($obj_info) ; echo '<br>' ;}

    if ($obj_info['pkey'] and $true_url and $true_url!=$cur_url)
      {   if ($GLOBALS['debug_page_relocation']) echo '<h2>Отладка redirect_301_to - несоответствие _CUR_PAGE_DIR href текущего объекта</h2>$true_url='.$true_url.'<br>$cur_url='.$cur_url.'<br>pkey='.$obj_info['pkey'].'<br>' ;
          $new_url=str_replace($cur_url,$true_url,rawurldecode($_SERVER['REQUEST_URI'])) ;
          if ($GLOBALS['debug_page_relocation']) echo 'Требуется перенаправление на правильный адрес, new_url='.$new_url.'<br>' ;
          redirect_301_to($new_url) ;
          $result=301 ;
      }


	// если раздел по пути не определен - ошибка 404 в заголовок клиенту, но страницу надо выводить
    if (!$section_id or !_sizeof($obj_info))
    {  if ($debug_obj_info) echo '<span class="red bold">Алгоритм 404</span><br>' ;
       _CUR_PAGE()->result=404 ;  // дубляж, не нужно
       $result=404 ;
       unset($section_id) ;
    }

    return($result) ;
  }

  function fill_obj_info_to_section_rec($section_id,&$obj_info)
    {  global $cur_section_obj ; 	$cur_section_obj[$this->name]=$this->tree[$section_id] ; // подраздел объекта //damp_array($cur_section_obj[$this->name]) ;
   	   global $cur_rasd_obj ; 		$cur_rasd_obj[$this->name]=$this->tree[$cur_section_obj[$this->name]->get_parent_obj(1)] ; // корневой подраздел объекта //damp_array($cur_rasd_obj) ;
   	   global $cur_sections_tree ; $cur_sections_tree[$this->name]=$cur_section_obj[$this->name]->get_arr_parent() ; // получаем массив, в котором индексы - уровни, значения - коды родительких объектов
       // новая система для отслеживания текущего раздела
      $GLOBALS[$this->name.'_cur_section']=$this->tree[$section_id] ; // текущий подраздел объекта в переменную типа goods_cur_section

       // заполняем список родителей по уровням
       $obj_info['__parents']=$this->tree[$section_id]->get_arr_parent() ;
      if (_sizeof($obj_info['__parents'])) foreach($obj_info['__parents'] as $level=>$parent_id) $obj_info['__parents_obj'][$level+1]=&$this->tree[$parent_id] ;
      $obj_info['__parent_obj']=&$this->tree[$obj_info['parent']] ;
      $obj_info['__this_obj']=&$this->tree[$obj_info['pkey']] ;
      $obj_info['__level']=_sizeof($obj_info['__parents'])-1 ;
      $obj_info['__href']=$this->tree[$section_id]->href ;
      $obj_info['__name']=$this->tree[$section_id]->name ;
      $obj_info['__all_cnt_clss']=$this->tree[$section_id]->all_cnt_clss ;
      $obj_info['__cur_cnt_clss']=$this->tree[$section_id]->cur_cnt_clss ;
      if (_sizeof($obj_info['obj_clss_3'])) $obj_info['__cur_cnt_clss'][3]=_sizeof($obj_info['obj_clss_3']) ;
       // заполняем список родителей по уровням
       //$obj_info['__childs_pkeys']=$this->tree[$section_id]->get_list_child() ; // используется редко - вызывать отдельно при необходимости
       //$obj_info['__childs']=select_obj_childs_clss_cnt($obj_info['_reffer']) ; // Провавильно использовать поле all_cnt_clss, тут не учитаваются правила показа на сайте из модели

       // заполняем инфу по текущему пути и заголовку h1 страницы объекта
       // 8.10.11 - теперь необходимо использовать свойства $page->h1 и $page->path
       //$obj_info['__page_path']=$this->tree[$section_id]->get_path(array('include_index'=>1,'cur_obj_pkey'=>$obj_info['pkey'])) ;
       //$obj_info['__page_title']=($obj_info['__name'])?  $obj_info['__name']:$obj_info['obj_name']  ;
       //_CUR_PAGE()->path=$this->tree[$section_id]->get_path(array('include_index'=>1,'cur_obj_pkey'=>$obj_info['pkey'])) ;
       //_CUR_PAGE()->h1=($obj_info['__name'])?  $obj_info['__name']:$obj_info['obj_name']  ;
 }


 // вынесено в функцию, чтобы получить возможность сохранять в obj_info не только стандартные объекты дерера каталога
 function get_obj_info_by_id($id,$add_usl='')
 {  global $debug_obj_info ;
    $obj_info=array() ;
    $tkey=$this->tkey_items ; // items могут находиться не в основной таблице
    //echo '$tkey='.$tkey.'<br>' ;
    //$obj_info=select_db_obj_info($tkey,$id,array('get_child_obj'=>'3,5','add_usl'=>$this->usl_show_items.$add_usl,'debug'=>$debug_obj_info)) ; // damp_array($obj_info) ;
    // ищем сначала по коду
    $int_id=$id*1 ;
    if ($int_id>0) $obj_info=select_db_obj_info($tkey,$id,array('get_all_child'=>1,'only_enabled_child'=>1,'add_usl'=>$this->usl_show_items.$add_usl,'debug'=>$debug_obj_info)) ; // damp_array($obj_info) ;
    // потом ищем по url_name
    if (!$obj_info['pkey']) $obj_info=select_db_obj_info($tkey,0,array('get_all_child'=>1,'only_enabled_child'=>1,'use_usl'=>'url_name="'.$id.'"','add_usl'=>$this->usl_show_items.$add_usl,'debug'=>$debug_obj_info)) ; // damp_array($obj_info) ;
    // на случай когда передается url name с нечитаемыми символами - пытаемся прочесть
    if (!$obj_info['pkey'])
    {  $id=iconv('utf-8','ASCII//TRANSLIT',$id) ;
       $obj_info=select_db_obj_info($tkey,0,array('get_all_child'=>1,'only_enabled_child'=>1,'use_usl'=>'url_name like "'.addslashes($id).'"','add_usl'=>$this->usl_show_items.$add_usl,'debug'=>$debug_obj_info)) ; // damp_array($obj_info) ;
    }

	return($obj_info) ;
 }

  // инициализация элемента дерева - подраздела каталога obj массивом rec
  // обычно уже её перектытие не требуется, т.к. все массив $rec сохраняется автоматом в $obj->rec при инициализации $obj
  function dop_save_info(&$obj,&$rec) {}

  // показ списка подразделов по указанному шаблону
  // obj может быть:
  // - код подраздела, будет выводтся list_obj данного подраздела
  // - объект дерева, будет выводтся list_obj данного подраздела
  // - массив подразделов, будет выводися этот массив

  function show_list_section($obj,$func_name,$options=array())
  { global $convert_obj_list_to_list_recs ;
    //if (!function_exists($func_name)) { damp_error('Шаблон <strong>'.$func_name.'</strong> не существует<br>',2) ; return ; }
    if ($options['debug']) trace() ;
    // если в первом параметре передан список кодов объектов
    if (is_array($obj))
    { if ($convert_obj_list_to_list_recs) $arr=$this->convert_tree_list_to_recs($obj) ;
      else                                $arr=$obj  ;
      $this->print_template($arr,$func_name,$options) ;
      return  ;
    }
    // если в первом параметре передан объект, список подразделов которого надо вывести
    if (is_object($obj))
    { if ($convert_obj_list_to_list_recs) $arr=$this->convert_tree_list_to_recs($obj->list_obj) ;
      else                                $arr=$obj->list_obj ;
      $this->print_template($arr,$func_name,$options) ;
      return ;
    }
    // если в первом параметре передан код подраздела, список подразделов которого надо вывести
    if (is_object($this->tree[$obj]))
    { $obj=$this->tree[$obj] ;
    if ($convert_obj_list_to_list_recs) $arr=$this->convert_tree_list_to_recs($obj->list_obj) ;
    else                                $arr=$obj->list_obj ;
    $this->print_template($arr,$func_name,$options) ; //  $func_name($this,$obj->list_obj,$options) ;
    }
    else
    {  // возможно, в первом параметре передано условие, по которому необходимо вывести подразделы
       if ($options['order_by']) $ord='order by '.$options['order_by'] ; else $ord='' ;
       $arr=execSQL_line('select pkey from '.$this->table_name.' where '.$obj.' '.$ord) ;
       if ($convert_obj_list_to_list_recs) $arr=$this->convert_tree_list_to_recs($arr) ;
       // damp_array($arr,1,-1) ;
       $this->print_template($arr,$func_name,$options) ; //  $func_name($this,$obj->list_obj,$options) ;

       // это было не условие
       //echo 'Раздел каталога "'.$obj.'" не существует<br>' ; return ;

    }
  }

   // преобразовываем объект в массив для вывода шаблоном
  function convert_tree_list_to_recs($list_pkeys)
  { $list=array() ;
    if (_sizeof($list_pkeys)) foreach($list_pkeys as $pkey) if (isset($this->tree[$pkey]))
    { // переносим в массив сохранную запись из объекта
      $list[$pkey]=$this->tree[$pkey]->rec ;
      // если рабочий язык страницы не основной, заносим значение локального поля в основное
      if (_sizeof($list[$pkey]) and _CUR_LANG) foreach($list[$pkey] as $fname=>$fvalue) if ($list[$pkey][$fname]) // только для заполненных полей
      { $suff1=strrchr($fname,_CUR_LANG_SUFF) ;
        if ($suff1==_CUR_LANG_SUFF) { $main_fname=str_replace(_CUR_LANG_SUFF,'',$fname) ; $list[$pkey][$main_fname]=$list[$pkey][$fname] ; /*echo 'fname='.$fname.' => |'.$suff1.'|<br>' ;*/}
      }

      $obj=$this->tree[$pkey] ;
      if (_sizeof($obj)) foreach($obj as $fname=>$fvalue) if ($fname!='system' and $fname!='rec') $list[$pkey][$fname]=$fvalue ;
      $list[$pkey]['__name']=$list[$pkey]['obj_name'];
      $list[$pkey]['__href']=$this->tree[$pkey]->href ;
      $list[$pkey]['cur_cnt_clss']=$this->tree[$pkey]->cur_cnt_clss ;
      $list[$pkey]['all_cnt_clss']=$this->tree[$pkey]->all_cnt_clss ;

      $list[$pkey]['__parents']=$this->tree[$pkey]->get_arr_parent() ;
      //$list[$pkey]['__childs_pkeys']=$this->tree[$pkey]->get_list_child() ; / используется редко - вызывать отдельно при необходимости
      //$list[$pkey]['__childs']=select_obj_childs_clss_cnt($obj_info['_reffer']) ; // Провавильно использовать поле all_cnt_clss, тут не учитаваются правила показа на сайте из модели
      $list[$pkey]['__level']=_sizeof($list[$pkey]['__parents'])-1 ;

    }
    //damp_array($list);
    return($list) ;
  }

  function adding_info_from_tree_model(&$obj_info)
  {  $obj=$this->tree[$obj_info['pkey']] ;
     if (_sizeof($obj)) foreach($obj as $fname=>$fvalue) if ($fname!='system' and $fname!='rec' and $fname!='level') if ($fvalue) $obj_info[$fname]=$fvalue ;
  }

  function get_list_pkeys_as_list_recs($pkey) { return($this->convert_tree_list_to_recs($this->tree[$pkey]->list_obj)) ; }
}

//===============================================================================================================================================
// Функции для вывода списоков по шаблонам из произволтных таблиц
//===============================================================================================================================================

 // выводит список элементов с таблицы $table_name, отобранные по условию $usl через шаблон $template_name
 // вся обработка полученных из базы элементов - в самом шаблоне вывода
 // 27.03.12 - добавлена возможсть указания в $options['pages_setup'] инициализационных параметров для вывода страниц

 function show_list_items($table_id,$usl,$func_name,$options=array())
 {  list($tkey,$table_name)=check_table_tkey($table_id) ; // table_id может быть как имя таблицы, так и её код
    $options['table_name']=$table_name ;
    if (isset($options['pages_setup'])) $options=array_merge($options,$_SESSION['init_options'][$options['pages_setup']]) ;
    //$options['debug']=0 ;
    $temp_system = new c_system($options)  ; //damp_array($temp_system) ;
    $cnt=$temp_system->show_list_items($usl,$func_name,$options) ;
    return($cnt) ;
 }

 // возвращает код и имя таблицы по параметру table_id, когда в функцию может быть передано как имя таблицы, так и её код или название подсистемы
 function check_table_tkey($table_id)
 {  if (!_DOT($table_id)->pkey) $tkey=$_SESSION['pkey_by_table'][$table_id] ; else $tkey=$table_id ;
	//echo 'tkey='.$tkey.'<br>' ;
	$table_name=_DOT($tkey)->table_name ;
    return(array($tkey,$table_name)) ;
 }

  function alert_not_found_template($func_name)
  {
      if ($func_name) echo '<div class=alert>Функция шаблона "<strong>'.$func_name.'</strong>" не найдена</div>' ;
      else 		{ echo '<div class=alert>Не задано имя шаблона</div>' ;
      					//trace(1) ;
      			}

  }

   // показ произвольного шаблона
  function print_template($rec,$func_name='',$options=array())
  { if ((!is_array($rec) and !is_object($rec)) or $rec=='-') { $options=$func_name ; $func_name=$rec ; $rec='-' ; }
    // определяем директрию шаблона по заданным опциям
    //if ($options['debug']) damp_array($options) ;
    $use_prev_include=0 ;  $template_dir='';  $template_script='' ; $template_script_exist=0 ;
    $arr=explode('/',$func_name) ;
    if (_sizeof($arr)==2) {$func_name=$arr[1] ; $options['ext']=$arr[0] ;}
    if (!function_exists($func_name))
    {   $template_dir=(isset($options['ext']))? _DIR_EXT.'/'.$options['ext'].'/':_DIR_TO_TEMPLATES.'/'  ;
        $use_prev_include=0 ;
    //$template_dir=safe_patch_files($template_dir) ; // защита от атак через корявый путь к директории
    // определяем файл шаблона
    $template_script=(isset($options['template_script']))? $options['template_script']:$func_name.'.php' ;
    $template_script_exist=(file_exists($template_dir.$template_script))? 1:0 ;
    // если скрипт не найден в директории заданной по опциям, ищем его в директории текущего скрипта
    if (!$template_script_exist)
    { $template_script_exist=(file_exists(_CUR_PAGE()->script_dir.$template_script))? 1:0 ;
      if ($template_script_exist) $template_dir=_CUR_PAGE()->script_dir ;
    }
        if ($template_script_exist) include_once($template_dir.$template_script) ;
    $template_func_exist=function_exists($func_name) ;
    }
    else
    {  $template_func_exist=1 ;
       $use_prev_include=1 ;
    }
    if ($GLOBALS['debug_templates'] or $options['debug'])
          { ?><div><span class=red>Шаблон: <strong><? echo ($options['ext'])? $options['ext'].'/'.$func_name:$func_name?></strong></span><br>
                   <?if ($template_dir){?><span class=green>Директория шаблона: <span class=black><? echo hide_server_dir($template_dir)?></span></span><br><?}?>
                   <?if ($template_script)
                   {?><span class=green>Скрипт шаблона: <span class=black><? echo $template_script?></span></span><br>
                   <span class=green>Скрипт найден: <? echo ($template_script_exist)? $GLOBALS['YES']:$GLOBALS['NO']?></span><br>
                   <span class=green>Функция найдена: <? echo ($template_func_exist)? $GLOBALS['YES']:$GLOBALS['NO']?></span><br>
                   <?}?>
                   <?if ($use_prev_include){?><span class=red>Функция шаблона уже определена в ранее подключенных файлах</span><br><?}?>
                   <span class=green>Опции шаблона:</span><? if (_sizeof($options))  damp_array($options,1,-1) ; ?>
              </div>
            <?
          }
    if ($template_func_exist) { if (is_array($rec)) $res=$func_name($rec,$options) ;
                                else if (is_object($rec)) $res=$func_name($rec,$options) ;
                                else                $res=$func_name($options) ;
                              }
    else                      { alert_not_found_template($func_name) ;
                                $res='' ;
    }
    return($res);
  }

  function ext_template($ext,$func_name,$options=array())
  {
      $options['ext']=$ext ;
      print_template($func_name,$options) ;
  }


 // новое обращение к функции - show_message_by_id('orders_message',$result) ;
 function show_message_by_id($group,$mess_id,$result=array())
 { if (is_array($mess_id)) { $result=parse_result($mess_id) ; // переводим результат в стандартный вид - на случай, если модуль старый
                             $mess_id=$result['code'] ;
                           }
   else $result=parse_result($result) ; // переводим результат в стандартный вид - на случай, если модуль старый
   if ($result['code'])
    { $mess_func_name=$group.'_'.$mess_id ;
      $res=0 ;
      if (function_exists($mess_func_name)) $res=$mess_func_name($result['rec']) ;
      else
        {  if (_IS_SYSTEM_IP) echo '<strong>Функция "'.$mess_func_name.'" не найдена. Проверьте наличие подключения файла "messages.php"</strong>' ;
           if ($result['type']=='error') echo '<div class=alert>'.$result['code'].'</div>' ;
           else                          echo '<div class=alert_info>'.$result['code'].'</div>' ;
        }

    }
   return($res) ;
 }



?>
