<?

// Разные функции


// Жесткие закрытия программы, без сохранения результатов
function hard_close_prog() {
	$v = new com('Shell.Application');
	$v->ShellExecute('taskkill',  '/im disk_revival_crash_control.exe /f' , '' , '', 0);
	application_terminate();
}

// Жесткая перезагрузка программы, без сохранения результатов
function hard_restart_prog($thread_restore = false) {
	// Почему то эта защита не работает, ну и фиг с ней. И так все работает.
	// иногда может случится так что она будет вызвана несколько раз подряд. Например в обработчике ошибок при ошибке переполнения памяти. И чтобы 2 раза не запустить программу, делаем защиту
	if(!empty($GLOBALS['restart_processing']))
		return false;

	$GLOBALS['restart_processing'] = true;
	$v = new com('Shell.Application');

	if($thread_restore)
		 $arg = 'crash_restore';
	else $arg = '';

	$v->ShellExecute(EXE_NAME , $arg, $arg,'',1); 
	application_terminate();
}


// !!!! ВНИМАНИЕ!!! На windows 8.1 и 10, запуск в режиме админа вызывает вопросы и винды и смотрятся они стремно
// поэтому лучше так не делать
// Перезапуск программы с правами администратора
// используется в нескольких местах потому вынес в виде функции
function prog_restart() {
	$v = new com('Shell.Application');
	$v->ShellExecute(EXE_NAME ,'/runas','','runas',1);
	application_terminate(); // после этого еще какое то время программа будет работать!
}


// открывает htm файл в браузере. передатьва пусть например: help/index.html
function openBrowser($local_path) {
	GLOBAL $progDir;
	Run("file:///".$progDir.$local_path, false);
}

function n() {
	err_no(); 
}

function y() {
	err_yes(); 
}


// Нужно использовать для вложенных элементов, когда у обоих в процессе меняется видимость
// когда один элемент вложен в другой и материнский может быть невидимым а у дочернего компонента меняется видимость, визуально она не меняется при активации материнского.
// или это глючит защита от лишней перерисовки
function visible_nobug($ui, $value) {
	// if(!$ui = get_ui($name))
	// 	throw new Error_def("Не обнаружен объект с именем '$name'");

	$ui->visible = !$value;
	$ui->visible = $value;
}


// имитирует выключение панелей и groupBox, затеняя все объекты в нем
// для groupBox не работает, componentList пустой
function enabled_component($name, $enabled, $color) {
	GLOBAL $log;

	$fmName = 'Fm';

	// если включаем, цвет делаем черным
	if($enabled)
		$color = 0x000000;

	$names = array(
		'stat_time_from_start',
		'stat_ostalos_time',
	);

	c($fmName.'->'.$name)->font->color = $color;

	foreach($names as $name) {
		$obj = get_ui($fmName.'->'.$name);
		if(!$obj) continue;

		$obj->font->color = $color;

		//$log->line($obj->name . ' красим в ' . $color);
	}
}


// имитирует выключение панелей и groupBox, затеняя все объекты в нем
// для groupBox не работает, componentList пустой
function enabled_component_2($name, $enabled, $color) {
	GLOBAL $log;

	$fmName = 'Fm';

	// если включаем, цвет делаем черным
	if($enabled)
		$color = 0x000000;

	c($fmName.'->'.$name)->font->color = $color;

	$objs = c($fmName.'->'.$name)->componentList;

	foreach($objs as $i=>$obj) {
		if(!$obj) continue;
		if(!in_array($obj->class_name, array('TLabel'))) continue;

		$obj->font->color = $color;

		//$log->line($obj->name . ' красим в ' . $color);
	}
}

// просто присваивает свойству text переданное значение
// но перед этим проверяет не чтобы оно уже не было таким же
function cCache_text($obj_or_name, $new_text) {
	// здесь нельзя указывать Fm

	if(is_string($obj_or_name))
		$obj = c($obj_or_name);
	else 
		$obj = $obj_or_name;

	if($obj->text != $new_text)
		$obj->text = $new_text;
}


