<?
include_once(_DIR_TO_ENGINE.'/admin/i_clss_func.php') ;

// тестовый класс, для проработки новой системы классов
class clss
{
    public $script_name ;
    public $clss ;
    public $extended_func=array() ;
    public $menu=array() ;
    public $icons='' ;
    public $table_code='' ;
    public $default=array() ;
    public $options=array() ;
    public $fields=array() ;
    public $fields_info=array() ;
    public $no_extended_func=0 ; // указать 1, если у класса точно нет внешних функций-обработчиков - для ускорения создания объекта.
    public $no_show_in_tree=0 ; // указать 1, если класс не надо показывать в дереве объектов
    public $no_create_by_list=0 ; // указать 1, если класс нельзя создавать через список
    public $no_show_child_in_tree=0 ; // указать 1, если  класс не разворачивать в дереве объектов
    public $no_show_dialog_to_create=0 ; // указать 1, если класс не надо показывать в диалоге "Вы можете..."
    public $no_use_trash=0 ; // указать 1, если не удалять объектв в корзину
    public $SEO_tab=0 ; // указать 1, если надо показывать в меню VIEWER вкладку SEO
    public $show_extended_props=0 ; // указать 1, если надо показывать в меню VIEWER вкладка свойства показывать расширенные свойства товара
    public $operations='' ; // название функции -
    public $count_obj_by_page=200 ; // число объектов на одной странице до подгрузки

    // ------------------------------------------------------------------------------
    // обработчики событий
    // ------------------------------------------------------------------------------
    function on_create_event($rec,$options=array()) {} // после создания нового объект, астарый аналог $_SESSION['descr_clss'][XXX]['on_create_event']='clss_XXX_on_create_event' ;

    function before_save_rec($tkey,$pkey,&$rec) {} // перед сохранением записи по объекту в базу, старый аналог $_SESSION['descr_clss'][XXX]['on_save_event']['obj_name']='clss_XXX_on_save_event' ;
    function on_change_event($tkey,$pkey,$fname,&$fvalue) {} // перед сохранением значения поля в базу, вызывает "this->on_change_event_XXX" или "clss_XXX_on_change_event_obj_name" ;
    function on_change_event_XXX($tkey,$pkey,&$fvalue) {}  // аналогично предудущему, но отделная функцию по указанному полю, старый аналог $_SESSION['descr_clss'][XXX]['on_change_event']['obj_name']='clss_XXX_on_change_event_obj_name' ;
    function after_save_rec($tkey,$pkey) {} // после сохранения записи по объекту в базу

    function before_view_rec(&$rec,$options=array()) {} // перед выводом записи объекта в админке, старый аналог $_SESSION['descr_clss'][XXX]['before_view_rec']='clss_XXX_before_view_rec' ;


}

class clss_0 extends clss
{
  var $index=array() ;
  public $name ;
  public $clss ;
  // конструктор
  function __construct($clss=0)
  { $arr=explode('_',__CLASS__) ;
    $this->clss=$arr[1] ;         // присваиваем код класса, на основе которого создается объект
    if ($clss) $this->clss=$clss ; // но если объект создается на остнове родительского класса (его класс не определен) - то код класса будет передан через конструктор

    $this->name=$_SESSION['descr_clss'][$this->clss]['name'] ;
    // собираем инфу по внешним функциям-обработчикам событий - они прописаны в $_SESSION['descr_clss'] или имееют заданный формат названий функций
    // теперь достаточно объявить функцию обработчик в составе класса
    // ВНИМАНИЕ!!! внешние обработчики событий теперь не наследуются - они вызываются только для указанного в объявлении обработчика классе
    // наследуются только обрабочики событий, обявленные в классе
    $this->search_extended_func('on_create_event') ;
    $this->search_extended_func('on_change_event') ;
    $this->search_extended_func('before_view_rec') ;
    $this->search_extended_func('on_save_event') ;

    // объявляем массивы, которые будут собираться по наследованию
    $this->view['list']['options']=array() ;
    $this->view['details']['options']=array() ;

    $mas_parent=$_SESSION['class_system']->tree[$this->clss]->get_list_parent_clss() ;
    // наследуем от предков их свойства
    // объявленное в классе свойство не имеет приоритет над описанным в $_SESSION['descr_clss']
    $default=array() ;$index=array() ; $fields=array() ;  $options=array() ;
    //damp_array($mas_parent,1,-1) ;
    if (_sizeof($mas_parent)) foreach($mas_parent as $parent_clss)
    {
      if (isset($_SESSION['descr_clss'][$parent_clss]['default']))  $default=array_merge($default,$_SESSION['descr_clss'][$parent_clss]['default']) ; // значения полей по умолчнию - суммируем по иеархии
      if (isset($_SESSION['descr_clss'][$parent_clss]['index']))  $index=array_merge($index,$_SESSION['descr_clss'][$parent_clss]['index']) ; // индексные пол - суммируем по иеархии
      if (isset($_SESSION['descr_clss'][$parent_clss]['options']))  $options=array_merge($options,$_SESSION['descr_clss'][$parent_clss]['options']) ; // значения полей по умолчнию - суммируем по иеархии
      if (isset($_SESSION['descr_clss'][$parent_clss]['fields']))   //$fields=array_merge($fields,$_SESSION['descr_clss'][$parent_clss]['fields']) ; // поля класса  - суммируем по иеархии
      {  foreach($_SESSION['descr_clss'][$parent_clss]['fields'] as $fname=>$finfo)
         { if (!is_array($finfo))  { $fields[$fname]=$finfo ;
                                     $this->fields_info[$fname]=array() ;
                                   }
           else  {                 $fields[$fname]=$finfo['type'] ;
                                   unset($finfo['type']) ;
                                   $this->fields_info[$fname]=$finfo ;

                                   if (is_array($_SESSION['descr_clss'][$parent_clss]['list']['field'][$fname])) $_SESSION['descr_clss'][$parent_clss]['list']['field'][$fname]=array_merge($_SESSION['descr_clss'][$parent_clss]['list']['field'][$fname],$finfo) ;
                                   else if (isset($_SESSION['descr_clss'][$parent_clss]['list']['field'][$fname]))
                                   { $finfo['title']=$_SESSION['descr_clss'][$parent_clss]['list']['field'][$fname] ;
                                     $_SESSION['descr_clss'][$parent_clss]['list']['field'][$fname]=$finfo ;
                                   }

                                   if (is_array($_SESSION['descr_clss'][$parent_clss]['details']['field'][$fname])) $_SESSION['descr_clss'][$parent_clss]['details']['field'][$fname]=array_merge($_SESSION['descr_clss'][$parent_clss]['details']['field'][$fname],$finfo) ;
                                   else if (isset($_SESSION['descr_clss'][$parent_clss]['details']['field'][$fname]))
                                   { $finfo['title']=$_SESSION['descr_clss'][$parent_clss]['details']['field'][$fname] ;
                                     $_SESSION['descr_clss'][$parent_clss]['details']['field'][$fname]=$finfo ;
                                   }

                 }

           if (isset($default[$fname])) $this->fields_info[$fname]['default']=$default[$fname] ;
           else if (isset($this->fields_info[$fname]['default'])) $default[$fname]=$this->fields_info[$fname]['default'] ;

           if (isset($index[$fname])) $this->fields_info[$fname]['index']=$index[$fname] ;
           else if (isset($this->fields_info[$fname]['index'])) $index[$fname]=$this->fields_info[$fname]['index'] ;


         }
      }
      /*
      if (_sizeof($_SESSION['descr_clss'][$parent_clss]['small']['field']))
      {   $this->view['small']['field']=array() ;
          foreach($_SESSION['descr_clss'][$parent_clss]['small']['field']  as $fname=>$item)
          if (!is_array($item)) $this->view['small']['field'][$fname]=(isset($_SESSION['pattern_clss_fields'][$item]))? $_SESSION['pattern_clss_fields'][$item]:array('title'=>$item) ;
          else                  $this->view['small']['field'][$fname]=$item ;
      }
      */

      if (_sizeof($_SESSION['descr_clss'][$parent_clss]['list']['field']))
      {   $this->view['list']['field']=array() ;
          foreach($_SESSION['descr_clss'][$parent_clss]['list']['field']  as $fname=>$item)
          {
            if (!is_array($item)) $this->view['list']['field'][$fname]=(isset($_SESSION['pattern_clss_fields'][$item]))? $_SESSION['pattern_clss_fields'][$item]:array('title'=>$item) ;
            else                  $this->view['list']['field'][$fname]=$item ;
            // дописываем опции из описания поля
            if (_sizeof($this->fields_info[$fname])) $this->view['list']['field'][$fname]=array_merge($this->view['list']['field'][$fname],$this->fields_info[$fname]) ;
          }
      }

      //damp_array($this->view['list']['field']) ;

      if (_sizeof($_SESSION['descr_clss'][$parent_clss]['details']['field']))
      {   $this->view['details']['field']=array() ;
          foreach($_SESSION['descr_clss'][$parent_clss]['details']['field'] as $fname=>$item)
          { if (!is_array($item)) $this->view['details']['field'][$fname]=(isset($_SESSION['pattern_clss_fields'][$item]))? $_SESSION['pattern_clss_fields'][$item]:array('title'=>$item) ;
            else                  $this->view['details']['field'][$fname]=$item ;
            // дописываем опции из описания поля
            if (_sizeof($this->view['list']['field'][$fname]) and _sizeof($this->fields_info[$fname])) $this->view['list']['field'][$fname]=array_merge($this->view['list']['field'][$fname],$this->fields_info[$fname]) ;
          }
      }

      //damp_array($this->view['list']['options']) ;
      //if ($this->clss==210) damp_array($_SESSION['descr_clss'][$parent_clss]['list']['options']) ;
      //if ($this->clss==210) echo $parent_clss.'<br>' ;

      if (isset($_SESSION['descr_clss'][$parent_clss]['list']['options']))      $this->view['list']['options']=array_merge($this->view['list']['options'],$_SESSION['descr_clss'][$parent_clss]['list']['options']) ;
      if (isset($_SESSION['descr_clss'][$parent_clss]['details']['options']))   $this->view['details']['options']=array_merge($this->view['details']['options'],$_SESSION['descr_clss'][$parent_clss]['details']['options']) ;
      if (isset($_SESSION['descr_clss'][$parent_clss]['show_extended_props']))  $this->show_extended_props=$_SESSION['descr_clss'][$parent_clss]['show_extended_props'] ;
      if (isset($_SESSION['descr_clss'][$parent_clss]['no_show_in_tree']))      $this->no_show_in_tree=$_SESSION['descr_clss'][$parent_clss]['no_show_in_tree'] ;
      if (isset($_SESSION['descr_clss'][$parent_clss]['no_create_by_list']))    $this->no_create_by_list=$_SESSION['descr_clss'][$parent_clss]['no_create_by_list'] ;
      if (isset($_SESSION['descr_clss'][$parent_clss]['no_show_child_in_tree']))  $this->no_show_child_in_tree=$_SESSION['descr_clss'][$parent_clss]['no_show_child_in_tree'] ;
      if (isset($_SESSION['descr_clss'][$parent_clss]['no_show_dialog_to_create']))  $this->no_show_dialog_to_create=$_SESSION['descr_clss'][$parent_clss]['no_show_dialog_to_create'] ;
      if (isset($_SESSION['descr_clss'][$parent_clss]['no_use_trash']))         $this->no_use_trash=$_SESSION['descr_clss'][$parent_clss]['no_use_trash'] ;
      if (isset($_SESSION['descr_clss'][$parent_clss]['SEO_tab']))              $this->SEO_tab=$_SESSION['descr_clss'][$parent_clss]['SEO_tab'] ;
      if (isset($_SESSION['descr_clss'][$parent_clss]['parent_to']))            $this->parent_to=$_SESSION['descr_clss'][$parent_clss]['parent_to'] ;
      if (isset($_SESSION['descr_clss'][$parent_clss]['child_to']))             $this->child_to=$_SESSION['descr_clss'][$parent_clss]['child_to'] ;
      if (isset($_SESSION['descr_clss'][$parent_clss]['menu']))                 $this->menu=$_SESSION['descr_clss'][$parent_clss]['menu'] ; // набор пунктов меню
      if (isset($_SESSION['descr_clss'][$parent_clss]['icons']))                $this->icons=$_SESSION['descr_clss'][$parent_clss]['icons'] ; // набор иконок объекта
      if (isset($_SESSION['descr_clss'][$parent_clss]['table_code']))           $this->table_code=$_SESSION['descr_clss'][$parent_clss]['table_code'] ; // набор иконок объекта
    }

    if (_sizeof($default)) $this->default=array_merge($default,$this->default) ;
    if (_sizeof($options)) $this->options=array_merge($options,$this->options) ;
    if (_sizeof($fields))  $this->fields=array_merge($fields,$this->fields) ;
    if (_sizeof($index))  $this->index=array_merge($index,$this->index) ;

    if ($this->view['list']['field']) foreach($this->view['list']['field'] as $fname=>$item) { if ($item['use_HTML_editor']==1) $this->fields_info[$fname]['use_HTML_editor']=1 ; }

    if ($this->view['details']['field']) foreach($this->view['details']['field'] as $fname=>$item) { if ($item['use_HTML_editor']==1) $this->fields_info[$fname]['use_HTML_editor']=1 ; }



    //damp_array($this) ;
    //$this->list=$_SESSION['descr_clss'][$this->clss]['list'] ;
    //echo 'Отработал конструктор для clss_'.$this->clss.' в классе '.__CLASS__.'<br>' ;
    //echo __CLASS__.'<br>' ;
    //echo __FILE__.'<br>' ;
  }

  // -----------------------------------------------------------------------------------------------------------------------------------------------------------------------
  //
  // ОБРАБОТЧИКИ СОБЫТИЙ
  //
  // -----------------------------------------------------------------------------------------------------------------------------------------------------------------------

  // обоработчик события изменения поля объекта класса при сохранении нового значения
  // вернуть 1, для разрешения сохранения
  // вернуть 0 - изменение не будет сохранено
  function on_change_event($tkey,$pkey,$fname,&$fvalue)
  {  $res=1 ;
     // сначала пытаемся найти обработчик события в классе
     $method_name='on_change_event_'.$fname ;
     if (method_exists($this,$method_name)) $res=$this->$method_name($tkey,$pkey,$fvalue) ;
     // иначе вызываем старый обработчик события, если он определен
     elseif (isset($this->extended_func) and isset($this->extended_func['on_change_event'][$fname]))
     { $func_params=$this->extended_func['on_change_event'][$fname] ;
       if (!is_array($func_params)) $res=$func_params($tkey,$pkey,$fvalue) ;
       else
       { $func_to_exec=DESKTOP()->include_script_cmd($func_params['cmd'],$func_params['script'],$func_params) ;
         if ($func_to_exec) $res=$func_to_exec($tkey,$pkey,$fvalue) ;
       }
     }
     return($res) ;
  }

  function before_save_rec($tkey,$pkey,&$rec)
  { // для совместимости старого формата on_save_event.
    if (isset($this->extended_func) and isset($this->extended_func['on_save_event']))
       { $func_name=$this->extended_func['on_save_event'] ;
         if (function_exists($func_name)) $func_name($tkey,$pkey,$rec) ;
       }
  }

  function after_save_rec($tkey,$pkey) {}


