<?

class Disc_info  {

	private $com_fso;
	public $curName;

	function __construct() {
		$this->testing_size = 0; // пространство с которым будем работать. Либо весь диск, либо если стоит галочка "использовать часть диска"
	}

	function setCur($disc_name) {
		$this->curName = $disc_name;
	}

	// $disc_name = cur  - это значит использовать текущий диск
	function isReady($disc_name) {
		if($disc_name == 'cur')
			$disc_name = $this->curName;

		if(!$this->com_fso)
			$this->com_fso = new COM("Scripting.FileSystemObject");

		try {
			if(!$this->com_fso->DriveExists("$disc_name:"))
				return false;

			$drives = $this->com_fso->Drives;
		
			$drive = $drives->Item("$disc_name:");
			$isReady = $drive->IsReady;
		}
		catch(Exception $e)  {
			return false;
		}

		return $isReady;
	}

	// список дисков с объемами
	// ВНИМАНИЕ! ДЛЯ usb дисков объем не высчитывается. Потому что они могут быть кард-ридерами и вылезет сообщение "Вставьте диск".
	// $add_info - добавлять ли информацию о диске
	function get_all($add_info=true) {

		// Set FSO = CreateObject("Scripting.FileSystemObject")
		// Set Drives = FSO.Drives
		// MsgBox "Всего дисков - " & Drives.Count
		// Set DriveC = Drives.Item("C:")
		// MsgBox "Диск C: имеет метку " & DriveC.VolumeName
		
		// узнать размер кластера: `fsutil fsinfo ntfsinfo c:` там права еще всякая фигня, надо распарсить

		// $FSO = new COM("Scripting.FileSystemObject");
		// $drives = $FSO->Drives;
		// foreach($drives as $drive)  {

		// 	print $drive->VolumeName . "\n";
		// }
		// $c = $drives->Item("D:");
		// print_r($c->VolumeName);

		$disc_mas = array();
		if(!$this->com_fso)
			$this->com_fso = new COM("Scripting.FileSystemObject");

		$drives = $this->com_fso->Drives;
		// начинаем с С, потому что непонятно, как будет размер на флоппике проверяться. Может и зависнуть тупо.
		for($disc_name = 'A'; $disc_name <= 'Z'; $disc_name++) {

			if(!$this->com_fso->DriveExists("$disc_name:")) continue;
			
			try {
				$drive = $drives->Item("$disc_name:");
			}
			catch(Exception $e)  {
				$disc_mas[] = "$disc_name  [проблема с диском]";
				continue;
			}			

			$drive_error = false;
			$label = '';

			//$type = osinfo_drivetype($disc_name.':\\') ;
			$type = $drive->DriveType;
			if(!($type == 1 || $type == 2 ))  continue; //только физические диски или флешки
			
			if($add_info) {
				$comment = '';
				if($type == 1)
					$comment = 'USB';

				// надеюсь что $drive->IsReady решит вопрос с вылезанием сообщения "вставьте диск" на кард-ридерах
				// так правильней, там делается блокировка ошибок на всякий случай
				if($this->isReady($disc_name)) {
					
					try { $label = $drive->VolumeName; }
					catch(Exception $e) {} //не будем это указывать $drive_error = true;

					if($label)
						$label = "[$label]";
					
					$size = $this->size($disc_name, "GB", 2);
					if(!$size['full'])
						$drive_error = true;

					if($drive_error)
						$disc = "$disc_name  [проблема с диском] $comment";
					else
						$disc = "$disc_name  $label  $size[full] GB ($size[free] free) $comment";
				}
				else {
					$disc = "$disc_name  [устройство не готово] $comment";
				}				
			}
			else $disc = $disc_name;

			$disc_mas[] = $disc;
		}
		
		return $disc_mas;
	}
	
	// размер диска
	// return {'full', 'free'}
	// $measure - единица измерения KB, MB, GB
	// disc_name может = cur
	function size($disc_name, $measure, $round=2, $is_format='format') {
		GLOBAL $log;

		if($disc_name == 'cur')
			$disc_name = $this->curName;

		//$log->line("size $disc_name");

		$disc_name = $disc_name .':\\';

		switch ($measure) {
			case 'GB':
				$denominator = 1024 * 1024 * 1024; break;
			case 'MB':
				$denominator = 1024 * 1024; break;
			case 'KB':
				$denominator = 1024; break;
			default:
				$denominator = 1;
		}


		//$size2 = osinfo_disktotal($disc_name);
		n(); $size = disk_total_space($disc_name); y();
		if(!$size or $size < 0)
			return array('full'=>0, 'free'=>0);
			// делаем return чтобы возможно предотвратить повторое появления окна "вставьте диск"
		
		if($denominator)
			 $full_size = $size / $denominator;
		else $full_size = $size;

		if($is_format == 'format') $full_size = number_format($full_size, $round);
		else $full_size = round_nobug($full_size, $round);
	        
		//$size2 = osinfo_diskfree($disc_name);
		n(); $size = disk_free_space($disc_name); y();
		if($size > 0) {
			if($denominator)
				 $free_size = $size / $denominator;
			else $free_size = $size;

			if($is_format == 'format') $free_size = number_format($free_size, $round);
			else $free_size = round_nobug($free_size, $round);
		}
		else $free_size = 0; 

		return array('full'=>$full_size, 'free'=>$free_size);
	}

	// серийный номер диска (раздела)
	// глючная вещь, поэтому отказались от него в пользу Disc_unid
	function serial($disc_name) {
		if(!preg_match('#^[a-z]$#i', $disc_name))
			throw new Error_def("Неправильная буква диска: $disc_name");
		
		// не всегда серийник определяется с первого раза
		for($i=1; $i<=20; $i++) {
			$serial = trim(osinfo_diskserial("$disc_name:\\"));
			 // иногда может выдать серийник из одних нулей или еще какой то бред
			if(preg_match('#^[a-f\d]+$#i', $serial) and !preg_match('#^0+$#', $serial)) { 
				return $serial;
			}
			usleep(10*1000);
		}
		
		throw new Error_def("Не удалось определить серийный номер раздела $disc_name. Последний предложенный серийник: $serial");
	}
}
