<?php
//check_engine_version() ; // проверяем, что версия engine cоответствует версии class

include_once('i_db_object.php') ;
//include_once('i_clss.php') ;
include_once('i_logs.php') ;
include_once('i_lists.php') ;
include_once('i_io.php') ;
include_once('i_device.php') ;
include_once('i_tree.php') ;
include_once('i_doc.php') ;
include_once('i_report.php') ;
include_once('i_mediaserver.php') ;
include_once('i_imagemagic.php') ;
include_once('i_disk.php') ;
include_once('i_setup.php') ;
include_once('i_mailbox.php') ;
include_once(_DIR_TO_MODULES.'/accounts/i_account.php') ;
define('_THEME_','megamenu') ; // тема по умолчанию
include_once(_DIR_EXT.'/'._THEME_.'/i_'._THEME_.'_form.php') ;

define('_STORAGE_DIR','/storage') ;
define('_TEMP_DIR',_DIR_TO_ROOT.'/temp/') ;
define('_TEMP_PATH',_PATH_TO_SITE.'/temp/') ;
define('_UPLOADS_DIR','/temp/uploads/') ;
define('_DEFAULT_TIMEZONE','Europe/Moscow') ;

$__functions['init'][]='_engine_site_vars' ;

function ENGINE() {if (is_object($_SESSION['engine_system'])) return($_SESSION['engine_system']);$_SESSION['engine_system']=new c_engine_system();return($_SESSION['engine_system']);} ;
function REPORTS() {return($_SESSION['engine_system']);$_SESSION['engine_system']=new c_engine_system();return($_SESSION['engine_system']);} ;
function SETTING($name) {return($GLOBALS['_SETTING'][$name]);} ;


function _engine_site_vars()
{   // ИНФОРМАЦИЯ ПО РОЛЯМ ВСЕХ МОДУЛЕЙ
    // 1  - Администратор
    // 2  - Фельдшер                    => ESMO
    // 3  - Цеховой терапевет           => TERAPEVT
    // 4  - Табельщик                   => ESMO
    // 5  - Техник                      => TO
    // 6  - Клиент                      => CLIENT
    // 7  - Менеджер по клиентам        => CLIENT
    // 8  - Ламповщик                   => MINE
    // 9  - Франчайзер                  => ESMO_BILLING:
    // 10 - Начальник СБ                => SKD
    // 11 - Сотрудник СБ                => SKD
    // 12 - Сотрудник БП                => SKD

    $_SESSION['ARR_monitor']=array(   0=>'SSE',
                                      1=>'AJAX',
                                      2=>'HTML'
                                       ) ;

    $_SESSION['indx_report_section']=array('МО - журналы',
                                           'МО - отчеты',
                                           'Персонал',
                                           'Служебные отчеты',
            ) ;

    $_SESSION['init_options']['engine']['debug']=0 ;


    $_SESSION['init_options']['default']['pages']['options']=array('pages_num_format'=>"%'1d",'page_max_number_count'=>50,'page_number_rasdel'=>'&nbsp;&nbsp;|&nbsp;&nbsp;','page_image_prev'=>'/images/arr_left_dark.gif','page_image_next'=>'/images/arr_right_dark.gif') ;
    $_SESSION['init_options']['default']['pages']['options']['page_mode']=0 ;
    $_SESSION['init_options']['default']['pages']['size']=array('50'=>'50 позиций на странице') ;

    $_SESSION['arr_color_sets']=array('bg-red'=>'red',
                                'bg-orange'=>'orange',
                                'bg-yellow'=>'yellow',
                                'bg-green'=>'green',
                                'bg-cyan'=>'cyan',
                                'bg-blue'=>'blue',
                                'bg-purple'=>'purple',
                                'bg-pink'=>'pink',
                                'bg-black'=>'black');

    //$_SESSION['ARR_chet_operation_types']=array(1=>'Поступление',2=>'Списание') ;
    //$_SESSION['ARR_chet_types']=array(0=>'Расходный',2=>'Приходный') ;

     ////
}

function _engine_site_boot($options)
{
  create_system_modul_obj('engine',$options) ;
  if (MEMBER()->info['timezone']) date_default_timezone_set(MEMBER()->info['timezone']);
}


class c_engine_system
{
    public $table_bill ;
    public $engine_list ;
    public $list_active_ext=array() ;
    public $reports_list ;
    public $reports_sections ;
    public $docs_list ;
    public $event_lister ;


    function __construct($create_options=array())
    {   $this->table_mo_log ='obj_'.SITE_CODE.'_mo_log' ;
        $this->table_mo_req ='obj_'.SITE_CODE.'_req_log' ;

        $this->reg_ext('aspmo_reports','Отчеты Медицина') ;
        $this->reg_ext('aspmo_setting','Настройки') ;
        $this->reg_ext('aspmo_debug','Отладка') ;
        $this->reg_ext('docs','Документы') ;
        $this->reg_ext('log','Служебные отчеты') ;

    }

    function declare_menu_items_3($page)
      {

          $page->menu['/cab/reports/']=array('title'=>'Отчеты',
                                        'class'=>'fas fa-table',
                                        //'items'=>array('/cab/reports/'=>array('title'=>'Создать отчет','class'=>'fa fa-users'))
                                        ) ;
      }

    function declare_menu_items_4($page)
    {
        $page->menu['/cab/setting/']=array('title'=>'Настройки',
                                           'no_link'=>1,
                                           'class'=>'fas fa-sliders-h',
                                           'items'=>array('/cab/setting/members/'=>array('title'=>'ЭСМО',
                                                                                        'class'=>'fa fa-users',
                                                                                        'items'=>array('/cab/setting/members/'=>'Персонал ЭСМО',
                                                                                                       '/cab/setting/member/new/'=>array('title'=>'Добавить...','class'=>'fa fa-user-plus'),
                                                                                                       '/cab/setting/members/rol/'=>array('title'=>'Роли персонала'),
                                                                                                       '/cab/setting/members/groups/'=>array('title'=>'Рабочие группы'),
                                                                                                       '/cab/setting/right/'=>array('title'=>'Права доступа'),
                                                                                                       //'/cab/setting/locals/'=>'Локализация',
                                                                                                       '/cab/setting/config/'=>'Системные настройки'
                                                                                                       )
                                                                                       ),
                                                         '/cab/setting/interface/'=>array('title'=>'Интерфейс',
                                                                                          'items'=>array(
                                                                                              '/cab/setting/interface/'=>'Настройки системы',
                                                                                              '/cab/setting/send_smtp/'=>'Отправка почты (smtp)'
                                                                                          )),
                                                         '/cab/manager/'=>array('title'=>'Клиенты',
                                                                                'class'=>'fa fa-users',
                                                                                'items'=>array(/*'/cab/setting/members/'=>'Список персонала',*/
                                                                                               '/cab/manager/client_create/'=>array('title'=>'Добавить клиента','class'=>'fa fa-user-plus')
                                                                                               )
                                                                               ),

                                                         //'/cab/setting/smena/'=>'Смены',
                                                         //'/cab/setting/rules/'=>'Критерии осмотра',
                                                         //'/cab/setting/arm/'=>'АРМ',
                                                         //'/cab/setting/terminal/'=>'Терминалы',
                                                         '/cab/setting/update/'=>'Обновление'
                                                        )
                                          ) ;

        // если авторизация под фельдшером и он в основной группе - значит это инсталятор и надо ему дать возможность зарегситрировать группу
//        if (MEMBER()->rol==2 and MEMBER()->cur_group_id==$GLOBALS['LS_AD_default_group'])  $page->menu['/cab/setting/members/new_group/']=array('title'=>'Регистрация группы','class'=>'fa fa-object-group') ;
    }

    function declare_menu_items_5($page)
    {

        $page->menu['/cab/log/events/']=array('title'=>'Отладка',
                                          'allow_access_to_rol'=>20,
                                          'class'=>'fa fa-cogs',
                                          'items'=>array('/cab/log/req/'=>'Журнал обмена',
                                                         '/cab/log/events/'=>array('title'=>'Журнал событий'),
                                                         '/cab/log/pages/'=>array('title'=>'Журнал страниц'),
                                                          '/cab/debug/info/'=>'Информация',
                                                         )
                                           ) ;
        //$this->menu['/cab/terminal/']='Терминалы' ;
    }

    function reg_ext($ext_name,$ext_title)
    {
      $this->list_active_ext[$ext_name]=$ext_title ;
    }


    function get_cron_by_code($code)
    {
      $rec=execSQL_van('select * from obj_site_crontab where cmd="'.$code.'" ') ;
      return($rec) ;
    }

    function reg_cron($name,$cmd,$intr,$options=array())
    {  include_once(_DIR_TO_MODULES.'/engine/i_setup.php') ;
       SETUP()->reg_cron($name,$cmd,$intr,$options) ;
    }