  // ищем внешние функции обработчики - они остались от старой модели классов и могут быть объявлены как обычные функции с формализованным названием
  function search_extended_func($event_name)
  {  if ($this->no_extended_func) return ;
     //damp_array($_SESSION['descr_clss'][$this->clss][$event_name]) ;
     // ищем прописанные в descr_clss обработчики событий - без проверки на существование функции
     if ($_SESSION['descr_clss'][$this->clss][$event_name]/* and function_exists($_SESSION['descr_clss'][$this->clss][$event_name])*/) $this->extended_func[$event_name]=$_SESSION['descr_clss'][$this->clss][$event_name] ;
     else  // ищем функции с формализованным названием
     { $event_func_name='clss_'.$this->clss.'_'.$event_name ;
       if (function_exists($event_func_name)) $this->extended_func[$event_name]=$event_func_name ;
     }
  }

  // -----------------------------------------------------------------------------------------------------------------------------------------------------------------------
  //
  //  ВЫВОД ОБЪЕКТОВ КЛАССА В ДЕРЕВО
  //
  // -----------------------------------------------------------------------------------------------------------------------------------------------------------------------

  // возвращает кол-во элементов, показанных в дереве
  // возвращать кол-во надо, так как не все классы показываются в дереве
  function print_list_recs_to_tree($recs,$options=array())
  { $cnt=0 ;      //  damp_array($recs) ;
    if (_sizeof($recs)) foreach ($recs as $rec) $cnt+=$this->print_rec_to_tree($rec,$options) ;
    return($cnt) ;
  }

  // показ одного элемента в дереве
  // возвращает 1, если элемент был показа, 0, если не был показан
  function print_rec_to_tree($rec,$options=array())
  { //if (!$this->no_show_in_tree) return(0) ;
    $this->prepare_public_info($rec) ;
    $_attr=array() ;
    if ($rec['code']) $_attr[]='code='.$rec['code'] ;
    if ($rec['clss']) $_attr[]='clss='.$rec['clss'] ;
    if ($rec['_reffer']) $_attr[]='reffer="'.$rec['_reffer'].'"' ;
    if ($rec['_in_tree_child_cnt'] and !$this->no_show_child_in_tree) $_attr[]='cnt='.$rec['_in_tree_child_cnt'] ;
    if (!$rec['enabled'])     $_attr[]='off' ;
    if ($rec['start_time'])   $_attr[]='start_time='.$rec['start_time'] ;
    if ($rec['end_time'])     $_attr[]='end_time='.$rec['end_time'] ;
    if ($options['attr'])     $_attr[]=$options['attr'] ;

    $attr=' '.implode(' ',$_attr) ;
    $cnt_info=($rec['_in_tree_child_cnt'] and !$this->no_show_child_in_tree)? '('.$rec['_in_tree_child_cnt'].')':'' ;
    echo '<li'.$attr.'><span class=name>'.$rec['_in_tree_name'].'</span><span class=cnt>'.$cnt_info.'</span></li>' ;
    return(1) ;
  }



  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)
  {   $name=$rec['obj_name'] ;
      $name=trim(strip_tags($name))  ;   // удаляем начальные и конечные пробелы и HTML-теги
      $name=str_replace(array("\n"),array(''),$name) ; // удяляем переносты строк
      if (!$name) $name='# '.$rec['pkey'] ;
      $rec['_in_tree_name']=$name ;
      if (isset($rec['_child_cnt'])) $rec['_in_tree_child_cnt']=$this->prepare_child_cnt_to_tree($rec['_child_cnt']) ;
      if (isset($this->parent_to) and !_sizeof($this->parent_to)) $rec['_in_tree_child_cnt']=0 ;
  }

  // получает суммарное кол-во дочерних объектов, которое будет показано в дереве
  // на основании инфы по кол-ву дочeрних объектов и правилам вывода дочерних объектов
  function prepare_child_cnt_to_tree($arr_clss_cnt)
  { $sum=0 ;
    if (is_array($arr_clss_cnt) and _sizeof($arr_clss_cnt)) foreach($arr_clss_cnt as $clss=>$cnt) if (!_CLSS($clss)->no_show_in_tree) $sum+=$cnt ;
    return($sum) ;
  }

  // возвращает имя класса для объекта, который будет дочерним для $tkey,$pkey
  function name($parent_reffer='')
  {  $tkey=0 ; $pkey=0 ; $name=$this->name ;
     if ($parent_reffer) list($pkey,$tkey)=explode('.',$parent_reffer) ;
     // если класс находиться в out таблице, название класса берем из названия out-таблицы
     //if ($tkey and isset(_DOT($tkey)->list_clss_ext[$this->clss]['out'])) $name=_DOT(_DOT($tkey)->list_clss_ext[$this->clss]['out'])->name ;
     // читаем правила для таблицы, правило типа array('to_pkey'=>64,'only_clss'=>11,'name_as'=>'Проект')
     // читаем правила для таблицы, правило типа array('to_pkey'=>64,'to_clss'=>11,'name_as'=>'Проект')
     if ($tkey and _sizeof(_DOT($tkey)->rules)) foreach(_DOT($tkey)->rules as $rec) if (($rec['only_clss']==$this->clss or $rec['to_clss']==$this->clss) and $rec['name_as']) // отбираем рравила для текущего класса
     {  //print_r($rec) ; echo '<br>' ;
        if (!$rec['to_pkey']) $name=$rec['name_as'] ; // если кв правиле не используетмя код объекта  - применяеме правило
        if ($pkey)
        { if ($rec['to_pkey']==$pkey)   $name=$rec['name_as'] ; // если код передан и код правила=переданнуму  - применяем правило
          else { $arr_parent_id=get_obj_parents_ids($parent_reffer) ; //print_r($arr_parent_id) ; echo '<br>' ;
                 // проверяем, есть ли правило для родительского элемента и данного класса
                 if (_sizeof($arr_parent_id)) foreach($arr_parent_id as $parent_id)
                    if ($parent_id==$rec['to_pkey']) { $name=$rec['name_as'] ; break ; }
               }
        }

     }
     return($name) ;

  }

