Your IP : 216.73.216.86


Current Path : /var/www/homesaver/www/bitrix/modules/webdebug.excel/classes/general/
Upload File :
Current File : /var/www/homesaver/www/bitrix/modules/webdebug.excel/classes/general/CWebdebugExcel2.php

<?

IncludeModuleLangFile(__FILE__);
class CWebdebugExcel2 {
	const ModuleID = 'webdebug.excel';
	const DateFormatDir = 'Y-m-d';
	const ImportIDPropCode = 'WDEXCEL_IMPORT_ID';
	const StoresProcessedPropCode = 'WDEXCEL_STORES_PROCESSED';
	const GlobalsTemp = 'WDEXCEL_TEMP';
	public $bSuccessLoaded = false;
	var $objPHPExcel;
	var $strDataFileName; // filename of file loaded from tar.gz
	var $arData; // data loaded from tar.gz
	var $strFileType; // EXCEL or TAR_GZ
	
	/**
	 *	Creating object with loading file
	 */
	function __construct($FileName, $Autoload=true) {
		$LocalFileName = false;
		if (self::IsFileValid($FileName,$LocalFileName,'TAR_GZ')) {
			$ExtractedFileName = self::ExtractTagGz($FileName);
			if ($ExtractedFileName!==false) {
				$this->strFileType = 'TAR_GZ';
				$this->bSuccessLoaded = true;
				$this->strDataFileName = $ExtractedFileName;
				if ($Autoload) {
					$this->LoadExtractedFile($ExtractedFileName);
				}
			}
		} elseif (self::IsFileValid($FileName,$LocalFileName,'EXCEL')) {
			require_once ($_SERVER["DOCUMENT_ROOT"].'/bitrix/modules/'.self::ModuleID.'/include/phpexcel/PHPExcel.php');
			if (self::IsUTF()) {
				ini_set('mbstring.func_overload', '0');
				ini_set('mbstring.internal_encoding', 'CP1251');
			}
			$FileName = self::ConvertCharset($FileName,'UTF-8','CP1251');
			if ($Autoload) {
				$this->objPHPExcel = PHPExcel_IOFactory::load($_SERVER['DOCUMENT_ROOT'].$FileName);
			}
			if (self::IsUTF()) {
				ini_set('mbstring.func_overload', '2');
				ini_set('mbstring.internal_encoding', 'UTF-8');
			}
			$this->strFileType = 'EXCEL';
			$this->bSuccessLoaded = true;
		}
	}
	function P($arData, $Return=false) {
		$strResult = "<style type='text/css'>pre {background:none repeat scroll 0 0 #FAFAFA; border-color:#AAB4BE #AAB4BE #AAB4BE #B4B4B4; border-style:dotted dotted dotted solid; border-width:1px 1px 1px 20px; font:normal 11px \"Courier New\",\"Courier\",monospace; margin:10px 0; padding:5px 0 5px 10px; position:relative; text-align:left; white-space:pre-wrap;}</style>";
		if (is_array($arData) && empty($arData)) $arData = "--- Array is empty ---";
		if ($arData===false) $arData = "false"; elseif ($arData===true) $arData = "true";
		$strResult .= "<pre>".print_r($arData,true)."</pre>";
		if ($Return) {
			return $strResult;
		} else {
			print $strResult;
		}
	}
	/**
	 *	Add message to log
	 */
	function Log($Message) {
		if (COption::GetOptionString(self::ModuleID,'log_errors')!='N') {
			if (is_array($Message)) $Message = print_r($Message,1);
			#$LogFileName = 'log_'.COption::GetOptionString('main','server_uniq_id').'.log';
			$LogFileName = COption::GetOptionString(self::ModuleID,'log_filename');
			$LogFileName = $_SERVER['DOCUMENT_ROOT'].$LogFileName;
			$Handle = @fopen($LogFileName, 'a+');
			@flock($Handle, LOCK_EX);
			@fwrite($Handle, '['.date('d.m.Y H:i:s').'] '.$Message."\r\n");
			@flock($Handle, LOCK_UN);
			@fclose($Handle);
		}
	}
	/**
	 *	Show error
	 */
	function ShowError($Message, $arData, $arErrorData=null) {
		if ((is_array($Message) && !empty($Message)) || (!is_array($Message) && trim($Message)!='')) {
			$LogMessage = $Message;
			if (is_string($Message)) {
				$Message = preg_replace('#<br([\s/]{0,})>$#is', '', $LogMessage);
				$LogMessage = $Message;
				if ($arData['INDEX']>0) {$LogMessage .= sprintf(GetMessage('WEBDEBUG_EXCEL_LOG_LINE'),$arData['STATUS']['COUNT'][$arData['SHEET']]['NAME'],$arData['INDEX']);}
			}
			self::Log($LogMessage);
			$GLOBALS['WEBDEBUG_EXCEL2_ERRORS_COUNT'] = IntVal($GLOBALS['WEBDEBUG_EXCEL2_ERRORS_COUNT']) + 1;
			?>
			<div class="wd_excel2_error"><?if(is_array($Message)):?><ul class="wd_excel2_error_inner"><?foreach($Message as $Item):?><li><?=$Item;?></li><?endforeach?></ul><?else:?><div class="wd_excel2_error_inner"><?=$Message;?><?if($arData['INDEX']):?><?=sprintf(GetMessage('WEBDEBUG_EXCEL_LOG_LINE'),$arData['STATUS']['COUNT'][$arData['SHEET']]['NAME'],$arData['INDEX']);?><?endif?></div><?endif?></div>
			<?
			if (in_array($arData['FIELDS']['PARAMS']['NO_BREAK_ON_ERROR'],array('','N'))) {
				self::Log(GetMessage('WEBDEBUG_EXCEL_EXIT_ON_LOG'));
				die();
			}
		}
	}
	/**
	 *	Check if file valid (by ext and size)
	 */
	function IsFileValid($FileName, &$LocalFileName, $Type=false) {
		if ($Type==false) $Type = 'ALL';
		// Check file ext
		$bTarGz = ToLower(self::Substr($FileName,-7))=='.tar.gz';
		$bExcel2003 = ToLower(self::Substr($FileName,-4))=='.xls';
		$bExcel2007 = ToLower(self::Substr($FileName,-5))=='.xlsx';
		$bExcel = $bExcel2003 || $bExcel2007;
		$bExtValid = ($Type=='TAR_GZ' && $bTarGz) || ($Type=='EXCEL' && $bExcel) || ($Type=='ALL' && ($bTarGz || $bExcel));
		/* FOR URL FILE DOWNLOAD
		// Check file exists
		$bFileExists = false;
		if (ToLower(self::substr($FileName,0,7))=='http://' || ToLower(self::substr($FileName,0,8))=='https://' || self::substr($FileName,0,2)=='//') {
			// Remote file
			$FileNameUniq = MD5(ToLower($FileName));
			$UploadDir = COption::GetOptionString('main','upload_dir','/upload/');
			$Date = date(self::DateFormatDir);
			$FilePath = $UploadDir.self::ModuleID.'/'.$Date.'/';
			mkdir($_SERVER['DOCUMENT_ROOT'].$FilePath, BX_DIR_PERMISSIONS, true);
			$DownloadedFileName = $FilePath.$FileNameUniq;
			if ($bExcel2003) {
				$DownloadedFileName .= self::Substr($FileName,-4);
			} elseif ($bExcel2007) {
				$DownloadedFileName .= self::Substr($FileName,-5);
			} elseif ($bTarGz) {
				$DownloadedFileName .= self::Substr($FileName,-7);
			}
			if (file_exists($DownloadedFileName)) {
				@unlink($DownloadedFileName);
			}
			$Timeout = COption::GetOptionString(self::ModuleID, 'files_timeout');
			$arContext = array(
				'http'=>array(
					'timeout' => $Timeout,
				)
			);
			$RemoteFileContents = file_get_contents($FileName,false,stream_context_create($arContext));
			if ($RemoteFileContents!==false) {
				@unlink($_SERVER['DOCUMENT_ROOT'].$DownloadedFileName);
				if (file_put_contents($_SERVER['DOCUMENT_ROOT'].$DownloadedFileName, $RemoteFileContents)) {
					$LocalFileName = $DownloadedFileName;
					$bFileExists = is_file($_SERVER['DOCUMENT_ROOT'].$DownloadedFileName) && filesize($_SERVER['DOCUMENT_ROOT'].$DownloadedFileName);
				}
			} else {
				self::ShowError(sprintf(GetMessage('WEBDEBUG_EXCEL_FILE_DOWNLOAD_FAILED'),$FileName,$FileName,$Timeout));
			}
		} else {
			// Local file
			$bFileExists = is_file($_SERVER['DOCUMENT_ROOT'].$FileName) && filesize($_SERVER['DOCUMENT_ROOT'].$FileName);
		}
		*/
		$bFileExists = is_file($_SERVER['DOCUMENT_ROOT'].$FileName) && filesize($_SERVER['DOCUMENT_ROOT'].$FileName);
		return $bFileExists && $bExtValid;
	}
	function ExtractTagGz($FileName) {
		$ExtractedFileName = false;
		$arFileInfo = pathinfo($FileName);
		if (ToLower(self::substr($arFileInfo['basename'],-7))=='.tar.gz') {
			$BaseName = self::substr($arFileInfo['basename'],0,-7);
			$UploadDir = COption::GetOptionString('main','upload_dir','/upload/');
			$DataFileExt = COption::GetOptionString(self::ModuleID,'data_file_ext');
			$Date = date(self::DateFormatDir);
			$Uniq = ToLower(RandString(32));
			$FilePath = '/'.$UploadDir.'/'.self::ModuleID.'/'.$Date.'/'.$BaseName.'/'.$Uniq.'/';
			mkdir($_SERVER['DOCUMENT_ROOT'].$FilePath, BX_DIR_PERMISSIONS, true);
			require_once($_SERVER['DOCUMENT_ROOT'].'/bitrix/modules/main/classes/general/tar_gz.php');
			$Archiver = new CArchiver($_SERVER['DOCUMENT_ROOT'].$FileName);
			$Archiver->extractFiles($_SERVER['DOCUMENT_ROOT'].$FilePath);
			$Handle = opendir($_SERVER['DOCUMENT_ROOT'].$FilePath);
			while (($File = readdir($Handle)) !== false)  {
				if($File != "." && $File != "..") {
					if(is_file($_SERVER['DOCUMENT_ROOT'].$FilePath.$File)) {
						if (ToLower(self::substr($File,-1*self::strlen($DataFileExt)))==ToLower($DataFileExt)) {
							$ExtractedFileName = $FilePath.$File;
						}
					}
				}
			}
			closedir($Handle);
			
		}
		return $ExtractedFileName;
	}
	function LoadExtractedFile() {
		if (is_file($_SERVER['DOCUMENT_ROOT'].$this->strDataFileName)) {
			$this->arData = unserialize(file_get_contents($_SERVER['DOCUMENT_ROOT'].$this->strDataFileName));
			if (is_array($this->arData)) {
				$Done = true;
				return true;
			}
		}
		if (!$Done) {
			return false;
		}
	}
	/**
	 *	Get current mictorime stamp
	 */
	function GetMicroTime() {
		list($usec, $sec) = explode(' ', microtime());
		return ((float)$usec + (float)$sec);
	}
	/**
	 *	Start time counter
	 */
	function StartTimeCounter() {
		$GLOBALS['WD_EXCEL2_START_TIME'] = self::GetMicroTime();
	}
	/**
	 *	Check, if time is over
	 */
	function CheckTimeIsOver($MaxTime) {
		$Time = self::GetMicroTime();
		return $Time - $GLOBALS['WD_EXCEL2_START_TIME'] >= $MaxTime;
	}
	/**
	 *	Check, if site charset is UTF-8
	 */
	function IsUTF() {
		return defined('BX_UTF') && BX_UTF===true;
	}
	/**
	 *	Convert charset of text
	 */
	function ConvertCharset($Text, $From='UTF-8', $To='CP1251') {
		return $GLOBALS['APPLICATION']->ConvertCharset($Text, $From, $To);
	}
	/**
	 *	Dump excel data to file (ToDo: Delete)
	 */
	function DumpToFile($FileName) {
		///
	}
	/**
	 *	Get number of columns
	 */
	function GetMaxColIndex($SheetIndex=0) {
		if ($this->strFileType=='TAR_GZ') {
			if (is_array($this->arData['SHEETS'][$SheetIndex]['ITEMS'])) {
				foreach($this->arData['SHEETS'][$SheetIndex]['ITEMS'] as $arItem) {
					return count($arItem);
				}
			} else {
				return 0;
			}
		} elseif ($this->strFileType=='EXCEL') {
			return PHPExcel_Cell::columnIndexFromString($this->objPHPExcel->getSheet($SheetIndex)->getHighestColumn());
		}
	}
	/**
	 *	Get number of rows
	 */
	function GetMaxRowIndex($SheetIndex=0) {
		if ($this->strFileType=='TAR_GZ') {
			if (is_array($this->arData['SHEETS'][$SheetIndex]['ITEMS'])) {
				return count($this->arData['SHEETS'][$SheetIndex]['ITEMS']);
			} else {
				return 0;
			}
		} elseif ($this->strFileType=='EXCEL') {
			return $this->objPHPExcel->getSheet($SheetIndex)->getHighestRow();
		}
	}
	/**
	 *	Get sheets list in XLS file
	 *	@param boolean $ShowHidden Flag indicates show || hide hidden sheets
	 */
	function GetSheetList($ShowHidden=false) {
		$arResult = array();
		if ($this->strFileType=='TAR_GZ') {
			foreach($this->arData['SHEETS'] as $SheetIndex => $arSheet) {
				$arResult[$SheetIndex] = $arSheet['NAME'];
				if (defined('BX_UTF') && BX_UTF===true) {
					$arResult[$SheetIndex] = self::ConvertCharset($arResult[$SheetIndex], 'CP1251', 'UTF-8');
				}
			}
		} elseif ($this->strFileType=='EXCEL') {
			$SheetCount = $this->objPHPExcel->getSheetCount();
			if ($SheetCount>0) {
				for ($i=0; $i<$SheetCount; $i++) {
					if ($this->objPHPExcel->getSheet($i)->getSheetState()=='visible' || $ShowHidden===true) {
						$arResult[$i] = $this->objPHPExcel->getSheet($i)->getTitle();
						if (!defined('BX_UTF') || BX_UTF!==true) {
							$arResult[$i] = self::ConvertCharset($arResult[$i], 'UTF-8', 'CP1251');
						}
					}
				}
			}
		}
		foreach(GetModuleEvents(self::ModuleID, 'OnGetSheetList', true) as $arEvent) {
			ExecuteModuleEventEx($arEvent, array(&$arResult, $ShowHidden));
		}
		return $arResult;
	}
	/**
	 *	Get cell as HTML
	 */
	function GetRichTextValue($Value, $SheetIndex, $Column, $Row) {
		$arResult = array();
		$arValueElemens = $Value->getRichTextElements();
		foreach ($arValueElemens as $objItem) {
			if ((get_class($objItem))=='PHPExcel_RichText_Run') {
				$objFont = $objItem->getFont();
				if(get_class($objFont)=='PHPExcel_Style_Font') {
					$Text = $objItem->getText();
					if (!self::IsUTF()) {
						$Text = self::ConvertCharset($Text, 'UTF-8', 'CP1251');
					}
					$arResult[] = array(
						'TEXT' => $Text,
						'FONT' => $objFont->getName(),
						'SIZE' => $objFont->getSize(),
						'COLOR' => $objFont->getColor()->getRGB(),
						'B' => $objFont->getBold(),
						'I' => $objFont->getItalic(),
						'U' => $objFont->getUnderline(),
						'S' => $objFont->getStrikethrough(),
						'SUP' => $objFont->getSuperScript(),
						'SUB' => $objFont->getSubScript(),
					);
				}
			}
		}
		return $arResult;
	}
	/**
	 *	Save status for file loading [1st procedure]
	 */
	function SetLoadingPosition($SessionID, $SheetIndex, $RowIndex) {
		$_SESSION['WEBDEBUG_EXCEL']['STATUS_SESSION'][$SessionID] = array(
			'SHEET' => $SheetIndex,
			'ROW' => $RowIndex,
		);
		if ($SheetIndex===false && $RowIndex===false) {
			unset($_SESSION['WEBDEBUG_EXCEL']['STATUS_SESSION'][$SessionID]);
		}
	}
	/**
	 *	Load status for file loading [1st procedure]
	 */
	function GetLoadingPosition($SessionID) {
		if (isset($_SESSION['WEBDEBUG_EXCEL']['STATUS_SESSION'][$SessionID]) && is_array($_SESSION['WEBDEBUG_EXCEL']['STATUS_SESSION'][$SessionID]) && is_numeric($_SESSION['WEBDEBUG_EXCEL']['STATUS_SESSION'][$SessionID]['SHEET']) && is_numeric($_SESSION['WEBDEBUG_EXCEL']['STATUS_SESSION'][$SessionID]['ROW'])) {
			return $_SESSION['WEBDEBUG_EXCEL']['STATUS_SESSION'][$SessionID];
		} else {
			return array(
				'SHEET' => false,
				'ROW' => false,
			);
		}
	}
	/**
	 *	Break process if that runs longer than max
	 */
	function BreakLoadingPosition($SessionID, $SheetIndex, $RowIndex, $LoadingTime, $WDMaxLoadingTime) {
		$TimeForSerializeAndSave = 3;
		if ($LoadingTime > $WDMaxLoadingTime-$TimeForSerializeAndSave) {
			self::SetLoadingPosition($SessionID, $SheetIndex, $RowIndex);
			return true;
		}
		return false;
	}
	/**
	 *	Get LoadingFilesRelPath
	 */
	function LoadingFilesRelPath($StartDate=false) {
		$Path = '/upload/'.self::ModuleID.'/';
		if ($StartDate===false) {
			$StartDate = date(self::DateFormatDir);
		}
		$Path .= $StartDate.'/';
		return $Path;
	}
	/**
	 *	Get Loading file name [!!!]
	 */
	function GetLoadingFileName($SessionID, $MakeDirIfNotExists=true) {
		$LoadingFilesRelPath = self::LoadingFilesRelPath();
		if ($MakeDirIfNotExists===true && !is_dir($_SERVER['DOCUMENT_ROOT'].$LoadingFilesRelPath)) {
			mkdir($_SERVER['DOCUMENT_ROOT'].$LoadingFilesRelPath, BX_DIR_PERMISSIONS, true);
		}
		$DataFileExt = COption::GetOptionString(self::ModuleID,'data_file_ext');
		return $LoadingFilesRelPath.$SessionID.'.'.$DataFileExt;
	}
	/**
	 *	Save $arData 
	 */
	function SetLoadedDataArray($SessionID, $arData) {
		file_put_contents($_SERVER['DOCUMENT_ROOT'].self::GetLoadingFileName($SessionID), serialize($arData));
	}
	/**
	 *	Load $arData 
	 */
	function GetLoadedDataArray($SessionID) {
		if (is_file($_SERVER['DOCUMENT_ROOT'].self::GetLoadingFileName($SessionID,false))) {
			$strData = @file_get_contents($_SERVER['DOCUMENT_ROOT'].self::GetLoadingFileName($SessionID,false));
			return unserialize($strData);
		}
		return array('SHEETS' => array());
	}
	/**
	 *	Next step on transforming EXCEL to ARRAY
	 */
	function NextStep_Excel(&$arStatus, $WDExcelMaxLoadingTime, $StartDate=false) {
		$SessionID = $arStatus['ID'];
		$FileName = $arStatus['FILE_NAME'];
		// Initiate variables
		$FlagBreaked = false;
		$FlagDone = false;
		$StartTime = self::GetMicroTime();
		// Open file
		$Excel2 = new CWebdebugExcel2($FileName);
		$arSheets = $Excel2->GetSheetList(true);
		// Break if first time
		$bNeedBreak = false;
		if (empty($arStatus['COUNT'])) {
			$bNeedBreak = true;
		}
		// Get sheets info
		foreach($arSheets as $SheetIndex => $SheetName) {
			$arSheets[$SheetIndex] = array(
				'NAME' => $SheetName,
				'ROWS' => $Excel2->GetMaxRowIndex($SheetIndex),
				'COLS' => $Excel2->GetMaxColIndex($SheetIndex),
			);
			if (!is_array($arStatus['COUNT'][$SheetIndex])) {
				$arStatus['COUNT'][$SheetIndex] = array(
					'NAME' => $SheetName,
					'ROWS' => $arSheets[$SheetIndex]['ROWS'],
					'CURR' => 0,
					'DONE' => false,
				);
			}
		}
		if ($bNeedBreak) {
			return false;
		}
		// Load last position
		$arLast = $Excel2->GetLoadingPosition($SessionID);
		$arData = $Excel2->GetLoadedDataArray($SessionID);
		// Get excel data
		foreach($arSheets as $SheetIndex => $arSheet) {
			if (($arLast['SHEET']!==false) && $SheetIndex<$arLast['SHEET']) {
				$arStatus['COUNT'][$SheetIndex]['DONE'] = true;
				continue;
			}
			if (!isset($arData['SHEETS'][$SheetIndex])) {
				$arData['SHEETS'][$SheetIndex] = array(
					'NAME' => $arSheet['NAME'],
					'VISIBLE' => $Excel2->objPHPExcel->getSheet($SheetIndex)->getSheetState()=='visible',
					'ITEMS' => array(),
				);
			}
			$objSheet = $Excel2->objPHPExcel->getSheet($SheetIndex);
			$MaxRows = $arSheet['ROWS'];
			$MaxCols = $arSheet['COLS'];
			for ($RowIndex=1; $RowIndex<=$MaxRows; $RowIndex++) {
				if ($arLast['SHEET']==$SheetIndex && $arLast['ROW']!==false && $RowIndex<=$arLast['ROW']) continue;
				$arData['SHEETS'][$SheetIndex]['ITEMS'][$RowIndex]['LEVEL'] = $objSheet->getRowDimension($RowIndex)->getOutlineLevel();
				for ($ColIndex=0; $ColIndex<$MaxCols; $ColIndex++) {
					$BgColorHEX = $objSheet->getStyle(PHPExcel_Cell::stringFromColumnIndex($ColIndex).$RowIndex)->getFill()->getStartColor()->getRGB();
					$arItem = array(
						'VALUE' => $objSheet->getCellByColumnAndRow($ColIndex,$RowIndex)->getValue(),
						'BG' => $BgColorHEX,
						'HTML' => array(),
					);
					if ($arItem['VALUE'] instanceof PHPExcel_RichText) {
						$arItem['HTML'] = $Excel2->GetRichTextValue($arItem['VALUE'], $SheetIndex, $ColIndex, $RowIndex);
						$arItem['VALUE'] = $arItem['VALUE']->GetPlainText();
					}
					if (!$Excel2->IsUTF()) {
						if ($arItem['VALUE']) $arItem['VALUE'] = $Excel2->ConvertCharset($arItem['VALUE'], 'UTF-8', 'CP1251');
					}
					$arData['SHEETS'][$SheetIndex]['ITEMS'][$RowIndex]['ITEMS'][$ColIndex] = $arItem;
					$arData['SHEETS'][$SheetIndex]['COLORS'][$BgColorHEX] = $BgColorHEX;
				}
				$arStatus['COUNT'][$SheetIndex]['CURR'] = $RowIndex;
				if (CWebdebugExcel2::BreakLoadingPosition($SessionID, $SheetIndex, $RowIndex, self::GetMicrotime() - $StartTime, $WDExcelMaxLoadingTime)) {
					$Excel2->SetLoadedDataArray($SessionID, $arData);
					$FlagBreaked = true;
					break 2;
				}
				$arStatus['COUNT'][$SheetIndex]['DONE'] = true;
			}
		}
		if ($FlagBreaked===false) {
			$Excel2->SetLoadedDataArray($SessionID, $arData);
			$Excel2->SetLoadingPosition($SessionID, false, false);
			#$Excel2->MoveLoadedFile($SessionID);
			$FlagDone = true;
		}
		$AllRows = 0;
		$CurRows = 0;
		foreach($arSheets as $Index => $arSheet) {
			$AllRows += $arSheet['ROWS'];
			if ($Index<$SheetIndex) {
				$CurRows += $arSheet['ROWS'];
				$arSheets[$Index]['DONE'] = 'Y';
			} elseif ($Index==$SheetIndex) {
				$CurRows += $RowIndex;
				$arSheets[$Index]['CURR'] = 'Y';
				$arSheets[$Index]['PERCENT'] = floor($RowIndex*100/$arSheet['ROWS']);
			} else {
				$arSheets[$Index]['DONE'] = 'N';
			}
		}
		if ($AllRows==0) $AllRows = 1;
		$arResult = array(
			'STATUS' => false,
			'FILE' => false,
			'CURRENT_SHEET' => $SheetIndex,
			'CURRENT_ROW' => $RowIndex,
			'ALL_ROWS' => $AllRows,
			'CUR_ROWS' => $CurRows,
			'PERCENT' => floor($CurRows*100/$AllRows),
			'SHEETS' => $arSheets,
		);
		if ($arResult['PERCENT']>100) $arResult['PERCENT'] = 100;
		if ($FlagDone===true) {
			$arResult['STATUS'] = 'DONE';
			$arResult['FILE'] = $Excel2->GetLoadingFileName($SessionID,false);
		} elseif ($FlagBreaked===true) {
			$arResult['STATUS'] = 'BREAKED';
		}
		return $arResult;
	}
	function ShowProgress($arProgress) {
		if (is_array($arProgress)) {
			?><div class="wd_progress_bars"><br/><?
			foreach($arProgress as $arItem) {
				$intProgress = '0.00';
				if ($arItem['CURR']>0 && $arItem['ROWS']>0) {
					$intProgress = number_format(($arItem['CURR'] / $arItem['ROWS']) * 100, 2, '.', '');
				}
				?>
					<div class="wd_progress">
						<div class="wd_progress_bar" style="width:<?=$intProgress;?>%"></div>
						<div class="wd_progress_txt"><table><tr><td><span class="title"><?=$arItem['NAME'];?>:&nbsp;</span> <span class="value"><?=$arItem['CURR'];?> / <?=$arItem['ROWS'];?> (<?=$intProgress;?>%)</span></td></tr></table></div>
					</div>
				<?
			}
			?></div><br/><?
		}
	}
	/**
	 *	Move loaded file to target directory
	 */
	/*
	function MoveLoadedFile($SessionID) {
		$Source = $_SERVER['DOCUMENT_ROOT'].self::GetLoadingFileName($SessionID,false);
		if (is_file($Source)) {
			$Target = $_SERVER['DOCUMENT_ROOT'].self::GetLoadingFileName($SessionID,true);
			copy($Source, $Target);
			@unlink($Source);
			if (is_file($Target)) return true;
		}
		return false;
	}
	*/
	function Substr($Text, $Start, $Length=false) {
		if (defined('BX_UTF') && BX_UTF===true && function_exists('mb_substr')) {
			if ($Length) {
				return mb_substr($Text, $Start, $Length);
			} else {
				return mb_substr($Text, $Start);
			}
		} else {
			if ($Length) {
				return substr($Text, $Start, $Length);
			} else {
				return substr($Text, $Start);
			}
		}
	}
	function Strlen($Text) {
		if (defined('BX_UTF') && BX_UTF===true && function_exists('mb_strlen')) {
			return mb_strlen($Text);
		} else {
			return strlen($Text);
		}
	}
	function GetFileExt($FileName) {
		$FileName = ToLower($FileName);
		$arExt = array(
			'xls',
			'xlsx',
			'tar.gz',
		);
		foreach($arExt as $Ext) {
			if (self::Substr($FileName, -1 * (self::Strlen($Ext)+1))=='.'.$Ext) {
				return $Ext;
			}
		}
		return false;
	}
	/**
	 *	Get list of currencies
	 */
	function GetCurrencyList() {
		$arResult = array();
		if (is_array($GLOBALS[WDEXCEL_TEMP]['CURRENCY_LIST'])) {
			$arResult = $GLOBALS[WDEXCEL_TEMP]['CURRENCY_LIST'];
		} else {
			if (CModule::IncludeModule('currency')) {
				$resCurrency = CCurrency::GetList($by='SORT', $order='ASC', LANGUAGE_ID);
				while ($arCurrency = $resCurrency->GetNext(false,false)) {
					$arCurrency['IS_BASE'] = FloatVal($arCurrency['AMOUNT'])==1 ? true: false;
					if (isset($arCurrency['DEAULT']) && !isset($arCurrency['DEFAULT'])) {
						$arCurrency['DEFAULT'] = $arCurrency['DEAULT'];
						unset($arCurrency['DEAULT']);
					}
					$arResult[ToUpper($arCurrency['CURRENCY'])] = $arCurrency;
				}
				foreach(GetModuleEvents(self::ModuleID, 'OnGetCurrencyList', true) as $arEvent) {
					ExecuteModuleEventEx($arEvent, array(&$arResult));
				}
				$GLOBALS[WDEXCEL_TEMP]['CURRENCY_LIST'] = $arResult;
			}
		}
		return $arResult;
	}
	/**
	 *	Get float value of string valua
	 */
	function GetFloatValue($Price) {
		$strResult = '';
		$arAllowSymbols = array('0','1','2','3','4','5','6','7','8','9','.',',');
		for ($i=0; $i<self::strlen($Price); $i++) {
			$Letter = self::substr($Price,$i,1);
			if (in_array($Letter,$arAllowSymbols)) {
				$strResult .= $Letter;
			}
		}
		$strResult = str_replace(',','.',$strResult);
		$strResult = FloatVal($strResult);
		return $strResult;
	}
	/**
	 *	Get list of modes
	 */
	function GetModesList() {
		$arResult = array();
		$arResult['COLORS'] = array('NAME' => GetMessage('WEBDEBUG_EXCEL_MODE_COLORS'),'SYSTEM' => true);
		$arResult['LEVELS'] = array('NAME' => GetMessage('WEBDEBUG_EXCEL_MODE_LEVELS'),'SYSTEM' => true);
		$arSystemModes = $arResult;
		foreach(GetModuleEvents(self::ModuleID, 'OnGetModesList', true) as $arEvent) {
			ExecuteModuleEventEx($arEvent, array(&$arResult));
		}
		foreach($arSystemModes as $Mode => $arMode) {
			if (isset($arResult[$Mode]) && is_array($arResult[$Mode])) {
				$arResult[$Mode]['SYSTEM'] = true;
				$arResult[$Mode]['PATH'] = '/bitrix/modules/'.self::ModuleID.'/modes/'.ToLower($Mode).'.php';
			}
		}
		foreach($arResult as $Mode => $arMode) {
			if (!is_file($_SERVER['DOCUMENT_ROOT'].$arMode['PATH'])) {
				unset($arResult[$Mode]);
			}
		}
		return $arResult;
	}
	/**
	 *	Get array of IBlocks
	 *	@param boolean $GroupByType Flag indicates that result will be grouped by infoblock types
	 *	@param boolean $ShowInActive Flag indicates select inactive or not
	 */
	function GetIBlockList($GroupByType=true, $ShowInActive=false) {
		$arResult = array();
		if (CModule::IncludeModule("iblock")) {
			if ($GroupByType!==false) {
				$resIBlockTypes = CIBlockType::GetList(array(),array());
				while ($arIBlockType = $resIBlockTypes->GetNext(false,false)) {
					$arIBlockTypeLang = CIBlockType::GetByIDLang($arIBlockType["ID"], LANGUAGE_ID, false);
					$arResult[$arIBlockType["ID"]] = array(
						"NAME" => $arIBlockTypeLang["NAME"],
						"ITEMS" => array(),
					);
				}
			}
			$arFilter = array();
			if ($ShowInActive!==true) $arFilter["ACTIVE"] = "Y";
			$resIBlock = CIBlock::GetList(array("SORT"=>"ASC"),$arFilter);
			while ($arIBlock = $resIBlock->GetNext(false,false)) {
				if ($GroupByType!==false) {
					$arResult[$arIBlock["IBLOCK_TYPE_ID"]]["ITEMS"][] = $arIBlock;
				} else {
					$arResult[] = $arIBlock;
				}
			}
		}
		foreach(GetModuleEvents(self::ModuleID, 'OnGetIBlockList', true) as $arEvent) {
			ExecuteModuleEventEx($arEvent, array(&$arResult, $GroupByType, $ShowInActive));
		}
		return $arResult;
	}
	/**
	 *	Get sections from IBlock in tree order
	 */
	function GetSectionsTree($IBlockID, $ShowActiveOnly=true) {
		$arResult = array();
		if (CModule::IncludeModule('iblock')) {
			$arFilter = array('IBLOCK_ID'=>$IBlockID);
			if ($ShowActiveOnly===true) {
				$arFilter['ACTIVE'] = 'Y';
			}
			$resSections = CIBlockSection::GetList(array('LEFT_MARGIN'=>'ASC'),$arFilter,false,array('ID','NAME','DEPTH_LEVEL'));
			while ($arSection = $resSections->GetNext(false,false)) {
				$arResult[] = $arSection;
			}
		}
		foreach(GetModuleEvents(self::ModuleID, 'OnGetSectionsTree', true) as $arEvent) {
			ExecuteModuleEventEx($arEvent, array(&$arResult, $IBlockID, $ShowActiveOnly));
		}
		return $arResult;
	}
	/**
	 *	Get IBlock section by ID, IBlockID
	 */
	function GetSection($ID,$IBlockID=false,$arSelectFields=false) {
		$arResult = array();
		$ID = IntVal($ID);
		if ($ID>0 && CModule::IncludeModule('iblock')) {
			$arFilter = array('ID'=>$ID);
			if ($IBlockID>0) {
				$arFilter['IBLOCK_ID'] = $IBlockID;
			}
			if (!is_array($arSelectFields)) $arSelectFields = array();
			if (!in_array('ID',$arSelectFields)) $arSelectFields[] = 'ID';
			$resSection = CIBlockSection::GetList(array(),$arFilter,false,$arSelectFields);
			if ($arSection = $resSection->GetNext(false,false)) {
				$arResult = $arSection;
			}
		}
		return $arResult;
	}
	/**
	 *	Get IBlock property ID by code
	 */
	function GetPropertyIdByCode($IBlockID, $Code) {
		$Result = false;
		if (CModule::IncludeModule('iblock')) {
			$resProp = CIBlockProperty::GetList(array(),array('IBLOCK_ID'=>$IBlockID,'CODE'=>$Code));
			if ($arProp = $resProp->GetNext(false,false)) {
				return $arProp['ID'];
			}
		}
		return $Result;
	}
	/**
	 *	Create WD_EXCEL_IMPORT_ID
	 */
	function CreateImportIdProperty($IBlockID, $bCreatePropForSections=true, $bCreatePropForOffers=true) {
		if ($IBlockID>0 && CModule::IncludeModule('iblock')) {
			$arProperty1Fields = array(
				'IBLOCK_ID' => false,
				'ACTIVE' => 'Y',
				'NAME' => GetMessage('WEBDEBUG_EXCEL_IMPORT_ID_PROPERTY_NAME'),
				'HINT' => GetMessage('WEBDEBUG_EXCEL_IMPORT_ID_PROPERTY_DESC'),
				'CODE' => self::ImportIDPropCode,
				'XML_ID' => self::ImportIDPropCode,
				'PROPERTY_TYPE' => 'S',
				'COL_COUNT' => '40',
			);
			$arProperty2Fields = array(
				'IBLOCK_ID' => false,
				'ACTIVE' => 'Y',
				'NAME' => GetMessage('WEBDEBUG_EXCEL_STORES_PROCESSED_PROPERTY_NAME'),
				'HINT' => GetMessage('WEBDEBUG_EXCEL_STORES_PROCESSED_PROPERTY_DESC'),
				'CODE' => self::StoresProcessedPropCode,
				'XML_ID' => self::StoresProcessedPropCode,
				'PROPERTY_TYPE' => 'L',
				'LIST_TYPE' => 'C',
			);
			$arSectionPropFields = array(
				'ENTITY_ID' => 'IBLOCK_'.$IBlockID.'_SECTION',
				'USER_TYPE_ID' => 'string',
				'SHOW_FILTER' => 'N',
				'SETTINGS' => array('SIZE'=>'40'),
				'FIELD_NAME' => 'UF_'.self::ImportIDPropCode,
				'XML_ID' => self::ImportIDPropCode,
				'SHOW_IN_LIST' => 'N',
				'EDIT_IN_LIST' => 'N',
				'EDIT_FORM_LABEL' => array(
					'ru' => GetMessage('WEBDEBUG_EXCEL_IMPORT_ID_PROPERTY_NAME'),
				),
				'HELP_MESSAGE' => array(
					'ru' => GetMessage('WEBDEBUG_EXCEL_IMPORT_ID_PROPERTY_DESC'),
				),
			);
			// Create props for selected IBlock
			$resProp = CIBlockProperty::GetList(array(),array('IBLOCK_ID'=>$IBlockID,'CODE'=>$arProperty1Fields['CODE']));
			if (!$resProp->GetNext(false,false)) {
				$arProperty1Fields['IBLOCK_ID'] = $IBlockID;
				$IBlockProperty = new CIBlockProperty;
				$PropID = $IBlockProperty->Add($arProperty1Fields);
			}
			$resProp = CIBlockProperty::GetList(array(),array('IBLOCK_ID'=>$IBlockID,'CODE'=>$arProperty2Fields['CODE']));
			if (!$resProp->GetNext(false,false)) {
				$arProperty2Fields['IBLOCK_ID'] = $IBlockID;
				$IBlockProperty = new CIBlockProperty;
				$PropID = $IBlockProperty->Add($arProperty2Fields);
				if ($PropID>0) {
					$IBlockPropertyEnum = new CIBlockPropertyEnum;
					$PropEnumID = $IBlockPropertyEnum->Add(array('PROPERTY_ID'=>$PropID,'IBLOCK_ID'=>$IBlockID,'XML_ID'=>'Y','VALUE'=>GetMessage('WEBDEBUG_EXCEL_STORES_PROCESSED_PROPERTY_Y'),'SORT'=>'10'));
				}
			}
			// Create prop for offers IBlock
			if ($bCreatePropForOffers==true && CModule::IncludeModule('catalog')) {
				$OffersIBlockID = IntVal(self::GetOffersIBlockID($IBlockID));
				if ($OffersIBlockID>0) {
					$resProp = CIBlockProperty::GetList(array(),array('IBLOCK_ID'=>$OffersIBlockID,'CODE'=>$arProperty1Fields['CODE']));
					if (!$resProp->GetNext(false,false)) {
						$arProperty1Fields['IBLOCK_ID'] = $OffersIBlockID;
						$IBlockProperty = new CIBlockProperty;
						$PropID = $IBlockProperty->Add($arProperty1Fields);
					}
					$resProp = CIBlockProperty::GetList(array(),array('IBLOCK_ID'=>$OffersIBlockID,'CODE'=>$arProperty2Fields['CODE']));
					if (!$resProp->GetNext(false,false)) {
						$arProperty2Fields['IBLOCK_ID'] = $OffersIBlockID;
						$IBlockProperty = new CIBlockProperty;
						$PropID = $IBlockProperty->Add($arProperty2Fields);
						if ($PropID>0) {
							$IBlockPropertyEnum = new CIBlockPropertyEnum;
							$PropEnumID = $IBlockPropertyEnum->Add(array('PROPERTY_ID'=>$PropID,'IBLOCK_ID'=>$OffersIBlockID,'XML_ID'=>'Y','VALUE'=>GetMessage('WEBDEBUG_EXCEL_STORES_PROCESSED_PROPERTY_Y'),'SORT'=>'10'));
						}
					}
				}
			}
			// Create section property
			if ($bCreatePropForSections==true) {
				$obUserField = new CUserTypeEntity;
				$PropID = $obUserField->Add($arSectionPropFields);
			}
		}
		return false;
	}
	/**
	 *	Get sheet table headers
	 */
	function GetSheetHeaders($SheetIndex, $Column=0, $Row=1) {
		$Column = IntVal($Column);
		if ($Column<0) $Column = 0;
		$Row = IntVal($Row);
		if ($Row<=1) $Row = 1;
		$arResult = array();
		if ($this->strFileType=='TAR_GZ') {
			$arHeader = $this->arData['SHEETS'][$SheetIndex]['ITEMS'][$Row]['ITEMS'];
			$MaxColumns = count($arHeader);
			for($i=$Column-1; $i<$MaxColumns; $i++) {
				$arResult[$i] = $arHeader[$i]['VALUE'];
				if (defined('BX_UTF') && BX_UTF===true) {
					$arResult[$i] = self::ConvertCharset($arResult[$i], 'CP1251', 'UTF-8');
				}
			}
		} elseif ($this->strFileType=='EXCEL') {
			$MaxColumns = $this->GetMaxColIndex($SheetIndex);
			for($i=$Column-1; $i<$MaxColumns; $i++) {
				$arResult[$i] = $this->objPHPExcel->getSheet($SheetIndex)->getCellByColumnAndRow($i,$Row)->getValue();
				if (!defined('BX_UTF') || BX_UTF!==true) {
					$arResult[$i] = $GLOBALS['APPLICATION']->ConvertCharset($arResult[$i], 'UTF-8', 'CP1251');
				}
			}
		}
		foreach(GetModuleEvents(self::ModuleID, 'OnGetSheetHeaders', true) as $arEvent) {
			ExecuteModuleEventEx($arEvent, array(&$arResult, $SheetIndex, $Column, $Row));
		}
		return $arResult;
	}
	/**
	 *	Get IBlock property list
	 *	@param int $IBlockID Infoblock ID
	 */
	function GetIBlockProps($IBlockID, $Grouped=false) {
		$arResult = array();
		if (CModule::IncludeModule('iblock')) {
			$resProps = CIBlock::GetProperties($IBlockID, array('SORT'=>'ASC'), array());
			while ($arProp = $resProps->GetNext(false,false)) {
				if(in_array($arProp['CODE'],array(self::ImportIDPropCode,self::StoresProcessedPropCode))) {
					continue;
				}
				// get enum values
				if (in_array($arProp['CODE'],array(self::ImportIDPropCode,'CML2_LINK'))) continue;
				if ($arProp['PROPERTY_TYPE']=='L') {
					$arProp['ENUMS'] = array();
					$resPropEnum = CIBlockPropertyEnum::GetList(array('SORT'=>'ASC', 'VALUE'=>'ASC'),array('IBLOCK_ID'=>$IBlockID,'PROPERTY_ID'=>$arProp['ID']));
					while ($arPropEnum = $resPropEnum->GetNext(false,false)) {
						$arProp['ENUMS'][] = $arPropEnum;
					}
				}
				if ($Grouped) {
					$arResult[$arProp['ID']] = $arProp;
				} else {
					$arResult[] = $arProp;
				}
			}
		}
		foreach(GetModuleEvents(self::ModuleID, 'OnGetIBlockProps', true) as $arEvent) {
			ExecuteModuleEventEx($arEvent, array(&$arResult, $IBlockID, $Grouped));
		}
		return $arResult;
	}
	/**
	 *	Get IBlock section property list
	 *	@param int $IBlockID Infoblock ID
	 */
	function GetSectionProps($IBlockID, $bWithLabels=false) {
		$arResult = array();
		if (CModule::IncludeModule("iblock")) {
			$resProps = CUserTypeEntity::GetList(array('SORT'=>'ASC'),array('ENTITY_ID'=>'IBLOCK_'.$IBlockID.'_SECTION'));
			while ($arProp = $resProps->GetNext(false,false)) {
				if (in_array($arProp['USER_TYPE_ID'],array('video'))) continue;
				if (in_array($arProp['FIELD_NAME'],array('UF_'.self::ImportIDPropCode))) continue;
				$arResult[$arProp['FIELD_NAME']] = $arProp;
				if ($bWithLabels) {
					$arProp = CUserTypeEntity::GetByID($arProp['ID']);
				}
				$arResult[$arProp["FIELD_NAME"]] = $arProp;
			}
		}
		foreach(GetModuleEvents(self::ModuleID, 'OnGetSectionProps', true) as $arEvent) {
			ExecuteModuleEventEx($arEvent, array(&$arResult, $IBlockID, $bWithLabels));
		}
		return $arResult;
	}
	/**
	 *	Get separator value
	 */
	function GetSeparator($Separator, $SeparatorOther) {
		$arSeparators = array(
			'new'=>"\n",
			'tab'=>"\t",
			'commas'=>',',
			'semicolon'=>';',
			'dash'=>'-',
			'space'=>' ',
		);
		if (isset($arSeparators[$Separator])) $Separator = $arSeparators[$Separator];
		return $Separator=='other' ? $SeparatorOther : $Separator;
	}
	/**
	 *	Get subsections list within a selected section
	 */
	function GetSubsections($arOrder=array(), $arFilter=array(), $bIncCnt=false, $arSelect=false/*, $IBlockID=false*/) {
		if (is_array($arFilter) && CModule::IncludeModule('iblock')) {
			if ($arFilter['PARENT_SECTION_ID']>0) {
				$Section = $arFilter['PARENT_SECTION_ID'];
				$LMargin = $arFilter['PARENT_SECTION_LEFT_MARGIN'] ? $arFilter['PARENT_SECTION_LEFT_MARGIN'] : false;
				$RMargin = $arFilter['PARENT_SECTION_RIGHT_MARGIN'] ? $arFilter['PARENT_SECTION_RIGHT_MARGIN'] : false;
				if ($LMargin===false || $RMargin===false) {
					$resSection = CIBlockSection::GetList(array(),array('ID'=>$Section),false,array('ID','IBLOCK_ID','LEFT_MARGIN','RIGHT_MARGIN'));
					if ($arSection = $resSection->GetNext(false,false)) {
						$Section = $arSection['ID'];
						$LMargin = $arSection['LEFT_MARGIN'];
						$RMargin = $arSection['RIGHT_MARGIN'];
					}
				}
				if ($LMargin && $RMargin) {
					unset($arFilter['PARENT_SECTION_ID'], $arFilter['PARENT_SECTION_LEFT_MARGIN'], $arFilter['PARENT_SECTION_RIGHT_MARGIN']);
					$arFilter = array_merge($arFilter,array('LEFT_MARGIN'=>$LMargin, 'RIGHT_MARGIN'=>$RMargin));
					return CIBlockSection::GetList($arOrder,$arFilter,$bIncCnt,$arSelect);
				}
			} else {
				return CIBlockSection::GetList($arOrder,$arFilter,$bIncCnt,$arSelect);
			}
		}
		return false;
	}
	/**
	 *	Check, if section is already exists
	 */
	function IsSectionExists($arSectionFields, $arData) {
		$SectionsExists = false;
		$arFilter = array(
			'IBLOCK_ID' => IntVal($arData['FIELDS']['MATCHES']['IBLOCK_ID_FOR_SHEET_'.$arData['SHEET']]),
		);
		$ParentSectionID = IntVal($arData['PARENT_SECTION']['ID']);
		if ($ParentSectionID>0) {
			$arFilter['PARENT_SECTION_ID'] = IntVal($arData['PARENT_SECTION']['ID']);
			$arFilter['PARENT_SECTION_LEFT_MARGIN'] = $arData['PARENT_SECTION']['LEFT_MARGIN'];
			$arFilter['PARENT_SECTION_RIGHT_MARGIN'] = $arData['PARENT_SECTION']['RIGHT_MARGIN'];
		}
		if ($arData['FIELDS']['PARAMS']['BIND_METHOD_SECTIONS']=='by_name') {
			$arFilter['NAME'] = $arSectionFields['NAME'];
		} elseif ($arData['FIELDS']['PARAMS']['BIND_METHOD_SECTIONS']=='by_uniq') {
			switch($arData['FIELDS']['PARAMS']['UNIQUE_TARGET_SECTIONS']) {
				case 'EXTERNAL_ID':
					$arFilter['EXTERNAL_ID'] = $arSectionFields['EXTERNAL_ID'];
					break;
				case 'CODE':
					$arFilter['CODE'] = $arSectionFields['CODE'];
					break;
				case 'other':
					if (trim($arData['FIELDS']['PARAMS']['UNIQUE_TARGET_SECTIONS_OTHER_VALUE'])!='') {
						$arFilter[$arData['FIELDS']['PARAMS']['UNIQUE_TARGET_SECTIONS_OTHER_VALUE']] = $arSectionFields[$arData['FIELDS']['PARAMS']['UNIQUE_TARGET_SECTIONS_OTHER_VALUE']];
					}
					break;
			}
		}
		$resSection = CWebdebugExcel2::GetSubsections(array(),$arFilter,false,array('ID','IBLOCK_ID','NAME')/*,$arSectionFields['IBLOCK_ID']*/);
		if ($resSection!==false) {
			while ($arSection = $resSection->GetNext(false,false)) {
				$SectionsExists = $arSection['ID'];
				break;
			}
		}
		return $SectionsExists;
	}
	/**
	 *	Check, if element is already exists
	 */
	function IsElementExists($arElementFields, $arData, $CustomName=false) {
		$ElementExists = false;
		if (CModule::IncludeModule('iblock')) {
			$arFilter = array(
				'IBLOCK_ID' => IntVal($arElementFields['IBLOCK_ID']),
				'SECTION_ID' => IntVal($arData['PARENT_SECTION']['ID']),
				'INCLUDE_SUBSECTIONS' => 'Y',
			);
			if (CModule::IncludeModule('catalog')) {
				$arCatalog = CCatalog::GetByID($arElementFields['IBLOCK_ID']);
			}
			if($arFilter['SECTION_ID']<=0 || is_array($arCatalog) && $arCatalog['PRODUCT_IBLOCK_ID']>0) {
				unset($arFilter['SECTION_ID']);
				unset($arFilter['INCLUDE_SUBSECTIONS']);
			}
			if ($arData['FIELDS']['PARAMS']['BIND_METHOD_ELEMENTS']=='by_name') {
				$arFilter['=NAME'] = $arElementFields['NAME'];
				if (trim($arFilter['=NAME'])=='' && $CustomName!==false) {
					$arFilter['=NAME'] = $CustomName;
				}
			} elseif ($arData['FIELDS']['PARAMS']['BIND_METHOD_ELEMENTS']=='by_uniq') {
				switch($arData['FIELDS']['PARAMS']['UNIQUE_TARGET_ELEMENTS']) {
					case 'EXTERNAL_ID':
						$arFilter['=EXTERNAL_ID'] = $arElementFields['EXTERNAL_ID'];
						break;
					case 'CODE':
						$arFilter['=CODE'] = $arElementFields['CODE'];
						break;
					case 'other':
						if (trim($arData['FIELDS']['PARAMS']['UNIQUE_TARGET_ELEMENTS_OTHER_VALUE'])!='') {
							$arFilter['='.$arData['FIELDS']['PARAMS']['UNIQUE_TARGET_ELEMENTS_OTHER_VALUE']] = $arElementFields[$arData['FIELDS']['PARAMS']['UNIQUE_TARGET_ELEMENTS_OTHER_VALUE']];
						}
						break;
				}
			}
			if (isset($arData['SKU_PROPERTY_ID']) && is_numeric($arData['SKU_PROPERTY_ID']) && $arData['SKU_PROPERTY_ID']>0) {
				$arFilter['PROPERTY_'.$arData['SKU_PROPERTY_ID']] = $arData['STATUS']['IBLOCK_ELEMENT_ID_LAST'];
			}
			foreach(GetModuleEvents(self::ModuleID, 'OnElementExistsFilter', true) as $arEvent) {
				ExecuteModuleEventEx($arEvent, array(&$arFilter, $arElementFields, $arData));
			}
			$resItem = CIBlockElement::GetList(array(),$arFilter,false,array('nTopCount'=>'1'),array('ID'));
			if ($arItem = $resItem->GetNext(false,false)) {
				$ElementExists = $arItem['ID'];
			}
		}
		return $ElementExists;
	}
	/**
	 *	Check, if array with fields (for CIBlockElement::Add or CIBlockSection::Add) is empty
	 */
	function AreFieldsEmpty($arData) {
		$strResult = '';
		foreach($arData['ITEM']['ITEMS'] as $arItem) {
			$strResult .= trim($arItem['VALUE']);
		}
		return $strResult=='';
	}
	/**
	 *	Get list of prices
	 */
	function GetPriceTypeList() {
		$arResult = array();
		if (CModule::IncludeModule("catalog")) {
			$resPrices = CCatalogGroup::GetList(array("SORT"=>"ASC"));
			while ($arPrice = $resPrices->GetNext(false,false)) {
				$arResult[] = $arPrice;
			}
		}
		foreach(GetModuleEvents(self::ModuleID, 'OnGetPriceTypeList', true) as $arEvent) {
			ExecuteModuleEventEx($arEvent, array(&$arResult));
		}
		return $arResult;
	}
	/**
	 *	Get catalog array of IBlock
	 */
	function GetCatalogInfo($IBlockID) {
		$Result = false;
		if (CModule::IncludeModule('catalog')) {
			$Result = CCatalog::GetByID($IBlockID);
		}
		return $Result;
	}
	/**
	 *	Get offers IBlock for selected products IBlock
	 */
	function GetOffersIBlockID($IBlockID) {
		if (CModule::IncludeModule('catalog')) {
			$resCatalog = CCatalog::GetList(array(),array('PRODUCT_IBLOCK_ID'=>$IBlockID));
			if ($arCatalog = $resCatalog->GetNext(false,false)) {
				return $arCatalog['IBLOCK_ID'];
			}
		}
		return false;
	}
	/**
	 *	Get IBlock translit settings
	 */
	function GetIBlockTranslitSettings($IBlockID, $IsSection=false) {
		$arResult = array();
		if (CModule::IncludeModule('iblock')) {
			$arIBlockFields = CIBlock::GetFields($IBlockID);
			$arIBlockFields[($IsSection?'SECTION_CODE':'CODE')]['DEFAULT_VALUE']['IS_REQUIRED'] = $arIBlockFields[($IsSection?'SECTION_CODE':'CODE')]['IS_REQUIRED'];
			$arResult = $arIBlockFields[($IsSection?'SECTION_CODE':'CODE')]['DEFAULT_VALUE'];
		}
		foreach(GetModuleEvents(self::ModuleID, 'OnGetIBlockTranslitSettings', true) as $arEvent) {
			ExecuteModuleEventEx($arEvent, array(&$arResult, $IBlockID, $IsSection));
		}
		return $arResult;
	}
	/**
	 *	Check CODE parameters (required, unique and other)
	 */
	function CheckCodeField($ID, &$arFields, $arData, $IsSection=false, $FindUnique=true) {
		if ($arFields['IBLOCK_ID']>0) {
			$arTranslitSettings = self::GetIBlockTranslitSettings($arFields['IBLOCK_ID'],$IsSection);
			if ($arTranslitSettings['IS_REQUIRED']=='Y' && trim($arFields['CODE'])=='') {
				$arFields['CODE'] = self::Translit($arFields['NAME'],self::IBlockTranslitSettingsToStandard($arTranslitSettings));
			}
			if ($arTranslitSettings['UNIQUE']=='Y' && $FindUnique) {
				$strCodeUniqueSymbols = COption::GetOptionString(self::ModuleID,'code_unique_symbols');
				$UniqueCode = $arFields['CODE'];
				if ($IsSection) {
					while(self::IBlockSectionExists($ID,$arFields['IBLOCK_ID'],$arFields['CODE'])) {
						if (preg_match('#^(.*?)'.$strCodeUniqueSymbols.'(\d+)$#',$arFields['CODE'],$M)) {
							$UniqueCode = $M[1];
							$UniqueIndex = $M[2];
						}
						$UniqueIndex++;
						$arFields['CODE'] = $UniqueCode.$strCodeUniqueSymbols.$UniqueIndex;
					}
				} else {
					while(self::IBlockElementExists($ID,$arFields['IBLOCK_ID'],$arFields['CODE'])) {
						if (preg_match('#^(.*?)'.$strCodeUniqueSymbols.'(\d+)$#',$arFields['CODE'],$M)) {
							$UniqueCode = $M[1];
							$UniqueIndex = $M[2];
						}
						$UniqueIndex++;
						$arFields['CODE'] = $UniqueCode.$strCodeUniqueSymbols.$UniqueIndex;
					}
				}
			}
		}
	}
	/**
	 *	Preprocess fields before add/update
	 */
	function PreprocessFields($arFields, $arData, $Operation='ADD', $Type='ELEMENT', $UpdateID=false) { // ELEMENT, OFFER, SECTION
		foreach(GetModuleEvents(self::ModuleID, 'OnBeforePreprocessFields', true) as $arEvent) {
			if (!ExecuteModuleEventEx($arEvent, array(&$arFields, &$arData, $Operation, $Type, $UpdateID))) {
				return $arFields;
			}
		}
		switch($Type) {
			case 'ELEMENT':
				if ($Operation=='UPDATE') {
					if (isset($arFields['NAME']) && $arData['FIELDS']['PARAMS']['UPDATE_ELEMENTS_NAME']!='Y') {
						unset($arFields['NAME']);
					}
					if (isset($arFields['CODE']) && $arData['FIELDS']['PARAMS']['UPDATE_ELEMENTS_CODE']!='Y') {
						unset($arFields['CODE']);
					}
					if (isset($arFields['IBLOCK_SECTION_ID']) && ( ($arData['FIELDS']['PARAMS']['SKIP_SECTIONS_ALL']=='Y') || ($arData['FIELDS']['PARAMS']['SKIP_MULTISECTIONS']=='Y' && self::ElementHasSomeParents($UpdateID)) )) {
						unset($arFields['IBLOCK_SECTION_ID']);
					}
				}
				if ($Operation=='ADD') {
					if ($arData['FIELDS']['PARAMS']['SKIP_SECTIONS_ALL']=='Y') {
						$DefaultSection = IntVal($arData['FIELDS']['MATCHES']['SECTION_ID_FOR_SHEET_'.$arData['SHEET']]);
						if ($DefaultSection>0) {
							$arFields['IBLOCK_SECTION_ID'] = $arData['FIELDS']['MATCHES']['SECTION_ID_FOR_SHEET_'.$arData['SHEET']];
						} else {
							unset($arFields['IBLOCK_SECTION_ID']);
						}
					}
					if ($arData['FIELDS']['PARAMS']['LOAD_INACTIVE_ELEMENTS']=='Y' && $arFields['ACTIVE']!='Y') {
						$arFields['ACTIVE'] = 'N';
					}
				}
				break;
			case 'OFFER':
				if ($Operation=='UPDATE') {
					if (isset($arFields['NAME']) && $arData['FIELDS']['PARAMS']['UPDATE_ELEMENTS_NAME']!='Y') {
						unset($arFields['NAME']);
					}
					if (isset($arFields['CODE']) && $arData['FIELDS']['PARAMS']['UPDATE_ELEMENTS_CODE']!='Y') {
						unset($arFields['CODE']);
					}
				}
				if ($Operation=='ADD') {
					if ($arData['FIELDS']['PARAMS']['LOAD_INACTIVE_ELEMENTS']=='Y' && $arFields['ACTIVE']!='Y' && COption::GetOptionString(self::ModuleID, 'load_inactive_offers')=='Y') {
						$arFields['ACTIVE'] = 'N';
					}
				}
				break;
			case 'SECTION':
				if ($Operation=='UPDATE') {
					if (isset($arFields['NAME']) && $arData['FIELDS']['PARAMS']['UPDATE_SECTIONS_NAME']!='Y') {
						unset($arFields['NAME']);
					}
					if (isset($arFields['CODE']) && $arData['FIELDS']['PARAMS']['UPDATE_SECTIONS_CODE']!='Y') {
						unset($arFields['CODE']);
					}
					if ($arData['FIELDS']['PARAMS']['EXIST_SECTION_NOLINK']=='Y') {
						unset($arFields['IBLOCK_SECTION_ID']);
					}
				}
				if ($Operation=='ADD') {
					if ($arData['FIELDS']['PARAMS']['LOAD_INACTIVE_SECTIONS']=='Y' && $arFields['ACTIVE']!='Y') {
						$arFields['ACTIVE'] = 'N';
					}
				}
				break;
		}
		foreach(GetModuleEvents(self::ModuleID, 'OnAfterPreprocessFields', true) as $arEvent) {
			ExecuteModuleEventEx($arEvent, array($arFields, $arData, $Operation, $Type, $UpdateID));
		}
		return $arFields;
	}
	/**
	 *	Check section exists with CODE
	 */
	function IBlockSectionExists($ID, $IBlockID, $Code) {
		if (CModule::IncludeModule('iblock')) {
			$resSection = CIBlockSection::GetList(array(),array('IBLOCK_ID'=>$IBlockID,'CODE'=>$Code,'!ID'=>$ID),false,array('ID'),array('nTopCount'=>'1'));
			return $resSection->GetNext(false,false) ? true : false;
		}
		return false;
	}
	/**
	 *	Check element exists with CODE
	 */
	function IBlockElementExists($ID, $IBlockID, $Code) {
		if (CModule::IncludeModule('iblock')) {
			$resElement = CIBlockElement::GetList(array(),array('IBLOCK_ID'=>$IBlockID,'CODE'=>$Code,'!ID'=>$ID),false,array('nTopCount'=>'1'),array('ID'));
			return $resElement->GetNext(false,false) ? true : false;
		}
		return false;
	}
	/**
	 *	Translit wrapper
	 */
	function Translit($Text, $arTranslitSettings) {
		$arTranslitSettingsDefault = Array( 
			 'max_len' => '100',
			 'change_case' => 'L',
			 'replace_space' => '-',
			 'replace_other' => '-',
			 'delete_repeat_replace' => 'true',
			 'safe_chars' => '',
		);
		if (is_array($arTranslitSettings)) {
			foreach($arTranslitSettingsDefault as $Key => $Value) {
				if (!isset($arTranslitSettings[$Key])) {
					$arTranslitSettings[$Key] = $Value;
				}
			}
		} else {
			$arTranslitSettings = $arTranslitSettingsDefault;
		}
		$bReturnText = false;
		foreach(GetModuleEvents(self::ModuleID, 'OnTranslit', true) as $arEvent) {
			$bReturnText = true;
			ExecuteModuleEventEx($arEvent, array(&$Text, $arTranslitSettings));
		}
		if ($bReturnText) {
			return $Text;
		}
		if (COption::GetOptionString(self::ModuleID,'use_own_translit')=='Y') {
			$strResult = self::TranslitOwn($Text, $arTranslitSettings);
		} else {
			$strResult = self::TranslitBitrix($Text, $arTranslitSettings);
		}
		return $strResult;
	}
	function TranslitBitrix($Text, $arTranslitSettings) {
		$strResult = CUtil::Translit($Text, LANGUAGE_ID, $arTranslitSettings);
		if ($arTranslitSettings["delete_repeat_replace"]==="true" || $arTranslitSettings["delete_repeat_replace"]===true) {
			$strResult = trim($strResult, $arTranslitSettings['replace_space']);
			$strResult = trim($strResult, $arTranslitSettings['replace_other']);
		}
		return $strResult;
	}
	function TranslitOwn($Text, $arTranslitSettings) {
		if ($arTranslitSettings['delete_repeat_replace']=='Y') {
			$arTranslitSettings['delete_repeat_replace'] = true;
		}
		$strResult = '';
		$RusSymbols = GetMessage('WEBDEBUG_EXCEL_TRANSLIT_RUS');
		$LatSymbols = GetMessage('WEBDEBUG_EXCEL_TRANSLIT_ENG');
		if (trim($arTranslitSettings['replace_space'])!='') {
			$LatSymbols .= $arTranslitSettings['replace_space'];
		} else {
			$LatSymbols .= '-';
		}
		$arRusSymbols = explode(',',$RusSymbols);
		$arLatSymbols = explode(',',$LatSymbols);
		for($i=0;$i<self::strlen($Text);$i++) {
			$Found=false;
			$Letter = self::substr($Text,$i,1);
			for($j=0;$j<=count($arRusSymbols);$j++) {
				if($Letter == $arRusSymbols[$j]) {
					$strResult .= $arLatSymbols[$j];
					$Found=true;
					break;
				}
			}
			if (!$Found) {
				$strResult .= $arTranslitSettings['replace_other'];
			}
		}
		if ($arTranslitSettings['max_len']>0) {
			$strResult = substr($strResult,0,$arTranslitSettings['max_len']);
		}
		if ($arTranslitSettings["delete_repeat_replace"]==='true' || $arTranslitSettings['delete_repeat_replace']===true) {
			while (strpos($strResult,$arTranslitSettings['replace_space'].$arTranslitSettings['replace_space'])!==false) {
				$strResult = str_replace($arTranslitSettings['replace_space'].$arTranslitSettings['replace_space'],$arTranslitSettings['replace_space'],$strResult);
			}
			while (strpos($strResult,$arTranslitSettings['replace_other'].$arTranslitSettings['replace_other'])!==false) {
				$strResult = str_replace($arTranslitSettings['replace_other'].$arTranslitSettings['replace_other'],$arTranslitSettings['replace_other'],$strResult);
			}
			$strResult = trim($strResult, $arTranslitSettings['replace_space']);
			$strResult = trim($strResult, $arTranslitSettings['replace_other']);
		}
		if ($arTranslitSettings['change_case']=='L') {
			$strResult = ToLower($strResult);
		} elseif ($arTranslitSettings['change_case']=='U') {
			$strResult = ToUpper($strResult);
		}
		return $strResult;
	}
	/**
	 *	
	 */
	function IBlockTranslitSettingsToStandard($arTranslitSettings) {
		$arResult = array();
		if (isset($arTranslitSettings["TRANS_LEN"])) $arResult["max_len"] = $arTranslitSettings["TRANS_LEN"];
		if (isset($arTranslitSettings["TRANS_CASE"])) $arResult["change_case"] = $arTranslitSettings["TRANS_CASE"];
		if (isset($arTranslitSettings["TRANS_SPACE"])) $arResult["replace_space"] = $arTranslitSettings["TRANS_SPACE"];
		if (isset($arTranslitSettings["TRANS_OTHER"])) $arResult["replace_other"] = $arTranslitSettings["TRANS_OTHER"];
		if (isset($arTranslitSettings["TRANS_EAT"])) $arResult["delete_repeat_replace"] = $arTranslitSettings["TRANS_EAT"];
		return $arResult;
	}
	/**
	 *	Get ID of SKU property to link to a products IBlock
	 */
	function GetOffersPropertyID($IBlockID) {
		if (CModule::IncludeModule('catalog')) {
			$resCatalog = CCatalog::GetList(array(),array('IBLOCK_ID'=>$IBlockID));
			if ($arCatalog = $resCatalog->GetNext(false,false)) {
				return $arCatalog['SKU_PROPERTY_ID'];
			}
		}
		return false;
	}
	/**
	 *	Get list of stores
	 */
	function GetStoresTypeList() {
		$arResult = array();
		if (CModule::IncludeModule('catalog') && class_exists('CCatalogStore')) {
			$resStores = CCatalogStore::GetList(array('SORT'=>'ASC'));
			while ($arStore = $resStores->GetNext(false,false)) {
				$arResult[] = $arStore;
			}
		}
		return $arResult;
	}
	/**
	 *	Set one price for product
	 */
	function SetProductPrice($ProductID, $PriceID, $PriceValue, $Currency) {
		$bResult = false;
		foreach(GetModuleEvents(self::ModuleID, 'OnBeforeSetProductPrice', true) as $arEvent) {
			if (!ExecuteModuleEventEx($arEvent, array($ProductID, $PriceID, &$PriceValue, &$Currency))) {
				return false;
			}
		}
		$arPriceFields = array(
			'PRODUCT_ID' => $ProductID,
			'CATALOG_GROUP_ID' => $PriceID,
			'PRICE' => $PriceValue,
			'CURRENCY' => $Currency,
		);
		$resPrice = CPrice::GetList(array(),array('PRODUCT_ID'=>$ProductID,'CATALOG_GROUP_ID'=>$PriceID));
		if ($arPrice = $resPrice->GetNext(false,false)) {
			$bResult = CPrice::Update($arPrice['ID'], $arPriceFields);
		} else {
			$bResult = CPrice::Add($arPriceFields);
			$bResult = $bResult>0;
		}
		foreach(GetModuleEvents(self::ModuleID, 'OnAfterSetProductPrice', true) as $arEvent) {
			ExecuteModuleEventEx($arEvent, array($ProductID, $PriceID, $PriceValue, $Currency));
		}
		return $bResult;
	}
	/**
	 *	Set quantity at a one store
	 */
	function SetProductStoreQuantity($ProductID, $StoreID, $Quantity) {
		$bResult = false;
		foreach(GetModuleEvents(self::ModuleID, 'OnBeforeSetProductStoreQuantity', true) as $arEvent) {
			if (!ExecuteModuleEventEx($arEvent, array($ProductID, $StoreID, &$Quantity))) {
				return false;
			}
		}
		$arStoreFields = array(
			'PRODUCT_ID' => $ProductID,
			'AMOUNT' => $Quantity,
			'STORE_ID' => $StoreID,
		);
		$resItem = CCatalogStoreProduct::GetList(array(),array('STORE_ID'=>$StoreID,'PRODUCT_ID'=>$ProductID),false,false,array('ID'));
		if ($arItem = $resItem->GetNext(false,false)) {
			$bResult = CCatalogStoreProduct::Update($arItem['ID'], $arStoreFields)>0;
		} else {
			$bResult = CCatalogStoreProduct::Add($arStoreFields)>0;
		}
		foreach(GetModuleEvents(self::ModuleID, 'OnAfterSetProductStoreQuantity', true) as $arEvent) {
			ExecuteModuleEventEx($arEvent, array($ProductID, $StoreID, $Quantity));
		}
		return $bResult;
	}
	/**
	 *	Determine currency in (price || currency)
	 */
	function DetermineCurrency($PriceValue, $Currency, $arData) {
		foreach(GetModuleEvents(self::ModuleID, 'OnDetermineCurrency', true) as $arEvent) {
			if (ExecuteModuleEventEx($arEvent, array($PriceValue, &$Currency, $arData))) {
				return $Currency;
			}
		}
		$bFoundInPrice = false;
		// Search in price
		foreach($arData['FIELDS']['PARAMS']['CURRENCY_EXT'] as $strCurrencyCode => $strCurrencySnippets) {
			$strCurrencySnippets = str_replace(';',',',$strCurrencySnippets);
			$arCurrencySnippets = explode(',',$strCurrencySnippets);
			foreach($arCurrencySnippets as $strCurrencySnippet) {
				$strCurrencySnippet = trim($strCurrencySnippet);
				if (stripos($PriceValue,$strCurrencySnippet)!==false) {
					$Currency = $strCurrencyCode;
					$bFoundInPrice = true;
					break 2;
				}
			}
		}
		// Search in currency
		if (!$bFoundInPrice) {
			foreach($arData['FIELDS']['PARAMS']['CURRENCY_EXT'] as $strCurrencyCode => $strCurrencySnippets) {
				$strCurrencySnippets = str_replace(';',',',$strCurrencySnippets);
				$arCurrencySnippets = explode(',',$strCurrencySnippets);
				foreach($arCurrencySnippets as $strCurrencySnippet) {
					$strCurrencySnippet = trim($strCurrencySnippet);
					if (stripos($Currency,$strCurrencySnippet)!==false) {
						$Currency = $strCurrencyCode;
						break 2;
					}
				}
			}
		}
		return $Currency;
	}
	/**
	 *	Set all product data (product as a catalog item)
	 */
	function SetProductData($ProductID, $arCatalogData, $arData) {
		$IBlockID = $arData['FIELDS']['MATCHES']['IBLOCK_ID_FOR_SHEET_'.$arData['SHEET']];
		foreach(GetModuleEvents(self::ModuleID, 'OnBeforeSetProductData', true) as $arEvent) {
			ExecuteModuleEventEx($arEvent, array($ProductID, $IBlockID, $arCatalogData, $arData));
		}
		if (!is_array($arCatalogData)) $arCatalogData = array();
		$arCatalogData['ID'] = $ProductID;
		// Prices
		$arPrices = array();
		if (isset($arCatalogData['PRICES'])) {
			if (is_array($arCatalogData['PRICES'])) $arPrices = $arCatalogData['PRICES'];
			unset($arCatalogData['PRICES']);
		}
		// Stores
		$arStores = array();
		if (isset($arCatalogData['STORES'])) {
			if (is_array($arCatalogData['STORES'])) $arStores = $arCatalogData['STORES'];
			unset($arCatalogData['STORES']);
		}
		// Currency [1st step]
		$DefaultCurrency = $arCatalogData['DEFAULT_CURRENCY'];
		$Currency = $DefaultCurrency;
		$arCurrencies = self::GetCurrencyList();
		if (isset($arCatalogData['CURRENCY']) && is_array($arCurrencies[$arCatalogData['CURRENCY']])) {
			$Currency = $arCatalogData['CURRENCY'];
			unset($arCatalogData['CURRENCY']);
		}
		unset($arCatalogData['DEFAULT_CURRENCY']);
		// Purchasing info
		if (isset($arCatalogData['PURCHASING_PRICE'])) {
			if (!is_array($arCurrencies[$arCatalogData['PURCHASING_CURRENCY']])) {
				$PurchasingCurrency = $DefaultCurrency;
			} else {
				$PurchasingCurrency = $arCatalogData['PURCHASING_CURRENCY'];
			}
			$PurchasingPriceFloatValue = self::GetFloatValue($arCatalogData['PURCHASING_PRICE']);
			if ($arData['FIELDS']['PARAMS']['CURRENCY_EXT_MODE']=='Y') {
				if (is_array($arData['FIELDS']['PARAMS']['CURRENCY_EXT'])) {
					$PurchasingCurrency = self::DetermineCurrency($arCatalogData['PURCHASING_PRICE'], $PurchasingCurrency, $arData);
				}
			}
			if ($arData['FIELDS']['PARAMS']['CURRENCY_CONVERT']=='Y' && $arData['FIELDS']['PARAMS']['CURRENCY_CONVERT_PURCHASING']=='Y' && CModule::IncludeModule('currency')) {
				if ($arData['FIELDS']['PARAMS']['DEFAULT_CURRENCY']!=$PurchasingCurrency) {
					if ($GLOBALS[WDEXCEL_TEMP]['CONVERT_FACTOR_'.$PurchasingCurrency.'_'.$arData['FIELDS']['PARAMS']['DEFAULT_CURRENCY']]>0) {
						$ConvertFactor = $GLOBALS[WDEXCEL_TEMP]['CONVERT_FACTOR_'.$PurchasingCurrency.'_'.$arData['FIELDS']['PARAMS']['DEFAULT_CURRENCY']];
					} else {
						$ConvertFactor = CCurrencyRates::GetConvertFactor($PurchasingCurrency, $arData['FIELDS']['PARAMS']['DEFAULT_CURRENCY']);
						$GLOBALS[WDEXCEL_TEMP]['CONVERT_FACTOR_'.$PurchasingCurrency.'_'.$arData['FIELDS']['PARAMS']['DEFAULT_CURRENCY']] = $ConvertFactor;
					}
					$PurchasingPriceFloatValue = $PurchasingPriceFloatValue * $ConvertFactor;
					$PurchasingCurrency = $arData['FIELDS']['PARAMS']['DEFAULT_CURRENCY'];
				}
			}
			$arCatalogData['PURCHASING_PRICE'] = $PurchasingPriceFloatValue;
			$arCatalogData['PURCHASING_CURRENCY'] = $PurchasingCurrency;
		}
		// VAT
		$arCatalogData['VAT_ID'] = $arCatalogData['DEFAULT_VAT_ID']>=1 ? $arCatalogData['DEFAULT_VAT_ID'] : false;
		if (isset($arCatalogData['VAT'])) {
			$arCatalogData['VAT_ID'] = self::GetVatByValue($arCatalogData['VAT'],true);
			unset($arCatalogData['VAT']);
		}
		unset($arCatalogData['DEFAULT_VAT_ID']);
		// Add/update
		if (CModule::IncludeModule('catalog') && CCatalogProduct::Add($arCatalogData)) {
			// Set measure ratio
			if($arCatalogData['MEASURE_RATIO']>0) {
				$resRatio = CCatalogMeasureRatio::GetList(array(),array('PRODUCT_ID'=>$ProductID));
				if ($arRatio = $resRatio->GetNext(false,false)) {
					CCatalogMeasureRatio::Update($arRatio['ID'],array('RATIO'=>$arCatalogData['MEASURE_RATIO']));
				} else {
					CCatalogMeasureRatio::Add(array('PRODUCT_ID'=>$ProductID,'RATIO'=>$arCatalogData['MEASURE_RATIO']));
				}
			}
			// Add/update prices
			foreach($arPrices as $PriceID => $PriceValue) {
				$PriceFloatValue = self::GetFloatValue($PriceValue);
				// Currency [2nd step]
				if ($arData['FIELDS']['PARAMS']['CURRENCY_EXT_MODE']=='Y') {
					if (is_array($arData['FIELDS']['PARAMS']['CURRENCY_EXT'])) {
						$Currency = self::DetermineCurrency($PriceValue, $Currency, $arData);
					}
				}
				// Currency convert
				if ($arData['FIELDS']['PARAMS']['CURRENCY_CONVERT']=='Y' && CModule::IncludeModule('currency')) {
					if ($arData['FIELDS']['PARAMS']['DEFAULT_CURRENCY']!=$Currency) {
						if ($GLOBALS[WDEXCEL_TEMP]['CONVERT_FACTOR_'.$Currency.'_'.$arData['FIELDS']['PARAMS']['DEFAULT_CURRENCY']]>0) {
							$ConvertFactor = $GLOBALS[WDEXCEL_TEMP]['CONVERT_FACTOR_'.$Currency.'_'.$arData['FIELDS']['PARAMS']['DEFAULT_CURRENCY']];
						} else {
							$ConvertFactor = CCurrencyRates::GetConvertFactor($Currency, $arData['FIELDS']['PARAMS']['DEFAULT_CURRENCY']);
							$GLOBALS[WDEXCEL_TEMP]['CONVERT_FACTOR_'.$Currency.'_'.$arData['FIELDS']['PARAMS']['DEFAULT_CURRENCY']] = $ConvertFactor;
						}
						$PriceFloatValue = $PriceFloatValue * $ConvertFactor;
						$Currency = $arData['FIELDS']['PARAMS']['DEFAULT_CURRENCY'];
					}
				}
				// Set price
				self::SetProductPrice($ProductID, $PriceID, $PriceFloatValue, $Currency);
			}
			// Add/update store quantity
			foreach($arStores as $StoreID => $Quantity) {
				self::SetProductStoreQuantity($ProductID, $StoreID, $Quantity);
			}
			// Reset stores processed property
			if ($arData['FIELDS']['PARAMS']['LINK_TO_STORE']=='Y' && $arData['FIELDS']['PARAMS']['CATALOG_STORE']>0) {
				CIBlockElement::SetPropertyValuesEx($ProductID, $IBlockID, array(self::StoresProcessedPropCode=>false));
			}
			// Calculate whole qunatity
			if ($arData['FIELDS']['PARAMS']['CALCULATE_QUANTITY']=='Y') {
				self::ProductRecalculateQuantity($ProductID);
			}
			// After events
			foreach(GetModuleEvents(self::ModuleID, 'OnAfterSetProductData', true) as $arEvent) {
				ExecuteModuleEventEx($arEvent, array($ProductID, $IBlockID, $arCatalogData, $arData));
			}
		}
	}
	/**
	 *	Recalculate quantity for product
	 */
	function ProductRecalculateQuantity($ProductID) {
		if (CModule::IncludeModule('catalog') && class_exists('CCatalogStore')) {
			$arActiveStoresID = array();
			$resStores = CCatalogStore::GetList(array(),array('ACTIVE'=>'Y'),false,false,array('ID'));
			while ($arStore = $resStores->GetNext(false,false)){
				$arActiveStoresID[] = $arStore['ID'];
			}
			if (!empty($arActiveStoresID)) {
				$intQuantity = 0;
				$resCount = CCatalogStoreProduct::GetList(array(), array('PRODUCT_ID'=>$ProductID,'STORE_ID'=>$arActiveStoresID)); 
				while ($arCount = $resCount->GetNext(false,false)){
					$intQuantity += $arCount['AMOUNT'];
				}
				$arProduct = array(
					'ID' => $ProductID,
					'QUANTITY' => $intQuantity,
				);
				$resProduct = CCatalogProduct::Add($arProduct);
			}
		}
	}
	/**
	 *	Execute after-save events
	 */
	function SetProductSaved($ProductID, $arData) {
		foreach(GetModuleEvents(self::ModuleID, 'OnProductSaved', true) as $arEvent) {
			ExecuteModuleEventEx($arEvent, array($ProductID, $arData));
		}
	}
	/**
	 *	Get VAT item ID by RATE value
	 */
	function GetVatByValue($Value, $AutoAdd=false) {
		if (!is_numeric($Value) || $Value<0) return false;
		if ($Value>=0 && CModule::IncludeModule('catalog')) {
			$resVat = CCatalogVat::GetList(false,array('RATE'=>$Value));
			if ($arVat = $resVat->GetNext(false,false)) {
				return $arVat['ID'];
			} elseif($AutoAdd) {
				$arFields = array(
					'ACTIVE' => 'Y',
					'SORT' => IntVal($Value),
					'RATE' => $Value,
					'NAME' => $Value.'%',
				);
				return CCatalogVat::Add($arFields);
			}
		}
		return false;
	}
	/**
	 *	Get VAT list
	 */
	function GetVatList() {
		$arResult = array();
		if (CModule::IncludeModule('catalog')) {
			$resVat = CCatalogVat::GetList(array('RATE'=>'ASC'),array('ACTIVE'=>'Y'));
			while ($arVat = $resVat->GetNext(false,false)) {
				$arResult[] = $arVat;
			}
		}
		foreach(GetModuleEvents(self::ModuleID, 'OnGetVatList', true) as $arEvent) {
			ExecuteModuleEventEx($arEvent, array());
		}
		return $arResult;
	}
	/**
	 *	Get weight units list
	 */
	function GetWeightUnitList() {
		$arResult = array(
			'1' => GetMessage('WEBDEBUG_EXCEL_WEIGHT_UNIT_GRAM'),
			'1000' => GetMessage('WEBDEBUG_EXCEL_WEIGHT_UNIT_KILOGRAM'),
			'1000000' => GetMessage('WEBDEBUG_EXCEL_WEIGHT_UNIT_TON'),
		);
		foreach(GetModuleEvents(self::ModuleID, 'GetWeightUnitList', true) as $arEvent) {
			ExecuteModuleEventEx($arEvent, array(&$arResult));
		}
		return $arResult;
	}
	/**
	 *	Get measure units
	 */
	function GetMeasureUnits() {
		$arResult = array();
		if (CModule::IncludeModule('catalog')) {
			$resMeasureUnits = CCatalogMeasure::getList(array('SORT'=>'ASC'));
			while ($arMeasureUnits = $resMeasureUnits->GetNext(false,false)) {
				$arResult[] = $arMeasureUnits;
			}
		}
		return $arResult;
	}
	/**
	 *	Get size (length, width, height) units list
	 */
	function GetSizeUnitList() {
		$arResult = array(
			'1' => GetMessage('WEBDEBUG_EXCEL_SIZE_UNIT_MM'),
			'10' => GetMessage('WEBDEBUG_EXCEL_SIZE_UNIT_CM'),
			'1000' => GetMessage('WEBDEBUG_EXCEL_SIZE_UNIT_M'),
		);
		foreach(GetModuleEvents(self::ModuleID, 'GetSizeUnitList', true) as $arEvent) {
			ExecuteModuleEventEx($arEvent, array(&$arResult));
		}
		return $arResult;
	}
	/**
	 *	Create array for product (product as a catalog item)
	 */
	function BuildProductArray($arData, $Type='ELEMENTS') {
		$arResult = array();
		$Type = in_array(ToUpper($Type),array('ELEMENTS','OFFERS')) ? $Type : 'ELEMENTS';
		$arMatches = $arData['FIELDS']['MATCHES']['SHEET'][$arData['SHEET']];
		$arResult['QUANTITY_TRACE'] = $arData['FIELDS']['PARAMS']['QUANTITY_TRACE']=='Y' ? 'Y' : 'N';
		$arResult['DEFAULT_CURRENCY'] = $arData['FIELDS']['PARAMS']['DEFAULT_CURRENCY'];
		$arResult['DEFAULT_VAT_ID'] = $arData['FIELDS']['PARAMS']['DEFAULT_VAT'];
		$arResult['VAT_INCLUDED'] = $arData['FIELDS']['PARAMS']['VAT_INCLUDED']=='Y' ? 'Y' : 'N';
		foreach($arData['ITEM']['ITEMS'] as $Column => $arCell) {
			$arMatch = $arMatches[$Column][$Type];
			if (is_array($arMatch) && trim($arMatch['TARGET'])!='') {
				if (preg_match('#PRICE_(\d+)#i',$arMatch['TARGET'],$M)) {
					if (!is_array($arResult['PRICES'])) $arResult['PRICES'] = array();
					$arResult['PRICES'][$M[1]] = $arCell['VALUE'];
				} elseif (preg_match('#STORE_(\d+)#i',$arMatch['TARGET'],$M)) {
					if (!is_array($arResult['STORES'])) $arResult['STORES'] = array();
					$arResult['STORES'][$M[1]] = $arCell['VALUE'];
				} elseif (in_array($arMatch['TARGET'],array('QUANTITY_TRACE','VAT_INCLUDED'))) {
					$arResult[$arMatch['TARGET']] = self::IsFlagChecked($arCell['VALUE'],$arData['FIELDS']['PARAMS']['FLAGS']) ? 'Y' : 'N';
				} elseif ($arMatch['TARGET']=='WEIGHT') {
					$Weight = self::GetFloatValue($arCell['VALUE']);
					$WeightUnit = self::GetFloatValue($arData['FIELDS']['PARAMS']['WEIGHT_UNIT']);
					if ($WeightUnit<=0) $WeightUnit = 1;
					$Weight = $Weight * $WeightUnit;
					$arResult[$arMatch['TARGET']] = $Weight;
				} elseif (in_array($arMatch['TARGET'],array('LENGTH','WIDTH','HEIGHT'))) {
					$Size = self::GetFloatValue($arCell['VALUE']);
					$SizeUnit = self::GetFloatValue($arData['FIELDS']['PARAMS'][$arMatch['TARGET'].'_UNIT']); // LENGTH_UNIT or WIDTH_UNIT or HEIGHT_UNIT
					if ($SizeUnit<=0) $SizeUnit = 1;
					$Size = $Size * $SizeUnit;
					$arResult[$arMatch['TARGET']] = $Size;
				} elseif (in_array($arMatch['TARGET'],array('QUANTITY','CURRENCY','PURCHASING_PRICE','PURCHASING_CURRENCY','VAT'))) {
					$arResult[$arMatch['TARGET']] = $arCell['VALUE'];
				} elseif ($arMatch['TARGET']=='MEASURE_UNIT') {
					if (strlen($arCell['VALUE'])) {
						$MeasureID = false;
						if (is_array($arData['FIELDS']['PARAMS']['MEASURE_UNITS'])) {
							foreach($arData['FIELDS']['PARAMS']['MEASURE_UNITS'] as $Key => $Value) {
								if (trim(ToLower($Value)) == trim(ToLower($arCell['VALUE']))) {
									$MeasureID = $Key;
									break;
								}
							}
						}
						if ($MeasureID>0) {
							$arResult['MEASURE'] = $MeasureID;
						}
					}
					unset($arMatch['TARGET']);
				} elseif ($arMatch['TARGET']=='MEASURE_RATIO') {
					if (strlen($arCell['VALUE'])) {
						$arResult['MEASURE_RATIO'] = FloatVal(str_replace(',','.',$arCell['VALUE']));
						if($arResult['MEASURE_RATIO']<0) {
							$arResult['MEASURE_RATIO'] = 1;
						}
					}
					unset($arMatch['TARGET']);
				}
			}
		}
		foreach(GetModuleEvents(self::ModuleID, 'OnBuildProductArray', true) as $arEvent) {
			ExecuteModuleEventEx($arEvent, array(&$arResult, $arData, $Type));
		}
		return $arResult;
	}
	/**
	 *	Check, if flag value is in a defined checked values list
	 */
	function IsFlagChecked($Value, $strFlags) {
		$arFlags = explode("\n",$strFlags);
		foreach($arFlags as $Flag) {
			if (ToLower(trim($Flag))==ToLower(trim($Value))) {
				return true;
			}
		}
		return false;
	}
	/**
	 *	Check if element has some parents
	 */
	function ElementHasSomeParents($ElementID) {
		if (CModule::IncludeModule('iblock')) {
			$resSections = CIBlockElement::GetElementGroups($ElementID,true,array('ID'));
			$intSectionsCount = 0;
			while ($arSectionToItem = $resSections->GetNext(false,false)) {
				$intSectionsCount++;
			}
			if ($intSectionsCount>1) {
				return true;
			}
		}
		return false;
	}
	/**
	 *	Process value for import to IBlock
	 *	Value is multiple for multiple properties
	 */
	function ProcessValue($Value, $Code, $Type, $Separator, $SeparatorOther, $arData) {
		foreach(GetModuleEvents(self::ModuleID, 'OnBeforeProcessValue', true) as $arEvent) {
			if (ExecuteModuleEventEx($arEvent, array(&$Value, &$Code, &$Type, &$Separator, &$SeparatorOther, $arData))) {
				return $Value;
			}
		}
		if (in_array($Code,array('NAME','CODE','SORT','PREVIEW_TEXT_TYPE','DETAIL_TEXT_TYPE','TAGS')) || $arData['IS_SEO_FIELD']) {
			// �� ����� ����� ��������� �� �������� ��������������
			return trim($Value);
		} elseif ($Code=='ACTIVE') {
			// ���������
			return self::IsFlagChecked($Value,$arData['FIELDS']['PARAMS']['FLAGS']) ? 'Y' : 'N';
		} elseif (in_array($Code,array('PREVIEW_TEXT','DETAIL_TEXT','DESCRIPTION'))) {
			if ($Type=='HTML' || (!is_array($arData['FIELDS']['PARAMS']['HTML_FORMATTING']) || count($arData['FIELDS']['PARAMS']['HTML_FORMATTING'])==0) ) {
				return $Value;
			} else {
				return self::GetHtmlFromElements($arData['HTML'],$arData['FIELDS']['PARAMS']['HTML_FORMATTING']);
			}
		} elseif ($Code=='SKIP_FLAG') {
			// ���� ��������
			return self::IsFlagChecked($Value,$arData['FIELDS']['PARAMS']['FLAGS']);
		} elseif (in_array($Code, array('PREVIEW_PICTURE','DETAIL_PICTURE','PICTURE'))) {
			// �� �������� (����� ��� ���������)
			$arImage = self::MakeFileArray($Value, $arData);
			return $arImage;
		} elseif ($arData['IS_ELEMENT']===true && preg_match('#PROPERTY_([0-9]+)#i', $Code, $M)) {
			// �������� ���������
			$arValues = false;
			$PropertyID = $M[1];
			if ($PropertyID>0 && CModule::IncludeModule('iblock')) {
				$resProp = CIBlockProperty::GetList(array(),array('ID'=>$PropertyID));
				if ($arProp = $resProp->GetNext(false,false)) {
					$arValues = array($Value);
					if ($arProp['MULTIPLE']=='Y') {
						$Separator = self::GetSeparator($Separator, $SeparatorOther);
						if ($Separator!='') {
							$arValues = explode($Separator, $Value);
						}
					}
					if ($arProp['PROPERTY_TYPE']=='N') {
						if ($Type=='FLOAT') {
							foreach($arValues as $Key => $PropValue) {
								$arValues[$Key] = FloatVal($PropValue);
								if(empty($arValues[$Key])) {
									$arValues[$Key] = false;
								}
							}
						} else {
							foreach($arValues as $Key => $PropValue) {
								$arValues[$Key] = IntVal($PropValue);
								if(empty($arValues[$Key])) {
									$arValues[$Key] = false;
								}
							}
						}
					} elseif ($arProp['PROPERTY_TYPE']=='L') {
						if ($Type=='FLAG') {
							if (self::IsFlagChecked($Value,$arData['FIELDS']['PARAMS']['FLAGS'])) {
								$resPropEnums = CIBlockPropertyEnum::GetList(array('SORT'=>'ASC'),array('PROPERTY_ID'=>$PropertyID));
								if ($arPropEnum = $resPropEnums->GetNext(false,false)) {
									$Value = $arPropEnum['ID'];
								} else {
									$Value = CIBlockPropertyEnum::Add(array(
										'PROPERTY_ID' => $PropertyID,
										'XML_ID' => 'Y',
										'VALUE' => GetMessage('MAIN_YES'),
										'SORT' => '500',
									));
								}
							} else {
								$Value = false;
							}
							$arValues = $Value;
						} else {
							foreach($arValues as $Key => $Value) {
								$arEnums = array();
								$Found = false;
								$resPropEnums = CIBlockPropertyEnum::GetList(array(),array('PROPERTY_ID'=>$PropertyID));
								while ($arPropEnum = $resPropEnums->GetNext()) {
									$CompareValue = $Type=='LIST_XML_ID'?$arPropEnum['~XML_ID']:trim($arPropEnum['~VALUE']);
									if (ToLower($CompareValue)==ToLower(trim($Value))) {
										$arValues[$Key] = $arPropEnum['ID'];
										$Found = true;
									}
								}
								if (!$Found) {
									$EnumID = CIBlockPropertyEnum::Add(array(
										'PROPERTY_ID' => $PropertyID,
										'XML_ID' => $Type=='LIST_XML_ID' ? trim($Value) : ToLower(MD5($Value)),
										'VALUE' => trim($Value),
										'SORT' => '500',
									));
									$arValues[$Key] = $EnumID; // was: $arValues[$Key] = $Found;
								}
							}
							$ValueFound = false;
							foreach($arValues as $Key => $Value) {
								if ($Value!==false) {
									$ValueFound = true;
									break;
								}
							}
							if (!$ValueFound) $arValues = false;
						}
					} elseif ($arProp['PROPERTY_TYPE']=='F') {
						foreach($arValues as $Key => $Value) {
							if ($Value) {
								$Value = trim($Value);
								$arFile = self::MakeFileArray($Value, $arData);
								if (is_array($arFile)) {
									$arValues[$Key] = $arFile;
								} else {
									$arValues[$Key] = false;
								}
							} else {
								$arValues[$Key] = false;
							}
						}
						$ValueFound = false;
						foreach($arValues as $Key => $Value) {
							if (is_array($Value)) {
								$ValueFound = true;
								break;
							}
						}
						if (!$ValueFound) $arValues = false;
					} elseif ($arProp['PROPERTY_TYPE']=='E') {
						if ($arProp['LINK_IBLOCK_ID']>0 && CModule::IncludeModule('iblock')) {
							foreach($arValues as $Key => $Value) {
								$Value = trim($Value);
								$arEnums = array();
								$Found = false;
								$arFilter = array('IBLOCK_ID'=>$arProp['LINK_IBLOCK_ID']);
								switch($Type) {
									case 'ELEMENT_ID':
										$arFilter['ID'] = $Value;
										break;
									case 'ELEMENT_CODE':
										$arFilter['CODE'] = $Value;
										break;
									case 'ELEMENT_NAME':
										$arFilter['NAME'] = $Value;
										break;
									case 'ELEMENT_EXTERNAL':
										$arFilter['EXTERNAL_ID'] = $Value;
										break;
								}
								$resPropItems = CIBlockElement::GetList(array(),$arFilter);
								if ($arPropItem = $resPropItems->GetNext(false,false)) {
									$arValues[$Key] = $arPropItem['ID'];
									$Found = true;
								}
								if (!$Found && $Type!='ELEMENT_ID') {
									$CurrentIBlockID = $arData['FIELDS']['MATCHES']['IBLOCK_ID_FOR_SHEET_'.$arData['SHEET']];
									$TargetIBlockID = $arProp['LINK_IBLOCK_ID'];
									if ($arProp['LINK_IBLOCK_ID']>0 && ($CurrentIBlockID!=$TargetIBlockID || $arData['FIELDS']['PARAMS']['CREATE_RELATED_SELF_IBLOCK']=='Y')) {
										$IBlockElement = new CIBlockElement;
										$arNewItemFields = array(
											'IBLOCK_ID' => $arProp['LINK_IBLOCK_ID'],
											'XML_ID' => $Type=='LIST_XML_ID' ? $Value : ToLower(MD5($Value)),
											'VALUE' => $Value,
											'SORT' => '500',
											'PROPERTY_VALUES' => array(
												self::ImportIDPropCode => $arData['STATUS']['ID'],
											),
										);
										switch($Type) {
											case 'ELEMENT_CODE':
												$arNewItemFields['NAME'] = $Value;
												$arNewItemFields['CODE'] = $Value;
												break;
											case 'ELEMENT_NAME':
												$arNewItemFields['NAME'] = $Value;
												break;
											case 'ELEMENT_EXTERNAL':
												$arNewItemFields['NAME'] = $Value;
												$arNewItemFields['EXTERNAL_ID'] = $Value;
												break;
										}
										$PropItemID = $IBlockElement->Add($arNewItemFields);
										if ($PropItemID>0) {
											$arValues[$Key] = $PropItemID;
										} else {
											unset($arValues[$Key]);
										}
									} else {
										unset($arValues[$Key]);
									}
								}
							}
						}
						$ValueFound = false;
						foreach($arValues as $Key => $Value) {
							if ($Value!==false) {
								$ValueFound = true;
								break;
							}
						}
						if (!$ValueFound) $arValues = false;
					} elseif ($arProp['PROPERTY_TYPE']=='G') {
						// ToDo !!! (������� � ��������)
					} else {
						if ($arProp['PROPERTY_TYPE']=='S' && $arProp['USER_TYPE']=='DateTime') {
							foreach($arValues as $Key => $PropValue) {
								if(is_numeric($PropValue)) {
									$Date = IntVal($PropValue);
									$Date = ($Date - 25569) * 86400;
									if($Date>0) {
										$arValues[$Key] = date(CDatabase::DateFormatToPHP($arProp['USER_TYPE']=='Date'?FORMAT_DATE:FORMAT_DATETIME),$Date);
									} else {
										$arValues[$Key] = '';
									}
								}
							}
						} elseif ($arProp['PROPERTY_TYPE']=='S' && $arProp['USER_TYPE']=='HTML') {
							if ($Type=='HTML' || (!is_array($arData['FIELDS']['PARAMS']['HTML_FORMATTING']) || empty($arData['FIELDS']['PARAMS']['HTML_FORMATTING']))) {
								$arValues = array(array('VALUE'=>$Value,'TYPE'=>$Type==''?'TEXT':'HTML'));
							} else {
								$arValues = array(array('VALUE'=>self::GetHtmlFromElements($arData['HTML'],$arData['FIELDS']['PARAMS']['HTML_FORMATTING']),'TYPE'=>'HTML'));
							}
						} else {
							if ($Type=='FLOAT') {
								foreach($arValues as $Key => $PropValue) {
									$arValues[$Key] = FloatVal($PropValue);
								}
							} elseif ($Type=='INTEGER') {
								foreach($arValues as $Key => $PropValue) {
									$arValues[$Key] = IntVal($PropValue);
								}
							} else {
								foreach($arValues as $Key => $PropValue) {
									$arValues[$Key] = trim($PropValue);
								}
							}
						}
					}
				}
				if ($arProp['MULTIPLE']!='Y' && is_array($arValues) && count($arValues)==1) {
					$arValues = $arValues[0];
				}
				#print 'Prop:'.$PropertyID.': '.$Value.'<br/>';
			}
			return $arValues;
		} elseif ($arData['IS_SECTION']===true && preg_match('#UF_.*?#i', $Code)) {
			// �������� ��������
			$arValues = false;
			$IBlockID = $arData['FIELDS']['MATCHES']['IBLOCK_ID_FOR_SHEET_'.$arData['SHEET']];
			$resProp = CUserTypeEntity::GetList(array('SORT'=>'ASC'),array('ENTITY_ID'=>'IBLOCK_'.$IBlockID.'_SECTION','FIELD_NAME'=>$Code));
			if ($arProp = $resProp->GetNext(false,false)) {
				$arValues = array($Value);
				if ($arProp['MULTIPLE']=='Y') {
					$Separator = self::GetSeparator($Separator, $SeparatorOther);
					if ($Separator!='') {
						$arValues = explode($Separator, $Value);
					}
				}
				if (in_array($arProp['USER_TYPE_ID'],array('string','datetime','string_formatted'))) {
					//$arValues = $arValues;
				} elseif (in_array($arProp['USER_TYPE_ID'],array('iblock_element','iblock_section'))) {
					$ValueFound = false;
					foreach($arValues as $Key => $Value) {
						if ($Value>0) {
							$ValueFound = true;
							break;
						}
					}
					if (!$ValueFound) $arValues = false;
				} elseif ($arProp['USER_TYPE_ID']=='integer') {
					foreach($arValues as $Key => $Value) {
						$arValues[$Key] = IntVal($Value);
					}
				} elseif ($arProp['USER_TYPE_ID']=='double') {
					foreach($arValues as $Key => $Value) {
						$arValues[$Key] = FloatVal($Value);
					}
				} elseif ($arProp['USER_TYPE_ID']=='enumeration') {
					$UserFieldEnum = new CUserFieldEnum;
					foreach($arValues as $Key => $Value) {
						$arEnums = array();
						$Found = false;
						$resUserFieldEnum = $UserFieldEnum->GetList(array(), array('USER_FIELD_ID'=>$arProp['ID']));
						while ($arUserFieldEnum = $resUserFieldEnum->GetNext(false,false)) {
							$arEnums[$arUserFieldEnum['ID']] = array(
								'XML_ID' => $arUserFieldEnum['XML_ID'],
								'VALUE' => $arUserFieldEnum['VALUE'],
								'SORT' => $arUserFieldEnum['SORT'],
								'DEF' => $arUserFieldEnum['DEF'],
							);
							$CompareValue = $Type=='LIST_XML_ID'?$arUserFieldEnum['XML_ID']:trim($arUserFieldEnum['VALUE']);
							if (ToLower($CompareValue)==ToLower(trim($Value))) {
								$arValues[$Key] = $arUserFieldEnum['ID'];
								$Found = true;
							}
						}
						if (!$Found) {
							$arEnums['n0'] = array(
								'XML_ID' => $Type=='LIST_XML_ID' ? trim($Value) : ToLower(MD5($Value)),
								'VALUE' => trim($Value),
								'SORT' => '500',
							);
							$UserFieldEnum->SetEnumValues($arProp['ID'], $arEnums);
							$resUserFieldEnum = $UserFieldEnum->GetList(array(), array('USER_FIELD_ID'=>$arProp['ID']));
							while ($arUserFieldEnum = $resUserFieldEnum->GetNext(false,false)) {
								$CompareValue = $Type=='LIST_XML_ID'?$arUserFieldEnum['XML_ID']:trim($arUserFieldEnum['VALUE']);
								if (ToLower($CompareValue)==ToLower(trim($Value))) {
									$arValues[$Key] = $arUserFieldEnum['ID'];
									break;
								}
							}
						}
					}
					$ValueFound = false;
					foreach($arValues as $Key => $Value) {
						if ($Value>0) {
							$ValueFound = true;
							break;
						}
					}
					if (!$ValueFound) $arValues = false;
				} elseif ($arProp['USER_TYPE_ID']=='file') {
					foreach($arValues as $Key => $Value) {
						if ($Value) {
							$arFile = self::MakeFileArray($Value, $arData);
							if (is_array($arFile)) {
								$arValues[$Key] = $arFile;
							} else {
								$arValues[$Key] = false;
							}
						} else {
							$arValues[$Key] = false;
						}
					}
					$ValueFound = false;
					foreach($arValues as $Key => $Value) {
						if (is_array($Value)) {
							$ValueFound = true;
							break;
						}
					}
					if (!$ValueFound) $arValues = false;
				} elseif ($arProp['USER_TYPE_ID']=='boolean') {
					$arFlags = explode("\n",$arData['FIELDS']['PARAMS']['FLAGS']);
					$FlagTrue = false;
					foreach($arValues as $Key => $Value) {
						foreach($arFlags as $Flag) {
							if (ToLower(trim($Flag))==ToLower(trim($Value))) {
								$FlagTrue = true;
							}
						}
					}
					if ($FlagTrue) {
						$arValues = true;
					} else {
						$arValues = false;
					}
				}
				if ($arProp['MULTIPLE']!='Y' && is_array($arValues) && count($arValues)==1) {
					$arValues = $arValues[0];
				}
				return $arValues;
			}
		}
		return $Value;
	}
	/**
	 *	Build HTML-code from HTML elements and settings
	 */
	function GetHtmlFromElements($arElements, $arHtmlFormatting) {
		$strResult = '';
		foreach($arElements as $arHTMLElement) {
			$arStyles = array();
			$arTags = array();
			if (in_array('color',$arHtmlFormatting) && $arHTMLElement['COLOR']!='') {
				$arStyles[] = 'color:#'.trim($arHTMLElement['COLOR']).';';
			}
			if (in_array('family',$arHtmlFormatting) && $arHTMLElement['FONT']) {
				$arStyles[] = 'font-family:'.trim($arHTMLElement['FONT']).';';
			}
			if (in_array('size',$arHtmlFormatting) && $arHTMLElement['SIZE']!='') {
				$arStyles[] = 'font-size:'.trim($arHTMLElement['SIZE']).'pt;';
			}
			if (in_array('b',$arHtmlFormatting) && $arHTMLElement['B']) {
				$arTags[] = 'b';
			}
			if (in_array('i',$arHtmlFormatting) && $arHTMLElement['I']) {
				$arTags[] = 'i';
			}
			if (in_array('u',$arHtmlFormatting) && $arHTMLElement['U']!='none') {
				$arTags[] = 'u';
			}
			if (in_array('s',$arHtmlFormatting) && $arHTMLElement['S']) {
				$arTags[] = 's';
			}
			if (in_array('sup',$arHtmlFormatting) && $arHTMLElement['SUP']) {
				$arTags[] = 'sup';
			}
			if (in_array('sub',$arHtmlFormatting) && $arHTMLElement['SUB']) {
				$arTags[] = 'sub';
			}
			$strHTMLElement = '';
			foreach($arTags as $Tag){$strHTMLElement .= '<'.$Tag.'>';}
			if (!empty($arStyles)) $strHTMLElement .= '<span style="'.implode(' ', $arStyles).'">';
			$strHTMLElement .= $arHTMLElement['TEXT'];
			if (!empty($arStyles)) $strHTMLElement .= '</span>';
			foreach($arTags as $Tag){$strHTMLElement .= '</'.$Tag.'>';}
			$strResult = $strHTMLElement;
		}
		return $strResult;
	}
	/**
	 *	Recursive search file in directory
	 */
	function SearchFile($dirname, $filename) {
		global $extentions, $count;
		$dir = opendir($_SERVER['DOCUMENT_ROOT'].$dirname);
		while (($file = readdir($dir)) !== false)  {
			if($file != "." && $file != "..") {
				if(is_file($_SERVER['DOCUMENT_ROOT'].$dirname.$file)) {
					if (strtolower($file)==strtolower($filename)) {
						return $dirname.$file;
					}
				}
				if(is_dir($_SERVER['DOCUMENT_ROOT'].$dirname.$file)) {
					$Found = self::SearchFile($dirname.$file.'/', $filename);
					if ($Found!==false) {
						return $Found;
					}
				}
			}
		}
		closedir($dir);
		return false;
	}
	/**
	 *	Own function to handle timeouts
	 */
	function MakeFileArray($Value, $arData) {
		if (trim($Value)=='') return false;
		$Value = str_replace('\\','/',$Value);
		$L1 = substr($Value,0,1);
		$L2 = substr($Value,1,1);
		if ($L1=='/' && $L2!='/') {
			if (file_exists($_SERVER['DOCUMENT_ROOT'].SITE_DIR.$Value)) {
				$Value = self::_MakeFileArray($_SERVER['DOCUMENT_ROOT'].SITE_DIR.$Value);
			}
		} elseif ($L1=='/' && $L2=='/') {
			$Value = self::_MakeFileArray('http:'.$Value);
		} elseif (substr($Value,0,7)=='http://') {
			$Value = self::_MakeFileArray($Value);
		} elseif (substr($Value,0,8)=='https://') {
			$Value = self::_MakeFileArray($Value);
		} elseif(COption::GetOptionString(self::ModuleID,'search_images_in_path')=='Y') {
			$strImagesPath = $arData['FIELDS']['PARAMS']['IMAGES_PATH_'.$arData['SHEET']];
			$strImagesPath = trim(str_replace('\\','/',$strImagesPath));
			if (trim($strImagesPath)!='') {
				if (substr($strImagesPath,-1)!='/') {$strImagesPath .= '/';}
				if (is_dir($_SERVER['DOCUMENT_ROOT'].$strImagesPath)) {
					if (is_file($_SERVER['DOCUMENT_ROOT'].$strImagesPath.$Value)) {
						$Value = self::_MakeFileArray($_SERVER['DOCUMENT_ROOT'].$strImagesPath.$Value);
					} elseif (COption::GetOptionString(self::ModuleID,'search_images_recursive')=='Y') {
						$FilePath = self::SearchFile($strImagesPath, $Value);
						if ($FilePath!==false) {
							$Value = self::_MakeFileArray($_SERVER['DOCUMENT_ROOT'].$FilePath);
						}
					}
				}
			}
		}
		return $Value;
	}
	/**
	 *	Helper for own function MakeFileArray();
	 */
	function _MakeFileArray($path, $mimetype = false, $skipInternal = false) {
		$io = CBXVirtualIo::GetInstance();
		$arFile = array();
		if(intval($path)>0) {
			if ($skipInternal) return false;
			$res = CFile::GetByID($path);
			if($ar = $res->Fetch()) {
				$bExternalStorage = false;
				foreach(GetModuleEvents("main", "OnMakeFileArray", true) as $arEvent) {
					if(ExecuteModuleEventEx($arEvent, array($ar, &$arFile))) {
						$bExternalStorage = true;
						break;
					}
				}
				if(!$bExternalStorage) {
					$arFile["name"] = (strlen($ar['ORIGINAL_NAME'])>0?$ar['ORIGINAL_NAME']:$ar['FILE_NAME']);
					$arFile["size"] = $ar['FILE_SIZE'];
					$arFile["type"] = $ar['CONTENT_TYPE'];
					$arFile["description"] = $ar['DESCRIPTION'];
					$arFile["tmp_name"] = $io->GetPhysicalName(preg_replace("#[\\\\\\/]+#", "/", $_SERVER['DOCUMENT_ROOT'].'/'.(COption::GetOptionString('main', 'upload_dir', 'upload')).'/'.$ar['SUBDIR'].'/'.$ar['FILE_NAME']));
				}
				return $arFile;
			}
		}
		$path = preg_replace("#(?<!:)[\\\\\\/]+#", "/", $path);
		if(strlen($path) == 0 || $path == "/"){
			return NULL;
		}
		if(preg_match("#^php://filter#i", $path)){
			return NULL;
		}
		if(preg_match("#^(http[s]?)://#", $path)){
			$temp_path = '';
			$bExternalStorage = false;
			foreach(GetModuleEvents("main", "OnMakeFileArray", true) as $arEvent){
				if(ExecuteModuleEventEx($arEvent, array($path, &$temp_path))){
					$bExternalStorage = true;
					break;
				}
			}
			if(!$bExternalStorage){
				$SkipImagesExt = COption::GetOptionString(self::ModuleID,'skip_images_ext')=='Y';
				if ($SkipImagesExt) {
					$temp_path = $_SERVER['DOCUMENT_ROOT'].'/upload/tmp/'.ToLower(RandString(16)).'/file_'.ToLower(RandString(16));
				} else {
					$temp_path = CFile::GetTempName('', bx_basename($path));
				}
				$ob = new CHTTP;
				$ob->http_timeout = COption::GetOptionString(self::ModuleID, 'images_timeout');
				$ob->follow_redirect = true;
				if($ob->Download($path, $temp_path)) {
					$arFile = CFile::MakeFileArray($temp_path);
					if ($SkipImagesExt) {
						$bBrokenImage = false;
						switch($arFile['type']) {
							case 'image/jpeg':
								$arFile['name'] .= '.jpg';
								break;
							case 'image/png':
								$arFile['name'] .= '.png';
								break;
							case 'image/gif':
								$arFile['name'] .= '.gif';
								break;
							case 'image/bmp':
								$arFile['name'] .= '.bmp';
								break;
							default:
								$bBrokenImage = true;
								break;
						}
						if ($bBrokenImage) {
							return NULL;
						}
					}
				}
			} elseif($temp_path) {
				$arFile = CFile::MakeFileArray($temp_path);
			}
		} elseif(preg_match("#^(ftp[s]?|php)://#", $path)) {
			if($fp = fopen($path,"rb")){
				$content = "";
				while(!feof($fp)) {
					$content .= fgets($fp, 4096);
				}
				if(strlen($content) > 0){
					$temp_path = CFile::GetTempName('', bx_basename($path));
					if (RewriteFile($temp_path, $content)) {
						$arFile = CFile::MakeFileArray($temp_path);
					}
				}
				fclose($fp);
			}
		} else {
			if(!file_exists($path)) {
				if (file_exists($_SERVER["DOCUMENT_ROOT"].$path)) {
					$path = $_SERVER["DOCUMENT_ROOT"].$path;
				} else {
					return NULL;
				}
			}
			if(is_dir($path)) return NULL;
			$arFile["name"] = $io->GetLogicalName(bx_basename($path));
			$arFile["size"] = filesize($path);
			$arFile["tmp_name"] = $path;
			$arFile["type"] = $mimetype;
			if(strlen($arFile["type"])<=0) {
				$arFile["type"] = CFile::GetContentType($path, true);
			}
		}

		if(strlen($arFile["type"])<=0) {
			$arFile["type"] = "unknown";
		}

		return $arFile;
	}
	/**
	 *	Delete old directories
	 */
	function DeleteOldDirectories($Days=false) {
		if ($Days===false){
			$Days = COption::GetOptionString(self::ModuleID,'delete_directories_after');
		}
		if (!is_numeric($Days) || $Days<0) {
			$Days = 2;
		}
		$MaxTime = time() - $Days*24*60*60;
		$UploadDir = '/'.COption::GetOptionString('main','upload_dir','/upload/').'/';
		$UploadDir = str_replace('\\\\','\\',$UploadDir);
		$UploadDir = str_replace('//','/',$UploadDir);
		$Path = $UploadDir.self::ModuleID.'/';
		if (is_dir($_SERVER['DOCUMENT_ROOT'].$Path)) {
			$Handle = opendir($_SERVER['DOCUMENT_ROOT'].$Path);
			while (($Item = readdir($Handle)) !== false)  {
				if($Item != "." && $Item != "..") {
					// ToDo: Format may be other - see begin of this class
					if(is_dir($_SERVER['DOCUMENT_ROOT'].$Path.$Item) && preg_match('#(\d{4})-(\d{2})-(\d{2})#i',$Item,$M)) {
						$Day = IntVal($M[3]);
						$Month = IntVal($M[2]);
						$Year = IntVal($M[1]);
						$Time = mktime(0,0,0,$Month,$Day,$Year);
						if ($Time<=$MaxTime) {
							DeleteDirFilesEx($Path.$Item);
						}
					}
				}
			}
			closedir($Handle);
		}
		return 'CWebdebugExcel2::DeleteOldDirectories();';
	}
	/**
	 *	Add agent for delete old directories
	 */
	function AddCleanupAgent() {
		$DateStart = date(CDatabase::DateFormatToPHP(FORMAT_DATETIME));
		CAgent::AddAgent(
			'CWebdebugExcel2::DeleteOldDirectories();',
			self::ModuleID,
			'N',
			'86400',
			$DateStart,
			'Y',
			$DateStart,
			'200'
		);
	}
	/**
	 *	Create panel button
	 */
	function PanelCreateHandler() {
		global $APPLICATION;
		if($APPLICATION->GetGroupRight('webdebug.excel') >= 'R') {
			$WebdebugExcelImportURL = $APPLICATION->GetPopupLink(
				array(
					'URL' => '/bitrix/admin/wd_excel2_popup.php?lang='.LANGUAGE_ID.'&public=Y&bxpublic=Y&str_URI='.urlencode($APPLICATION->GetCurPageParam('', array('clear_cache', 'sessid', 'login', 'logout', 'register', 'forgot_password', 'change_password', 'confirm_registration', 'confirm_code', 'confirm_user_id', 'bitrix_include_areas', 'show_page_exec_time', 'show_include_exec_time', 'show_sql_stat', 'show_link_stat'))).'&site='.SITE_ID,
					'PARAMS' => array(
						'width' => COption::GetOptionString('webdebug.excel','popup2_width'),
						'height' => COption::GetOptionString('webdebug.excel','popup2_height'),
						'resize' => false,
						'resizable' => false,
					)
				)
			);
			$APPLICATION->AddPanelButton(array(
				'HREF' => 'javascript:'.$WebdebugExcelImportURL,
				'ICON' => 'icon-wizard',
				'TEXT' => GetMessage('WEBDEBUG_EXCEL_BUTTON_TEXT'),
				'MAIN_SORT' => '1000',
				'SORT' => '1000',
				'RESORT_MENU' => true,
				'HINT' => array(
					'TITLE' => GetMessage('WEBDEBUG_EXCEL_BUTTON_HINT_TITLE'),
					'TEXT' => GetMessage('WEBDEBUG_EXCEL_BUTTON_HINT_TEXT'),
				),
			));
		}
	}
}
?>