  //$now=getdate() ;
  //if (!$this->filter['data_from']) $this->filter['data_from']=date('d.m.Y',mktime(0,0,0,$now['mon']-1,1,$now['year']));
  //if (!$this->filter['data_to'])   $this->filter['data_to']=date('d.m.Y',mktime(0,0,0,$now['mon'],1,$now['year'])-1);
    function cron_exec()
    {   set_time_point('cron_exec start') ;

        $t_start=fixed_time() ;
        // получаем список кронов
        if (!$GLOBALS['LS_cron_active']) return ;
        // время старта крона, без секунд
        $now=getdate() ;
        $cur_time=mktime($now['hours'],$now['minutes'],0,$now['mon'],$now['mday'],$now['year']);
        ob_start() ;

        // сбрасываем задания, которые высят уже более часа
        $check_time=mktime($now['hours'],$now['minutes']-60,$now['seconds'],$now['mon'],$now['mday'],$now['year']);
        $recs=execSQL('select * from obj_site_crontab where status=1 and last_exec<'.$check_time) ;
        if (_sizeof($recs))
        {  ob_start() ;
           echo 'Зависшие задания от '.date('d.m.Y H:i:s',$check_time).'<br>' ;
           echo 'Текущее время'.date('d.m.Y H:i:s').'<br>' ;
           print_2x_arr($recs) ;
           $cnt=execSQL_update('update obj_site_crontab set last_exec_end=0,time_exec=0,status=0 where status=1 and last_exec<'.$check_time,array('debug'=>2)) ;
           echo 'Было сброшено <strong>'.$cnt.'</strong> зависшых заданий<br>' ;
           $text=ob_get_clean() ;
           echo $text.'<br>' ;
           $fname=LOGS()->reg_file_log('crontab_init',$text) ;
           LOGS()->reg_log('crontab_init','<a target=_blank href="' . $fname . '" target=_BLANK>Отчет</a>') ;
           update_site_setting('LS_last_cron_status',0,array('no_log'=>1)) ;
           $GLOBALS['LS_last_cron_status']=0 ;
        }
        set_time_point('проверка зависших заданий') ;

        // настройка LS_last_cron_status ставиться при начале выполнения cron и сбрасывеется при окончании выполнения cron
        if ($GLOBALS['LS_last_cron_status'])
        {   LOGS()->reg_log('exec_crontab','Выполняется сеанс планировщика от '.date('d.m.Y H:i:s',$GLOBALS['LS_last_cron_status']).', выполнение текущего сеанса отменено') ;

        }
        else
        { update_site_setting('LS_last_cron_status',time(),array('no_log'=>1)) ;
        $list_crontab=execSQL('select pkey,c_data,cmd,obj_name,last_exec,last_exec_end,time_exec,intr,status from obj_site_crontab where enabled=1 and status=0 order by intr',0) ;
        if (_sizeof($list_crontab)) foreach($list_crontab as $rec_cron)
        {  $result=array() ;
           // парсим в часы минут время последнего выполнения задания
           $last_exec=($rec_cron['last_exec'])? getdate($rec_cron['last_exec']):getdate($rec_cron['c_data']) ;
           // расчитываем время выполнения задания
           $m_every=-1 ; $m_fix=-1 ; $h_every=-1 ; $h_fix=-1; $d_every=-1 ; $d_fix=-1 ;
           $next_exec_h=-1 ; $next_exec_m=-1 ; $next_exec_d=-1 ;
           $arr=explode(' ',$rec_cron['intr']) ;
           $arr2=explode('/',$arr[0]) ;
           if ($arr2[0]!='*') $m_fix=$arr2[0] ; else if ($arr2[1]) $m_every=$arr2[1] ; else  $m_fix=$last_exec['minutes'] ;
           $arr2=explode('/',$arr[1]) ;
           if ($arr2[0]!='*') $h_fix=$arr2[0] ; else if ($arr2[1]) $h_every=$arr2[1] ; else  $h_fix=$last_exec['hours'] ;
           $arr2=explode('/',$arr[2]) ;
           if ($arr2[0]!='*') $d_fix=$arr2[0] ; else if ($arr2[1]) $d_every=$arr2[1] ; else  $d_fix=$last_exec['mday'] ;



           if ($m_every>0) $next_exec_m=$last_exec['minutes']+$m_every ; else if ($m_fix>=0) $next_exec_m=$m_fix ;
           if ($h_every>0) $next_exec_h=$last_exec['hours']+$h_every ; else if ($h_fix>=0) $next_exec_h=$h_fix ;
           if ($d_every>0) $next_exec_d=$last_exec['mday']+$d_every ; else if ($d_fix>=0) $next_exec_d=$d_fix ;


           // $cur_time -
           //
           if ($m_every>0 or $h_every>0 or $d_every>0) $plan_exec= mktime($next_exec_h,$next_exec_m,0,$last_exec['mon'],$next_exec_d,$last_exec['year']);     // для регулярных заданий
           else                                      $plan_exec= mktime($next_exec_h,$next_exec_m,0,$now['mon'],$now['mday'],$now['year']);                 // для заданий по времени
           //$plan_exec=$next_exec ;
           /*if ($next_exec<$cur_time)
           {   $next_exec_al=0 ;
               // условия 2 и 3 никогда не отрабатывают
               // так как для заданий по заданному времени в день всегда $d_fix>=0 and $h_fix>=0 and $m_fix>=0
               // а для заданий по периоду всегда m_fix=-1
               if ($d_fix>=0 and $h_fix>=0 and $m_fix>=0) { $next_exec= mktime($next_exec_h,$next_exec_m,0,$last_exec['mon'],$next_exec_d+1,$last_exec['year']);  $next_exec_al=1 ; }
               else if ($h_fix>=0 and $m_fix>0)           { $next_exec= mktime($next_exec_h+1,$next_exec_m,0,$last_exec['mon'],$next_exec_d,$last_exec['year']);  $next_exec_al=2 ; }
               else if ($m_fix>0)                         { $next_exec= mktime($next_exec_h,$next_exec_m+1,0,$last_exec['mon'],$next_exec_d,$last_exec['year']);  $next_exec_al=3 ; }

               $result['next_exec_al']=$next_exec_al;
           } */

           $result['ID']=$rec_cron['pkey'] ;
           $result['Расписание']=$rec_cron['intr'] ;
           $result['Операция']=$rec_cron['cmd'] ;
           $result['d_fix']=$d_fix;
           $result['h_fix']=$h_fix;
           $result['m_fix']=$m_fix;
           $result['d_every']=$d_every;
           $result['h_every']=$h_every;
           $result['m_every']=$m_every;
           $result['next_exec_d']=$next_exec_d;
           $result['next_exec_h']=$next_exec_h;
           $result['next_exec_m']=$next_exec_m;

           $result['last_exec']=($rec_cron['last_exec'])? date('d.m.Y H:i:s',$rec_cron['last_exec']):'-';
           $result['cur_time']=date('d.m.Y H:i:s',$cur_time);
           $result['plan_exec']=date('d.m.Y H:i:s',$plan_exec);

           $result['plan_exec']=date('d.m.Y H:i:s',$plan_exec);

           //$result['delta_after_plan_exec']=$plan_exec-$cur_time;
           //$result['delta_after_last_exec']=$plan_exec-$rec_cron['last_exec'];

           //if (isset($d_fix))

           if ($next_exec_h>=0 and $next_exec_m>=0 and $next_exec_d>=0)
           { if ($plan_exec<=$cur_time and $plan_exec>$rec_cron['last_exec'])
             {  echo '<span class="green">Выполняем задание <strong>'.$rec_cron['obj_name'].'</strong></span>' ;

                $arr=explode('/',$rec_cron['cmd']) ;
                if (_sizeof($arr)==2 or _sizeof($arr)==3)
                {   if (is_object($arr[0]()))
                    { if (method_exists($arr[0](),$arr[1]))
                      {   ob_start() ;
                          //damp_array($rec_cron,1,-1) ;
                          set_time_point('Выполнение задания '.$rec_cron['obj_name'].' - start') ;
                          // status=1 - флаг, что задание выпоняется. Задания с этим статусом не будут проверяться при следующем запуске планировщика
                          execSQL_update('update obj_site_crontab set last_exec='.time().',last_exec_end=0,time_exec=0,status=1 where pkey='.$rec_cron['pkey'],array('debug'=>0)) ;
                          $t1=fixed_time() ;

                          $func_name=$arr[0] ;
                          $method_name=$arr[1] ;
                          if ($func_name and $method_name) $result=$func_name()->$method_name() ;

                          $t2=fixed_time($t1,'Выполнено задание "'.$rec_cron['obj_name'].'"') ;
                          set_time_point('Выполнение задания '.$rec_cron['obj_name'].' - end') ;
                          execSQL_update('update obj_site_crontab set last_exec_end='.time().',time_exec="'.$t2.'",status=0 where pkey='.$rec_cron['pkey'],array('debug'=>0)) ;
                          if (_sizeof($result)) damp_array($result,1,-1) ;
                          $text_debug=ob_get_clean() ;
                          //$t1=fixed_time() ;
                          $log_fname=LOGS()->reg_file_log('exec_crontab',$text_debug) ;
                          set_time_point('Сохранен файловый лог задания задания '.$rec_cron['obj_name'].' - end') ;
                          echo ' <a href="/logs/'.str_replace(array('[fname=',']'),'',basename($log_fname)).'" target=_blank>Отчет</a>, '.round($t2,4).' сек.<br>';
                          //fixed_time($t1,'Сохранен лог выполения задания') ;
                      }
                      else echo '<div class="alert">В модуле <strong>'.$arr[0].'</strong> не найден метод <strong>'.$arr[1].'</strong></div>' ;
                    }
                    else echo '<div class="alert">Не найден модуль <strong>'.$arr[0].'</strong> с методом <strong>'.$arr[1].'</strong></div>' ;
                }

                $result['process']='Старт' ;

             }
             else if ($plan_exec>$cur_time) { if ($GLOBALS['LS_crontab_log_full']) echo '<div style="color:#b94a48">Задание <strong>'.$rec_cron['obj_name'].'</strong> - еще рано, будет выполнено '.date('d.m.Y H:i',$plan_exec).'</div>' ;}
             else if ($plan_exec<$rec_cron['last_exec']) { if ($GLOBALS['LS_crontab_log_full']) echo '<div style="color:#0D9EDF">Задание <strong>'.$rec_cron['obj_name'].'</strong> - уже выполнено '.date('d.m.Y H:i',$rec_cron['last_exec']).'</div>' ;}
           } else { if ($GLOBALS['LS_crontab_log_full']) echo 'Задание <strong>'.$rec_cron['obj_name'].'</strong> - $next_exec_h=0 or $next_exec_m=0 or $next_exec_d=0<br>' ; }
           $cron_result[$rec_cron['obj_name']]=$result ;
        }
        }
        $text=ob_get_clean() ;
        ob_start() ;
        print_2x_arr($cron_result) ;
        $text_arr=ob_get_clean() ;echo $text_arr.'<br>'.$text ;
        set_time_point('Все задания выполнены') ;
        LOGS()->reg_log('exec_crontab',$text,array('start'=>$t_start,'save_to_file'=>$text_arr)) ;
        update_site_setting('LS_last_cron_time',$cur_time,array('no_log'=>1)) ;
        update_site_setting('LS_last_cron_status',0,array('no_log'=>1)) ;
        set_time_point('Переменные обновлены') ;

    }

    function check_mail_box()
    {   include_once(_DIR_TO_MODULES."/engine/i_mailbox.php");
        $mail_box=new c_mailbox()  ;
        $mail_box->read_mail() ;
    }

    function clear_mp4_from_temp_dir()
    {
        $t=fixed_time() ;
        $hour=($GLOBALS['LS_lifetime_temp_video'])? $GLOBALS['LS_lifetime_temp_video']:24 ;
        exec('find '._DIR_TO_ROOT.'/temp -name "*.mp4" -type f -mmin +'.($hour*60).' -print0 | xargs -0 rm -f') ;
        fixed_time($t,'Удаление файлов .mp4 из /temp (через вызов shell exec), срок хранения '.$hour.' час.') ;
    }

    // добавить флаг работы с низнким приоритетом
    function clear_temp_dirs()
    { $hour=($GLOBALS['LS_lifetime_logs'])? $GLOBALS['LS_lifetime_logs']:24 ;
      $t=fixed_time() ;
      exec('find '._DIR_TO_ROOT.'/logs -type f -mmin +'.($hour*60-1).' -print0 | xargs -0 rm -f') ;
      fixed_time($t,'Очистка директории /logs (через вызов shell exec), срок хранения '.$hour.' час.') ;
      $t=fixed_time() ;
      $hour=($GLOBALS['LS_lifetime_temp'])? $GLOBALS['LS_lifetime_temp']:24 ;
      exec('find '._DIR_TO_ROOT.'/temp -type f -mmin +'.($hour*60-1).' -print0 | xargs -0 rm -f') ;
      fixed_time($t,'Очистка директории /temp (через вызов shell exec), срок хранения '.$hour.' час.') ;
      $t=fixed_time() ;
      exec('find '._DIR_TO_ROOT.'/tmp -type f -mmin +'.($hour*60-1).' -print0 | xargs -0 rm -f') ;
      fixed_time($t,'Очистка директории /tmp (через вызов shell exec), срок хранения '.$hour.' час.') ;
    }

    function test_cron()
    {
       echo 'test_cron: <br>';
    }


//--------------------------------------------------------------------------------------------------------
//
// Обработка событий
//
// --------------------------------------------------------------------------------------------------------
    // регистрация теста:  SETUP()->reg_event_lister('test','ENGINE','test_event_lister') ;
    // вызов теста: ENGINE()->on_event('test',array('a'=>1,'b'=>2,'c'=>3),array('debug'=>0)) ;
    function test_event_lister($data)
  {
      LOGS()->reg_log('test_event_lister','тест пройден успешно',array('data'=>$data)) ;
  }

