<?

/*
лог
*/

class Log {
	
	public $lines_max = 50; //120; // это кол-во значений хранящихся (а не показывающихся) в обычном логе. Если маленькое, часть записей будет теряться в случае если обработка идет быстро. И в полном логе это будет заметно и вызовет вопросы.
	//private $display_num_lines = 50; // это то сколько реально будет отображаться в логе. ПРоблема в том что если lines_max небольшой, то часть записей просто пропадает, так и не дойдя до полного лога
	public $fulllog_line_max = 20000;

	public $thread_temp = array(); // сюда пихаем все сообщения, а при отправке info, они будут отсюда перемещаться в $log_lines и отправляться во вне

	private $log_lines = array(); //
	private $fulllog_lines = array(); //
	private $new_data = false; //поступила новая информация, надо обновлять дисплей
	private $display_name;
	private $is_thread = false; // метка поток ли это

	protected $fmName = 'Fm';
	// отладка
	public $backup_input  = array();

	function __construct($display_name='') {
		$this->display_name = $display_name;
		$this->cur_line = '';
		$this->display_no_update = false;
		$this->is_thread = false;

		// if(file_exists('THIS_DEWELOPER'))
		// 	$this->lines_max = 30;

		// пометка пользователю что в логе появились новые записи и надо бы обновить дисплей
		if($display_name) {

			$this->display_need_update = get_ui($this->fmName.'->'.'log_need_update');
			//$this->display_need_update_comment = get_ui('display_need_update_comment');
		}
	}

	// чтобы не пропадали сообщения, в потоке нужно выставить большое значение, а уже в ui можно поменьше
	function set_lines_max($num) {
		$this->lines_max = $num;
	}


	function is_thread($is) {
		$this->is_thread = $is;
		if($is) {
			$GLOBALS['thread']->set_protect('log_lines', array());
		}
	}

	// групповое добавлении сообщений. 
	// Используем при перемещении сообщений из потока
	function add_line_mas($mas) {
		if(!$mas) throw new Error_def("Передан пустой параметр вместо массива");

		// foreach($mas as $line) {
		// 	if(!trim($line)) continue;

		// 	$this->line($line);
		// }	

		$this->_add_lines($mas);

	}

	public function line($str='', $logFile=false) {

		if($this->is_thread and $str)  {
			$this->thread_temp[] = $str;
			return;
		}

		if($this->cur_line) {
			$this->_add_lines($this->cur_line);
			$this->cur_line = '';
		}
		$this->_add_lines($str);

		// сохраняем в файловый лог
		if($logFile and $str)
			logFile($str);
	}

	// отправка сообщений из потока в интерфейс программы
	public function send_thread_temp() {
		if(!$this->thread_temp) return true;

		$this->_add_lines($this->thread_temp, true);
		$this->thread_temp = array();
	}