// возвращает массив класс=имя, которые возможно добавлять в качестве дочерних к классу $clss таблицы $tkey
 function get_adding_clss($tkey,$pkey=0,$debug=0)
 { $return_list=array() ;

   if (_sizeof(_DOT($tkey)->list_clss)) $res_list=array_keys(_DOT($tkey)->list_clss) ; // по умолчанию используем список классов таблицы
   if ($debug) { print_r($res_list) ; echo '<br>' ; }
   if ($debug) { damp_array($this) ; echo '<br>' ; }

   if(is_array($this->parent_to)) $res_list=$this->parent_to; // если в descr_clss[$clss]['parent_to'] прямо указан список классов используем его
   if ($debug) { print_r($res_list) ; echo '<br>' ; }
   // добавляем классы, которое указают себя в качестве дочерних к данному классу
   if (_sizeof(_DOT($tkey)->list_clss)) foreach(_DOT($tkey)->list_clss as $table_clss=>$table_tkey) if (_sizeof(_CLSS($table_clss)->child_to) and array_search($this->clss,_CLSS($table_clss)->child_to)!==false) $res_list[]=$table_clss ;
   if ($debug) { print_r($res_list) ; echo '<br>' ; }
   //damp_array($res_list) ;
   // читаем правила для таблицы, правило типа:
   //  array('to_pkey'=>64,'only_clss'=>11,'name_as'=>'Проект') // разрешаем добавлять в объект id=64 только классы 11, назвать "проект"
   //  array('to_clss'=>10,'only_clss'=>array(3,11))
   //  array('to_clss'=>10,'only_clss'=>11)
   if ($debug) echo 'tkey='.$tkey.'<br>pkey='.$pkey.'<br>this->clss='.$this->clss.'<br>' ;
   $clss_by_rules=array() ;
   //echo 'this->clss=' ; echo $this->clss.'<br>' ;
   if ($debug) echo 'Правила для таблицы:'.print_r(_DOT($tkey)->rules,true).'<br>Всего '._sizeof(_DOT($tkey)->rules).' правил<br>' ;
   if ($tkey and _sizeof(_DOT($tkey)->rules)) foreach(_DOT($tkey)->rules as $rec) if (isset($rec['only_clss'])) // если задано условие ограничения класса
   {  if ($debug) echo 'Проверяем правило:'.print_r($rec,true).'<br>' ;
      $_clss=0 ;
      if (!$rec['to_pkey'] and !$rec['to_clss'])            $_clss=$rec['only_clss'] ; // для правила   [only_clss] => 11 [name_as] => Прайс-лист
      if (!$rec['to_pkey'] and  $rec['to_clss'] and $rec['to_clss']==$this->clss) $_clss=$rec['only_clss'] ; // для случаев когда надо собрать все классы таблицы, определяемые правилами
      if ($pkey and $rec['to_pkey']==$pkey)                 $_clss=$rec['only_clss'] ; // для правила  [to_pkey] => 99 [only_clss] => 11 [name_as] => Прайс-лист
      //echo '$_clss=' ; print_r($_clss) ; echo '<br>' ;
      if (is_array($_clss)) { foreach($_clss as $clss)      $clss_by_rules[]=$clss ; break ; } // применяем только одно правило - то, кторое идет первым
      else if ($_clss)      {                               $clss_by_rules[]=$_clss ; break ; }
   }
   if ($debug) echo 'Классы по заданным правилам:'.print_r($clss_by_rules,true).'<br>' ;
   //damp_array($clss_by_rules) ;
   if (_sizeof($clss_by_rules)) $res_list=$clss_by_rules ;
   if (_sizeof($res_list)) $res_list=array_unique($res_list) ; // удаляем дубликаты классов

   // удаляем из данного списка классы, которых не поддерживаются текущей таблицей
   //print_r($res_list);
   if (_sizeof($res_list)) foreach($res_list as $i=>$res_clss)
    { if (!isset(_DOT($tkey)->list_clss[$res_clss])) unset($res_list[$i]) ;
      // удаляем из данного списка системные классы
      if ($res_clss==112) unset($res_list[$i]) ;

    }

   if (_sizeof($res_list)) foreach($res_list as $i=>$res_clss) if (!isset(_DOT($tkey)->list_clss[$res_clss])) unset($res_list[$i]) ;


   // удаляем из списка классы, в descr_clss[$clss]['child_to'] прямо указаны разшененные классы
   if (_sizeof($res_list)) foreach($res_list as $i=>$res_clss)
    if (is_array(_CLSS($res_clss)->child_to) and !in_array($this->clss,_CLSS($res_clss)->child_to)) unset($res_list[$i]) ;
   // добавляем имена классов в массив
   if (_sizeof($res_list)) foreach($res_list as $res_clss) $return_list[$res_clss]=_CLSS($res_clss)->name($pkey.'.'.$tkey) ;
   return($return_list) ;
 }


  // -----------------------------------------------------------------------------------------------------------------------------------------------------------------------
  //
  //  ВЫВОД ОБЪЕКТОВ КЛАССА В VIEWER - показ списка дочерних объектов
  //
  // -----------------------------------------------------------------------------------------------------------------------------------------------------------------------

  // вывод дочерних объектов объекта
  function show_list_children($obj_rec,$options=array())
  {  $options['page']=1 ;
     //$options['cur_obj_rec']=$obj_rec ;
     //unset($options['clss']);
     //return ;
     damp_array($options) ;

     //damp_array(get_included_files(),1,-1) ;
     if (isset($options['show_clss']))
     { $tkey_clss=_DOT($obj_rec['tkey'])->list_clss[$options['show_clss']] ;
       _CLSS($options['show_clss'])->show_list_items($tkey_clss,'parent='.$obj_rec['pkey'],$options);
       // показ дочерних объектов через отчет
       $this->view_childs_objects(array('show_clss'=>$options['show_clss'],'clss'=>$obj_rec['clss'],'reffer'=>$obj_rec['_reffer'])) ;


     }
     else
     { $child_info=select_obj_childs_clss_cnt($obj_rec['_reffer']) ;
       //print_2x_arr($child_info) ;
       if (_sizeof($child_info)) foreach($child_info as $clss=>$cnt)
       { $tkey_clss=_DOT($obj_rec['tkey'])->list_clss[$clss] ;
         /*?><h2><?echo _CLSS($clss)->name($obj_rec['_parent_reffer'])?></h2><?*/
         _CLSS($clss)->show_list_items($tkey_clss,'parent='.$obj_rec['pkey'],$options);
       }
     }

  }

    function view_childs_objects($options=array())
    { list($pkey,$tkey)=explode('.',$options['reffer']) ;
      ?><div id="report_objects_clss_<?echo $options['show_clss']?>"><?
      include_once(_DIR_EXT.'/class/report_objects.php') ;
      $report_obj=new report_objects() ;
      $report_obj->no_view_title=1 ;
      $report_obj->table_name=_DOT($tkey)->table_name ;
      $report_obj->root_id=$pkey ;
      if ($options['show_clss']) $report_obj->view_clss=$options['show_clss'] ;
      //$report_obj->view_panel_info=0 ;
      $report_obj->setting() ;
      //$report_obj->panel_info_filter() ;
      $report_obj->view() ;
      ?></div><?

      $options=array_merge($this->view['list']['options'],$options) ;
      damp_array($options) ;
      if (_sizeof($options['buttons'])) $this->show_buttons($options) ;
    }

  function before_view_rec(&$rec,$options=array())
  {
     if (isset($this->extended_func['before_view_rec']))
       { $func_name=$this->extended_func['before_view_rec'] ;
         $func_name($rec,$options) ;
       }
  }

  // вывод списка объектов - взамен cmd_show_clss_0_list
  // функция работает в двух режимах - с двумя наборами параметров
  // 1. - show_list_items($list_obj,$options=array()) - вывод готового списка записей, первый параметр - массив
  // 2. - show_list_items($table_id,$usl='',$options=array()) - вывод записей, которые будут отобраны по условию, первый параметр - строка или число
  // $options:  - order:        - вид и направление сортировки, можно задавать вместо отдельных опций order_by и order_mode, например, "c_data desc"
  //            - order_by      - вид сортировки, указывать поле сортировки, например "obj_name"
  //            - order_mode    - направление сортировки, значение "desc" или "asc"
  //            - default_order - вид и направление сортировки по умолчанию, если список выводися первый раз за время работы сессии
  //            - buttons       - описание кнопок после вывода списка записей. Указать либо код кнопки:
  //                                $options['buttons']=array('save','create','delete','copy')
  //                              либо краткое описание кнопки:
  //                                $options['buttons']=array('save','create','delete','copy','mail_self_test'=>'Проверка на себя')
  //                              либо массив с описанием:
  //                                $options['buttons']=array('save','create','delete','copy',array('title'=>'Проверка на себя','cmd'=>'mail_self_test')) - все опции массива описания кнопки кроме title будут помещены в атрибуты кнопки
  //            - count         - ограничение по числу выводимых записей
  //            - title         - заголовок таблицы
  //            - no_check      - не показывать чекбоксы выбора строки
  //            - no_icon_edit  - не показывать иконки редактирования записи строки
  //            - no_icon_photo  - не показывать иконки фото
  //            - cur_obj_rec
  //            - return_cur_rec - вернуть выведенную запись - чтобы не получать его отдельным запросом при обновлении дерева

  function show_list_items($table_id,$usl='',$options=array())
  {
     include_once(_DIR_TO_ENGINE.'/admin/i_clss_func.php') ;
     $options_select=array() ; $next_page=0 ;
     if (!$options['page']) $options['page']=1 ;

     if (is_array($table_id))
      {  $list_obj=$table_id ;
         $options=$usl ;
         $options['no_ext_func']=1 ; // запрет вызова расширенных функций
         $options['clss']=$this->clss ; // запрет вызова расширенных функций
         $this->show_based_obj_list($list_obj,$options) ; // пока просто вызываем стурую функцию из i_clss_func.php
         return(array()) ;
      }
     else
     {   list($tkey,$table_name)=check_table_tkey($table_id) ; // table_id может быть как имя таблицы, так и её код или название подсистемы
         // определяем имя и код таблицы, где храняться объекты отображаемого класса
         $clss_table_id=_DOT($tkey)->list_clss[$this->clss] ;
         if (!$clss_table_id)
         { echo '<div class=alert>Объекты класса '.$this->clss.' не поддерживаются текущей таблицей</div>' ;
           return(array()) ;
         }
         $options=array_merge($this->view['list']['options'],$options) ;
         damp_array($this->view['list']['options']) ;

         //echo '$this->clss='.$this->clss.'<br>' ;
         //echo '$clss_table_id='.$clss_table_id.'<br>' ;
         $clss_table_name=$_SESSION['tables'][$clss_table_id] ; //echo '$clss_table_name='.$clss_table_name.'<br>' ;
         // готовим запрос для выборки объектов
         $usl_select='clss='.$this->clss ;
         if ($usl) $usl_select.=' and '.$usl ;
         if ($options['usl_filter']) $usl_select.=' and '.$options['usl_filter'] ;

         //echo 'usl='.$usl.'<br>' ;
         //echo 'usl_filter='.$options['usl_filter'].'<br>' ;


         if (!$options['default_order']) $options['default_order']='indx asc' ;
         list($def_order,$def_mode)=explode(' ',$options['default_order']) ;
         if (!$_SESSION['table_order'][$tkey][$this->clss]['order_by']) $_SESSION['table_order'][$tkey][$this->clss]['order_by']=$def_order ;
         if (!$_SESSION['table_order'][$tkey][$this->clss]['order_mode']) $_SESSION['table_order'][$tkey][$this->clss]['order_mode']=$def_mode ;
         //damp_array($options) ; echo '---------------------------------------------------------' ;
         //damp_array($_SESSION['table_order'][$tkey][$this->clss]) ; echo '---------------------------------------------------------' ;
         if ($options['order']) list($options['order_by'],$options['order_mode'])=explode(' ',$options['order']) ;

         if (!$options['order_by'])   $options['order_by']=$_SESSION['table_order'][$tkey][$this->clss]['order_by'] ;
         if (!$options['order_mode']) $options['order_mode']=$_SESSION['table_order'][$tkey][$this->clss]['order_mode'] ;

         $options_select['order_by']=$options['order_by'].' '.$options['order_mode'] ;

         // делаем запрос на общее число объектов без разбиения на страницы
         $count_recs=execSQL_value('select count(pkey) from '.$clss_table_name.'  where '.$usl_select.$options_select['limit']) ; //

         if ($options['count']) // если задано число выводимых строк, разбивку на страницы не производим
         {  $from_pos=0 ;
            if ($options['count']<$count_recs) $count_recs=$options['count'] ;  // если в базе более записей чем надо показать, то считаеи число записаей = $options['count']
            $to_pos=$count_recs ;
            $options_select['limit']=' limit '.$options['count'] ;
         }
         else // иначе по текущей страницы определяем параметры limit для запроса
         {  $from_pos=($options['page']-1)*$this->count_obj_by_page ;
            $to_pos=$from_pos+$this->count_obj_by_page ;
            if ($to_pos>$count_recs) $to_pos=$count_recs ;
            $options_select['limit']='limit '.$from_pos.','.$this->count_obj_by_page ;
            $ostatok=$count_recs-$to_pos ;
            $next_page=($to_pos<$count_recs)? ($options['page']+1):0 ;
         }
         //echo '$usl_select='.$usl_select.'<br>' ;
         if ($options['link_to']) $options_select['link_to']=$options['link_to'] ;
         //damp_array($options_select) ;
         //$options_select['debug']=1 ;
         //damp_array($options_select) ;
         $options_select['debug']=$options['debug'] ;

         $list_items=select_db_recs($clss_table_id,$usl_select,$options_select) ;
         //print_2x_arr($list_items) ;
         $this->prepare_public_info_for_arr($list_items) ;
         //print_2x_arr($list_items) ;

         // если задана опция показывать свойства объекта вместо одной записи
         if ($options['show_van_rec_as_item'] and _sizeof($list_items)==1)
         {  list($id,$rec)=each($list_items) ;
            $this->show_props($rec) ;
            return(array()) ;
         }

         $options['info_count_text']='1...'.$to_pos.' из '.$count_recs  ;

         ///damp_array($list_items) ;
         if ($options['only_tr_content']) $this->show_based_obj_list($list_items,$options) ;   // будет вызвана функция show_based_obj_list($list_obj,$options) ;
         else
         {   $list_id='list_'.rand(1,1000000) ;
             ?><div class="list_item" id="<?echo $list_id?>" tkey="<?echo $tkey?>" clss="<?echo $this->clss?>" usl="<?echo $usl?>" usl_filter="<?echo $options['usl_filter']?>" list_id="<?echo $list_id?>"  read_only="<?echo $options['read_only']?>" no_check="<?echo $options['no_check']?>" no_icon_edit="<?echo $options['no_icon_edit']?>" no_view_field="<?echo $options['no_view_field']?>" no_icon_photo="<?echo $options['no_icon_photo']?>" order_by="<?echo $options['order_by']?>" order_mode="<?echo $options['order_mode']?>" count="<?echo $options['count']?>"><?
                if (_sizeof($list_items))
                  { if ($count_recs>50 and _sizeof($options['buttons'])) { $this->show_buttons($options) ; echo '<br>' ; }
                    $this->show_based_obj_list($list_items,$options) ;   // будет вызвана функция show_based_obj_list($list_obj,$options) ;
                    if ($next_page) {?><div class=next_page><input type="button" class=view_page page="<?echo $next_page?>" value="Еще <?echo $ostatok?> строк"></div><?}
                    // показываем кнопки списка
                    //damp_array($options) ;
                    if (_sizeof($options['buttons'])) $this->show_buttons($options) ;
                  }
                else echo '<div class=empry_list>Ничего не найдено</div>' ;
             ?></div><?
         }
         if ($to_pos>$count_recs) $to_pos=$count_recs ;
         $result=array('from'=>$from_pos+1,'to'=>$to_pos,'all'=>$count_recs,'next_page'=>$next_page) ;
         if (_sizeof($list_items)==1 and $options['return_cur_rec'])
         { reset($list_items) ;
           list($id,$rec)=each($list_items) ;
           $result['cur_rec']=$rec ;
         }
         return($result) ;
     }
  }

  // $options['buttons']  - описание кнопок
  // $options['cur_obj_rec'] - запись по текущенму объекту страницы
  function show_buttons($options=array())
  { //damp_array($options) ;
    $arr_buttons=$options['buttons'] ;  // damp_array($arr_buttons,1,-1) ;
    if (_sizeof($arr_buttons)) foreach($arr_buttons as $button_cmd=>$rec_button)
      if (is_array($rec_button) and _sizeof($rec_button)) {?><button <?foreach($rec_button as $key=>$value) if ($key!='title') echo $key.'="'.$value.'" '?>><?echo $rec_button['title']?></button><?}
      else switch($rec_button)
       {  case 'save':    ?><button cmd=save_list mode=tr_update>Сохранить</button><? break ;
          case 'delete':  ?><button cmd=delete_check_objs data-confirm="Вы действительно хотите удалить выбранные объекты?">Удалить</button><? break ;
          case 'copy':    ?><button cmd=add_obj_to_cart>Копировать</button><? break ;
          case 'create':  $parent_reffer=($options['cur_obj_rec']['_reffer'])? $options['cur_obj_rec']['_reffer']:$_POST['parent_reffer'] ;
                          if ($parent_reffer) echo $this->get_create_button_html($parent_reffer) ; break ; // показываем кнопку для создания объекта определенного класса
          default:        ?><button cmd=<?echo $button_cmd?>><?echo $rec_button?></button><? break ;
       }
  }

  // возвращает текст html кнопки для создания объекта
  // часть классов создают новые объекты через модальное окно - у них метод будет переопределен
  function get_create_button_html($parent_reffer)
    { $text='<button mode=append_viewer_main cmd=create_obj clss="'.$this->clss.'" parent_reffer="'.$parent_reffer.'">Создать еще '.$this->name($parent_reffer).'</button>'  ;
      return($text) ;
    }

  // возвращает текст html ссылки для создания объекта
  function get_create_a_html($parent_reffer)
    { $text='<a href="#" class=button mode=append_viewer_main  cmd=create_obj clss="'.$this->clss.'" parent_reffer="'.$parent_reffer.'">'.$this->name($parent_reffer).'</a>'  ;
      return($text) ;
    }

  function panel_fast_search() {}
  function prepare_search_usl() {}


 // вывод списка объектов как стандартных объектов
 // при выводе объектов используем список полей класса
 // ожижвается, что объекту будут одного класса!!!!!
 // определение происходит по первой записи
 // параметры:
 // arr_rec = array (pkey => array (obj_info),....)
 // options - массив набора параметров
 //  - read_only 	0/1
 //	 - no_header	0/1 не показывать заголовки
 //  - small		0/1 вывод в краткой форме (enabled,indx,obj_name)
 //  - no_check		0/1 не показывать чекбокс выбора объекта, если read_only=1, то = 1
 //  - no_indx_enabled 0/1 не показывать попя indx enabled в режиме small

 function show_based_obj_list(&$arr_rec,$options=array())
 {
   //damp_array($arr_rec) ;
   //trace() ;
   if (!_sizeof($arr_rec)) { if (!$options['no_show_not_found']) echo '<p class=alert>Ничего не найдено</p>' ; return ; }
   // берем tkey и clss из первой записи
   reset($arr_rec); list($first_pkey,$first_rec)=each($arr_rec) ; prev($arr_rec) ; //print_r($first_rec) ;
   $tkey=$first_rec['tkey'] ;
   $clss=($options['clss'])? $options['clss']:$first_rec['clss'] ; //echo 'clss='.$clss ; echo '<br>' ;
   // tckb
   //damp_array($arr_rec) ;

   // если в init.php задан шаблон вывода объектов текущего класса, то использовать его
   // список полей для быстрого редактирования будет или задан для таблицы или взять с класса по умолчанию
   $list_block=($options['small'])? 'small':'list' ;
   $edit_list=_CLSS($clss)->view[$list_block]['field'] ; //damp_array($edit_list); echo '<br>' ;
   $options['space_value']='1111' ; // массив не должен быть пустым - иначе php может зависнуть
   if (is_array(_CLSS($clss)->view[$list_block]['options'])) $options=array_merge($options,_CLSS($clss)->view[$list_block]['options']) ;
   $options['edit_by_click']=1 ;
   //$options['debug']=2 ;
   //echo 'clss='.$clss ; //echo '<br>' ; exit ;
   //print_r($arr_rec);  echo '<br>' ;
   //print_r($options); echo '<br>' ;

   //$full_size=_sizeof($arr_rec) ; //echo '$full_size='.$full_size.'<br>' ;

   //$start_indx=0 ; $cur_size=_sizeof($arr_rec) ;

   // если у объектов таблицы есть фото в дочерних элементах - получаем информацию о количесте фото для каждого выводимого элемента
   if (_DOT($tkey)->list_clss[3]) update_obj_all_image(_DOT($tkey)->list_clss[3],$arr_rec) ;

   //damp_array($options) ;
   /* отключено 1.02.13 - переделан вывод для CLSS 100
   if (_sizeof($options['list_reffers_obj']))
   {list($_id,$_rec)=each($options['list_reffers_obj']) ;
     if (_DOT($_rec['tkey'])->list_clss[3]) update_obj_all_image(_DOT($_rec['tkey'])->list_clss[3],$options['list_reffers_obj']) ;
   } */
   //damp_array($options) ;

   $title=($options['title'])? $options['title']:_CLSS($clss)->name($options['cur_obj_rec']['_reffer']) ;
   /*?><h2><?echo $title?></h2><?*/

   if (!$options['only_tr_content'] )
   { ?><table class="clss list"><?
     $this->print_table_colgroup($tkey,$clss,$edit_list,$options) ;
   }

   if (!$options['no_header'] and !$options['only_tr_content']) // выводим заголовок таблицы
   {

      $header_options['colspan']=100 ; //_sizeof($edit_list)+3 ;
      $header_options['icon_clss']=$clss ;
      $header_options['page_info']=$options['info_count_text'] ;

      if (!$options['no_table_header']) $this->print_table_header($title,$header_options) ;

	      ?><tr class=td_header><?
	          $this->print_td_header($tkey,$clss,$edit_list,$options) ;

		      // если передан списко ссылающихся обхектов, то выводим их заголовки тоже
              /* отключено 1.02.13 - переделан вывод для CLSS 100
			  if (_sizeof($options['list_reffers_obj']))
              { //damp_array($options['list_reffers_obj']);
                //list($id,$obj_ref)=each($options['list_reffers_obj']) ;
                //damp_array($options) ;
                $RF_edit_list=_CLSS($options['list_reffers_obj_clss'])->view['list']['field'] ;
                $this->print_td_header($options['list_reffers_obj_tkey'],$options['list_reffers_obj_clss'],$RF_edit_list,array('read_only'=>1,'no_check'=>1)) ;
              } */

	      ?></tr><?
   }

   // выводим содержимое полей
   //print_r($arr_rec) ; echo '<br>' ;
   //echo 'tkey='.$tkey ; echo '<br>' ;

    //damp_array(get_included_files()) ;

    if (_sizeof($arr_rec)) foreach ($arr_rec as $rec)
    {
        $this->view_obj_item($rec,$edit_list,$options) ;

	}
    if (!$options['only_tr_content']) {?></table><?}
    //trace() ;
 }


    function print_table_colgroup($tkey,$clss,$edit_list,$options=array())
    { if (!$options['no_check']) 														    $cols[]='<col id=check>' ;
      if (!$options['read_only'] and !$options['no_icon_edit'] and !$options['_small']) 	$cols[]='<col id=edit>' ;    // временно отключено для  small
      if (!$options['no_icon_photo'] and $clss!=3 and isset(_DOT($tkey)->list_clss[3])) 	$cols[]='<col id=img>' ;

	   if (_sizeof($edit_list)) foreach ($edit_list as $fname=>$edit_info)
	   {

	     //$width='' ; //$width=$edit_list[$fname]['width'] ;
	     //if (!$width)
             $width='auto' ;

	     $i=0 ;
	     if (_DOT($tkey)->list_clss_ext[$clss]['multilang'][$fname] )
           { if (_sizeof($GLOBALS['lang_arr'])) foreach($GLOBALS['lang_arr'] as $lang_info)
             {  $lang_fname=$fname.$lang_info['suff'] ;
                if (isset(_DOT($tkey)->field_info[$lang_fname])) {$cols[]='<col style="'.$width.';">' ; $i++ ;}
             }
           }

         if (!$i) $cols[]='<col style="'.$width.';">' ; // если ничего не было показано - обычный вывод поля
	   }
	  echo '<colgroup>'.implode('',$cols).'</colgroup>' ;
   }

  // заголовок таблицы с типом класса
  function print_table_header($title,$options=array())
  { $obj_clss=_CLSS($options['icon_clss']);
    if ($options['icon_clss']) $icon_text='<div class=clss_icon><img alt="" src='.$obj_clss->icons.' width="16" height="64" alt="" border="0" /></div> ' ;
    if ($options['colspan']) $colspan_text='colspan='.$options['colspan'] ;
    /*?><tr class=clss_header><td <?echo $colspan_text?>><span class=fast_search><input class="fast_search text" type=text></span><span class=setting><?echo $options['page_info']?></span></td></tr><?*/
    ?><tr class=clss_header><td <?echo $colspan_text?>><span class=title><? echo $icon_text.$title?></span><span class=setting><?echo $options['page_info']?></span></td></tr><?
  }


    // показывает запись в виде строки таблицы (<td>...<td><td>...<td><td>...<td><td>...<td>)
    function view_obj_item(&$rec,$edit_list=array(),$options=array())
    {   ?><tr class="item <?echo (!$rec["enabled"])? 'off':'on'?>" reffer="<?echo $rec['_reffer']?>"><?
        $tkey=$rec["tkey"] ;
        $clss=($options['clss'])? $options['clss']:$rec['clss'] ; $rec['clss']=$clss ;

        $obj_clss=_CLSS($clss) ;

        $obj_clss->before_view_rec($rec,$options) ;

        $hidden_fields=(isset($options['no_view_field']))? explode(',',$options['no_view_field']):array() ;
        if (_sizeof($hidden_fields)) foreach($hidden_fields as $fname) unset($edit_list[$fname]) ;

   		// если в init.php задан шаблон вывода объектов текущего класса, то использовать его
   		// список полей для быстрого редактирования будет или задан для таблицы или взять с класса по умолчанию
   		if (!_sizeof($edit_list)) // если список полей не передали ищем сами
   		{ $list_block=($options['small'])? 'small':'list' ;
   		  $edit_list=$obj_clss->view[$list_block]['field'] ; //damp_array($edit_list); echo '<br>' ;
   		  if (is_array($obj_clss->view[$list_block]['options'])) $options=array_merge($options,$obj_clss->view[$list_block]['options']) ;
   		}

        // если объект - ссылка - добавляем соответвующую иконку
        if (_sizeof($rec['__reffer_from'])) $icon_short='<img src="'._PATH_TO_ADMIN_IMG.'/short2.gif" width="16" height="16" alt="Текущая запись - ссылка" border="0" />' ;
         else $icon_short='' ;

        // если разрешено выделение объектов выводим колонку чекбокса
        $check_status=($options['check_all'])? 'checked':'' ;
        if (!$options['no_check'])
          {  include_once(_DIR_TO_ENGINE.'/admin/i_clss_func.php') ;
             if (!_sizeof($rec['__reffer_from'])) $check_box=generate_check($rec["tkey"],$rec["clss"],$rec['pkey'],$rec["parent"],$check_status) ;
            else                                $check_box=generate_check($rec['__reffer_from']['tkey'],$rec['__reffer_from']['clss'],$rec['__reffer_from']['pkey'],$rec['__reffer_from']['parent'],$check_status,$rec['tkey'],$rec["clss"],$rec['pkey'],$rec["parent"],$check_status) ;
            $check_td='<td>'.$icon_short.$check_box.'</td>' ;
          }
        else $check_td='' ;

        $edit_td=$this->get_edit_td($rec,$options) ;

        // если таблица поддерживает фото, то значок для добавления фото объекта
        $icon_edit_img=(!$options['read_only'])? '<img class=v2 cmd=panel_obj_img_upload parent_reffer="'.$rec['_reffer'].'" clss=3 after_close_window="update_tr_rec" src="'._PATH_TO_ADMIN_IMG.'/tree_close.gif" alt="Редактировать фото" border="0" />':'' ;

        // показ иконки изображения объекта
        // будет показано фото, кроме объектов "фото" и наследуемых от них - у них показ фото отдельным "edit_element"
        if (!$options['no_icon_photo'] and $clss!=3 and isset(_DOT($tkey)->list_clss[3]))
        { if ($rec["_image_name"])
               { $image_td='<td class=img_preview>' ;
                 // пока показываем только первое фото
                 $image_td.='<a href="" onclick="show_obj('.$rec["tkey"].','.$rec["pkey"].',1,\'structure_3\');return(false);"><img src="'.img_clone($rec,'small').'"></a>' ;
                 if (!$options['no_edit_img'])
                 { $image_td.=$icon_edit_img ;
                   $image_td.='<div class=cnt_img><a href="" onclick="show_obj('.$rec["tkey"].','.$rec["pkey"].',1,\'structure_3\');return(false);">'._sizeof($rec['_all_images']).' шт.</a></div>' ;
                 }
                 $image_td.='</td>' ;
               }
          else { $image_td='<td class=img_preview>' ;
                 if (!is_array($obj_clss->parent_to) or array_search(3,$obj_clss->parent_to)!==false) $image_td.=$icon_edit_img ;
                 $image_td.='</td>' ;
               }
        } else   $image_td='' ;

          echo $check_td ; // ячека с выбором объекта
          echo $edit_td ;  // ячейка с редактированием
          echo $image_td ; // ячейка с фото

	      // идем по списку полей редактирования для данного класса данной таблицы
	      //print_r($edit_list) ;

          //print_r(_DOT($tkey)->list_clss_ext[$clss]['multilang']) ;
          if (_sizeof($edit_list)) foreach ($edit_list as $fname=>$edit_info)
			{ //if (!is_array($edit_info)) if (isset($_SESSION['pattern_clss_fields'][$edit_info])) $edit_info=$_SESSION['pattern_clss_fields'][$edit_info] ; else $edit_info=array('title'=>$edit_info) ;
			  //print_r($edit_info) ; echo '<br>' ;
			  //echo 'fname='.$fname.'<br>' ;


			  $td_class=($edit_info['td_class'])? 'class="'.$edit_info['td_class'].' gi"':'class=gi' ;
			  //$td_id='id=td_'.$rec['pkey'].'_'.$fname ;
			  //$td_onclick=(isset(_DOT($tkey)->list_connect[$clss][$fname]))? 'onclick=generate_select(this,"'.$fname.'","'.$rec[$fname].'","'.$edit_info['class'].'")':'' ;

			  //if ($options['read_only']) 			$edit_info['read_only']=1 ;
			  //if ($options['no_htmlspecialchars']) 	$edit_info['no_htmlspecialchars']=1 ;

              $edit_options=array_merge($edit_info,$options) ;
              unset($edit_options['cur_obj']) ;

			  	// делаем проверку на мультиязыность, если + , то выводим доп. колонку
				// условие +:
				// у таблицы включена мультиязчность, текущее поле имеет тип "строка", поле с соответствующем языком есть в базе
			  $i=0 ;
			  if (_DOT($tkey)->list_clss_ext[$clss]['multilang'][$fname])
				  { //echo 'multilang='._DOT($tkey)->list_clss_ext[$clss]['multilang'][$fname].'<br>';
				     if (_sizeof($GLOBALS['lang_arr'])) foreach($GLOBALS['lang_arr'] as $lang_info)
                     { $lang_fname=$fname.$lang_info['suff'] ;
                       if (isset(_DOT($tkey)->field_info[$lang_fname]))
				       { $edit_options['source_fname']=$fname ;
				         list($text,$td_attr)=$this->generate_field_text($rec,$lang_fname,$edit_options) ;
				       	 ?><td <?echo $td_attr?>><?echo $text?></td><?
				       	 $i++ ;
				       }
                     }
				  }

              // если ничего не было показано - обычный вывод поля
			  if (!$i)
			  { list($text,$td_attr)=$this->generate_field_text($rec,$fname,$edit_options) ; //print_r($res) ;
			  	?><td <?echo $td_attr?>><?echo $text?></td><?
			  }
			}

           ?></tr><?
	    }

        // выделено в функцию чтобы различные классы могли сами изменять содержимое значка редактирования
        function get_edit_td($rec,$options=array())
        { $edit_td=(!$options['read_only'] and !$options['no_icon_edit'] and !$options['_small'])? '<td class=to_edit></td>':'' ;
          return($edit_td) ;
        }


    // генерация элементра редактирования для поля
     // $tkey  - код таблицы
     // $rec   - запись (важны поля $tkey,$clss,$pkey,$enabled,$parent,$obj_name,)
     // $fname - название поля
     // options - массив набора параметров
     //  - read_only 	0/1
     //  - edit_element =1: поле ввода
     // 				=2: окошко
     // 				=3: чекбокс
     // 				=10:
     //
     //  - size			- размер поля ввода
     // memo_rows,memo_colls - размеры для мемo

      function generate_field_text($rec,$fname,$options=array())
       {  // системные массивы
         if (!is_array($options)) {echo '$options='.$options.'<br>' ; $options=array() ; }
         $gen_elem='' ;
         $tkey=$rec['tkey'] ;
         $pkey=$rec['pkey'] ;
         $clss=$rec['clss'] ;

         if ($options['on_view_before']) if (function_exists($options['on_view_before'])) $options['on_view_before']($rec,$tkey,$pkey,$options,$fname) ;

         //$fname=$fname.'' ;
         //damp_array($options) ;

         if (!$fname) $fname='' ;

         $options['no_htmlspecialchars']=1 ; // введено, т.к. переть текст отображается как есть

         // оставляем поле fname для использования с моделью классов и таблиц - т.к. там прописано все для исходного поля
         // и используем далее  $cur_fname для обращения к полю с учетом текущего языка
         // 8.10.09 заремировано, т.к. в $cur_fname уже передается имя поля с учетом текущего языка
         //$cur_fname=($options['_use_lang_suff'])? $fname.$options['use_lang_suff']:$fname ;
         $cur_fname=$fname ;

         // получаем ОТОБРАЖАЕМОЕ значение поля на основе РЕАЛЬНОГО значения
         // в развиии необходимо переместить внуть get_rec_field все нижеследующие отдачи значений поля
         $value=$this->get_rec_field($rec,$cur_fname,$options) ;

         // функция htmlspecialchars применяется для того, чтобы корректно отображать текст с тегами из БД. Если
         // не применять данную функцию, то при выводе текста из полей таблиц в поля редактирования происходит
         // искажение отображения элементов редактирования. Простое экранирование ковычек не помогает.
         //if (!$options['no_htmlspecialchars']) $value=htmlspecialchars($value,ENT_QUOTES) ;

         $class_element=($options['class'])? $options['class']:'' ;

         //echo 'tkey='.$tkey.'<br>';
         //echo 'fname='.$fname.'<br>'; print_r($options) ; echo '<br>' ;
         //damp_array(_DOT($tkey)->field_info).'<br>' ;

         $table_tkey=(isset(_DOT($tkey)->field_info[$fname]))? $tkey:_DOT($tkey)->list_clss_ext[$clss]['ext'] ;
         $element_name="obj[".$table_tkey."][".$clss."][".$pkey."][".$cur_fname."]" ; //echo 'element_name='.$element_name.'<br>' ;
         $element_id="obj_".$table_tkey."_".$clss."_".$pkey."_".$cur_fname ;

         //85.175.46.122
         //85.175.46.130
         if ($options['before_view'] and function_exists($options['before_view'])) $options['before_view']($rec,$tkey,$pkey,$options,$cur_fname) ;

         // раскрываем опции
         $edit_element=$options['edit_element'] ; // echo 'edit_element='.$edit_element.'<br>' ;

         $edit_element_size=$options['size'] ;
         $read_only=$options['read_only'] ; //echo 'read_only='.$read_only.'<br>' ;

         $td_attr_arr=array() ;
         $td_attr_arr['class'][]='v2' ;
         $td_attr_arr['cmd'][]='class/edit' ;
         $td_attr_arr['id'][]='el_'.str_replace('.','_',$rec['_reffer']).'_'.$fname ;

         //echo 'fname='.$fname.'<br>'; damp_array($options) ; damp_array($rec) ;

         // поле '__'.$fname будет присутствовать, если все записи прошли предварительную групповую обработку set_reffer_values
         if ($this->fields[$fname]=='any_object' and !isset($rec['__'.$fname])) $edit_element='any_object' ;
         if ($this->fields[$fname]=='reffer' and !isset($rec['__'.$fname])) $edit_element='any_object' ;
         if ($fname=='parent' and $this->fields[$fname]!='int(11)') $edit_element='-' ;    // реализация $_SESSION['descr_clss'][9]['fields']['parent']=array('type'=>'indx_select','array'=>'ARR_news_themes') ;

         // в первую очередь проверяем есть ли заданное функция вывода поля
         if ($options['use_func'])        $options['on_view']=$options['use_func'];

         if (method_exists($this,'VIEW_FIELD_'.$cur_fname))
         { $method_name='VIEW_FIELD_'.$cur_fname ;
           $res=$this->$method_name($rec,$options) ;
           if (is_array($res)) list($text,$gen_elem,$dop_td_attr)=array_values($res) ; else $text=$res ;
         }
         elseif ($options['on_view'])
         { // ищем функцию из on_view или в методе класа
           if (method_exists($this,$options['on_view']))
            { $res=$this->$options['on_view']($rec,$tkey,$pkey,$options,$cur_fname) ;
              if (is_array($res)) list($text,$gen_elem,$dop_td_attr)=array_values($res) ; else $text=$res ;
            }
           // или в объявленных функциях
           elseif (function_exists($options['on_view']))
            { $res=$options['on_view']($rec,$tkey,$pkey,$options,$cur_fname) ;
             if (is_array($res)) list($text,$gen_elem,$dop_td_attr)=array_values($res) ; else $text=$res ;
           }

         }
         // $options['view'] отличается от $options['on_view'] тем, что первой передается меньшее число параметров - только $rec и $options
         // сделано, так как обычно через $options['on_view'] вызывается функция для заведомо известного поля
         elseif ($options['view'])
         { //if ($fname=='type') damp_array($options) ;
           // ищем функцию из on_view или в методе класа
           if (method_exists($this,$options['view']))
            { $res=$this->$options['view']($rec,$options) ;
              if (is_array($res)) list($text,$gen_elem,$dop_td_attr)=array_values($res) ; else $text=$res ;
            }
           // или в объявленных функциях
           else
           { // если в имени команды есть ext - подключаем это расширение
             //list($result,$cmd_exec)=

             DESKTOP()->include_script_cmd($options['view'],$options['script'],array('cur_page'=>_CUR_PAGE())) ;
             //check_and_include_ext($options['view']) ;

             if (function_exists($options['view']))
             { $res=$options['view']($rec,$options) ;
               if (is_array($res)) list($text,$gen_elem,$dop_td_attr)=array_values($res) ; else $text=$res ;
             }
           }
           // или в расширениях


         }
         else
         // во вторую очередь смотрим на имя поля - вывод для этих полей определен именем поля $fname. $edit_element добавлено чтобы уйти от вывода полей тут, если указан $edit_element
         switch ($fname.$edit_element)
         { case 'pkey' : $text=$value ;
         				 break ;
           case 'parent' : // вывести название род-кого объекта
                           // переделана 27.08.11 на основе функции get_obj_parents_name
                           $text=get_obj_patch($rec) ;
         				 break ;
           case 'c_data':
           case 'e_data':
           case 'r_data': $text=$value ;
                          if (($options['is_edit'] or $options['datepicker']) and !$read_only) $gen_elem='gi' ;
                         break ;
           case 'enabled':
                        if (!$options['indx_select'])
                 		{ $text=($value)? '<i class="nav-icon icon-check green"></i>':'<i class="nav-icon icon-close red"></i>' ;
                          if ($options['read_only']) $text=($value)? '<i class="nav-icon icon-check green"></i>':'<i class="nav-icon icon-close red"></i>' ;
                          $td_attr_arr['cmd']=['class/check'] ;
           				}
                        break ;
           case '_parent_reffer': $text=generate_obj_text($value,$options) ;
           				break ;
           case 'url_name': $text=$this->prepare_url_obj($rec) ;
                            if (!$rec['url_name']) update_rec_in_table($tkey,array('url_name'=>$text),'pkey='.$pkey) ;
                            else                   $text=$rec['url_name'] ;
                            $gen_elem='gi' ;
                            break ;
           case 'clss_5_file_size':	    $text=round(filesize($rec['pkey'])/1024).' кБ' ; break ;

           //case 'clss_7_preview':		$text='_info_id('.$rec['pkey'].')' ; break ;
           case 'clss_16_goto':		    $text='<a href="fra_viewer_support.php?tkey='.$rec['tkey'].'&pkey='.$rec['pkey'].'">Перейти</a>' ; break ;
           case 'clss_21_arr_name':     $text='$_SESSION[\''.get_IL_array_name($rec)."']" ;break ;
           case 'clss_23_status':       $text=($rec['r_data']>time())? '+':''; break ;


           // если для имени поля нет предопределенной функции, производим вывод функции в соотвествии со значением edit_element
           default: $source_fname=($options['source_fname'])? $options['source_fname']:$fname ;
                    $edit_element=$this->get_edit_element_to_field($source_fname,$options) ;
                    // вывод поля в зависимости от значения $edit_element
                    switch ($edit_element)
    			 	       {// генерироемое поле 'memo'
    		           		case 'memo':
                                     $view_as_HTML=($this->use_HTML_editor($rec,$fname))? 1:0 ;  // если редактор не используется, используем nl2br
                                     $text=$value ;
                                     if (!$view_as_HTML) $options['show_html_code']=1 ;
                                     if ($options['view_as_HTML']) $options['show_html_code']=0 ;
                                     if ($options['show_html_code']) $text=htmlspecialchars($text) ;
                                     //if (!$view_as_HTML and stripos($text,'<script')===false) $text=nl2br($text) ;
    		           		         if (!$read_only and $options['no_generate_element'])
                                        { $text="<textarea class='memo' name='".$element_name."' id='".$element_id."' type='text' cols=10 rows=5 wrap=on>".$text."</textarea>" ;
                                          if ($view_as_HTML and _CKEDITOR_ and _CKEDITOR_!='none') $text.='<SCRIPT type="text/javascript" src="'._EXT.'/'._CKEDITOR_.'/ckeditor.js" ></SCRIPT><script type="text/javascript">window.addEvent("domready",function(){editor = CKEDITOR.replace("'.$element_id.'")});</script>' ;
                                        }
    	 	    	         		 else $gen_elem='gm' ;
    	 	    	         		 $td_class='left' ;
    	 	    	         		 break ;

    		           		// генерироемое поле 'input'
    		           		case 'input':
    		           			 	 $text=$value ;
    	 	                		 if (!$read_only and $options['no_generate_element'] and $value) $text="<input class=text name='".$element_name."' type='text' value='".$value."' size=".$edit_element_size." />" ;
    	 	    	         		 else $gen_elem='gi' ;
    	 	                		 break ;

    		           		// генерироемое поле 'checkbox'
    		           		case 'checkbox': // в дальшейшем заменить off3.gif и on3.gif на программируемые значения, например check_0.gif и check_1.gif
                                   if ($value) { $img_src=($class_element=='inverse')? "off3.gif":"on3.gif" ;  $img_alt='+' ;}
                                   else        { $img_src=($class_element=='inverse')? "on3.gif":"off3.gif" ;  $img_alt='-' ;}
          			               $text='<img src="'._PATH_TO_ADMIN_IMG.'/'.$img_src.'" width="16" height="16" border="0" alt="'.$img_alt.'">';
    				 	    	   $gen_elem='gc' ;
    	 	                 	   break ;

    		           		// генерироемое поле 'input' для ввода даты
    		           		// 'data_format' - могут быть следующие варианты: 'd.m.y G:i','d.m.y','d.m.y G:i'
    		           		case 'timedata':
    		           		case 'data_input':
                                     if (!$read_only) $gen_elem='gi' ;
    		                         $text=$value;
    	 	                		 break ;
                            case 'serialize':
                                     if ($value) $arr=unserialize($value) ;
                                     if (is_array($arr)) $text=get_damp_array($arr,1,-1) ; else $text=$value ;

                                     break ;
                            // показать значение из массива
                            case 'indx_array_value':
                                     if (!$value) $value=0 ;
                                     global ${$options['indx_array']} ;
                                     $text=${$options['indx_array']}[$value] ;
                                     break ;

                            // масств в виде select
                            case 'indx_select':
                                     $arr_name='' ;
    								 if ($options['indx_select']) $arr_name=$options['indx_select'] ;
                                     if ($options['array'])       $arr_name=$options['array'] ;
                                     if (!$arr_name)              $arr_name=_CLSS($rec['clss'])->fields_info[$fname]['array'] ;
                                     //damp_array(_CLSS($rec['clss'])) ;
                                     $list=_IL($arr_name)->recs ;
                                     $indx_field=($options['indx_field'])? $options['indx_field']:_CLSS($rec['clss'])->fields_info[$fname]['indx_field'] ;
                                     if (!$indx_field) $indx_field='obj_name' ;
                                     if ($arr_name)
                                         if (is_array($list))
                                         { $text=(is_array($list[$value]))? $list[$value][$indx_field]:$list[$value] ;
                                           if (!$read_only) { $gen_elem='gs' ;
                                                              $dop_td_attr='ai="'.$arr_name.'" as="'.$value.'" af="'.$indx_field.'"' ;
    								                        }
                                         } else $text='<span class=red>Массив "'.$arr_name.'" не существует</span>' ;
                                     else $text='<span class=red>Не указано имя массива</span>' ;
                                     break ;
                            // массив для мультивыбора
                            case 'multichange':
                                     $arr_name=$options['array'] ;
                                     $indx_field=($options['fname'])? $options['fname']:'obj_name'  ;
                                     $td_class='left' ;
                                     if (mb_substr($arr_name,0,3)=='IL_') $text=_IL($arr_name)->get_multichange_field_view($value,$options) ;
                                     elseif ($value) // переделать потом для простых списков (одномерных массивов)
                                     { $list=_IL($arr_name)->recs ;
                                       $arr_values=array() ;
                                       $arr_id=explode(' ',trim($value))  ;
                                       if (_sizeof($arr_id)) foreach($arr_id as $id) $arr_values[]=$list[$id][$indx_field] ;
                                       if (_sizeof($arr_values)) $text=implode('<br>',$arr_values) ; else $text='' ;
                                     }

    								 if (!$read_only) { $gen_elem='gmc' ;
                                                        $dop_td_attr='ai="'.$arr_name.'" as="'.trim($value).'" af="'.$indx_field.'"' ;
    								                  }
                                     break ;

                 			//case 'show_obj_field_functions': $text=$show_obj_field_functions[$cur_fname]($rec,$tkey,$pkey,$options,$cur_fname) ; break ;
    						case 'urldecode': $text=urldecode($value) ; break ;
    			       		case 'href': if ($value and strpos($value,_MAIN_PROTOCOL)===false) $value=_MAIN_PROTOCOL.$value ;
                                         $text=($value)? '<a href="'.htmlspecialchars(urldecode($value)).'" target=_blank>'.htmlspecialchars(urldecode($value)).'</a>':'' ;
                                         break ;
    			       		case 'any_object': if ($value) $text=generate_obj_text($value,$options) ;
                                               else if ($options['select_from_table']) $text=generate_select_object_from_table($tkey,$clss,$pkey,$cur_fname,$options) ;
                                               break;

                            // вычисляемые поля ----------------------------------------------------------------------------------------------------------
                            case 'clss_patch': 	$text=get_obj_patch($rec) ; break ;

                            case 'clss_all_prices': $text=on_view_show_all_prices($rec) ; break ; // на удаление, должна вызываться через func_name

    				        case 'parent_clss' :
    				                     $text=(!$read_only)? generate_element('text',$edit_element_size,$tkey,$clss,$pkey,$cur_fname,$value).'&nbsp;&nbsp;'.$this->name:$this->name.' ('.$value.')' ; break;
    				     				 break ;

    				        case 'file_upload': if (!$read_only)
    				      						  {     $text='<INPUT   name="upload_file['.$tkey.']['.$pkey.']" type=file class=file><br/><br/>' ;
    				       				 				$text.= '<input name="upload_file_by_href['.$tkey.']['.$pkey.']" type=text class=text value=""> Ссылка' ;
    				       				 		  }
    				       				 		 break ;
    				        case 'file_preview_upload'
    				        				  : if (!$read_only)
    				      						  {     $text='<INPUT   name="upload_preview_file['.$tkey.']['.$pkey.']" type=file class=file><br/><br/>' ;
    				       				 				$text.= '<input name="upload_preview_file_by_href['.$tkey.']['.$pkey.']" type=text class=text value=""> Ссылка' ;
    				       				 		  }
    				       				 		break ;
    				        case 'file_preview':$file_dir=_DOT($tkey)->dir_to_file.$rec['file_name'] ;
                                                DESKTOP()->include_extension('get_file_view_text')  ;
                                                $text=get_file_view_text($file_dir,array('flash_width'=>200,'use_preview'=>1)) ;
    				        					break ;

    				        case 'file_name':	$text=($read_only)? $value:'<a target=_clean href="'._DOT($tkey)->patch_to_file.$value.'">'.$value.'</a>' ;
    				       						break ;

    				        case 'file_href':	$text='/'._DOT($tkey)->dir_name.$rec['file_name'].'<br><br>'._DOT($tkey)->patch_to_file.$rec['file_name'] ;
    				       						break ;

    				        case 'show_size':	$text=format_size($value) ;
    				        					break ;

                            case 'clss_3_size': $text=get_image_info(_DOT($tkey)->dir_to_file.'source/'.$rec['file_name'],$rec['obj_name']) ; break ;
                            case 'clss_3_image': $text=strip_tags(get_image_info(_DOT($tkey)->dir_to_file.'source/'.$rec['file_name'],$rec['obj_name'])) ;
                                                 $text='<a href="'.img_clone($rec,'source').'" id=img_'.$pkey.'  target=_clear onclick="return hs.expand(this)" title="Размер: '.$text.'"><img src="'.img_clone($rec,'small').'" border="0" width=100 height=100/></a>';
                                                 break ;
                            case 'clss_3_clone':$text=get_clone_info($tkey,$rec['file_name']) ; break ;
                            case 'clss_3_reffers':$text=get_img_reffers($tkey,$rec['file_name']) ; break ;

                            case 'clss_100_image': //$text=strip_tags(get_image_info(_DOT($tkey)->dir_to_file.'source/'.$rec['file_name'],$rec['obj_name'])) ;
                                                   $rec_img=get_img_info_to_reffer($rec['reffer']) ;
                                                   if ($rec_img['pkey']) $text='<a href="'.img_clone($rec_img,'source').'" id=img_'.$pkey.'  target=_clear onclick="return hs.expand(this)"><img src="'.img_clone($rec_img,'small').'" border="0" width=100 height=100/></a>';
                                                   break ;

    				        case 'clss_104_class_name': $text=_CLSS($rec['indx'])->name ; break ;
    			       		default: $text=($options['no_htmlspecialchars'])? $value:$value ;
    					   }
         }

        if ($options['ue'] and $text) $text.=' '.$options['ue'] ;
        if ($options['format_as_price'] and $text) { $text=_format_price($text) ; $td_class='right' ; }
        if ($options['suff'] and $text) $text.=$options['suff'] ;
        if ($options['pref'] and $text) $text=$options['pref'].$text ;
        if ($options['base_ue'] and $text) $text.=' '.$GLOBALS['base_ue'] ;
        if ($options['wrap']=='nowrap' and $text) $text='<div style="white-space: nowrap;">'.$text.'</div>' ;
        if ($options['nl2br']) $text=nl2br($text) ;


        // добавить  - для ReadOnly - убрать все заданные функции click
        // описываем класс ячейки - в нем будет передаваться вся информация: наименование поля, класс элемента, имя функции для генерации элемента
        //if ($fname)                     $td_attr_arr['fn'][]=$fname ;
        if ($td_class)                  $td_attr_arr['class'][]=$td_class ;
        if ($options['td_class'])       $td_attr_arr['class'][]=$options['td_class'] ;
        //if ($class_element)             $td_attr_arr['ec'][]=$class_element ;
        //if ($gen_elem and !$read_only)  $td_attr_arr['el'][]=$gen_elem ;

        if ($dop_td_attr)
        { $arr=explode(' ',$dop_td_attr) ;
          if (_sizeof($arr)) foreach($arr as $val)
          { $arr2=explode('=',$val) ;
            $td_attr_arr[$arr2[0]][]=str_replace(array('"',"'"),'',$arr2[1]) ;
          }
        }
        $arr=array() ;
        if (_sizeof($td_attr_arr)) foreach($td_attr_arr as $param=>$arr_values) $arr[]=$param.'="'.implode(' ',$arr_values).'"' ;
        $td_attr=(_sizeof($arr))? implode(' ',$arr):'' ;

        if ($options['on_view_after']) if (function_exists($options['on_view_after'])) $options['on_view_after']($rec,$tkey,$pkey,$options,$fname,$text) ;

        return(array($text,$td_attr)) ;
       }

      function generate_edit_element($rec,$fname,$options=array())
           {
               //damp_array($this) ;

               // системные массивы
             if (!is_array($options)) {echo '$options='.$options.'<br>' ; $options=array() ; }
             $gen_elem='' ;
             $tkey=$rec['tkey'] ;
             $pkey=$rec['pkey'] ;
             $clss=$rec['clss'] ;
             //trace() ;
             //damp_array($options) ;




             if ($options['on_view_before']) if (function_exists($options['on_view_before'])) $options['on_view_before']($rec,$tkey,$pkey,$options,$fname) ;

             //$fname=$fname.'' ;
             //damp_array($options) ;

             if (!$fname) $fname='' ;

             $options['no_htmlspecialchars']=1 ; // введено, т.к. переть текст отображается как есть

             // оставляем поле fname для использования с моделью классов и таблиц - т.к. там прописано все для исходного поля
             // и используем далее  $cur_fname для обращения к полю с учетом текущего языка
             // 8.10.09 заремировано, т.к. в $cur_fname уже передается имя поля с учетом текущего языка
             //$cur_fname=($options['_use_lang_suff'])? $fname.$options['use_lang_suff']:$fname ;
             $cur_fname=$fname ;

             // получаем ОТОБРАЖАЕМОЕ значение поля на основе РЕАЛЬНОГО значения
             // в развиии необходимо переместить внуть get_rec_field все нижеследующие отдачи значений поля
             $value=$this->get_rec_field($rec,$cur_fname,$options) ;

             // функция htmlspecialchars применяется для того, чтобы корректно отображать текст с тегами из БД. Если
             // не применять данную функцию, то при выводе текста из полей таблиц в поля редактирования происходит
             // искажение отображения элементов редактирования. Простое экранирование ковычек не помогает.
             //if (!$options['no_htmlspecialchars']) $value=htmlspecialchars($value,ENT_QUOTES) ;

             $class_element=($options['class'])? $options['class']:'' ;

             //echo 'tkey='.$tkey.'<br>';
             //echo 'fname='.$fname.'<br>'; print_r($options) ; echo '<br>' ;
             //damp_array(_DOT($tkey)->field_info).'<br>' ;

             //$table_tkey=(isset(_DOT($tkey)->field_info[$fname]))? $tkey:_DOT($tkey)->list_clss_ext[$clss]['ext'] ;
             $table_tkey=$tkey;
             $element_name="obj[".$tkey."][".$clss."][".$pkey."][".$cur_fname."]" ; //echo 'element_name='.$element_name.'<br>' ;
             $element_id="obj_".$table_tkey."_".$clss."_".$pkey."_".$cur_fname ;

             //85.175.46.122
             //85.175.46.130
             if ($options['before_view'] and function_exists($options['before_view'])) $options['before_view']($rec,$tkey,$pkey,$options,$cur_fname) ;

             // раскрываем опции
             $edit_element=$options['edit_element'] ; // echo 'edit_element='.$edit_element.'<br>' ;

             $edit_element_size=$options['size'] ;
             $read_only=$options['read_only'] ; //echo 'read_only='.$read_only.'<br>' ;

             //echo 'fname='.$fname.'<br>'; damp_array($options) ; damp_array($rec) ;

             // поле '__'.$fname будет присутствовать, если все записи прошли предварительную групповую обработку set_reffer_values
             if ($this->fields[$fname]=='any_object' and !isset($rec['__'.$fname])) $edit_element='any_object' ;
             if ($this->fields[$fname]=='reffer' and !isset($rec['__'.$fname])) $edit_element='any_object' ;
             if ($fname=='parent' and $this->fields[$fname]!='int(11)') $edit_element='-' ;    // реализация $_SESSION['descr_clss'][9]['fields']['parent']=array('type'=>'indx_select','array'=>'ARR_news_themes') ;



             $source_fname=($options['source_fname'])? $options['source_fname']:$fname ;
            $edit_element=$this->get_edit_element_to_field($source_fname,$options) ;
            echo '$fname='.$fname.'<br>' ;
            echo '$source_fname='.$source_fname.'<br>' ;
            echo '$edit_element='.$edit_element.'<br>' ;
            // вывод поля в зависимости от значения $edit_element
            switch ($edit_element)
                   {// генерироемое поле 'memo'
                    case 'memo':
                             $view_as_HTML=($this->use_HTML_editor($rec,$fname))? 1:0 ;  // если редактор не используется, используем nl2br
                             $text=$value ;
                             if (!$view_as_HTML) $options['show_html_code']=1 ;
                             if ($options['view_as_HTML']) $options['show_html_code']=0 ;
                             if ($options['show_html_code']) $text=htmlspecialchars($text) ;
                             //if (!$view_as_HTML and stripos($text,'<script')===false) $text=nl2br($text) ;
                             $text="<textarea class='memo' name='".$element_name."' id='".$element_id."' type='text' cols=10 rows=5 wrap=on>".$text."11</textarea>" ;
                             if ($view_as_HTML and _CKEDITOR_ and _CKEDITOR_!='none') $text.='<SCRIPT type="text/javascript" src="'._EXT.'/'._CKEDITOR_.'/ckeditor.js" ></SCRIPT><script type="text/javascript">window.addEvent("domready",function(){editor = CKEDITOR.replace("'.$element_id.'")});</script>' ;
                             break ;

                    // генерироемое поле 'input'
                    case 'input':
                             $text=$value ;
                             if (!$read_only and $options['no_generate_element'] and $value) $text="<input class=text name='".$element_name."' type='text' value='".$value."' size=".$edit_element_size." />" ;
                             else $gen_elem='gi' ;
                             break ;

                    // генерироемое поле 'checkbox'
                    case 'checkbox': // в дальшейшем заменить off3.gif и on3.gif на программируемые значения, например check_0.gif и check_1.gif
                           if ($value) { $img_src=($class_element=='inverse')? "off3.gif":"on3.gif" ;  $img_alt='+' ;}
                           else        { $img_src=($class_element=='inverse')? "on3.gif":"off3.gif" ;  $img_alt='-' ;}
                           $text='<img src="'._PATH_TO_ADMIN_IMG.'/'.$img_src.'" width="16" height="16" border="0" alt="'.$img_alt.'">';
                           $gen_elem='gc' ;
                           break ;

                    // генерироемое поле 'input' для ввода даты
                    // 'data_format' - могут быть следующие варианты: 'd.m.y G:i','d.m.y','d.m.y G:i'
                    case 'timedata':
                    case 'data_input':
                             if (!$read_only) $gen_elem='gi' ;
                             $text=$value;
                             break ;
                    case 'serialize':
                             if ($value) $arr=unserialize($value) ;
                             if (is_array($arr)) $text=get_damp_array($arr,1,-1) ; else $text=$value ;

                             break ;
                    // показать значение из массива
                    case 'indx_array_value':
                             if (!$value) $value=0 ;
                             global ${$options['indx_array']} ;
                             $text=${$options['indx_array']}[$value] ;
                             break ;

                    // масств в виде select
                    case 'indx_select':
                             $arr_name='' ;
                             if ($options['indx_select']) $arr_name=$options['indx_select'] ;
                             if ($options['array'])       $arr_name=$options['array'] ;
                             if (!$arr_name)              $arr_name=_CLSS($rec['clss'])->fields_info[$fname]['array'] ;
                             //damp_array(_CLSS($rec['clss'])) ;
                             $list=_IL($arr_name)->recs ;
                             $indx_field=($options['indx_field'])? $options['indx_field']:_CLSS($rec['clss'])->fields_info[$fname]['indx_field'] ;
                             if (!$indx_field) $indx_field='obj_name' ;
                             if ($arr_name)
                                 if (is_array($list))
                                 { $text=(is_array($list[$value]))? $list[$value][$indx_field]:$list[$value] ;
                                   if (!$read_only) { $gen_elem='gs' ;
                                                      $dop_td_attr='ai="'.$arr_name.'" as="'.$value.'" af="'.$indx_field.'"' ;
                                                    }
                                 } else $text='<span class=red>Массив "'.$arr_name.'" не существует</span>' ;
                             else $text='<span class=red>Не указано имя массива</span>' ;
                             break ;
                    // массив для мультивыбора
                    case 'multichange':
                             $arr_name=$options['array'] ;
                             $indx_field=($options['fname'])? $options['fname']:'obj_name'  ;
                             $td_class='left' ;
                             if (mb_substr($arr_name,0,3)=='IL_') $text=_IL($arr_name)->get_multichange_field_view($value,$options) ;
                             elseif ($value) // переделать потом для простых списков (одномерных массивов)
                             { $list=_IL($arr_name)->recs ;
                               $arr_values=array() ;
                               $arr_id=explode(' ',trim($value))  ;
                               if (_sizeof($arr_id)) foreach($arr_id as $id) $arr_values[]=$list[$id][$indx_field] ;
                               if (_sizeof($arr_values)) $text=implode('<br>',$arr_values) ; else $text='' ;
                             }

                             if (!$read_only) { $gen_elem='gmc' ;
                                                $dop_td_attr='ai="'.$arr_name.'" as="'.trim($value).'" af="'.$indx_field.'"' ;
                                              }
                             break ;

                    //case 'show_obj_field_functions': $text=$show_obj_field_functions[$cur_fname]($rec,$tkey,$pkey,$options,$cur_fname) ; break ;
                    case 'urldecode': $text=urldecode($value) ; break ;
                    case 'href': if ($value and strpos($value,_MAIN_PROTOCOL)===false) $value=_MAIN_PROTOCOL.$value ;
                                 $text=($value)? '<a href="'.htmlspecialchars(urldecode($value)).'" target=_blank>'.htmlspecialchars(urldecode($value)).'</a>':'' ;
                                 break ;
                    case 'any_object': if ($value) $text=generate_obj_text($value,$options) ;
                                       else if ($options['select_from_table']) $text=generate_select_object_from_table($tkey,$clss,$pkey,$cur_fname,$options) ;
                                       break;

                    // вычисляемые поля ----------------------------------------------------------------------------------------------------------
                    case 'clss_patch': 	$text=get_obj_patch($rec) ; break ;

                    case 'clss_all_prices': $text=on_view_show_all_prices($rec) ; break ; // на удаление, должна вызываться через func_name

                    case 'parent_clss' :
                                 $text=(!$read_only)? generate_element('text',$edit_element_size,$tkey,$clss,$pkey,$cur_fname,$value).'&nbsp;&nbsp;'.$this->name:$this->name.' ('.$value.')' ; break;
                                 break ;

                    case 'file_upload': if (!$read_only)
                                          {     $text='<INPUT   name="upload_file['.$tkey.']['.$pkey.']" type=file class=file><br/><br/>' ;
                                                $text.= '<input name="upload_file_by_href['.$tkey.']['.$pkey.']" type=text class=text value=""> Ссылка' ;
                                          }
                                         break ;
                    case 'file_preview_upload'
                                      : if (!$read_only)
                                          {     $text='<INPUT   name="upload_preview_file['.$tkey.']['.$pkey.']" type=file class=file><br/><br/>' ;
                                                $text.= '<input name="upload_preview_file_by_href['.$tkey.']['.$pkey.']" type=text class=text value=""> Ссылка' ;
                                          }
                                        break ;
                    case 'file_preview':$file_dir=_DOT($tkey)->dir_to_file.$rec['file_name'] ;
                                        DESKTOP()->include_extension('get_file_view_text')  ;
                                        $text=get_file_view_text($file_dir,array('flash_width'=>200,'use_preview'=>1)) ;
                                        break ;

                    case 'file_name':	$text=($read_only)? $value:'<a target=_clean href="'._DOT($tkey)->patch_to_file.$value.'">'.$value.'</a>' ;
                                        break ;

                    case 'file_href':	$text='/'._DOT($tkey)->dir_name.$rec['file_name'].'<br><br>'._DOT($tkey)->patch_to_file.$rec['file_name'] ;
                                        break ;

                    case 'show_size':	$text=format_size($value) ;
                                        break ;

                    case 'clss_3_size': $text=get_image_info(_DOT($tkey)->dir_to_file.'source/'.$rec['file_name'],$rec['obj_name']) ; break ;
                    case 'clss_3_image': $text=strip_tags(get_image_info(_DOT($tkey)->dir_to_file.'source/'.$rec['file_name'],$rec['obj_name'])) ;
                                         $text='<a href="'.img_clone($rec,'source').'" id=img_'.$pkey.'  target=_clear onclick="return hs.expand(this)" title="Размер: '.$text.'"><img src="'.img_clone($rec,'small').'" border="0" width=100 height=100/></a>';
                                         break ;
                    case 'clss_3_clone':$text=get_clone_info($tkey,$rec['file_name']) ; break ;
                    case 'clss_3_reffers':$text=get_img_reffers($tkey,$rec['file_name']) ; break ;

                    case 'clss_100_image': //$text=strip_tags(get_image_info(_DOT($tkey)->dir_to_file.'source/'.$rec['file_name'],$rec['obj_name'])) ;
                                           $rec_img=get_img_info_to_reffer($rec['reffer']) ;
                                           if ($rec_img['pkey']) $text='<a href="'.img_clone($rec_img,'source').'" id=img_'.$pkey.'  target=_clear onclick="return hs.expand(this)"><img src="'.img_clone($rec_img,'small').'" border="0" width=100 height=100/></a>';
                                           break ;

                    case 'clss_104_class_name': $text=_CLSS($rec['indx'])->name ; break ;
                    default: $text=($options['no_htmlspecialchars'])? $value:$value ;
                   }


             //$text=$edit_element ;

            if ($options['ue'] and $text) $text.=' '.$options['ue'] ;
            if ($options['format_as_price'] and $text) { $text=_format_price($text) ; $td_class='right' ; }
            if ($options['suff'] and $text) $text.=$options['suff'] ;
            if ($options['pref'] and $text) $text=$options['pref'].$text ;
            if ($options['base_ue'] and $text) $text.=' '.$GLOBALS['base_ue'] ;
            if ($options['wrap']=='nowrap' and $text) $text='<div style="white-space: nowrap;">'.$text.'</div>' ;
            if ($options['nl2br']) $text=nl2br($text) ;

        	$td_attr_arr=array() ;
             $td_attr_arr['class'][]='v2' ;
             $td_attr_arr['cmd'][]='class/edit' ;
             $td_attr_arr['id'][]='el_'.str_replace('.','_',$rec['_reffer']).'_'.$fname ;
            // добавить  - для ReadOnly - убрать все заданные функции click
            // описываем класс ячейки - в нем будет передаваться вся информация: наименование поля, класс элемента, имя функции для генерации элемента
            //if ($fname)                     $td_attr_arr['fn'][]=$fname ;
            //if ($td_class)                  $td_attr_arr['class'][]=$td_class ;
            //if ($options['td_class'])       $td_attr_arr['class'][]=$options['td_class'] ;
            //if ($class_element)             $td_attr_arr['ec'][]=$class_element ;
            //if ($gen_elem and !$read_only)  $td_attr_arr['el'][]=$gen_elem ;

            if ($dop_td_attr)
            { //if (preg_match_all('/(\w+?)=[\"\']([^\'\"]+?)[\"\']/is',$dop_td_attr,$matches,PREG_SET_ORDER))
              //    //foreach($matches as $match) array_push($a,array($match[1],$match[2]));
              $arr=explode(' ',$dop_td_attr) ;
              if (_sizeof($arr)) foreach($arr as $val)
              { $arr2=explode('=',$val) ;
                $td_attr_arr[$arr2[0]][]=str_replace(array('"',"'"),'',$arr2[1]) ;
              }
            }
            $arr=array() ;
            if (_sizeof($td_attr_arr)) foreach($td_attr_arr as $param=>$arr_values) $arr[]=$param.'="'.implode(' ',$arr_values).'"' ;
            $td_attr=(_sizeof($arr))? implode(' ',$arr):'' ;

            if ($options['on_view_after']) if (function_exists($options['on_view_after'])) $options['on_view_after']($rec,$tkey,$pkey,$options,$fname,$text) ;

            return($text) ;
      }

  // -----------------------------------------------------------------------------------------------------------------------------------------------------------------------
  //
  //  ВЫВОД СВОЙСТВ ОБЪКТА В VIEWER
  //
  // -----------------------------------------------------------------------------------------------------------------------------------------------------------------------

  // подпобное описание объекта
  function show_props($obj_info,$options=array()) // показываем стандартный объект
  { if (_sizeof($options['obj_info'])) $obj_info=$options['obj_info'] ;
    //damp_array($obj_info) ;	 					 // исходные данные по выводимому объекту
    $clss=$obj_info['clss'] ;
    $pkey=$obj_info['pkey'] ;
    $tkey=$obj_info['tkey'] ;
    $header_options['colspan']=2 ;
    $header_options['icon_clss']=$clss ;
    $html_fields=array() ;
    $obj_clss=_CLSS($clss) ;
    //damp_array($obj_info) ;

    //print_r($options);
    // если сщуествует информация по настроке редактирования полей данного класса в данной таблице, то используем её, иначе используем настройку полей по умолчанию
    if (isset($options['edit_list']) and _sizeof($options['edit_list'])) $edit_list=$options['edit_list']['field'] ;
      else if (isset($obj_clss->view['details']['field'])) $edit_list=&$obj_clss->view['details']['field'] ;
        else $edit_list=&$obj_clss->view['list']['field'] ;

    //generate_JS_array($tkey,$clss) ; - удалено, выводы всех массивов через запросы JQ

    if (!$options['no_auto_check']){?><input name="_check[<?echo $obj_info['tkey']?>][<?echo $obj_info['clss']?>][<?echo $obj_info['pkey']?>]" type="hidden" value="1"><?}?>
      <table class="clss details item" reffer="<?echo $obj_info['_reffer']?>"><?
	if (!$options['no_header']) $this->print_table_header(_CLSS($clss)->name,$header_options) ;
    ?>
	  <tr class=td_header><td>Поле</td><td>Значение</td></tr>
   	  <?if (_sizeof($edit_list)) foreach($edit_list as $fname=>$edit_info)
        { if (!is_array($edit_info)) /* if (isset($_SESSION['pattern_clss_fields'][$edit_info])) $edit_info=$_SESSION['pattern_clss_fields'][$edit_info] ; else */ $edit_info=array('title'=>$edit_info) ;
          // определяем, выводить данное поле в обычном виде или мультиязычном варианте - это будет переделано
          $lang_support=(isset(_DOT($tkey)->list_clss_ext[$clss]['multilang'][$fname]))? 1:0 ;
          //echo '$fname='.$fname.' $lang_support='.$lang_support.'<br>' ;
          //$edit_info['no_generate_element']=1 ;
          //$edit_info['']
          if (!$edit_info['td_class']) $edit_info['td_class']='left' ;

          if (strpos($fname,'__group_title')===false)
          { if (!$lang_support) // если таблица не поддерживает языки или языки не определены, то выводим как есть
	          { list($text,$td_attr)=$this->generate_field_text($obj_info,$fname,$edit_info) ; //print_r($res) ;
                // вывод полей с редактором  HTML показывать позднее
                if ($options['no_extended_info'] or !$obj_clss->view['details']['field'][$fname]['use_HTML_editor'])
                    {?><tr><td class='nowrap left'><?echo $edit_info['title']?>&nbsp;</td><td <?echo $td_attr?>><?echo $text;?></td></tr><?}
                else $html_fields[$fname]=$edit_info['title'] ;
              }
            else foreach($GLOBALS['lang_arr'] as $lang_info) // иначе выводим мультиязычные версии поля
            { $lang_fname=$fname.$lang_info['suff'] ;
              $edit_info['source_fname']=$fname ;
              list($text,$td_attr)=$this->generate_field_text($obj_info,$lang_fname,$edit_info) ; //print_r($res) ;
              echo $td_attr ; echo '<br>' ;
              // вывод полей с редактором  HTML показывать позднее
              if ($options['no_extended_info'] or !$obj_clss->view['details']['field'][$fname]['use_HTML_editor'])
                {?><tr reffer="<?echo $obj_info['_reffer']?>"><td class='nowrap left'><?echo $edit_info['title'].' ('.$lang_info['name'].')';?>&nbsp;</td><td <?echo $td_attr?>><?echo $text?></td></tr><?}
              else $html_fields[$lang_fname]=$edit_info['title'].' ('.$lang_info['name'].')' ;
            }
          }else{?><tr class=group_title><td colspan=2><?echo $edit_info['title']?></td></tr><?}


        }?>
	   </table>
       <? if (_sizeof($obj_clss->view['details']['options']['buttons'])) $this->show_buttons($obj_clss->view['details']['options']) ;

      if ($options['no_extended_info'] or !$obj_clss->show_extended_props) return ; // если не показывать расширенные свойства товара - выходим

      // показываем поля в HTML редакторе, которые не были показаны ранее
      //if (_sizeof($html_fields)) foreach($html_fields as $fname=>$title) show_ckeditor_hidden_panel($title,$fname,strlen($obj_info[$fname])) ;
      if (_sizeof($html_fields)) foreach($html_fields as $fname=>$title) show_ckeditor_visible_panel($title,$fname,strlen($obj_info[$fname])) ;
      // получаем инфу по всем дочерним элементам раздела
      $arr_obj_childs=select_db_obj_child_recs($obj_info['_reffer']) ;

      if (_sizeof($obj_info['obj_clss_3']))
      {  ?><h1>Фото</h1><?
          ?><div id=panel_img_inner><? $this->show_based_obj_list($obj_info['obj_clss_3'],array('no_show_not_found'=>1)) ; ?></div><br><?
          show_add_image_button($obj_info['tkey'],$obj_info['pkey']) ;
          //if (_sizeof($obj_info['obj_clss_3'])) show_standart_button() ; //   show_standart_button - более не используется
      }

      if ($obj_clss->SEO_tab) { ?><h1>Метатеги</h1><? show_SEO_small() ; }

      if (_sizeof($arr_obj_childs)) foreach($arr_obj_childs as $child_tkey=>$arr_clss)
        if (_sizeof($arr_clss)) foreach($arr_clss as $child_clss=>$arr_childs)
          if ($child_clss!=3) // фото уже показано ранее
            { ?><h1><?echo _CLSS($child_clss)->name?>ы <span class=small>[<?echo _sizeof($arr_childs)?>]</span></h1><div class=expand_panel>развернуть/свернуть панель</div><div class="panel hidden"><? $this->show_based_obj_list($arr_childs) ; ?><br><?  /*show_standart_button() ; */?></div><?}



      //$options['show_img']=(_sizeof($obj_info['obj_clss_3']))? 0:1 ;
      //$options['obj_info']=$obj_info ;
      //$options['no_create_from_list']=1 ;
      //panel_child_create_select($options) ;  - функция перенесена в c_site::c_fra_based

  }

  function get_search_usl($fname,$search)
  { $_usl=array() ; $usl='' ;
    //damp_array($this->fields) ;
    //if (_sizeof($this->fields)) foreach($this->fields as $fname=>$type)
    if (isset($this->fields[$fname]))
    {  $type=get_name_type($this->fields[$fname]) ;
       switch($type)
        { case 'text':
          case 'varchar': $_usl[]=$fname.' like "%'.$search.'%"' ; break ;
          case 'int':     $_usl[]=$fname.' = "'.$search.'"' ; break ;

        }
    }

    if (_sizeof($_usl)) $usl='('.implode(' or ',$_usl).')' ;
    return($usl) ;
  }

  // показывает заголовки для ячеек таблицы для конкетного класса
  function print_td_header($tkey,$clss,$edit_list,$options=array())
    { $edit_td='' ;   $image_td='' ;

      //if (!$options['no_check']) $check_td='<td><input name="check_all" type="checkbox" value="ON" /></td>' ;

      if (!$options['no_check'])
          { //if (!_sizeof($first_rec['__reffer_from']))
              $check_td='<td><input name="check_all" type="checkbox" value="ON" /></td>' ;
            //else
            //  $check_td='<td><input name="check_all" type="checkbox" value="ON"/></td>' ;
          } else $check_td='' ;

      if (!$options['read_only'] and !$options['no_icon_edit'] and !$options['_small']) $edit_td ='<td>Правка</td>' ;
      if (!$options['no_icon_photo'] and $clss!=3 and isset(_DOT($tkey)->list_clss[3])) $image_td='<td>Фото</td>' ;

	   // выводим заголовки полей
	   echo $check_td.$edit_td.$image_td ;
	   if (_sizeof($edit_list)) foreach ($edit_list as $fname=>$edit_info) if (!isset($options['no_view_field'][$fname]))
	   { if (!is_array($edit_info)) if (isset($_SESSION['pattern_clss_fields'][$edit_info])) $edit_info=$_SESSION['pattern_clss_fields'][$edit_info] ; else $edit_info=array('title'=>$edit_info) ;
         // делаем проверку на мультиязыность, если + , то выводим доп. колонку
	     // условие +:
	     // у таблицы включена мультиязчность, текущее поле имеет тип "строка", поле с соответствующем языком есть в базе
	     $i=0 ;
	     if (_DOT($tkey)->list_clss_ext[$clss]['multilang'][$fname] )
           { if (_sizeof($GLOBALS['lang_arr'])) foreach($GLOBALS['lang_arr'] as $lang_info)
             {  $lang_fname=$fname.$lang_info['suff'] ;
                if (isset(_DOT($tkey)->field_info[$lang_fname])) {?><td><?echo $edit_info['title'].' ('.$lang_info['name'].')' ; $i++ ;?></td><?}
             }
           }

         if ($fname and $options['order_by']==$fname) $sort_img_src=($options['order_mode']=='asc')? _PATH_TO_ENGINE.'/admin/images/sort_down.png':_PATH_TO_ENGINE.'/admin/images/sort_up.png' ;
         else                              $sort_img_src='' ;
         if ($sort_img_src)                $img='<img class=sort src="'.$sort_img_src.'">' ;
         else                              $img='' ;

         if (!$i) {?><td <?if ($fname and !$options['no_ext_func']) echo 'fname="'.$fname.'"'?>><?echo $edit_info['title']?><?echo $img?></td><?} // если ничего не было показано - обычный вывод поля
	   }
   }

  // -----------------------------------------------------------------------------------------------------------------------------------------------------------------------
  //
  //
  //
  // -----------------------------------------------------------------------------------------------------------------------------------------------------------------------

 function has_parent_clss($parent_clss)
 { $mas_parent=$_SESSION['class_system']->tree[$this->clss]->get_list_parent_clss() ;
   return((in_array($parent_clss,$mas_parent)!==false)? true:false) ;
 }

 function get_arr_child_clss()
 {
    return($_SESSION['class_system']->tree[$this->clss]->get_arr_child_clss()) ;
 }

  function show_this()
  { echo '<h1>clss_'.$this->clss.'</h1>' ;
    //$this->a1='12' ;
    damp_array($this,1,-1) ;
  }

  // -----------------------------------------------------------------------------------------------------------------------------------------------------------------------
  //
  // Создание объектов
  //
  // -----------------------------------------------------------------------------------------------------------------------------------------------------------------------
  /*
  function _obj_create_dialog()
  { $form_id='form_obj_create_dialog_clss_'.$this->clss ;
    ?><form method="POST" action="ajax.php" id=<?echo $form_id?>>Укажите имя нового объекта: <input name=new_obj[obj_name] value="" class="text" data-required><br><br>
          <input type=submit id=submit class=button_green mode=append_viewer_main cmd=create_obj_after_dialog clss=<?echo $this->clss?> parent_reffer="<?echo $_POST['parent_reffer']?>" value="Создать объект">
          и <? show_select_action('after_clss_'. $this->clss.'_create_action',array('go_list'=>'перейти к списку объектов','go_this'=>'перейти к созданному объекту','go_create'=>'создать еще один объект')) ;?>
          <script type="text/javascript">new mForm.Submit({form:'<?echo $form_id?>',validateOnBlur:true,blinkErrors:true,shakeSubmitButton: true,submitButton:$('submit'),ajax: true, showLoader: true, responseSuccess:'any',onSuccess:function(responseText, responseXML){if (responseXML!=null) mForm_Submit_AJAX_onSuccess(responseXML);}});</script>
      </form>
    <?
  } */

  // выполнение создания объекта по результатам диалога
  function create_obj_after_dialog()
  { ob_start() ;
    //damp_array($_POST) ;
    $new_obj_rec=$this->obj_create($_POST['new_obj']) ;
    // готовим массив для сохранения параметров объекта обычным способом
    if (is_array($new_obj_rec))
    { $list_obj[$new_obj_rec['tkey']][$new_obj_rec['clss']][$new_obj_rec['pkey']]=$_POST['new_obj'] ;
      save_list_obj($list_obj) ;

      if (_sizeof($_FILES['new_obj_append']['name'])) foreach($_FILES['new_obj_append']['name'] as $clss=>$arr_files_names) if (_sizeof($arr_files_names)) foreach($arr_files_names as $indx=>$fname)
      {     $cur_file_info=array() ;
            $cur_file_info['name']		=$_FILES['new_obj_append']['name'][$clss][$indx];
			$cur_file_info['type']		=$_FILES['new_obj_append']['type'][$clss][$indx];
			$cur_file_info['tmp_name']	=$_FILES['new_obj_append']['tmp_name'][$clss][$indx];
			$cur_file_info['error']		=$_FILES['new_obj_append']['error'][$clss][$indx] ;
			$cur_file_info['size']		=$_FILES['new_obj_append']['size'][$clss][$indx] ;
	        // вызываем стандартную функцию для загрузки фото
            if (!$cur_file_info['error']) switch($clss)
            { case 3: obj_upload_image($new_obj_rec['_reffer'],$cur_file_info,array('view_upload'=>1)) ;
                      break ;
              case 5: $obj_file=_CLSS(5)->obj_create(array(),array('parent_reffer'=>$new_obj_rec['_reffer'])) ;
                      obj_upload_file($obj_file['_reffer'],$cur_file_info,array('view_upload'=>1)) ;
                      break ;
            }
      }
     $text=ob_get_clean()  ;
     echo $text ;
    }
    return($new_obj_rec) ;
  }

  // создаем объект нужного класса
  // ВНИМАНИЕ! для создания больше не используется переменнные формы pkey и tkey
  // ВНИМАНИЕ! после создания возвращается запись по объекту, а не reffer
  function obj_create($finfo,$options=array())
  {  if  (is_demo_mode()) return(array()) ;
     if ($options['debug']) echo '<div class="green bold">Создаем объект класса '.$this->clss.'</div>' ;

     $cur_tkey=0 ; $new_obj_reffer='' ;  $parent_tkey=0 ; $parent_pkey=1 ; $obj_info=array() ;
     // опредяем код таблицы, куда сохряняем запись по объекту
     $parent_reffer=$_POST['parent_reffer'] ;
     if ($options['parent_reffer']) $parent_reffer=$options['parent_reffer'] ;
     if ($parent_reffer) list($parent_pkey,$parent_tkey)=explode('.',$parent_reffer) ;
     if ($parent_tkey)      $cur_tkey=$parent_tkey ;
     if ($finfo['tkey'])    $cur_tkey=$finfo['tkey'] ;
     if ($options['tkey'])  $cur_tkey=$options['tkey'] ;
     if (!$finfo['clss'])   $finfo['clss']=$this->clss  ;
     if (!$finfo['parent']) $finfo['parent']=$parent_pkey  ;
     if (!$finfo['obj_name']) $finfo['obj_name']=$this->name($parent_reffer)  ;
     if ($cur_tkey)         $new_obj_reffer=save_obj_in_table($cur_tkey,$finfo,$options) ;
     else                   echo 'Не указан tkey таблицы для добавления новой записи<br>' ;

     if ($new_obj_reffer)
           {   $obj_info=get_obj_info($new_obj_reffer,array('no_child_obj'=>1)) ;
               $data=array() ;
               if ($obj_info['obj_name']==$this->name($parent_reffer))
               {  $data['obj_name']=$this->name($parent_reffer).' # '.$obj_info['pkey'] ;
                  $obj_info['obj_name']=$data['obj_name'] ;
               }
                  if (isset(_DOT($obj_info['tkey'])->field_info['url_name'])) $data['url_name']=_CLSS($obj_info['clss'])->prepare_url_obj($obj_info) ;
               if (_sizeof($data)) update_rec_in_table($obj_info['tkey'],$data,'pkey='.$obj_info['pkey']) ;
               //$obj_info=array_merge($obj_info,$data) ;
           }

     if ($new_obj_reffer and !$options['no_reg_events']) _event_reg('Создание объекта','',$new_obj_reffer) ; // регистрируем событие 'Создание объекта'
     // вызываем функцию-обработчик события
     if ($new_obj_reffer) $this->on_create_event($obj_info) ;

     // перегружаем админку
     //reboot_engine() ;

     return($obj_info) ;
  }

  function on_create_event($obj_info,$options=array())
  {  if ($this->extended_func['on_create_event'])
        { if (!is_array($this->extended_func['on_create_event'])) $func_name=$this->extended_func['on_create_event'] ;
          else $func_name=DESKTOP()->include_script_cmd($this->extended_func['on_create_event']['cmd'],$this->extended_func['on_create_event']['script']) ;
          if ($options['debug']) echo 'Вызываем функцию-обработчик "<strong>'.$func_name.'</strong>"' ;
          if (function_exists($func_name)) $func_name($obj_info) ;
          if ($options['debug']) echo '...ok<br>' ;
        }
  }

  // -----------------------------------------------------------------------------------------------------------------------------------------------------------------------
  //
  // Сохранение объектов
  //
  // -----------------------------------------------------------------------------------------------------------------------------------------------------------------------


  // -----------------------------------------------------------------------------------------------------------------------------------------------------------------------
  //
  //  Удаление объектов
  //
  // -----------------------------------------------------------------------------------------------------------------------------------------------------------------------

  function obj_delete($tkey,$pkeys,$options=array())
  {
    if  (is_demo_mode()) return ;
    $debug=$options['debug'] ;

    $pkey_str=(is_array($pkeys))? implode(',',$pkeys):$pkeys ; // собираем id объектов одного класса в строчку - они гарантированно будут в одной таблицк
 	if ($debug) echo '<strong>Готовимся удалять</strong>  id='.$pkey_str.' из '._DOT($tkey)->name.' (tkey='.$tkey.',mode='._DOT($tkey)->mode.')<br>' ;
    // получаем инфу по дочерним объектам

    $childs_obj=select_db_obj_all_child_pkeys($tkey,$pkey_str) ;
    if ($debug) { echo '<strong class=blau>Получем дочерние объекты для </strong>  id='.$pkey_str.' из '._DOT($tkey)->name.'<br>' ; damp_array($childs_obj,1,-1) ; if (!_sizeof($childs_obj)) echo '<span class=green>Дочерних объектов нет</span><br>' ; }
    if (_sizeof($childs_obj)) foreach($childs_obj as $child_tkey=>$arr_clss)
       if (_sizeof($arr_clss)) foreach($arr_clss as $clss=>$childs_pkeys) _CLSS($clss)->obj_delete($child_tkey,$childs_pkeys,$options) ; ;


    // после удаления всех дочерних объектов, можно удалить сам объект
    if ($debug) echo '<strong class=red>Удаляем объекты </strong>  id='.$pkey_str.' из '._DOT($tkey)->name.'<br>' ;
    $list_deleted_recs=execSQL('select * from '._DOT($tkey)->table_name.' where pkey in ('.$pkey_str.')') ;

    $sql="delete from "._DOT($tkey)->table_name." where pkey in ($pkey_str)" ;
    execSQL_update($sql) ;
    // далее по каждому удаленному объекту отдельно
    if (_sizeof($list_deleted_recs)) foreach($list_deleted_recs as $rec)
    {  delete_link($rec['_reffer']) ;
       $this->on_delete_event($rec,$options) ;
    }
  }

  // реакция на событие удаления объекта - у каждого класса должно выражаться по своему
  function on_delete_event($obj_info,$options=array())
  { $obj_title='<span class=green>'.$this->name.'</span> <strong class=black>'.$obj_info['obj_name'].'</strong> (id='.$obj_info['pkey'].')' ;
    if ($options['obj_title']) $obj_title=$options['obj_title'] ;
    //if ($rec['clss']==36) $obj_title='<span class=green>'.$this->name.'</span> - <strong class=black>'.$rec['url'].'</strong>' ;
    echo 'Удален: '.$obj_title.'<br>' ;
    _event_reg('Удаление объекта',$obj_title,$obj_info['_reffer']) ; // регистрируем событие 'Удаление объекта'
    // удаляем запись по объект из карты сайта
    $sql='delete from '.TM_SITEMAP.' where obj_reffer="'.$obj_info['_reffer'].'"' ;
    execSQL_update($sql) ;

    // если есть левый фрейм с деревом, удаляем оттуда li удаленного объекта
    ?><script type="text/javascript">delete_item_from_tree("<? echo $obj_info['_reffer']?>")</script><?
  }

  // -----------------------------------------------------------------------------------------------------------------------------------------------------------------------
  //
  //  другие функции
  //
  // -----------------------------------------------------------------------------------------------------------------------------------------------------------------------

  function get_menu_set_to_table($tkey=0,$pkey=0)
  { $cur_menu=$this->menu ; // по умолчанию используем меню класса
    // читаем правила для таблицы, правило типа
    //  array('to_clss'=>clss,'use_menu'=>array('save','delete')) ; // описание меню для объектов класса clss в таблице tkey
    //  array('to_pkey'=>pkey,'use_menu'=>array('save','delete')) ; // описание меню для объекта pkey в таблице tkey
    if ($tkey and _sizeof(_DOT($tkey)->rules)) foreach(_DOT($tkey)->rules as $rec) if (isset($rec['use_menu'])) // если задано меню в правиле
      {  if ($rec['to_pkey'] and $rec['to_pkey']==$pkey)        $cur_menu=$rec['use_menu'] ; // если в правиле используетмя код объекта=текущему коду объекта  - применяеме правило
         if ($rec['to_clss'] and $rec['to_clss']==$this->clss)  $cur_menu=$rec['use_menu'] ; // если код передан и код правила=переданнуму  - применяем правило
      }
    if ($tkey and _sizeof(_DOT($tkey)->rules)) foreach(_DOT($tkey)->rules as $rec) if (isset($rec['add_menu'])) // если задано меню в правиле
      {  if ($rec['to_pkey'] and $rec['to_pkey']==$pkey)        $cur_menu=array_merge($cur_menu,$rec['add_menu']) ; // если в правиле используетмя код объекта=текущему коду объекта  - применяеме правило
         if ($rec['to_clss'] and $rec['to_clss']==$this->clss)  $cur_menu=array_merge($cur_menu,$rec['add_menu']) ; // если код передан и код правила=переданнуму  - применяем правило
      }
    return($cur_menu) ;
  }

  // выводит в выпадающем списке перечень полей класса
  // имя списка - select_clss
  //
  // опции: no_show_clss - класс, который не показывать
  function show_select_to_list_field($options=array())
  { global  $select_fname;
    ?><select size="1" name="select_fname"><?
      if (_sizeof($this->fields)) foreach($this->fields as $fname=>$ftype)
       if (!_sizeof($options['no_show_field']) or (_sizeof($options['no_show_field']) and !in_array($fname,$options['no_show_field'])))
        { $title=(isset($_SESSION['descr_clss'][$this->clss]['list']['field'][$fname]))? $_SESSION['descr_clss'][$this->clss]['list']['field'][$fname]['title'].' ('.$fname.')':$fname ;
          ?><option value="<?echo $fname?>" <?if ($select_fname==$fname) echo 'selected'?>><?echo $title?></option><?
        }
      ?></select><?
  }

  // -----------------------------------------------------------------------------------------------------------------------------------------------------------------------
  //
  //  функции для вывода объектов в таблицах
  //
  // -----------------------------------------------------------------------------------------------------------------------------------------------------------------------