    function on_event($event_name,$data=array(),$options=array())
    { //LOGS()->reg_log('event_lister',$event_name,array('data'=>$this->event_lister)) ;
      $debug=$options['debug'] ;  ob_start() ;
      $check=($debug)? $debug:$options['check'] ;
      if (!$check) $check=0 ;
      $arr_errors=array() ; $result=array() ;

      $event_listers=execSQL('select * from event_lister where obj_name="'.$event_name.'"',$debug) ;
      if (_sizeof($event_listers)) foreach($event_listers as $rec)
      {  $system=null ; $system_name=$rec['system_name'] ;
          if ($debug) echo 'Ищем функцию '.$system_name.'()<br>' ;
         if (function_exists($system_name))  { $system=$system_name() ; if ($debug) echo 'найдена функция '.$system_name.'()<br>' ;  }
         else
         { $arr_errors[]='Функция '.$system_name.'() не найдена' ;
           if (isset($_SESSION[$system_name]))  {  $system=$_SESSION[$system_name] ; if ($debug) echo 'найдена функция $_SESSION['.$system_name.']<br>' ;  }
           else
           {   $arr_errors[]='$_SESSION['.$system_name.'] не найдена' ;
               if (isset($GLOBALS[$system_name]))  { $system=$GLOBALS[$system_name] ; if ($debug) echo 'найдена функция $GLOBALS['.$system_name.']<br>' ; }
               else $arr_errors[]='$GLOBALS['.$system_name.'] не найдена' ;
           }
         }
         $method=$rec['method_name'] ;
          if (is_object($system) and method_exists($system,$method))
          {  //LOGS()->reg_log('event_lister',$event_name.': '.$system_name.' => '.$method,array('data'=>$data)) ;
             if (!$check) $result=$system->$method($data) ;
          }
          else if (is_object($system) and !method_exists($system,$method))
          { LOGS()->reg_log('event_lister',$event_name.': '.$system_name.'->'.$method.' НЕ НАЙДЕН',array('data'=>$data)) ;
            $arr_errors[]=$event_name.': '.$system_name.'()->'.$method.'() НЕ НАЙДЕН' ;
      }
          else if (!is_object($system))
          { LOGS()->reg_log('event_lister',$event_name.': '.$system->name.' СИСТЕМА НЕ НАЙДЕНА',array('data'=>$data)) ;
            $arr_errors[]=$event_name.': '.$system_name.'() СИСТЕМА НЕ НАЙДЕНА' ;
    }
      }
      if (_sizeof($arr_errors))
      { $result['error']=implode('<br>',$arr_errors) ;
        LOGS()->reg_log('event_lister',$result['error']) ;
      }

      $text=ob_get_clean() ;
      echo $text ;
      //if ($text) LOGS()->reg_log('event_lister_debug',$text) ;
      return($result) ;
    }
    function on_event_by_pointer($event_name,&$param1=null,&$param2=null,&$param3=null,&$param4=null,&$param5=null,&$param6=null)
    { //LOGS()->reg_log('event_lister',$event_name,array('data'=>$this->event_lister)) ;
      //$debug=$options['debug'] ;
      //$check=($debug)? $debug:$options['check'] ;
      $debug=0 ; $check=0 ;
      if (!$check) $check=0 ;
      $arr_errors=array() ; $result=array() ;

      $event_listers=execSQL('select * from event_lister where obj_name="'.$event_name.'"',$debug) ;
      if (_sizeof($event_listers)) foreach($event_listers as $rec)
      {  $system=null ; $system_name=$rec['system_name'] ;
          if ($debug) echo 'Ищем функцию '.$system_name.'()<br>' ;
         if (function_exists($system_name))  { $system=$system_name() ; if ($debug) echo 'найдена функция '.$system_name.'()<br>' ;  }
         else
         { $arr_errors[]='Функция '.$system_name.'() не найдена' ;
           if (isset($_SESSION[$system_name]))  {  $system=$_SESSION[$system_name] ; if ($debug) echo 'найдена функция $_SESSION['.$system_name.']<br>' ;  }
           else
           {   $arr_errors[]='$_SESSION['.$system_name.'] не найдена' ;
               if (isset($GLOBALS[$system_name]))  { $system=$GLOBALS[$system_name] ; if ($debug) echo 'найдена функция $GLOBALS['.$system_name.']<br>' ; }
               else $arr_errors[]='$GLOBALS['.$system_name.'] не найдена' ;
           }
         }
         $method=$rec['method_name'] ;
          if (is_object($system) and method_exists($system,$method))
          {  //LOGS()->reg_log('event_lister',$event_name.': '.$system_name.' => '.$method,array('data'=>$data)) ;
             if (!$check) $system->$method($param1,$param2,$param3,$param4,$param5,$param6) ;
          }
          else if (is_object($system) and !method_exists($system,$method))
          { LOGS()->reg_log('event_lister',$event_name.': '.$system_name.'->'.$method.' НЕ НАЙДЕН') ;
            $arr_errors[]=$event_name.': '.$system_name.'()->'.$method.'() НЕ НАЙДЕН' ;
      }
          else if (!is_object($system))
          { LOGS()->reg_log('event_lister',$event_name.': '.$system->name.' СИСТЕМА НЕ НАЙДЕНА') ;
            $arr_errors[]=$event_name.': '.$system_name.'() СИСТЕМА НЕ НАЙДЕНА' ;
    }
      }
      if (_sizeof($arr_errors)) $result['error']=implode('<br>',$arr_errors) ;
      return($result) ;
    }



    function on_event_obj($rec,$event_name,$params=array())
    {
        list($ext,$class_name)=explode('/',$rec['source_obj']) ;
        $script_name=$class_name.'.php' ;
  	    if (isset($GLOBALS['_SETTING']['ext_local'][$ext]) and file_exists(_DIR_EXT_LOCAL.'/'.$ext.'/'.$script_name))  { $script_dir=_DIR_EXT_LOCAL.'/'.$ext.'/'.$script_name ; $is_local=1 ; }
        elseif (file_exists(_DIR_EXT.'/'.$ext.'/'.$script_name)) $script_dir=_DIR_EXT.'/'.$ext.'/'.$script_name ;

        $data_log=array('cur_obj_name'=>$rec['obj_name'],
                        'source_tkey'=>$rec['source_pkey'],
                        'source_pkey'=>$rec['source_tkey'],
                        'source_obj'=>$rec['source_obj'],
                        'event_name'=>$event_name,
                        'script_dir'=>$script_dir,
                        'class_name'=>$class_name
                       ) ;
        $result=array() ;

        if (file_exists($script_dir))
        { include_once($script_dir) ;
          if (class_exists($class_name))
           { $obj=new $class_name() ;
             if (method_exists($obj,$event_name)) $result=$obj->$event_name($rec,$params) ;
             else LOGS()->reg_log('on_event','В классе '.$rec['source_obj'].' не найден метод '.$event_name,array('data'=>$data_log)) ;
           }
          else LOGS()->reg_log('on_event','В скрипте '.$script_dir.' не найден класс '.$class_name,array('data'=>$data_log)) ;
        } else LOGS()->reg_log('on_event','Не найден скрипт '.$script_dir.' для заданного обработчика '.$rec['source_obj'],array('data'=>$data_log)) ;

        return($result) ;
    }


//--------------------------------------------------------------------------------------------------------
//
// работа с отчетами
//
// --------------------------------------------------------------------------------------------------------

    // после сведения версий перенести вызов SETUP()->reg_report('МО - отчеты'..... в в function _aspmo_install_modul($DOT_root)


    function reg_reports_old($system,$name,$script_dir,$class_name)
    {  $this->reports_list[$name]=array('script_dir'=>$script_dir,'class_name'=>$class_name,'section_title'=>$system->system_title) ;
    }

    function reg_reports($section_title,$script_dir,$temp1='',$temp2='')
    {  /*if (is_object($section_title)) {$this->reg_reports_old($section_title,$script_dir,$temp1,$temp2); return ; }
       $arr=explode('/',$script_dir) ;
       $arr2=explode('.',$arr[1]) ;
       $class_name=$arr2[0] ;
       //$name=str_replace('report_','',$class_name) ;
       $name=$class_name ;
       $this->reports_list[$name]=array('script_dir'=>$script_dir,'class_name'=>$class_name,'section_title'=>$section_title) ;
       $this->reports_sections[$section_title][$name]=array('script_dir'=>$script_dir,'class_name'=>$class_name,'section_title'=>$section_title) ;
       */
       include_once(_DIR_TO_MODULES.'/engine/i_setup.php') ;
       SETUP()->reg_report($section_title,$script_dir,1) ;

    }

    //SETUP()->reg_report('Товары','stats1','angelo_photo/report_stats1.php','report_stats1') ;         //
    function reg_doc($section_title,$script_dir,$name='',$options=array())
    {  include_once(_DIR_TO_MODULES.'/engine/i_setup.php') ;
       SETUP()->reg_report($section_title,$script_dir,2,$options) ;
    }

    function upload_reports_docs()
    {   $this->docs_list=array() ;
        $this->reports_list=array() ;
        $this->reports_sections=array() ;

        ob_start() ;
        $recs=execSQL('select * from reports order by indx') ;

        if (_sizeof($recs)) foreach($recs as $rec) if (!$rec['virt'])
        {   $code=$rec['code'] ;
            $data=array('script_dir'=>$rec['script'],
                        'class_name'=>$rec['class_name'],
                        'section_title'=>$rec['group_name'],
                        'name'=>$rec['obj_name'],
                       ) ;

            if ($rec['type']==1 and isset($this->reports_list[$code])) $data['overload']=$this->reports_list[$code] ;
            if ($rec['type']==2 and isset($this->docs_list[$code]))    $data['overload']=$this->docs_list[$code] ;

            if ($rec['type']==1)  $this->reports_list[$code]=$data ;
            if ($rec['type']==1)  $this->reports_sections[$rec['group_name']][$code]=$data ;
            if ($rec['type']==2)  $this->docs_list[$code]=$data ;


        }
        //damp_array($this->reports_sections,1,-1);
        //damp_array($this->reports_list,1,-1);
        //damp_array($this->docs_list,1,-1);
        $text=ob_get_clean() ;
        echo $text ;
        //LOGS()->reg_log('upload_reports_docs',$text) ;
    }