// Имя файла он берет из глобальной переменной logFile_fname
// logFile_datetype = timestamp|date  - нужно для потоков, где функция date почему то не работает
// иногда полезно руками указывать fname
function logFile($str, $fname=false) {
	GLOBAL $LogFile, $log;

	$file_max_size = 1024*1024*3; // 3mb. при привышении объема, обрезаем в 2 раза

	// Иногда эта конструкция не дает файлу записаться, поскольку он еще заблокирован (на некоторых компьютерах есть такой эффект)
	// поэтому делаем геморрой с fopen
	//file_put_contents('log.txt', date("[ H:i:s ]") . $str .  "\r\n" . file_get_contents('log.txt'));

	// на всякий случай, вдруг операция будет не успешной, блокируем все ошибки

	if(!$fname)
		$fname = $LogFile['fname'];

	n();

	if(!$fh = fopen($fname, 'a')) {
		y();
		trigger_error("Не удалось открыть файл для записи: $fname", E_USER_NOTICE);
		return false;
	}

	if($LogFile['datetype'] == 'date')
		$time = date("H:i:s");
	else $time = time();

	fwrite($fh, "\r\n[$time] " . $str);
	fclose($fh);

	// если размер больше 2-х метров, обрезаем до метра
	if(filesize($fname) > $file_max_size) {
		if($content = file_get_contents($fname)) { // на случай вдруг файл не откроется
			$content = substr($content, round($file_max_size/2)); // обрезаем половину файла
			file_put_contents($fname, $content);
			//$log->line("$fname обрезаем лог");
		}
	}
	y();

	return true;
}

// тоже самое что и обычный диалог только шрифт побольше
//$self->buttonsWidth
function my_message_dialog($text, $buttons='OK', $setting=array()) {
	$dialog = с('custom_dialog');
	$dialog->title = $text;
	$dialog->font->size = 10;
	$dialog->buttons = $buttons;

	foreach ($setting as $name => $value) {
		$dialog->$name = $value;
	}
	
	return $dialog->execute();
}


// function () {

// 	$words = explode(" ", $str);
// 	$res_str = '';
// 	foreach($words as $word)
// }

// показывает/скрывает выделение группые объектов, с базовым именем $base_name
// выделение это любые объекты вроде Tshape 
// имена элементов выделения должны заканчивать на _s1, _s2...  например button_s1, button_s2
// ВНИМАНИЕ. Используется также для кнопки Завершающий этап
function visible_group($base_name, $visible, $cause_name='') {
	GLOBAL $log;
	STATIC $Cause_mas = array();

	$fmName = 'Fm';

	//$log->line('visible_group');
	if(! $s1 = get_ui($fmName."->{$base_name}_s1")) return false;

	// причины показывать/скрывать выделение
	if($cause_name) {

		$Cause_mas[$base_name][$cause_name] = $visible;

		// если хотя бы у одной причины стоит true, значит, показываем, иначе скрываем
		if(in_array(true, $Cause_mas[$base_name])) {
			$visible = true;
			//$log->line("делаем видимым");
		}
		else {
			$visible = false;
			//$log->line('скрываем');
		}
	}

	// если выделение и так уже видно
	if($s1->visible == $visible) return false;

	//$log->line("visible_group: $visible");

	$s1->visible = $visible;
	for($i=2; $i<=100; $i++) {
		//$log->line("{$ui_name}_s{$i}");
		if(!$s = get_ui($fmName."->{$base_name}_s{$i}")) break;
		$s->visible = $visible;
	}

	//с($base_name)->enabled = $visible;  в другом месте будем управлять этим

	// перерисовываем объект который выделяем потому что бывают артефакты
	// иногда эта функция не нужна и объектам с таким именем нет.
	if($base_obj = get_ui($fmName."->".$base_name))
		$base_obj->repaint(); 
	
}

function show_hide($name, $x=false, $y=false) {

	// не нужен, потомо что прямо в name уже будет указан
	//$fmName = 'Fm';

	$panel = get_ui($name);

	if($x !== false and $y !== false) {
		$panel->x = $x;
		$panel->y = $y;
	}

	if($panel->visible == 0) {
		$panel->visible = 1;
	}
	else {
		$panel->visible = 0;
	}
}

// запуск статического метода в классе, если существует сам класс и метод
function run_method_exists($class_name, $method_name) {
	GLOBAL $log;

	// не каждому этапу нужна функция проверки, поэтому проверяем ее наличие
	//if(!in_array($class_name, $this->used_class_mas))
	if(!class_exists($class_name))
		return true;

	if(!method_exists($class_name, $method_name))
		return true;

	return $class_name::$method_name();
}


// в devel studio если передать в round 0 (причем чтобы был тип float), будет зависон.
function round_nobug($number, $precision=0) {
	if($number == 0)
		return 0;

	return round($number, $precision);
}

// небольшое улучшение стандартной функции - с
// возвращает false если объект не найден
function get_ui($name) {
	if(!$name)
		throw new Error_def("Не передано имя объекта");

	$obj = c($name);
	
	if(get_class($obj) == 'DebugClass')  return false;
	else return $obj;
}

