<?

/*
Тестирование потоков путем эмуляции плохих и медленных блоков

В файле где будут указаны тестовые файлы, но задать значения статических переменных:
File_func_test::$def_sect_speed = 10;

*/

class File_func_test {
	
	static $files; // массив с тестовыми блоками. Загружается где нибудь в начале скрипта
	static $def_sect_speed = 10; // Mb/s скорость сектора если не указана в тестовом файле. Устанавливается в файле с тестовыми блоками

	private $fname; // имя открытого файла
	private $count_read = 0; // счетчик запуска функции read. Нужен чтобы имитировать посекторное чтение файла

	function __construct($OP) {
		GLOBAL $log;

		$this->OP = $OP;
	}

	// все сообщения выдаем через эту функцию
	// $method нужно указывать если используется промежуточная функция, такая как is_open_file
	private function _error($str, $method='') {
		GLOBAL $log;
		
		if(!$method) {
			$stack = debug_backtrace();
			$method = $stack[0]['func'];
		}
		$log->line("File_func_test::{$method}(): $str");
	}
	
	function is_exists($fname) {
		$this->fname = $this->_parse_fname($fpath);

		if(!empty(self::$files[$this->fname]['no_exists'])) 
			return false;
		else 
			return true;
	}


	function fopen($fpath, $mode) {
		$this->fname = $this->_parse_fname($fpath);
		
		$this->count_read = 0;
		
		if(!empty(self::$files[$this->fname][$mode.'_open_error'])) {
			return false;
		}
		return true; // по большому счету не важно что мы вернем, все равно только этот класс будет работать с этой переменной
	}

	// парсинг имени файла из путя.
	private function _parse_fname($fpath) {
		// вырезаем строку после последнего слеша
		//$fpath = str_replace('\\', '/', $fpath);
		if(!preg_match('#/([^/]+)$#', $fpath, $res)) {
			$this->_error("не удается выделить имя файла из пути '$fpath'");
			return false;
		}
		return $res[1];
	}
	
	
	
	function fwrite($fh, $data_str, &$write_time) {
		// замедление записи файла

		$speed = self::$files[$this->fname]['write_speed'];
		$write_time = ($this->OP['block_size'] / 1024) / $speed;

		usleep($write_time*1000*1000); // чтобы можно было указывать 0.5 сек например. usleep работает очень не точно
		
		// нехватка места (строка записалась частично)
		$len = strlen($data_str);
		if(!empty(self::$files[$this->fname]['write_need_space']))
			$len -= 2;
		
		return $len;
	}
	
	// замедление чтение файла
	// 
	function fread($fh, $len_bt, &$read_time) {
		GLOBAL $log;

		$file_info = self::$files[$this->fname];

		// имитация ошибки чтения
		if(!empty($file_info['read_error']))
			return false;
		
		// берем скорость сектора
		$cur_sect_speed = isset($file_info['read_speed'][$this->count_read])
								? $file_info['read_speed'][$this->count_read]
								: self::$def_sect_speed;

		$cur_sect_time = ($this->OP['sect_size'] / 1024) / $cur_sect_speed;
		//$log->line('sect:' . $this->count_read . '   скорость: ' . $cur_sect_speed . '  время: ' .$cur_sect_time);

		usleep($cur_sect_time*1000*1000); // чтобы можно было указывать 0.5 сек например
		// usleep работает очень грубо, поэтому время мы передаем руками
		$read_time = $cur_sect_time;

		$this->count_read ++;

		// имитируем возврат данных
		return Gen_str::simple($len_bt); 
	}
	
	function set_write_buffer($fh, $size_bt) {
		return true;
	}

	function fflush() {
		return true;
	}
	
	function fclose() {
		return true;
	}
}

?>