    // если code=report_mo_3 то ищем в массиве зарегистрированных отчетов
    // если code=doc/esmo_magnit_pmo/napravlenie то подкючаем скрипт doc_napravlenie.php в  расширении esmo_magnit_pmo
    // если code=report/esmo_magnit_pmo/mo_3 то подкючаем скрипт report_xxxx.php в расширении esmo_magnit_pmo
    //  $obj=ENGINE()->get_report_obj_by_code('doc/esmo_magnit_pmo/napravlenie') ;
    //  $obj=ENGINE()->get_report_obj_by_code('report/events/events_info') ;
    //  $obj=ENGINE()->get_report_obj_by_code('esmo_magnit/doc_napravlenie.php') ;
    //  $obj=ENGINE()->get_report_obj_by_code('esmo_magnit_pmo/doc_union') ;  --- эта схема представляется самой логичной, так как прямо указывает на скрипт отчета/документа
    //  $obj=ENGINE()->get_report_obj_by_code('itog2') ;
    function get_report_obj_by_code($code,$options=array())
    { if (is_array($code)) $rec_report=$code ;
      else
      {   $arr=explode('/',$code) ; $rec_report=array() ;
          if (_sizeof($arr)==3)
          { if ($arr[0]=='doc')    $rec_report=array('script_dir'=>$arr[1].'/doc_'.$arr[2].'.php','class_name'=>'doc_'.$arr[2]) ;
            if ($arr[0]=='report') $rec_report=array('script_dir'=>$arr[1].'/report_'.$arr[2].'.php','class_name'=>'report_'.$arr[2]) ;
          }
          elseif (_sizeof($arr)==2)
          {   // удаляем/добавляем ".php" для возможности передачи кода отчета без .php
              $arr[1]=str_replace('.php','',$arr[1]).'.php' ;
              $rec_report=array('script_dir'=>$arr[0].'/'.$arr[1],'class_name'=>str_replace('.php','',$arr[1])) ;
          }
          else if (isset($this->reports_list[$code])) $rec_report=$this->reports_list[$code] ;
          else if (isset($this->reports_list['report_'.$code])) $rec_report=$this->reports_list['report_'.$code] ;
          else if (isset($this->docs_list[$code])) $rec_report=$this->docs_list[$code] ;
      }
      $report_obj=null ; $error='' ;
      if (_sizeof($rec_report))
      { $script_dir=$rec_report['script_dir'] ;
        $class_name=$rec_report['class_name'] ;
        $is_local_verson=$this->include_report($script_dir) ;

            if (class_exists($class_name))
            { $report_obj=new $class_name($options) ;
              $report_obj->script_dir=$rec_report['script_dir'] ;
              $report_obj->class_name=$rec_report['class_name'] ;
          $report_obj->is_local_verson=$is_local_verson ;
            }
        else $error='Не обнаружена класс отчета '.$code;



      } else $error='Отчет не зарегистрирован в системе' ;
      if (!is_object($report_obj)) { $report_obj=new stdClass() ; $report_obj->error=$error ; }
      return($report_obj) ;
    }

    function include_report($script_dir,$options=array())
    {   $is_local_verson=0 ;
        //$options['debug']=1 ;
        if (file_exists(_DIR_EXT_LOCAL.'/'.$script_dir))
        { include_once(_DIR_EXT_LOCAL.'/'.$script_dir) ;
          $is_local_verson=1 ;
          if ($options['debug']) echo 'Подключен '.$script_dir.' из локального класса<br>' ;
        }
        elseif (file_exists(_DIR_EXT.'/'.$script_dir))
        { include_once(_DIR_EXT.'/'.$script_dir) ;
          if ($options['debug']) echo 'Подключен '.$script_dir.' из основного класса<br>' ;
        }
        return($is_local_verson) ;
    }



//--------------------------------------------------------------------------------------------------------
//
// служебные функции
//
// --------------------------------------------------------------------------------------------------------
    /* вынесены в i_system
     function encrypt_string($string,$key=_APP_KEY) {
      $iv = openssl_random_pseudo_bytes(openssl_cipher_iv_length('aes-256-cbc'));
        //echo 'encrypt_string "'.$string.'"'.'<br>' ; echo '_APP_KEY='._APP_KEY.'<br>' ;
      $encrypted_data = openssl_encrypt($string, 'aes-256-cbc', $key, 0, $iv);
      return base64_encode($encrypted_data.'::'.$iv);
    }

    function decrypt_string($string,$key=_APP_KEY) {
      list($encrypted_data, $iv) = explode('::', base64_decode($string), 2);
          //echo 'decrypt_string "'.$string.'"'.'<br>' ; echo '_APP_KEY='._APP_KEY.'<br>' ;
          return openssl_decrypt($encrypted_data, 'aes-256-cbc', $key, 0, $iv);
    }  */


    function update_personals_age()
    {
      $recs=execSQL_row('select pkey,dr from obj_site_personals where dr like "'.date('d.m.',time()).'%"') ;
      if (_sizeof($recs)) foreach($recs as $id=>$dr)
      {  $age=ENGINE()->get_age_by_dr($dr) ;
         update_rec_in_table('obj_site_personals',array('age'=>$age),'pkey='.$id,array('debug'=>0)) ;
      }
      echo 'Обновлены даты рождения, '._sizeof($recs).' сотрудников<br>' ;
    }


    function get_age_by_dr($dr)
    { list($d,$m,$y)=explode('.',$dr)  ;
      if($m > date('m') || $m == date('m') && $d > date('d')) $age=date('Y') - $y - 1;
      else $age=date('Y') - $y;
      if ($age<0) $age=0 ;
      return($age) ;
    }

    // дата идет в формате 01/01/10, переводим в формат обычной даты
    function get_dr_age($str_data)
    {  $str_data=str_replace(array('/','-'),'.',$str_data) ;
       $arr=explode('.',$str_data) ;
       $dr='' ; $age=0 ;
       if (_sizeof($arr)==3)
        { $now_year=(int)date('y') ;
          $_y=(int)$arr[2] ;
          if (strlen($arr[2])==4)  $yaer=$_y ;
          else if ($now_year>$_y)  $yaer=(int)'20'.$arr[2] ;
          else                     $yaer=(int)'19'.$arr[2] ;
          $month=(int)$arr[1] ;
          $day=(int)$arr[0] ;
          $dr=sprintf("%02d.%02d.%04d", $day, $month, $yaer);
          $tt = mktime(0,0,0,$month,$day,date('Y'));   // дата день рождения в этом году
          $now_year=(int)date('Y') ;
          $age=$now_year-$yaer ;
          if (time()<$tt) $age=$age-1 ;
        }
       return(array($dr,$age)) ;
    }


    function get_rand_string($count)
    {  $arr=array() ;
     for($i=0;$i<$count;$i++)  $arr[]=rand(1,9) ;
     return(implode('',$arr)) ;
    }

    //  преобразовываем русские вуквы в англиские аналоги
    function translit($text)
    { if(preg_match("/[А-я]/", $text))
      { $trans = array("а" => "a", "в" => "b", "е" => "e","к" => "k","м" => "m","н" => "h","о" => "o","р" => "p","с" => "c","т" => "t","х" => "x","у" => "y","ф" => "f",
                       "А" => "A","В" => "B","Е" => "E","К" => "K","М" => "M","Н" => "H","О" => "O","Р" => "P","С" => "C","Т" => "T","Х" => "X","У" => "Y","Ф" => "F");
        $res=strtr($text, $trans);
      }
      else $res=$text;
      return($res) ;
    }

    //  преобразовываем англиский вуквы в русские аналоги
    function translit2($text)
    { if(preg_match("/[A-z]/", $text))
      { $trans = array("а" => "a", "в" => "b", "е" => "e","к" => "k","м" => "m","н" => "h","о" => "o","р" => "p","с" => "c","т" => "t","х" => "x","у" => "y",
                       "А" => "A","В" => "B","Е" => "E","К" => "K","М" => "M","Н" => "H","О" => "O","Р" => "P","С" => "C","Т" => "T","Х" => "X","У" => "Y");
        $trans=array_flip($trans) ;
        return strtr($text, $trans);
      }
      else return $text;
    }

    //  преобразовываем англиский вуквы в русские аналоги
    function translit3($text)
    { if(preg_match("/[А-я]/", $text))
      { $trans = array("ф" => "a", "и" => "b","с" => "c","в" => "d","у" => "e","а" => "f",
                       "Ф" => "A", "И" => "B","С" => "C","В" => "D","У" => "E","А" => "F");
        return strtr($text, $trans);
      }
      else return $text;
    }

    function convert_to_hex($value)
    {
        $pass_seria=substr($value,0,3) ;
        $pass_number=substr($value,3,5) ;
        $pass_seria_h=dechex($pass_seria) ;
        $pass_number_h=dechex($pass_number) ;
        $pass_h=$pass_seria_h.$pass_number_h ;
        $pass_h=sprintf ("%08s",$pass_h) ;
        return ($pass_h) ;
    }

    function convert_to_dec($value)
    {
        $pass_seria=substr($value,0,4) ;
        $pass_number=substr($value,4,4) ;
        $pass_seria_d=hexdec($pass_seria) ;
        $pass_number_d=hexdec($pass_number) ;
        $pass_d=$pass_seria_d.$pass_number_d ;
        return ($pass_d) ;
    }

    function convert_to_dec2($value)
    {
        $pass_d=hexdec($value) ;
        return ($pass_d) ;
    }

    function convert_to_hex2($value)
    {
        $pass_h=dechex($value) ;
        $pass_h=sprintf ("%08s",$pass_h) ;
        return ($pass_h) ;
    }

    function convert_full_name_to_FIO($name)
    {  $arr=explode(' ',$name) ;
       $res=$arr[0].' '.mb_substr($arr[1],0,1).'.'.mb_substr($arr[2],0,1).'.' ;
       return($res) ;
    }

    function send_cmd_reboot_client()
    {  //$xmpp_message['ajax_cmd']='aspmo/reboot' ;
       //$xmpp_message['member_id']=$member->id ;  // кто отправил команду, чтобы потом не перегружать себя
       //$text_json=json_encode($xmpp_message,JSON_UNESCAPED_UNICODE) ;
       // отправляем данные всем сотрудникам АСПМО
       //$recs_member=$this->get_list_members() ;
       //if (_sizeof($recs_member)) foreach($recs_member as $member_info) if ($member_info['XMPP_login']) $this->send_XMPP_message($member_info['XMPP_login'],'aspmo_server','12345',$text_json);
       // вписываем в записи аккаунтов флаг требования провести перезагруку
       if (MEMBER()->cur_group_id) { execSQL_update('update '.ACCOUNTS()->table_account.' set reboot=1 where parent='.MEMBER()->cur_group_id) ; return(1) ;}
       else  return(0)  ;
    }

    //https://stackoverflow.com/questions/20107147/php-reading-shell-exec-live-output
    function liveExecuteCommand($cmd)
       {   while (@ ob_end_flush()); // end all output buffers if any

           $proc = popen("$cmd 2>&1 ; echo Exit status : $? &", 'r');

           $live_output     = "";
           $complete_output = "";

           while (!feof($proc))
           {
               $live_output     = fread($proc, 4096);
               $complete_output = $complete_output . $live_output;
               //echo "$live_output";
               //@ flush();
           }

           pclose($proc);

           // get exit status
           preg_match('/Exit status : [0-9]+/', $complete_output, $matches);
           //damp_array($matches) ;
           //return($matches) ;

           // return exit status and intended output
           return array (
                           'exit_status'  => str_replace("Exit status : ",'',$matches[0]),
                           'output'       => trim(str_replace($matches[0],'',$complete_output))

                        );

       }

    function terminal_send_async_cmd($terminal_id,$cmd,$options=array())
    {
        DEVICE()->device_send_async_cmd($terminal_id,$cmd,$options) ;
      }



    // запрос к терминалу на перезагрузку
    // переносим функцию в DEVICE
    function terminal_send_data($terminal_rec,$cmd,$send_array,$options=array())
    {
        $result=DEVICE()->terminal_send_data($terminal_rec,$cmd,$send_array,$options) ;
       return($result) ;
    }


    function generate_UID()
    {
      return(md5(uniqid(rand(),true))) ;
    }


    function get_setting_value($name)
        {
          $value=execSQL_value('select value from obj_site_setting where comment="'.$name.'" and enabled=1') ;
          return($value) ;
        }

     function strtotime($d,$options=array())
     {
         $arr=explode(' ',$d) ;
         if (_sizeof($arr)==1 and $options['default_His'])  $arr[1]=$options['default_His'] ;
         $d=trim($arr[0].' '.$arr[1]) ;
         $t=strtotime($d) ;
         return($t) ;
     }