// возвращает название элемента, которым будет редактироваться поле $fname.
  // $options - опции из $_SESSION['descr_clss'][11]['list']['field']['obj_name']		=array('title'=>'Наименование','class'=>'small','td_class'=>'justify') ;
  // ??? fields_info
  function get_edit_element_to_field($fname,$options=array())
  {   // сначала проверяем прямое указание элемента в опциях
      $edit_element=$options['edit_element'] ;
      if ($edit_element>=1 and $edit_element<=10) $edit_element='' ;
      // если были опции - получаем по наличию опций
      if ($options['indx_array'])  	  $edit_element='indx_array_value' ;
      if ($options['indx_select'])    $edit_element='indx_select' ;
      if ($options['view_as'])        $edit_element=$options['view_as'];
      // если опций не было - получаем по типу поля
      $field_type=($options['type'])? $options['type']:$this->fields[$fname];
      list($type,$size)=get_info_db_field_type($field_type) ;
      if (!$edit_element) switch ($type) // если значение $edit_element не опеределено, определяем его на основе типа поля
      { case 'timedata':
        case 'serialize':
        case 'multichange':
        case 'indx_select':  $edit_element=$type ; break ;
        case 'mediumtext':
        case 'text':        $edit_element='memo' ; break ;
        case 'varchar':
        case 'float':       $edit_element='input' ; break ;
        case 'int':    	   $edit_element=($size>1)? 'input':'checkbox' ; break ;
        default:           $edit_element=$field_type ;
       }
      //echo $this->fields[$fname].'-'.$type.'-'.$size.'-'.$edit_element.'<br>' ;
      return($edit_element) ;
  }


    // возвращает значение поля fname массива объекта класса. Отдельная функция необходима, т.к. иногда есть необходимость корректировать значения поля перед отдачей в вывод
    function get_rec_field($rec,$fname,$options=array())
     { $value=$rec[$fname] ;
       if ($this->view['list']['field'][$fname]['edit_element']=='data_input' or $this->fields[$fname]=='timedata')  //$obj_clss - чтобы тип поля брался у родителя, если у текущего класса наследуется
       {  $format=$options['format']? $options['format']:'d.m.Y G:i' ;
     	  $format=$options['data_format']? $options['data_format']:$format ;
     	  $value=($value)? date($format,$value):'' ;
       }
       return($value) ;
     }

    function use_HTML_editor($rec,$fname)
    { $use_HTML_editor=0 ;
      if ($this->fields_info[$fname]['use_HTML_editor']) $use_HTML_editor=1 ;
      if (array_key_exists('is_HTML',$rec) and ($rec['is_HTML']==0 or $rec['is_HTML']=='')) $use_HTML_editor=0 ;
      //if (array_key_exists('is_HTML',$rec) and $rec['is_HTML']==1) $use_HTML_editor=1 ;
      return($use_HTML_editor) ;
    }

    // подготовка url для страницы объекта
    function prepare_url_obj($rec)
    {   $url_name=safe_text_to_url($rec['obj_name'],$rec['tkey']) ;
        return($url_name) ;
    }


  // -----------------------------------------------------------------------------------------------------------------------------------------------------------------------
  //
  //  вывод объекта в XML
  //
  // -----------------------------------------------------------------------------------------------------------------------------------------------------------------------

 // $doc 			- сслылка на объект класса DomDocument();
 // $parent 		- сслылка на ветвь, куда добавляется объект
 // $parent_tkey	- таблица, в которой находиться родитель экспортируемых объектов (сохраняется в виде отдельного поля)
 // $tkey			- таблица, из которой необходимо экспортировать объекты
 // $str_pkey		- коды объектов, которые необходимо экспортировать

 function export_to_XML(&$doc,&$parent_obj_xml,$parent_tkey,$tkey,$str_pkeys,$options=array())
 {
   // получаем инфу по объектам
   $options_select=array ('no_connect_table'=>1,'no_image'=>1,'no_group_clss'=>1,'no_out_table'=>1) ;
   // делаем запрос по конкретно указанным кодам объектов в указанной таблице
   $objs_info=select_objs($tkey,'*','pkey in ('.$str_pkeys.')',$options_select) ;
   //echo 'Получаем '
   //damp_array($objs_info) ;
   //damp_array($options) ;
   if (_sizeof($objs_info[$tkey])) foreach($objs_info[$tkey] as $rec)
 	{  // создаем объект XML в текущем дереве
 	   $obj = add_element($doc,$parent_obj_xml,'obj','',array('id'=>$rec['pkey'])) ;
       $obj_clss=_CLSS($rec['clss']);

 	   add_element($doc,$obj,'tkey',$rec['tkey']) ;
 	   if ($parent_tkey) add_element($doc,$obj,'parent_tkey',$parent_tkey) ;  // только если определена таблица родительского объекта
 	   // для копирования фото
       if ($rec['clss']==3) { if ($options['copy_file_to_trash'])
                              {   add_element($doc,$obj,'_patch_to_file_',_PATH_TO_DELETED.'/') ;
                                  copy_obj_img_to_trash($tkey,$rec['file_name']) ;
                              }
                              else if ($options['use_inner_file_dir']) add_element($doc,$obj,'_dir_to_file_',hide_server_dir(_DOT($tkey)->dir_to_file)) ;
                              else add_element($doc,$obj,'_patch_to_file_',_DOT($tkey)->patch_to_file) ;
                            }
 	   // для копирования файла
       if ($rec['clss']==5) { if ($options['use_inner_file_dir']) add_element($doc,$obj,'_dir_to_file_',hide_server_dir(_DOT($tkey)->dir_to_file)) ;
                              else add_element($doc,$obj,'_patch_to_file_',_DOT($tkey)->patch_to_file) ;
                            }

 	   if (_sizeof($obj_clss->fields)) foreach($obj_clss->fields as $fname=>$finfo)
 	    {
 	      if ($fname=='enabled') $value=($rec[$fname])? 'on':'off' ;
 	       else 				 $value=$rec[$fname] ;
 	      if ($value) add_element($doc,$obj,$fname,$value) ; // выгружам в XML только поля со значениями
 	    }
 	   // получаем инфу по наличию дочерних объектам
       //echo 'Получаем инфо для объекта:'.$rec['obj_name'].'<br>';
       $child_info=select_obj_childs_clss_cnt($rec['pkey'].'.'.$tkey) ;
       if (_sizeof($child_info)) foreach($child_info as $child_clss=>$cnt) if (!_CLSS($child_clss)->no_export_in_xml)
	   {   //damp_array($child_info,1,-1) ;
	       $child_tkey=_DOT($tkey)->list_clss[$child_clss] ;
	       $child_pkeys_arr=execSQL_line('select pkey from '._DOT($child_tkey)->table_name.' where parent='.$rec['pkey']) ;
	       //damp_array($child_pkeys_arr) ;
	       if (_sizeof($child_pkeys_arr)) $child_pkeys=implode(',',$child_pkeys_arr) ;
	       else                          $child_pkeys='' ;
	       //echo '$child_pkeys='.$child_pkeys.'<br>' ;


           _CLSS($child_clss)->export_to_XML($doc,$obj,$tkey,$child_tkey,$child_pkeys,$options) ;

	       //$func_export='export_XML_clss_'.$child_clss ;
		   //if (function_exists($func_export)) $func_export($doc,$obj,$tkey,$child_tkey,$child_pkeys,$options) ;
		   //else export_XML_clss_0($doc,$obj,$tkey,$child_tkey,$child_pkeys,$options) ;
	   }
 	}
 }

 function get_key_field()  { return('pkey') ;  }

}





?>