	private function _add_lines(&$str_or_mas, $calling_send_thread_temp=false) {
		GLOBAL $thread;
		// return true;
		// нельзя показывать сообщения снизу вверх. Иначе будет непонятно где заголовок, где данные
		
		// сохраняем последние  сообщения
		/* пока не нужен этот функционал
		$this->backup_input[] = $str;
		if(sizeof($this->backup_input) > 1) {
			array_shift($this->backup_input);
		}*/

		// вызывает дублирование строки и вставку их не туда куда надо. пока отлючим
		// а нет, вставка сообщение не туда происходит где то в другом месте. Но все равно эта функция дублирует сообщения.
		/*
		if(!$calling_send_thread_temp AND $this->is_thread) {
			if(is_string($str_or_mas)) {
				$this->thread_temp[] = $str_or_mas;
			}
			else {
				foreach($str_or_mas as $str) {
					$this->thread_temp[] = $str;
				}
			}
			
					// не делаем выход чтобы thread_temp и фактический лог дублировались и без thread->send_info() все что отправленно в $log->line() сразу же показывалось. А то что отправляют в thread_temp будет показываться при send_info но без потери данных отправленных через log->line()
					// return true;
		}*/

		// мы должны сначала взять весь массив
		// Иначе если лог работает в потоке, будут проблемы из-за того что в $thread есть проблемы с массивами в качестве свойств.

		$start = 0;
		
		if(is_array($str_or_mas)) {
			$new_lines =& $str_or_mas;
			if(sizeof($new_lines) > $this->lines_max) {
				$start = sizeof($new_lines) - $this->lines_max + 1;
			}
		}
		else {
			$new_lines = array($str_or_mas);	
		}

		$lines = $this->_get_storage();

		for($i=$start; $i<sizeof($new_lines); $i++) 
			$lines[] = $new_lines[$i];

		// удаление лишних строк
		if(sizeof($lines) > $this->lines_max) {
			$del = sizeof($lines) - $this->lines_max;
			for($i=1; $i<=$del; $i++)
				array_shift($lines);
		}

		$this->_set_storage($lines);
		$this->new_data = true;


		// полный лог
		if(!$this->is_thread) {
			// добавление строк в полный лог
			foreach($new_lines as $line) 
				$this->fulllog_lines[] = $line;

			// удаляем лишние
			$need_del = sizeof($this->fulllog_lines) - $this->fulllog_line_max;
			if($need_del > 0 ) {
				reset($this->fulllog_lines);
				$first = key($this->fulllog_lines);
				$finish =$first+$need_del;
				for($i=$first; $i<=$finish; $i++)
					unset($this->fulllog_lines[$i]);
			}
		}
	}


	// это временный пиздец. Надо будет переделать.
	private function _set_storage($lines) {
		GLOBAL $thread;

		if($this->is_thread)
			$thread->set_protect('log_lines', $lines);
		else
			$this->log_lines = $lines;
	}

	private function _get_storage() {
		GLOBAL $thread;

		if($this->is_thread)
			return $thread->get_protect('log_lines');
		else
			return $this->log_lines;
	}

	// очищаем буфер
	function clear() {
		$this->new_data = true;
		$this->_set_storage(array());
		$this->cur_line = '';
	}
	
	/* 
	Отключили потому что лог у нас глобальный. Если в нескольких местах открыть новую строку, то данные перепутаются.
	Короче, это была плохая идея.

	// открывает новую линию. Нужно если данные в линию будут дописываться
	public function open_line() {
		if($this->cur_line) {
			$this->_add_lines($this->cur_line);
		}
		
		$this->cur_line = '';
	}
	
	// необязательно закрывать. line или open_line автоматом закроют линию если она была
	public function close_line() {
		$this->open_line();
	}
	
	public function add_to_line($str) {
		$this->cur_line .= $str;
	}
	*/
	
	// нельзя делать вызов из потока
	public function update_display() {
		if(!$this->new_data) return false;

		if($this->display_no_update) {
			// лог выводить нельзя
			// показываем отметку что в логе есть данные для обновления
			$this->display_need_update->visible = 1;

			return false;
		}
		else {
			// скрываем сообщение о новых данных в логе
			$this->display_need_update->visible = 0;
		}
		
		// $all_str = $this->_get_storage();
		// $num_str = sizeof($all_str);
		// if($num_str <= $this->display_num_lines)
		// 	 $start = 0;
		// else $start = $num_str - $this->display_num_lines;
		
		// $this->display_num_lines

		// $content = implode("\r\n", array_slice($this->_get_storage(), $this->display_num_lines*-1, $this->display_num_lines));

		$content =  implode("\r\n", $this->_get_storage());
		
		$memo = c($this->fmName.'->'.$this->display_name);
		$memo->text  = $content;
		
		// скролим вниз путем выделения последней строки
		$memo->selStart = strlen($content) - 5;
		$memo->selLength = 2;
		
		$this->new_data = false;
	}

	// Заполняем лог в окне "полный лог"
	public function update_fulldisplay() {
		
		$content = implode("\r\n", $this->fulllog_lines);
		
		$memo = c("fmLog->display_log");
		$memo->text  = $content;
		
		// скролим вниз путем выделения последней строки
		$memo->selStart = strlen($content) - 5;
		$memo->selLength = 2;
	}

}

?>