    function get_text_time_diff($t1,$t2)
      {  $datetime1 = new DateTime(date('d.m.Y H:i:s',$t1));
         $datetime2 = new DateTime(date('d.m.Y H:i:s',$t2));
         $interval = $datetime1->diff($datetime2);
         $text=array() ;
         //damp_array($interval,1,-1) ;
         if ($interval->d) $text[]=$interval->d.' '.get_case_by_count_1_2_5($interval->d,'день,дня,дней') ;
         if ($interval->h) $text[]=$interval->h.' '.get_case_by_count_1_2_5($interval->h,'час,часа,часов') ;
         if ($interval->i) $text[]=$interval->i.' '.get_case_by_count_1_2_5($interval->i,'минута,минуты,минут') ;
         if (!$interval->d and !$interval->h and !$interval->i and $interval->s>0) $text[]=$interval->s.' '.get_case_by_count_1_2_5($interval->s,'секунда,секунды,секунд') ;
         return(implode(' ',$text)) ;
      }

    function resize_image($fname_old,$fname_new,$koow_w,$koof_h)
        {
                 // получение нового размера
                 list($width, $height) = getimagesize($fname_old);
                 $newwidth = $width * $koow_w;
                 $newheight = $height * $koof_h;

                 // загрузка
                 $thumb = imagecreatetruecolor($newwidth, $newheight);
                 $source = imagecreatefromjpeg($fname_old);

                 // изменение размера
                 imagecopyresized($thumb, $source, 0, 0, 0, 0, $newwidth, $newheight, $width, $height);

                 // вывод
                 imagejpeg($thumb,$fname_new,100);
      }

    function rotare_image($fname_old,$fname_new,$angle)
        {

                 // загрузка
                 $source = imagecreatefromjpeg($fname_old);

                 // изменение размера
                 $rotate=imagerotate($source,$angle,0);

                 // вывод
                 imagejpeg($rotate,$fname_new,100);
        }

    function get_window_mode_by_HTTP_REFERER()
    {   $arr=parse_url($_SERVER['HTTP_REFERER']) ;
        //damp_array($arr,1,-1)  ;
        $arr2=explode('/',$arr['path']) ;
        //damp_array($arr2,1,-1) ;
        //echo  $arr2[1] ;
        return($arr2[1]) ;
    }

    function delete_temp_tables()
    {  ?><h2>Удаление временных резервных копий таблиц</h2><?
       $arr_tables=execSQL_line('show tables like "res_%"') ;
       if (_sizeof($arr_tables)) foreach($arr_tables as $res_table_name)
       {   list($data,$table_name)=explode('__',$res_table_name) ;
           $data=str_replace('res_','',$data) ;
           $arr_data=explode('_',$data) ;
           if (_sizeof($arr_data)==6)
           { $time=mktime($arr_data[3],$arr_data[4],$arr_data[5],$arr_data[1],$arr_data[2],$arr_data[0]) ;
             if ($time)
               { echo date('d.m.Y H:i:s',$time).' - удалена временная резервная копия таблицы '.$table_name.'<br>' ;
                 execSQL_update('drop table IF EXISTS '.$res_table_name,array('debug'=>0)) ;
               }
           }
       }
       else echo 'Временных резервных копий таблиц не найдено<br>' ;

       ?><h2>Удаление временных таблиц</h2><?
       $arr_tables=execSQL_line('show tables like "temp_%"') ;
       if (_sizeof($arr_tables)) foreach($arr_tables as $table_name)
       {   echo 'Удалена временная резервная копия таблицы '.$table_name.'<br>' ;
           execSQL_update('drop table IF EXISTS '.$table_name,array('debug'=>0)) ;
       }
       else echo 'временных таблиц не найдено<br>' ;
    }

    function hide_last_name($fio)
    {  $arr=explode(' ',$fio) ;
       $arr[]=mb_substr($arr[0],0,1).'.' ;
       unset($arr[0]) ;
       $res=implode(' ',$arr) ;
       return($res) ;
    }

    function get_file_perms_info($dir,$options=array())
    {  $uid=fileowner($dir) ;
       if (function_exists('posix_getpwuid')) $uid_info=posix_getpwuid($uid) ;
       if (function_exists('posix_getgrgid')) $groupinfo = posix_getgrgid($uid_info['gid']);
       $cur_perms=mb_substr(sprintf('%o', fileperms($dir)),-4) ;
       if (!$options['symbol']) return(array('perms'=>$cur_perms,'owner'=>$uid_info['name'],'group'=>$groupinfo['name'])) ;
       else                     return(array('perms'=>$this->convert_perm($cur_perms).' ('.$cur_perms.')','owner'=>$uid_info['name'],'group'=>$groupinfo['name'])) ;
    }

    function convert_perm($perms)
     {
         switch ($perms & 0xF000) {
             case 0xC000: // сокет
                 $info = 's';
                 break;
             case 0xA000: // символическая ссылка
                 $info = 'l';
                 break;
             case 0x8000: // обычный
                 $info = 'r';
                 break;
             case 0x6000: // файл блочного устройства
                 $info = 'b';
                 break;
             case 0x4000: // каталог
                 $info = 'd';
                 break;
             case 0x2000: // файл символьного устройства
                 $info = 'c';
                 break;
             case 0x1000: // FIFO канал
                 $info = 'p';
                 break;
             default: // неизвестный
                 $info = 'u';
         }

         // Владелец
         $info .= (($perms & 0x0100) ? 'r' : '-');
         $info .= (($perms & 0x0080) ? 'w' : '-');
         $info .= (($perms & 0x0040) ?
                     (($perms & 0x0800) ? 's' : 'x' ) :
                     (($perms & 0x0800) ? 'S' : '-'));

         // Группа
         $info .= (($perms & 0x0020) ? 'r' : '-');
         $info .= (($perms & 0x0010) ? 'w' : '-');
         $info .= (($perms & 0x0008) ?
                     (($perms & 0x0400) ? 's' : 'x' ) :
                     (($perms & 0x0400) ? 'S' : '-'));

         // Мир
         $info .= (($perms & 0x0004) ? 'r' : '-');
         $info .= (($perms & 0x0002) ? 'w' : '-');
         $info .= (($perms & 0x0001) ?
                     (($perms & 0x0200) ? 't' : 'x' ) :
                     (($perms & 0x0200) ? 'T' : '-'));

         return($info) ;
     }

    // выдит значения дней/часов/минут типа 0.007 в человечесом виде  10 мин. 04 сек.
        function view_human_time_period($source_time_format,$value)
        {   $sec=0 ; $arr=array() ;
            if ($source_time_format=='day') $sec=60*60*24*$value ;
            if ($source_time_format=='hour') $sec=60*60*$value ;
            if ($source_time_format=='min') $sec=60*$value ;
            if ($source_time_format=='sec') $sec=$value ;
            if ($source_time_format=='msec') $sec=$value/1000 ;
            if ($sec)
            { $z=gmdate('z',$sec) ; ;
              $h=gmdate('G',$sec) ; ;    // G - без нуля, H - с нулем
              $i=(int)gmdate('i',$sec) ; ;
              $s=(int)gmdate('s',$sec) ; ;
              if ($z>0) $arr[]=$z.' <span>день</span>' ;
              if ($h>0) $arr[]=$h.' <span>час.</span>' ;
              if ($i>0) $arr[]=$i.' <span>мин.</span>' ;
              if ($s>0) $arr[]=$s.' <span>сек.</span>' ;
            }
            $result=implode(' ',$arr) ;
            return($result) ;
        }


     function update_IS_setting($settings_new)
     {   include($_SERVER['DOCUMENT_ROOT'].'/ini/spyc.php');
         $setting_fname=$_SERVER['DOCUMENT_ROOT'].'/ini/ini.yaml' ;
         $settion_cur = Spyc::YAMLLoad($setting_fname);



         if (_sizeof($settings_new)) foreach($settings_new as $section_name=>$items)
         switch($section_name)
         { case 'modules': foreach($items as $key=>$value)
                           {   $arr=explode('|',$key) ;
                               if (_sizeof($arr)) foreach($arr as $subkey) $settion_cur[$section_name][$subkey]=(int)$value ;
                           }
                           break ;
           case 'plugins': foreach($items as $key=>$value)
                           {   $arr=explode('|',$key) ;
                               if (_sizeof($arr)) foreach($arr as $subkey) $settion_cur[$section_name][$subkey]=($value)? 1:0 ;
                           }
                           break ;
           default:        foreach($items as $key=>$value) $settion_cur[$section_name][$key]=($value)? $value:0 ;
         }
         // в дальнейшем реализовать зависимости в самих модулях
         if ($settion_cur['modules']['kt']) $settion_cur['modules']['skd']=1 ;
         if ($settion_cur['modules']['media_content'])  $settion_cur['modules']['event']=1 ;
         if ($settion_cur['modules']['quiz'])           $settion_cur['modules']['event']=1 ;
         if ($settion_cur['modules']['poll'])           $settion_cur['modules']['event']=1 ;
         if ($settion_cur['modules']['esmo_magnit']) $settion_cur['modules']['event']=1 ;
         if ($settion_cur['plugins']['esmo_intro'])  $settion_cur['modules']['event']=1 ;
         if ($settion_cur['modules']['enterprise'])  $settion_cur['modules']['event']=1 ;
         if ($settion_cur['modules']['enterprise'])  $settion_cur['modules']['esmo_magnit']=1 ;


         $yaml = Spyc::YAMLDump($settion_cur,4,60);
         $success=file_put_contents($setting_fname,$yaml) ;
         //$_SETTING = Spyc::YAMLLoad($setting_fname);
         //damp_array($settings_new,1,-1) ;
         //damp_array($settion_old,1,-1) ;
         //damp_array($settings_update,1,-1) ;
         return($success) ;
     }

    // возвращает время из метки $unix_time в часовом поясе $timezone
    function get_local_time($unix_time,$regional_timezone,$format='d.m.Y H:i:s')
    {   $local_data=date('d.m.Y H:i:s',$unix_time) ; // получаем отпечаток даты и времени в локали сервера (_DEFAULT_TIMEZONE,  Europe/Moscow)
        $dateTimeZone_default = new DateTimeZone(_DEFAULT_TIMEZONE);
        $dateTime = new DateTime($local_data, $dateTimeZone_default); //echo '$dateTime2='.$dateTime2.'<br>' ;
        $dateTimeZone_regional = new DateTimeZone($regional_timezone);
        $dateTime->setTimezone($dateTimeZone_regional) ;
        $regional_data=$dateTime->format($format);
        return($regional_data) ;
      }


    function reg_file($data=array())
    {
       $data['clss']=5 ;
       $data['parent']=1 ;
       $data['indx']=1 ;
       $data['account_id']=MEMBER()->id ;
       $id=adding_rec_to_table('files',$data) ;
       return($id) ;
    }

    function server_get_memory_info()
     {   $res=array() ;
         $result = ENGINE()->liveExecuteCommand('cat /proc/meminfo');
         $arr=explode("\n",$result['output']) ;
         if (_sizeof($arr)) foreach($arr as $item)
         { list($id,$size)=explode(':',$item) ;
           $size=(int)$size*2014  ;
           $id=trim($id) ;
           if ($id) $res[$id]=show_size($size) ;
         }
         return($res) ;
     }