// возвращает дамп в виде строки
function var_dump_str($var) {
	ob_start();
	var_dump($var);
	$str = ob_get_clean();

	return $str;
}

// обычный array_search периодически глючит если числа float
function array_search_nobug($need, $mas) {
	//$need = $need + 2;
	foreach($mas as $k=>$v) {

		//$v = $v + 2;

		

		if($v == $need) 
			return $k;
		else {
			print var_dump_str($v) . '!=' .var_dump_str($need) . "\n";
		}
	}
	return false;
}

// каждый элемент массива разбиваем на равное кол-во частей
// Например
// был {0, 1} . Разбиваем на 3 части.
// стал {0, 0.33, 0.66, 1}
function array_partition_values($mas, $parts) {
	GLOBAL $log;

	$result = array();
	$keys = array_fill_keys($mas, NULL);

	$last_v = -1;
	foreach($keys as $k=>$t) {
		list($floor, $ceil) = near_keys($keys, $k);
		$unit = ($ceil - $floor) / $parts;

		//if($log) $log->line("unit: $unit, floor: $floor");

		$i = (float)$floor;
		while($i<$ceil) {
			if($i != $last_v)  { // чтобы ключевые числа не добавлялись в массив 2 раза
				$result[] = $i;
				$last_v = $i;
			}
			$i = $i + (float)$unit;
			
			// иногда в процессе сложения float чисел получаются числа которые выглядят как одинаковые, но по факту разные. например 0.3 != 0.3.
			// Видимо там после кучи нулей какая то погрешность идет. 
			// Поэтому нужно делать округление
			$i = round_nobug($i, 5); 
		}
	}
	return $result;
}


/* 
ближайшие ключи, как сверху так и снизу
$mas не сортируется по возрастанию ключей, за этим надо следить самостоятельно
ключи с точкой брать в кавычки, иначе они будут преобразованы в целые числа
Пример массива:
	array(
		-1=>'a',
		 0=>array(), 
		 '0.5'=>'w',
		  1=>'e', 
	);
}
*/

function near_keys($mas, $number) {
	if(!$mas)
		throw new Error_def('Передан пустой массив');

	reset($mas);
	$prev = key($mas);
	foreach($mas as $k=>$v) {
		if($k > $number) {
			$floor = $prev;
			$ceil = $k;
			break; 
		}
		$prev = $k;
	}

	if(!isset($floor)) 
		$floor = $ceil = $k;

	// определение, какое значение ближе
	if(abs($floor - $number) > abs($ceil - $number))
		$near = $ceil;
	else $near = $floor;

	return array($floor, $ceil, $near);
}

// это максимально оптимизированная функция используется очень много в анализе
// ее нельзя делать тяжелей
function floor_keys(&$mas, $number) {
	if(!$mas)
		throw new Error_def('Передан пустой массив');

	reset($mas);
	$prev = key($mas);
	foreach($mas as $k=>$v) {
		if($k > $number) {
			return $prev;
		}
		$prev = $k;
	}
	return $k;
}

// тоже самое что и near_keys() только сразу и плюсуем значение у найденного ключа
// модифицирует переданные массив
function add_to_key_floor(&$mas, $find_number, $add_number) {
	//GLOBAL $log;
	//return true;
	$key = floor_keys($mas, $find_number);
	$mas[$key] += $add_number;
}

// устанавливает значение для каждого элемента массива
function array_set_values(&$mas, $value) {
	foreach($mas as $k=>$v) 
		$mas[$k] = $value;
}

// Не дает компу заснуть. 
// с интервалом в $interval_check чекает на то что за компом никого нет и отправляет клавишу {left}
function nosleep($interval_check) {
	GLOBAL $log;

	static $prev_x = 0;
	static $prev_y = 0;
	static $time_check = 0;

	// проверяем координаты с интервалом $interval_check
	if($time_check + $interval_check < time()) {
		$user_active = false;
		
		 //$log->line('чекаем');

		// изменились ли координаты мышки
		if(cursor_pos_x() != $prev_x) {
			$prev_x = cursor_pos_x();
			$user_active = true;
		}
		if(cursor_pos_y() != $prev_y) {
			$prev_y = cursor_pos_y();
			$user_active = true;
		}

		if(!$user_active) {
			//$log->line('никого нет, <left>');
			// координаты изменились, подаем признаки жизни
			$WshShell = new COM("WScript.Shell");
			$WshShell->SendKeys("{LEFT}");
		}

		$time_check = time();
	}
}


/*
равно одному из всех
все равны

// первая переменная должна равняться одному из переданных параметров
function one_of_all($var_where) {
	func_get_args()
}
{in_array($thread_status, array('complete', 'error'))
*/

?>