     function server_get_disk_free_info()
     {   $res=array() ;
         $result = ENGINE()->liveExecuteCommand('df -P');
         $arr=explode("\n",$result['output']) ;

         if (_sizeof($arr)) foreach($arr as $id=>$item) if ($id)
         {   $item=preg_replace('/(\s+)/is',' ',$item) ;
             $arr2=explode(" ",$item) ;
             if ($arr2[0])  $res[]=array('Mounted'=>$arr2[5],
                                         'filesystem'=>$arr2[0],
                                         //'1024_blocks'=>$arr2[1],
                                         'Used'=>trim($arr2[2]),
                                         'Available'=>trim($arr2[3]),
                                         'Capacity'=>trim($arr2[4]),
                     ) ;
         }
         return($res) ;
     }

     function server_get_processor_info()
     {   $res=array() ;
        $result = ENGINE()->liveExecuteCommand('cat /proc/cpuinfo');
        $arr=explode("\n",$result['output']) ;
        if (_sizeof($arr)) foreach($arr as $item)
        { list($id,$value)=explode(':',$item) ;
          $id=trim($id) ;
          if ($id) $res[$id]=trim($value) ;
        }
        $res['processor']++ ;
        return($res) ;
     }

     function server_get_OS_info()
     {   $res=array() ;
         $result = ENGINE()->liveExecuteCommand('uname -a');
         return($result['output']) ;
     }

     function server_get_LAMP_info()
     {   $res=array() ;
         //$result = ENGINE()->liveExecuteCommand('apache -v'); // нет работает, нет прав для www-data
         $res['server']=$_SERVER['SERVER_SOFTWARE'] ;
         $res['php']=phpversion(); ;
         $res['db']=mysqli_get_server_info($GLOBALS['DB_LINK']) ;
         return($res) ;
}

  function get_arr_to_edit_element($ext_info=array())
     {   $arr=array() ;
         if ($ext_info['array'])
         { if (isset($_SESSION[$ext_info['array']])) $arr=$_SESSION[$ext_info['array']] ;
           else
           { list($system_name,$array_name)=explode('/',$ext_info['array']) ;
             if (function_exists($system_name)) $arr=$system_name()->$array_name ;
           }
         }
         //else if ($ext_info['module_array'])
         //{ list($system_name,$array_name)=explode('/',$ext_info['module_array']) ;
         //  if (function_exists($system_name)) $arr=$system_name()->$array_name ;
         //}
         else if ($ext_info['array_func'])
         { list($system_name,$method_name)=explode('.',$ext_info['array_func']) ;
           if (function_exists($system_name))
           { if (method_exists($system_name(),$method_name)) $arr=$system_name()->$method_name() ;
           }
         }
         return($arr) ;
     }

 function redirect_301_to($to_url,$no_used_cur_domain=0)
         {   $arr=parse_url($to_url) ;
             if (!$no_used_cur_domain and !$arr['host']) $arr['host']=_CUR_DOMAIN ;
             //damp_array($arr) ;
             $arr['path']=str_replace('//','/',$arr['path']) ;
             if ($arr['scheme']) $arr['scheme'].='://' ;
             else                $arr['scheme']=_CUR_SHEME ;
             $to_url=$arr['scheme'].$arr['host'].$arr['path'] ;

             $from_url=_MAIN_PROTOCOL._CUR_DOMAIN._CUR_PAGE_DIR._CUR_PAGE_NAME;
             if ($to_url==$from_url) return ;

             header("HTTP/1.1 301 Moved Permanently");
             header("Location: ".$to_url);
             //echo $to_url ;
             _exit() ;
         }

 function get_default_rec_of_clss($clss)
 { $rec=array() ;
   $descr_clss=_CLSS($clss) ;
   if (_sizeof($descr_clss->fields_info)) foreach($descr_clss->fields_info as $fname=>$descr)
   {  if (isset($descr['default'])) $rec[$fname]=$descr['default'] ;
      else  $rec[$fname]='' ;
   }
   $rec['clss']=$clss ;
   unset($rec['pkey']) ;
   unset($rec['tkey']) ;
   return($rec) ;
 }

   function get_html_doc_content($text)
         {
            $result='<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"><html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"><head>
                    <title>ЭСМО</title>
                     <META http-equiv="Content-Type" content="text/html; charset=utf-8">
                     <META NAME="Document-state" CONTENT="Dynamic">
                     <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
                     <meta name="robots" content="noindex, nofollow, noarchive">
                     <META name="viewport"  content="width=device-width, initial-scale=0.9, minimum-scale=0.9, user-scalable=no">
             	    <link rel="stylesheet" type="text/css" href="/'._CLASS_.'/style.css" charset="utf-8">
             	</head><body>'.$text.'</body>' ;
             return($result) ;
         }

 function upload_files_to_temp_dir($session_UID)
      {   $arr_uploaded_files=array() ;
          if (_sizeof($_FILES))
             { $recs_files=conver_FILES_to_recs($_FILES['upload_file']) ;
               if (_sizeof($recs_files)) foreach($recs_files as $i=>$rec_file)
                 { //if ($recs_files[0]['type']=='application/vnd.ms-excel')
                   { ?><h3>Загружаем данные из файла "<?echo $rec_file['name']?>"</h3><?
                     $arr=explode('.',$rec_file['name']) ;
                     $ext=$arr[_sizeof($arr)-1] ;
                     $tmp_fname='/temp/'.$i.'_'.$session_UID.'.'.$ext ;
                     $result=move_uploaded_file($recs_files[0]['tmp_name'],_DIR_TO_ROOT.$tmp_fname) ;
                     if ($result)
                     { echo 'Файл загружен в: <a target=_blank href="'.$tmp_fname.'">'.$tmp_fname.'</a><br>' ;
                       $arr_uploaded_files[]=array('source_fname'=>$rec_file['name'],'upload_fname'=>$tmp_fname) ;
                     }
                     else
                     { echo '<div class=alert>Не удалось загрузить файл: <a target=_blank href="'.$this->xls_fname.'">'.$this->xls_fname.'</a></div>' ;
                       ?><h3>upload info</h3><?
                       damp_array($recs_files[0],1,-1) ;
                       $perm=ENGINE()->get_file_perms_info(_DIR_TO_ROOT.'/temp/',array('symbol'=>1)) ;
                       ?><h3>/temp/ permissions</h3><?
                       damp_array($perm,1,-1) ;
                     }
                   }
                 }
             }
          return($arr_uploaded_files) ;
      }

    function check_changes($title,$fname,$rec,$form,&$data,&$arr_changes,$options=array())
    {   $fname_form=($options['fname_form'])? $options['fname_form']:$fname ;
        $old_value=($options['old_value'])? $options['old_value']:$rec[$fname] ;
        $new_value=($options['new_value'])? $options['new_value']:$form[$fname_form] ;
        if (!$options['new_value'] and !isset($form[$fname_form])) return ;
        $view_old_value=($options['view_old_value'])? $options['view_old_value']:$old_value ;
        $view_new_value=($options['view_new_value'])? $options['view_new_value']:$new_value;

        if ($old_value!=$new_value) { $arr_changes[$title]=$view_old_value.' => '.$view_new_value ; $data[$fname]=$new_value ; }
}

    /**************************************************************************************************************************************/
     //
     // РАБОТА с URL, разбор параметров
     //
     /**************************************************************************************************************************************/


    function parse_url($url,$options=array())
        {  $filter=array() ;
           $str=str_replace(array($options['base_url'],'/','[',']'),'',$url) ;
           $arr_params=explode(',',$str) ;
           if (_sizeof($arr_params)) foreach($arr_params as $str_params)
           { $arr=explode('=',($str_params)) ;
             if (_sizeof($arr)==2) {
                                    $arr[1]=rawurldecode($arr[1]);
                                    if (strpos($arr[1],'(')!==false and strpos($arr[1],')')!==false)
                                    { $arr2=explode(';',rawurldecode(str_replace(array('(',')'),'',$arr[1]))) ;
                                      $filter[$arr[0]]=array_flip($arr2);
                                      foreach($filter[$arr[0]] as $id=>$value) $filter[$arr[0]][$id]=1 ;
                                    }
                                    else $filter[$arr[0]]=str_replace('|','/',rawurldecode($arr[1])) ;
                                  }
             else                 if ($str_params) $filter[$str_params]=1 ;
           }
          return($filter) ;
        }

       // prepare_url by POST
       function prepare_url($filter,$options=array())
       {   $url=array() ; $_str_url=array() ;  $res_url=$options['base_url'] ;  //damp_array($options,1,-1) ;
           if (_sizeof($filter)) foreach($filter as $key=>$value) if ($value !== '' and $value)
           { if (is_array($value)) { if (_sizeof($value))  $_str_url[]=$key.'=('.implode(';',$value).')' ;}
             elseif ((string)$value!='1') $_str_url[]=$key.'='.rawurlencode($value) ;
             else  $_str_url[]=rawurlencode($key) ;
           }
           //if (_sizeof($url)) foreach($url as $key=>$value) if ($value!=1) $_str_url[]=$key.'='.$value ; else  $_str_url[]=$key ;
           // добавлена автозамена /=>| чтобы не портить URL фильтра
           if (_sizeof($_str_url))  $res_url.='['.implode(',',str_replace(['/','%2F'],'|',$_str_url)).']/';
           //$res_url=str_replace(' ','-',$res_url) ;
           return($res_url) ;
       }

      function prepare_url_by_filter($filter,$options=array())
       {   $url=array() ; $_str_url=array() ;  $res_url=$options['base_url'] ;  //damp_array($options,1,-1) ;
           if (_sizeof($filter)) foreach($filter as $key=>$value) if ($value !== '')
           { if (is_array($value))
             { if (_sizeof($value))
               { // еслим первый элемент с индексом 0 - значит значения в value, иначе - значения в keys
                 if (isset($value[0]))  $_str_url[]=$key.'=('.implode(';',$value).')' ;
                 else                   $_str_url[]=$key.'=('.implode(';',array_keys($value)).')' ;
               }
             }
             elseif ($value!=1) $_str_url[]=$key.'='.rawurlencode($value) ;
             else  $_str_url[]=$key ;
           }
           //if (_sizeof($url)) foreach($url as $key=>$value) if ($value!=1) $_str_url[]=$key.'='.$value ; else  $_str_url[]=$key ;
           if (_sizeof($_str_url))  $res_url.='['.implode(',',$_str_url).']/';
           //$res_url=str_replace(' ','-',$res_url) ;
           return($res_url) ;
       }

       // меняем местами ключи со значениями в массивах фильтра
       function filter_array_flip($filter)
          { $res=array() ;
            if (_sizeof($filter)) foreach($filter as $id=>$value) if (is_array($value)) $res[$id]=array_flip($value) ; else $res[$id]=$value ;
            return($res) ;
          }

       // меняем местами ключи со значениями в массивах фильтра
       function clear_space_value($filter)
          { $res=$filter ;
            if (_sizeof($filter)) foreach($filter as $id=>$value)
            {   if (!is_array($value)) { if (!$value) unset($res[$id]) ;}
                else if (!_sizeof($value))  unset($res[$id])  ;
            }
            return($res) ;
          }

       function clear_filter_space_values($filters)
       {
           $setting=[];
           if(_sizeof($filters)) foreach($filters as $id=>$value)
           {
               if(is_array($value) and _sizeof($value)) $setting[$id]=$value;
               if(is_string($value) and $value!="") $setting[$id]=$value;
               if(is_int($value) and $value!=0) $setting[$id]=$value;
               if(is_float($value) and $value!=0.00) $setting[$id]=$value;
           }
           return ($setting);
       }

       function get_filter_to_params($filter,$params,$options=array())
       { $temp_filter=array_merge($filter,$params) ;
         $dir_filter=$this->prepare_url_by_filter($temp_filter) ;
         //$url_report=($options['url_report'])? $options['url_report']:'/cab/reports/'.$this->report_code.'/' ;
         $url_report=($options['url_report'])? $options['url_report']:'' ;
         return($url_report.$dir_filter) ;
       }

       function get_time_range_by_filter_to_cur_day($filter)
       { // если дата задана через фильтр, используем её. Иначе используем текущую дату время. Используем getdate для разненесения значений в массив
         $data_from=($filter['data_from'])? getdate(strtotime($filter['data_from'])):getdate() ;
         $data_to=($filter['data_to'])? getdate(strtotime($filter['data_to'])):getdate() ;
         // если дата задана через фильтр, преобразовыаем в текст без коррекции. Если была использована текущая дата - добавляем границы текущего дня. Испольщуем mktime
         $fime_from2=($filter['data_from'])? mktime($data_from['hours'],$data_from['minutes'],0,$data_from['mon'],$data_from['mday'],$data_from['year']):mktime(0,0,0,$data_from['mon'],$data_from['mday'],$data_from['year']);
         $fime_to2=($filter['data_to'])? mktime($data_to['hours'],$data_to['minutes'],0,$data_to['mon'],$data_to['mday'],$data_to['year']):mktime(23,59,59,$data_to['mon'],$data_to['mday'],$data_to['year']);
         return(array($fime_from2,$fime_to2)) ;
       }

    function get_doc_dir($doc_code='',$time=0)
    {   $safe_doc_code=str_replace(array('/','.php'),array('_',''),$doc_code) ;
        $dir_time=($time)? date('Y_m',$time):date('Y_m') ;
        $doc_dir=($safe_doc_code)? $safe_doc_code.'/'.$dir_time.'/':$dir_time.'/' ;
        //ob_start() ; trace() ; $text=ob_get_clean() ; LOGS()->reg_log('pdf_trace','',array('save_to_file'=>$text)) ;
        return($doc_dir) ;
    }

    function get_number_dir_by_id($session_id,$base_dir)
    { $max_file_count=10000 ; // максимальное кол-во файлов в директории
      $dir_number=(int)($session_id/$max_file_count)  ;
      $dir_name=$base_dir.$dir_number.'/' ;

      if (!file_exists(_DIR_TO_ROOT.$dir_name))
      { ob_start() ;
        check_exists_dir($dir_name) ;
        $text=ob_get_clean() ;
        LOG_JSON('mo_session')->reg('create_dir',$text) ;
      }
      return($dir_name) ;
    }

    function get_dir_by_id($session_id,$mode,$type,$options=array())
   	   {  $max_file_count=10000 ; // максимальное кол-во файлов в директории
   	      $dir_number=(int)($session_id/$max_file_count)  ;
   	      $dir_name_old=$options['base_dir'] ;
   	      $file_dir_old=$dir_name_old.$session_id.$type ;

   	      $dir_name=$options['base_dir'].$dir_number.'/' ;
   	      //$file_dir_default='/images/no-avatar-62.png' ;

   	      // при получении имени файла для его последующего сохранения должна передаваться опция check_directory, по ней будет создана нужная директория
   	      if ($options['check_directory'] and !file_exists(_DIR_TO_ROOT.$dir_name))
   	      { ob_start() ;
   	      	check_exists_dir($dir_name) ;
   		    $text=ob_get_clean() ;
   	      	LOG_JSON('mo_session')->reg('create_dir',$text) ;
   	      }

   	      $file_dir=$dir_name.$session_id.$type ;

   	      // при получении имени файла для его последующего сохранения должна передаваться опция no_check_exist_file, по ней будет возвращено имя файла в нужной директории
   	      if ($options['no_check_exist_file'])                   $result=array('dir'=>_DIR_TO_ROOT.$file_dir,'url'=>_PATH_TO_SITE.$file_dir,'relative'=>$file_dir) ;
   	      else if (file_exists(_DIR_TO_ROOT.$file_dir))          $result=array('dir'=>_DIR_TO_ROOT.$file_dir,'url'=>_PATH_TO_SITE.$file_dir,'relative'=>$file_dir) ;
   	      else if (file_exists(_DIR_TO_ROOT.$file_dir_old))      $result=array('dir'=>_DIR_TO_ROOT.$file_dir_old,'url'=>_PATH_TO_SITE.$file_dir_old,'relative'=>$file_dir_old) ;
   	      //else if (!$options['no_default_img'])                  $result=array('dir'=>_DIR_TO_ROOT.$file_dir_default,'url'=>_PATH_TO_SITE.$file_dir_default,'relative'=>$file_dir_default) ;
   	      else                                                   $result=array('dir'=>'','url'=>'','relative'=>'') ;

   	      if ($mode) return($result[$mode]) ;
   	      else return($result) ;
   	   }

        function read_menu_from_yaml($menu_name)
        {
          include_once('Spyc.php');
          $menu_fname='menu_'.$menu_name.'.yaml' ;
          $menu = (file_exists(_DIR_TO_ROOT.'/ini/'.$menu_fname))? Spyc::YAMLLoad(_DIR_TO_ROOT.'/ini/'.$menu_fname):array();
          return($menu) ;
        }

    function save_temp_setting($setting=array(),$uid='')
       {   if (!$uid) $uid=$this->generate_UID() ;
           $fname='setting_'.$uid.'.yaml' ;
           include_once('Spyc.php');
           $yaml = Spyc::YAMLDump($setting,4,60);
           $success=file_put_contents(_TEMP_DIR.$fname,$yaml) ;
           if (!$success) {?><div style="color:red;">Не удалось сохранить изменения в "<?echo $fname?>". Проверьте права доступа файлов хоста, они должны принадлежать esmo или apache</div><?}
           return($uid) ;
       }

    function load_temp_setting($uid)
       {   include_once('Spyc.php');
           $fname='setting_'.$uid.'.yaml' ;
           $arr=(file_exists(_TEMP_DIR.$fname))? Spyc::YAMLLoad(_TEMP_DIR.$fname):array();
           return($arr) ;
}

    function delete_temp_setting($uid)
    {
        $fname='setting_'.$uid.'.yaml' ;
        unlink(_TEMP_DIR.$fname) ;
    }

    function get_list_active_ext()
    {
        include_once('Spyc.php');
        $menu_fname='ext.yaml' ;
        $list_ext = (file_exists(_DIR_TO_ROOT.'/ini/'.$menu_fname))? Spyc::YAMLLoad(_DIR_TO_ROOT.'/ini/'.$menu_fname):array();
        return($list_ext) ;
    }

    function set_end_of_day_if_time_undefined($time)
      {
         $t=(stripos($time,'.')!==false or stripos($time,'-')!==false)? strtotime($time):$time  ;
         $now=getdate($t) ;
         if (!$now['hours'] and !$now['minutes'] and !$now['seconds']) { $now['hours']=23 ; $now['minutes']=59 ;$now['seconds']=59 ; }
         $tt=mktime($now['hours'],$now['minutes'],$now['seconds'],$now['mon'],$now['mday'],$now['year']);
         return($tt) ;
      }

    function to_unix_time($time)
    { $t=(stripos($time,'.')!==false or stripos($time,'-')!==false)? strtotime($time):$time  ;
      return($t)  ;
    }

    function get_procent($all,$cur,$round=2)
    {
        return(round($cur*100/$all,$round)) ;
    }

    function get_ini_yaml_setting()
    {
        $setting=[];
        if (file_exists($_SERVER['DOCUMENT_ROOT'].'/ini/spyc.php') and file_exists($_SERVER['DOCUMENT_ROOT'].'/ini/ini.yaml'))
        {
            include_once($_SERVER['DOCUMENT_ROOT'].'/ini/spyc.php');
            $setting = Spyc::YAMLLoad($_SERVER['DOCUMENT_ROOT'].'/ini/ini.yaml');
        }
        return $setting;
    }

    function exists_setup_dir()
    {
        if (file_exists(_DIR_TO_ROOT.'/setup')) return(1) ;
        else return(0) ;
    }

    // заполняет поля parent1,parent3,parent3... для item
       function full_parent_levels_to_rec($table_name,&$data)
       {  $rec_parent_section=execSQL_van('select pkey,level,parent,parent1,parent2,parent3,parent4,parent5,parent6,parent7,parent8,parent9 from '.$table_name.' where pkey='.$data['parent']) ;    // echo 'parent_level='.$rec_parent_section['level'].'<br>' ;
          if ($rec_parent_section['level'])
          { if ($rec_parent_section['parent']) for ($i=1;$i<$rec_parent_section['level'];$i++)  $data['parent'.$i]=$rec_parent_section['parent'.$i] ;
            else $data['parent1']=1 ;
            $data['parent'.$rec_parent_section['level']]=$data['parent'] ;
            $data['level']=$rec_parent_section['level']+1 ;
          }
       }


 function copy_log_from_now()
   {
        LOGS()->copy_log_from_now() ;
   }

   function exec_bash_cmd($cmd)
   {
       $temp_fname=_TEMP_DIR.'temp_'.ENGINE()->generate_UID().'.txt' ;
       $cmd.=' > '.$temp_fname ;
       exec($cmd) ;
       $result=file_get_contents($temp_fname) ;
       unlink($temp_fname) ;
       return($result) ;
   }


  function htmlentities_open_tag($content)
  {
      if (stripos($content, 'windows-1251')!==false)  $content=iconv('windows-1251','UTF-8', $content) ;
      /*$result=str_replace(['<?','?>','</'],[htmlentities('<?'),htmlentities('?>'),htmlentities('</')], $content) ;*/
      $result=str_replace(['<?' , '?>'],[htmlentities('<?'),htmlentities('?>')], $content) ;
      return($result) ;
  }

  // успешнные сообщения
  // $result=ENGINE()->prepare_result(['comment'=>'Титул '.$rec_packet['packet_type'].' сформрован и отправлен на подпись','packet_id'=>$rec_packet['pkey']]) ;
  // $result=ENGINE()->prepare_result(['packet_id'=>$packet_id]) ;
  // $result=ENGINE()->prepare_result(['comment'=>'Титул 2 подписан','packet_id'=>$rec_packet['pkey']]) ;
  // неуспешные сообешия
  // $result=['error'=>['code'=>'source_error','comment'=>'not found signature file']] ;
  // $result=ENGINE()->prepare_result(['error'=>'mo_not_found','comment'=>'МО не найден','packet_id'=>$rec_packet['pkey'],'driver_id'=>$rec_pl['driver_id']]) ;
  //  $result=ENGINE()->prepare_result(['error'=>'sign_not_found','comment'=>'Подпись не найдена','packet_id'=>$rec_packet['pkey']]) ;
  //
  function prepare_result($options=[])
  {   //if (is_int($options) and $options)
      $result=[] ;
      $result['status']=($options['error'])? 'failed':'success' ;
      if ($options['error']) $result['error_code']=$options['error'] ;
      if ($options['comment']) $result['comment']=$options['comment'] ;
      if (sizeof($options)) foreach ($options as $key=>$value) if ($key!='error' and $key!='status' and $key!='code' and $key!='comment') $result[$key]=$value ;
      return($result) ;
  }

}

function send_cmd_reboot_client() { ENGINE()->send_cmd_reboot_client() ; ; }

class JSON
{

        public static $TAB = "\t";

        private static $instance;

        public static function encode($in, $indent = 0, \Closure $_escape = null)
        {
                if (!self::$instance) {
                        self::$instance = new self();
                }
                return self::$instance->_formatJSON($in, $indent, $_escape);
        }

        public static function getErrorMessage($errorCode)
        {
                switch ($errorCode) {
                        case JSON_ERROR_NONE:
                                return 'No error has occurred';
                        case JSON_ERROR_DEPTH:
                                return 'The maximum stack depth has been exceeded';
                        case JSON_ERROR_STATE_MISMATCH:
                                return 'Invalid or malformed JSON';
                        case JSON_ERROR_CTRL_CHAR:
                                return 'Control character error, possibly incorrectly encoded';
                        case JSON_ERROR_SYNTAX:
                                return 'Syntax error, Invalid JSON';
                        case JSON_ERROR_UTF8:
                                return 'Malformed UTF-8 characters, possibly incorrectly encoded';
                        default:
                                return 'Unknown error';
                }
        }

        private function _formatJSON($in, $indent = 0, \Closure $_escape = null)
        {
                if (__CLASS__ && isset( $this )) {
                        $_myself = array($this, __FUNCTION__);
                } elseif (__CLASS__) {
                        $_myself = array('self', __FUNCTION__);
                } else {
                        $_myself = __FUNCTION__;
                }

                if (is_null($_escape)) {
                        $_escape = function ($str) {
                                return str_replace(
                                        array('\\', '"', "\n", "\r", "\b", "\f", "\t", '/', '\\\\u'),
                                        array('\\\\', '\\"', "\\n", "\\r", "\\b", "\\f", "\\t", '\\/', '\\u'),
                                        $str);
                        };
                }

                $out = '';

                $idx     = 0;
                $isArray = true;
                if (_sizeof($in)) foreach ($in as $k1 => $v1) {
                        if (!is_numeric($k1) || ( (int)$k1 != $idx )) {
                                $isArray = false;
                                break;
                        }
                        $idx++;
                }

                $maxLen = 0;
                if (_sizeof($in)) foreach ($in as $key => $value) {
                        $len = strlen((string)$key);
                        if ($len > $maxLen) $maxLen = $len;
                }

                if (_sizeof($in)) foreach ($in as $key => $value) {
                        $out .= str_repeat(self::$TAB, $indent + 1);
                        if (!$isArray) {
                                $len = strlen((string)$key);
                                $out .= "\"" . $_escape((string)$key) . "\""
                                        . str_repeat(" ", $maxLen - $len) . ": ";
                        }

                        if (is_object($value) || is_array($value)) {
//                              $out .= "\n";
                                $out .= call_user_func($_myself, $value, $indent + 1, $_escape);
                        } elseif (is_bool($value)) {
                                $out .= $value ? 'true' : 'false';
                        } elseif (is_null($value)) {
                                $out .= 'null';
                        } elseif (is_string($value)) {
                                $out .= "\"" . $_escape($value) . "\"";
                        } else {
                                $out .= $value;
                        }

                        $out .= ",\n";
                }

                if (!empty( $out )) {
                        $out = substr($out, 0, -2);
                }

//              $out = str_repeat("\t", $indent) . "{\n" . $out;
                if ($isArray) {
                        $out = "[\n" . $out;
                        $out .= "\n" . str_repeat(self::$TAB, $indent) . "]";
                } else {
                        $out = "{\n" . $out;
                        $out .= "\n" . str_repeat(self::$TAB, $indent) . "}";
                }

                return $out;
        }
}

function multiSQL_insert($table_name,$options=array())
{ if (!isset($GLOBALS['multiSQL_insert_'.$table_name])) $GLOBALS['multiSQL_insert_'.$table_name]=new c_multiSQL_insert($table_name,$options) ;
  return($GLOBALS['multiSQL_insert_'.$table_name]);
  return(new c_multiSQL_insert($table_name,$options)) ;    // для навигации в  phpStorm
} ;

class c_multiSQL_insert
{   var $table_name ;
    var $limit=500 ;
    var $debug ;
    var $time_start ;
    var $time_last ;
    var $recs=array() ;
    var $mode='INSERT' ;

    function __construct($table_name,$options=array())
    { $this->table_name=$table_name ;
      if ($GLOBALS['LS_insert_rows_count']>100) $this->limit=$GLOBALS['LS_insert_rows_count'] ;
      if ($options['limit'])                    $this->limit=$options['limit'] ;
      $this->debug=0 ;
      list($usec, $sec) = explode(' ', microtime());
      $this->time_start=((float)$usec + (float)$sec);
      $this->time_last=((float)$usec + (float)$sec);
      if ($options['mode']=='REPLACE') $this->mode='REPLACE' ;
      //echo 'Создан объект c_multiSQL_insert<br>' ;
    }

    function  check_recs_before_append($recs)
    { $keys=array() ;
      if (_sizeof($recs)) foreach($recs as $rec) $keys=array_merge($keys,array_keys($rec)) ;
      $result=array() ;
      if (_sizeof($recs)) foreach($recs as $i=>$rec) foreach($keys as $key) $result[$i][$key]=(isset($rec[$key]))? $rec[$key]:null ;
      return($result) ;
    }

    function append($rec)
    {   $this->recs[]=$rec ;
        if (_sizeof($this->recs)>=$this->limit) $this->flush(0) ;
    }

    function flush($destroy=1)
    { if (_sizeof($this->recs))
      {  $recs_to_insert=$this->check_recs_before_append($this->recs) ;
         $fnames=array_keys($recs_to_insert[0]) ;

         $lines=array() ;
         foreach($recs_to_insert as $rec)
    {   $fields=array() ;
          	if (_sizeof($rec)) foreach($rec as $key=>$value)
      	    { if ($value===NULL) $fields[]='NULL' ;
      	      else if (is_array($value)) $fields[]='"'.addslashes(add_data_to_serialize_array('',$value)).'"' ;
      		  else $fields[]=(is_string($value))? '"'.addslashes($value).'"':'"'.$value.'"' ;
	    }
      	    if (_sizeof($fields)) $lines[]='('.implode(',',$fields).')' ;
    }

          $sql=$this->mode.' INTO '.$this->table_name.' ('.implode(',',$fnames).') VALUES '.implode(', ',$lines).';' ;
         //echo $sql.'<br>' ;
          $cnt=execSQL_update($sql,array('debug'=>$this->debug)) ;

          list($usec, $sec) = explode(' ', microtime());
          $querytime_now = ((float)$usec + (float)$sec);
          $querytime_delta = $querytime_now - $this->time_start;
          $querytime_delta2 = $querytime_now - $this->time_last;
          echo sprintf('%01.3f',$querytime_delta).' (+'.sprintf('%01.3f',$querytime_delta2).' сек.): добавлено <strong>'.$cnt.'</strong> записей в таблицу '.$this->table_name.' <br>' ;
          $this->time_last=((float)$usec + (float)$sec);

          //if (!$comment)
          $comment='Таблица '.$this->table_name.' - добавлено '.$cnt.' строк' ;
          // 0 - не выводить текст в окно, только в лог
          FILE_LOG()->append($comment,0) ;
          $this->recs=array() ;
      }

      if ($destroy)
      { unset($GLOBALS['multiSQL_insert_'.$this->table_name]) ;

      }
      //$this->table_name='' ;
    }

}

function check_engine_version()
{   // проверяем правильность задания _DIR_TO_ENGINE
    if (stripos(_DIR_TO_ENGINE,'system')===false)
    {   $res=change_versions(_CLASS_VERS) ;
        if ($res)
        { include_once(_DIR_TO_MODULES.'/engine/i_setup.php') ;
          SETUP()->check_exists_file('/cab/ajax.php') ;
          echo '<div class="green">Скорректирована версия engine, страница будет перезагружена...</div>' ;
          ?><script type="text/javascript">setTimeout(function() {document.location="/cab/setting/update/";},2000);</script><?
        }
        else
        { echo '<div class="alert">Не удалось внести изменения в файл конфигурации ('._DIR_TO_ROOT.'/ini/ini.yaml)</div>' ;
          echo 'Для обновления систему на последнюю версию требуется запуск инсталятора.' ;
        }
        exit() ;
    }
}

function change_versions($class_vers)
{  // новая схема
     $res=0 ;
     if (file_exists($_SERVER['DOCUMENT_ROOT'].'/ini/spyc.php') and file_exists($_SERVER['DOCUMENT_ROOT'].'/ini/ini.yaml'))
     { include($_SERVER['DOCUMENT_ROOT'].'/ini/spyc.php');
       $_SETTING = Spyc::YAMLLoad($_SERVER['DOCUMENT_ROOT'].'/ini/ini.yaml');
       $_SETTING['dist']['esmo_version']='class_v'.$class_vers ;
       $_SETTING['dist']['engine_version']='class_v'.$class_vers.'/system' ;
       $yaml = Spyc::YAMLDump($_SETTING,4,60);
       $res=file_put_contents(_DIR_TO_ROOT.'/ini/ini.yaml',$yaml) ;
     }
     return($res) ;
}

/**
* Compute the start and end date of some fixed o relative quarter in a specific year.
* @param mixed $quarter  Integer from 1 to 4 or relative string value:
*                        'this', 'current', 'previous', 'first' or 'last'.
*                        'this' is equivalent to 'current'. Any other value
*                        will be ignored and instead current quarter will be used.
*                        Default value 'current'. Particulary, 'previous' value
*                        only make sense with current year so if you use it with
*                        other year like: get_dates_of_quarter('previous', 1990)
*                        the year will be ignored and instead the current year
*                        will be used.
* @param int $year       Year of the quarter. Any wrong value will be ignored and
*                        instead the current year will be used.
*                        Default value null (current year).
* @param string $format  String to format returned dates
* @return array          Array with two elements (keys): start and end date.
*/
function get_dates_of_quarter($quarter = 'current', $year = null, $format = null)
{
    if ( !is_int($year) ) {
       $year = (new DateTime)->format('Y');
    }
    $current_quarter = ceil((new DateTime)->format('n') / 3);
    switch (  strtolower($quarter) ) {
    case 'this':
    case 'current':
       $quarter = ceil((new DateTime)->format('n') / 3);
       break;

    case 'previous':
       $year = (new DateTime)->format('Y');
       if ($current_quarter == 1) {
          $quarter = 4;
          $year--;
        } else {
          $quarter =  $current_quarter - 1;
        }
        break;

    case 'first':
        $quarter = 1;
        break;

    case 'last':
        $quarter = 4;
        break;

    default:
        $quarter = (!is_int($quarter) || $quarter < 1 || $quarter > 4) ? $current_quarter : $quarter;
        break;
    }
    if ( $quarter === 'this' ) {
        $quarter = ceil((new DateTime)->format('n') / 3);
    }
    $start = new DateTime($year.'-'.(3*$quarter-2).'-1 00:00:00');
    $end = new DateTime($year.'-'.(3*$quarter).'-'.($quarter == 1 || $quarter == 4 ? 31 : 30) .' 23:59:59');

    return array(
        'start' => $format ? $start->format($format) : $start,
        'end' => $format ? $end->format($format) : $end,
    );
}



?>
