<commit_before><?php
/**
 * Class for the handling Bulk upload using XML in the system 
 * 
 * @package Scheduler
 * @subpackage Provision
 */
class BulkUploadEngineXml extends KBulkUploadEngine
{
	/**
	 * The defalut thumbnail tag
	 * @var string
	 */
	const DEFAULT_THUMB_TAG = 'default_thumb';
	
	/**
	 * The default ingestion profile id
	 * @var int
	 */
	private $defaultConversionProfileId = null;
	
	/**
	 * Holds the number of the current proccessed item
	 * @var int
	 */
	private $currentItem = 0;
	
	/**
	 * The engine xsd file path
	 * @var string
	 */
	protected $xsdFilePath = null;
	
	/**
	 * Allows the usage of server content resource
	 * @var bool
	 */
	protected $allowServerResource = false;
	
	/**
	 * Maps the flavor params name to id
	 * @var array()
	 */
	private $assetParamsNameToIdPerConversionProfile = null;

	/**
	 * Maps the asset id to flavor params id
	 * @var array()
	 */
	private $assetIdToAssetParamsId = null;
	
	/**
	 * Maps the access control name to id
	 * @var array()
	 */
	private $accessControlNameToId = null;
	
	/**
	 * Maps the converstion profile name to id
	 * @var array()
	 */
	private $conversionProfileNameToId = array();
	
	/**
	 * Maps the storage profile name to id
	 * @var array()
	 */
	private $storageProfileNameToId = null;
	
	/**
	 * Conversion profile xsl file
	 * @var string
	 */
	protected $conversionProfileXsl = null;

	/**
	 * @param KSchedularTaskConfig $taskConfig
	 * @param KalturaClient $kClient
	 * @param KalturaBatchJob $job
	 */
	public function __construct( KSchedularTaskConfig $taskConfig, KalturaClient $kClient, KalturaBatchJob $job)
	{
		parent::__construct($taskConfig, $kClient, $job);
		
		$this->xsdFilePath = 'http://' . kConf::get('www_host') . '/api_v3/index.php/service/schema/action/serve/type/' . KalturaSchemaType::BULK_UPLOAD_XML;
		if($taskConfig->params->xsdFilePath) 
			$this->xsdFilePath = $taskConfig->params->xsdFilePath;
			
		if($taskConfig->params->allowServerResource) 
			$this->allowServerResource = (bool) $taskConfig->params->allowServerResource;
	}
	
	/* (non-PHPdoc)
	 * @see KBulkUploadEngine::HandleBulkUpload()
	 */
	public function handleBulkUpload() 
	{
		$this->validate();
	    $this->parse();
	}
	
	/**
	 * Validates that the xml is valid using the XSD
	 *@return bool - if the validation is ok
	 */
	protected function validate() 
	{
		if(!file_exists($this->data->filePath))
		{
			throw new KalturaBatchException("File doesn't exist [{$this->data->filePath}]", KalturaBatchJobAppErrors::BULK_FILE_NOT_FOUND);
		}
		
		libxml_use_internal_errors(true);
		
		$this->loadXslt();
			
		$xdoc = new DomDocument();
		
		$xmlContent = $this->xslTransform($this->data->filePath);
		libxml_clear_errors();
		if(!$xdoc->loadXML($xmlContent)){
			$errorMessage = kXml::getLibXmlErrorDescription($xmlContent);
			KalturaLog::debug("Could not load xml");
			throw new KalturaBatchException("Could not load xml [{$this->job->id}], $errorMessage", KalturaBatchJobAppErrors::BULK_VALIDATION_FAILED);
		}
		//Validate the XML file against the schema
		libxml_clear_errors();
		if(!$xdoc->schemaValidate($this->xsdFilePath)) 
		{
			$errorMessage = kXml::getLibXmlErrorDescription($xmlContent);
			KalturaLog::debug("XML is invalid:\n$errorMessage");
			throw new KalturaBatchException("Validate files failed on job [{$this->job->id}], $errorMessage", KalturaBatchJobAppErrors::BULK_VALIDATION_FAILED);
		}
		
		return true;
	}
	
	/**
	 * Load xsl transform
	 */
	protected function loadXslt() 
	{
		$data = self::getData();
		$conversionProfileId = $data->conversionProfileId;
		if($data->conversionProfileId == -1){
			$conversionProfileId = PartnerPeer::retrieveByPK($this->currentPartnerId)->getDefaultConversionProfileId();
		}
		
		$this->impersonate();
		$conversionProfile = $this->kClient->conversionProfile->get($conversionProfileId);
		$this->unimpersonate();
		if(!$conversionProfile || !$conversionProfile->xslTransformation)
			return false;
		$this->conversionProfileXsl = $conversionProfile->xslTransformation;
		return true;
	}

	/**
	 * Transform Xml file with conversion profile xsl
	 * If xsl is not found, original Xml returned
	 * @param string $filePath the original xml that was taken from partner file path 
	 * @return string - transformed Xml
	 */
	protected function xslTransform($filePath)
	{
		$xdoc = file_get_contents($filePath);
		if(is_null($xdoc) || is_null($this->conversionProfileXsl))
			return $xdoc;
		
		libxml_clear_errors();
		$xml = new DOMDocument();
		if(!$xml->loadXML($xdoc)){
			KalturaLog::debug("Could not load xml");
			$errorMessage = kXml::getLibXmlErrorDescription($xdoc);
			throw new KalturaBatchException("Could not load xml [{$this->job->id}], $errorMessage", KalturaBatchJobAppErrors::BULK_VALIDATION_FAILED);
		}
		
		libxml_clear_errors();
		$proc = new XSLTProcessor;
		$xsl = new DOMDocument();
		if(!$xsl->loadXML($this->conversionProfileXsl)){
			KalturaLog::debug("Could not load xsl".$this->conversionProfileXsl);
			$errorMessage = kXml::getLibXmlErrorDescription($this->conversionProfileXsl);
			throw new KalturaBatchException("Could not load xsl [{$this->job->id}], $errorMessage", KalturaBatchJobAppErrors::BULK_VALIDATION_FAILED);
		}
		$proc->importStyleSheet($xsl);
		libxml_clear_errors();
		$transformedXml = $proc->transformToXML($xml);
		if(!$transformedXml){
			KalturaLog::debug("Could not transform xml".$this->conversionProfileXsl);
			$errorMessage = kXml::getLibXmlErrorDescription($this->conversionProfileXsl);
			throw new KalturaBatchException("Could not transform xml [{$this->job->id}], $errorMessage", KalturaBatchJobAppErrors::BULK_VALIDATION_FAILED);
		}
		return $transformedXml;
	}
	
	/**
	 * Parses the Xml file lines and creates the right actions in the system
	 */
	protected function parse()
	{
		$this->currentItem = 0;
		
		$xdoc = new SimpleXMLElement($this->xslTransform($this->data->filePath));
		
		foreach( $xdoc->channel as $channel)
		{
			$this->handleChannel($channel);
			if($this->exceededMaxRecordsEachRun) // exit if we have proccessed max num of items
				return;
		}
	}

	/**
	 * @param string $referenceId
	 * @return string entry id 
	 */
	protected function getEntryIdFromReference($referenceId)
	{
		$existingEntry = $this->getEntryFromReference($referenceId);
		if($existingEntry)
			return $existingEntry->id;
			
		return null;
	}

	/**
	 * @param string $referenceId
	 * @return KalturaBaseEntry
	 */
	protected function getEntryFromReference($referenceId)
	{
		$filter = new KalturaBaseEntryFilter();
		$filter->referenceIdEqual = $referenceId;
		$filter->statusIn = implode(',', array(
			KalturaEntryStatus::ERROR_IMPORTING,
			KalturaEntryStatus::ERROR_CONVERTING,
			KalturaEntryStatus::IMPORT,
			KalturaEntryStatus::PRECONVERT,
			KalturaEntryStatus::READY,
			KalturaEntryStatus::PENDING,
			KalturaEntryStatus::NO_CONTENT,
		));
		$pager = new KalturaFilterPager();
		$pager->pageSize = 1;
		
		$this->impersonate();
		$entries = null;
		try
		{
			$entries = $this->kClient->baseEntry->listAction($filter, $pager);
		}
		catch (KalturaException $e)
		{
			KalturaLog::err($e->getMessage());
		}
		$this->unimpersonate();
		
		/* @var $entries KalturaBaseEntryListResponse */
		if(!$entries || !$entries->totalCount)
			return null;
		
		return reset($entries->objects);
	}

	/**
	 * @param string $entryId
	 * @return KalturaBaseEntry
	 */
	protected function getEntry($entryId)
	{
		$entry = null;
		$this->impersonate();
		try
		{
			$entry = $this->kClient->baseEntry->get($entryId);
		}
		catch (KalturaException $e)
		{
			KalturaLog::err($e->getMessage());
		}
		$this->unimpersonate();
		
		return $entry;
	}

	/**
	 * Gets and handles a channel from the mrss
	 * @param SimpleXMLElement $channel 
	 */
	protected function handleChannel(SimpleXMLElement $channel)
	{
		$startIndex = $this->getStartIndex();
		KalturaLog::debug("startIndex [$startIndex]");
		
		//Gets all items from the channel
		foreach( $channel->item as $item)
		{
			
			if($this->currentItem < $startIndex)
			{
				$this->currentItem++;
				continue;
			}
				
			
			if($this->exceededMaxRecordsEachRun) // exit if we have proccessed max num of items
				return;
			
			$this->currentItem++; //move to the next item (first item is 1)
			try
			{
				$this->checkAborted();
				
				$actionToPerform = self::$actionsMap[KalturaBulkUploadAction::ADD];
						
				$action = KalturaBulkUploadAction::ADD;
				if(isset($item->action))
				{
					$actionToPerform = strtolower($item->action);
				}
				elseif(isset($item->entryId))
				{
					$actionToPerform = self::$actionsMap[KalturaBulkUploadAction::UPDATE];
				}
				elseif(isset($item->referenceId))
				{
					if($this->getEntryIdFromReference("{$item->referenceId}"))
						$actionToPerform = self::$actionsMap[KalturaBulkUploadAction::UPDATE];
				}
				
				switch($actionToPerform)
				{
					case self::$actionsMap[KalturaBulkUploadAction::ADD]:
						$action = KalturaBulkUploadAction::ADD;
						$this->validateItem($item);
						$this->handleItemAdd($item);
						break;
					case self::$actionsMap[KalturaBulkUploadAction::UPDATE]:
						$action = KalturaBulkUploadAction::UPDATE;
						$this->handleItemUpdate($item);						
						break;
					case self::$actionsMap[KalturaBulkUploadAction::DELETE]:
						$action = KalturaBulkUploadAction::DELETE;
						$this->handleItemDelete($item);					
						break;
					default :
						throw new KalturaBatchException("Action: {$actionToPerform} is not supported", KalturaBatchJobAppErrors::BULK_ACTION_NOT_SUPPORTED);
				}
			}
			catch (Exception $e)
			{
				KalturaLog::err('Item failed (' . get_class($e) . '): ' . $e->getMessage());
				$bulkUploadResult = $this->createUploadResult($item, $action);
				$bulkUploadResult->errorDescription = $e->getMessage();
				$bulkUploadResult->entryStatus = KalturaEntryStatus::ERROR_IMPORTING;
				$this->addBulkUploadResult($bulkUploadResult);
			}
		}
	}
	
	/**
	 * Validates the given item so it's valid (some validation can't be enforced in the schema)
	 * @param SimpleXMLElement $item
	 */
	protected function validateItem(SimpleXMLElement $item)
	{
		//Validates that the item type has a matching type element
		$this->validateTypeToTypedElement($item);
	}		
	
	/**
	 * Gets the flavor params from the given flavor asset
	 * @param string $assetId
	 */
	protected function getAssetParamsIdFromAssetId($assetId, $entryId)
	{
		if(is_null($this->assetIdToAssetParamsId[$entryId]))
		{
			$this->initAssetIdToAssetParamsId($entryId);
		}
		
		if(isset($this->assetIdToAssetParamsId[$entryId][$assetId]))
		{
			return $this->assetIdToAssetParamsId[$entryId][$assetId];
		}
		else //The asset wasn't found on the entry
		{
			throw new KalturaBatchException("Asset Id [$assetId] not found on entry [$entryId]", KalturaBatchJobAppErrors::BULK_ITEM_VALIDATION_FAILED);
		}
	}
	
	/**
	 * Removes all non updatble fields from the entry
	 * @param KalturaBaseEntry $entry
	 */
	protected function removeNonUpdatbleFields(KalturaBaseEntry $entry)
	{
		$retEntry = clone $entry;
		$retEntry->conversionProfileId = null;
		return $retEntry;
	}
	
	/**
	 * Handles xml bulk upload update
	 * @param SimpleXMLElement $item
	 * @throws KalturaException
	 */
	protected function handleItemUpdate(SimpleXMLElement $item)
	{
		KalturaLog::debug("xml [" . $item->asXML() . "]");
		
		$entryId = null;
		$conversionProfileId = null;
		if(isset($item->entryId))
		{
			$entryId = "{$item->entryId}";
			
			$existingEntry = $this->getEntry($entryId);
			if(!$existingEntry)
				throw new KalturaBatchException("Entry id [$entryId] not found", KalturaBatchJobAppErrors::BULK_ITEM_NOT_FOUND);
				
			$conversionProfileId = $existingEntry->conversionProfileId;
		}
		elseif(isset($item->referenceId))
		{
			$existingEntry = $this->getEntryFromReference("{$item->referenceId}");
			if(!$existingEntry)
				throw new KalturaBatchException("Reference id [{$item->referenceId}] not found", KalturaBatchJobAppErrors::BULK_ITEM_NOT_FOUND);
				
			$entryId = $existingEntry->id;
			$conversionProfileId = $existingEntry->conversionProfileId;
		}
		else
		{
			throw new KalturaBatchException("Missing entry id element", KalturaBatchJobAppErrors::BULK_MISSING_MANDATORY_PARAMETER);
		}
		
		// Overwriting conversionProfileId if one is supplied in the XML
		if(isset($item->conversionProfileId) || isset($item->conversionProfile))
			$conversionProfileId = $this->getConversionProfileId($item);
		KalturaLog::DEBUG("Conversion profile found within XML - setting to [ $conversionProfileId ]");
		
		//Throw exception in case of max proccessed items and handle all exceptions there
		$updatedEntryBulkUploadResult = $this->createUploadResult($item, KalturaBulkUploadAction::UPDATE);
		
		if($this->exceededMaxRecordsEachRun) // exit if we have proccessed max num of items
			return;

		$entry = $this->createEntryFromItem($item, $existingEntry->type); //Creates the entry from the item element
		
		$this->handleTypedElement($entry, $item); //Sets the typed element values (Mix, Media, ...)
		KalturaLog::debug("current entry is: " . print_r($entry, true));
				
		$thumbAssets = array();
		$thumbAssetsResources = array();
		$flavorAssets = array();
		$flavorAssetsResources = array();
		$noParamsThumbAssets = array(); //Holds the no flavor params thumb assests
		$noParamsThumbResources = array(); //Holds the no flavor params resources assests
		$noParamsFlavorAssets = array();  //Holds the no flavor params flavor assests
		$noParamsFlavorResources = array(); //Holds the no flavor params flavor resources
		$flavorAssetsForUpdate = array();
		$flavorResources = array();
		$thumbAssetsForUpdate = array();
		$thumbResources = array();
		$resource = new KalturaAssetsParamsResourceContainers(); // holds all teh needed resources for the conversion
		$resource->resources = array();
		
		
		if(isset($item->contentAssets->action) && (isset($item->thumbnails->action)))
		{
			$contentAssetsAction = strtolower($item->contentAssets->action);
			$thumbnailsAction = strtolower($item->thumbnails->action);
		}
		elseif (isset($item->contentAssets->action))
		{
			$contentAssetsAction = strtolower($item->contentAssets->action);
			$thumbnailsAction = strtolower($item->contentAssets->action);
		}
		elseif (isset($item->thumbnails->action))
		{
			$contentAssetsAction = strtolower($item->thumbnails->action);
			$thumbnailsAction = strtolower($item->thumbnails->action);
		}
		else
		{
			//default action to perfom for assets and thumbnails is replace
			$contentAssetsAction = self::$actionsMap[KalturaBulkUploadAction::REPLACE];
			$thumbnailsAction = self::$actionsMap[KalturaBulkUploadAction::REPLACE];
		}
		
		
		
		if (isset($item->contentAssets->action) && isset($item->thumbnails->action) && ($contentAssetsAction != $thumbnailsAction))
			throw new KalturaBatchException("ContentAsset->action: {$contentAssetsAction} must be the same as thumbnails->action: {$thumbnailsAction}", KalturaBatchJobAppErrors::BULK_ACTION_NOT_SUPPORTED);
		
		//For each content in the item element we add a new flavor asset
		if(isset($item->contentAssets))
		{		
			foreach ($item->contentAssets->content as $contentElement)
			{
				KalturaLog::debug("contentElement [" . print_r($contentElement->asXml(), true). "]");
				
				if(empty($contentElement)) // if the content is empty skip
				{
					continue;
				}
								
				$flavorAsset = $this->getFlavorAsset($contentElement, $conversionProfileId);
				$flavorAssetResource = $this->getResource($contentElement, $conversionProfileId);
				if(!$flavorAssetResource)
					continue;
				
				$assetParamsId = $flavorAsset->flavorParamsId;
	
				$assetId = kXml::getXmlAttributeAsString($contentElement, "assetId");
				if($assetId) // if we have an asset id then we need to update the asset
				{
					KalturaLog::debug("Asset id [ $assetId]");
					$assetParamsId = $this->getAssetParamsIdFromAssetId($assetId, $entryId);
				}
			
				KalturaLog::debug("assetParamsId [$assetParamsId]");
							
				if(is_null($assetParamsId)) // no params resource
				{
					$noParamsFlavorAssets[] = $flavorAsset;
					$noParamsFlavorResources[] = $flavorAssetResource;
					continue;
				}
				else 
				{
					$flavorAssetsResources[$flavorAsset->flavorParamsId] = $flavorAssetResource;
				}
				
				$flavorAssets[$flavorAsset->flavorParamsId] = $flavorAsset;
				$assetResource = new KalturaAssetParamsResourceContainer();
				$assetResource->resource = $flavorAssetResource;
				$assetResource->assetParamsId = $assetParamsId;
				$resource->resources[] = $assetResource;
			}
		}
		
		//For each thumbnail in the item element we create a new thumb asset
		if(isset($item->thumbnails))
		{
			foreach ($item->thumbnails->thumbnail as $thumbElement)
			{
				if(empty($thumbElement)) // if the content is empty
				{
					continue;
				}
				
				KalturaLog::debug("thumbElement [" . print_r($thumbElement->asXml(), true). "]");
							
				$thumbAsset = $this->getThumbAsset($thumbElement, $conversionProfileId);
				$thumbAssetResource = $this->getResource($thumbElement, $conversionProfileId);
				if(!$thumbAssetResource)
					continue;
										
				$assetParamsId = $thumbAsset->thumbParamsId;
	
				$assetId = kXml::getXmlAttributeAsString($thumbElement, "assetId");
				if($assetId) // if we have an asset id then we need to update the asset
				{
					KalturaLog::debug("Asset id [ $assetId]");
					$assetParamsId = $this->getAssetParamsIdFromAssetId($assetId, $entryId);
				}
							
				KalturaLog::debug("assetParamsId [$assetParamsId]");
				
				if(is_null($assetParamsId))
				{
					$noParamsThumbAssets[] = $thumbAsset;
					$noParamsThumbResources[] = $thumbAssetResource;
					continue;
				}
				else
				{
					$thumbAssetsResources[$thumbAsset->thumbParamsId] = $thumbAssetResource;
				}
				
				$thumbAssets[$thumbAsset->thumbParamsId] = $thumbAsset;
				$assetResource = new KalturaAssetParamsResourceContainer();
				$assetResource->resource = $thumbAssetResource;
				$assetResource->assetParamsId = $assetParamsId;
				$resource->resources[] = $assetResource;
			}
		}
		
		if(!count($resource->resources))
		{
			if (count($noParamsFlavorResources) == 1)
			{
				$resource = reset($noParamsFlavorResources);
				$noParamsFlavorResources = array();
				$noParamsFlavorAssets = array();
			}
			else
			{
				$resource = null;
			}
		}
		
		switch($contentAssetsAction)
		{
			case self::$actionsMap[KalturaBulkUploadAction::UPDATE]:
				$entry = $this->sendItemUpdateData($entryId, $entry, $flavorAssets, $flavorAssetsResources, $thumbAssets, $thumbAssetsResources);
				break;
			case self::$actionsMap[KalturaBulkUploadAction::REPLACE]:
				$entry = $this->sendItemReplaceData($entryId, $entry, $resource, 
												  $noParamsFlavorAssets, $noParamsFlavorResources, 
												  $noParamsThumbAssets, $noParamsThumbResources);
				$entryId = $entry->id;
				break;
			default :
				throw new KalturaBatchException("Action: {$contentAssetsAction} is not supported", KalturaBatchJobAppErrors::BULK_ACTION_NOT_SUPPORTED);
		}
							  
		//Adds the additional data for the flavors and thumbs
		$this->handleFlavorAndThumbsAdditionalData($entryId, $flavorAssets, $thumbAssets);
				
		//Handles the plugin added data
		$pluginsErrorResults = array();
		$pluginsInstances = KalturaPluginManager::getPluginInstances('IKalturaBulkUploadXmlHandler');
		foreach($pluginsInstances as $pluginsInstance)
		{
			/* @var $pluginsInstance IKalturaBulkUploadXmlHandler */
			try {
				$pluginsInstance->configureBulkUploadXmlHandler($this);
				$pluginsInstance->handleItemUpdated($entry, $item);
			}catch (Exception $e)
			{
				KalturaLog::err($pluginsInstance->getContainerName() . ' failed: ' . $e->getMessage());
				$pluginsErrorResults[] = $pluginsInstance->getContainerName() . ' failed: ' . $e->getMessage();
			}
		}
		
		if(count($pluginsErrorResults))
			throw new Exception(implode(', ', $pluginsErrorResults));
	
		//Updates the bulk upload result for the given entry (with the status and other data)
		$this->updateObjectsResults(array($entry), array($updatedEntryBulkUploadResult));
	}

	/**
	 * (non-PHPdoc)
	 * @see KBulkUploadEngine::addBulkUploadResult()
	 */
	protected function addBulkUploadResult(KalturaBulkUploadResult $bulkUploadResult)
	{
		parent::addBulkUploadResult($bulkUploadResult);
					
		$this->handledRecordsThisRun++; //adds one to the count of handled records
	}
	
	/**
	 * Sends the data using a multi requsest according to the given data
	 * @param int $entryID
	 * @param KalturaBaseEntry $entry
	 * @param KalturaResource $resource - the main resource collection for the entry
	 * @param array $noParamsFlavorAssets - Holds the no flavor params flavor assets 
	 * @param array $noParamsFlavorResources - Holds the no flavor params flavor resources
	 * @param array $noParamsThumbAssets - Holds the no flavor params thumb assets
	 * @param array $noParamsThumbResources - Holds the no flavor params thumb resources
	 * @return $requestResults - the multi request result
	 */
	protected function sendItemReplaceData($entryId, KalturaBaseEntry $entry ,KalturaResource $resource = null, 
										array $noParamsFlavorAssets, array $noParamsFlavorResources, 
										array $noParamsThumbAssets, array $noParamsThumbResources)
	{
		
		KalturaLog::debug("Resource is: " . print_r($resource, true));
		
		$this->impersonate();
		$updateEntry = $this->removeNonUpdatbleFields($entry);
		$updatedEntry = $this->kClient->baseEntry->get($entryId);
		
		$this->kClient->startMultiRequest();
		
		$updatedEntryId = $updatedEntry->id;   	
		if(!is_null($updatedEntry->replacingEntryId))
			$updatedEntryId = $updatedEntry->replacingEntryId;
					
		if($resource)
			$this->kClient->baseEntry->updateContent($updatedEntryId ,$resource, $entry->conversionProfileId); //to create a temporery entry.
		
		foreach($noParamsFlavorAssets as $index => $flavorAsset) // Adds all the entry flavors
		{
			$flavorResource = $noParamsFlavorResources[$index];
			$flavor = $this->kClient->flavorAsset->add($updatedEntryId, $flavorAsset);
			$this->kClient->flavorAsset->setContent($this->kClient->getMultiRequestResult()->id, $flavorResource);		// TODO: use flavor instead of getMultiRequestResult
		}
		
		foreach($noParamsThumbAssets as $index => $thumbAsset) //Adds the entry thumb assests
		{
			$thumbResource = $noParamsThumbResources[$index];
			$thumb = $this->kClient->thumbAsset->add($updatedEntryId, $thumbAsset);
			$this->kClient->thumbAsset->setContent($this->kClient->getMultiRequestResult()->id, $thumbResource);		// TODO: use thumb instead of getMultiRequestResult
		}
		
		$requestResults = $this->kClient->doMultiRequest();
		
		//update is after add content since in case entry replacement we want the duration to be set on the new entry.
		$updatedEntry = $this->kClient->baseEntry->update($entryId, $updateEntry);
		
		$this->unimpersonate();
		
		if(is_array($requestResults))
			foreach($requestResults as $requestResult)
				if($requestResult instanceof Exception)
					throw $requestResult;
		
		return $updatedEntry;
	}

	/**
	 * Handles xml bulk upload delete
	 * @param SimpleXMLElement $item
	 * @throws KalturaException
	 */
	protected function handleItemDelete(SimpleXMLElement $item)
	{
		$entryId = null;
		if(isset($item->entryId))
		{
			$entryId = "{$item->entryId}";
		}
		elseif(isset($item->referenceId))
		{
			$entryId = $this->getEntryIdFromReference("{$item->referenceId}");
			if(!$entryId)
				throw new KalturaBatchException("Reference id [{$item->referenceId}] not found", KalturaBatchJobAppErrors::BULK_ITEM_NOT_FOUND);
		}
		else
		{
			throw new KalturaBatchException("Missing entry id element", KalturaBatchJobAppErrors::BULK_MISSING_MANDATORY_PARAMETER);
		}
		
		$this->impersonate();
		$result = $this->kClient->baseEntry->delete($entryId);
		$this->unimpersonate();
		
		$bulkUploadResult = $this->createUploadResult($item, KalturaBulkUploadAction::DELETE);
		
		if($this->exceededMaxRecordsEachRun) // exit if we have proccessed max num of items
			return;
		
		$bulkUploadResult->entryId = $entryId;
		$this->addBulkUploadResult($bulkUploadResult);
	}

	/**
	 * Gets an item and insert it into the system
	 * @param SimpleXMLElement $item
	 */
	protected function handleItemAdd(SimpleXMLElement $item)
	{
		KalturaLog::debug("xml [" . $item->asXML() . "]");
		
		//Throw exception in case of  max proccessed items and handle all exceptions there
		$createdEntryBulkUploadResult = $this->createUploadResult($item, KalturaBulkUploadAction::ADD);

		if($this->exceededMaxRecordsEachRun) // exit if we have proccessed max num of items
			return;
		
		$entry = $this->createEntryFromItem($item); //Creates the entry from the item element
		$this->handleTypedElement($entry, $item); //Sets the typed element values (Mix, Media, ...)
		KalturaLog::debug("current entry is: " . print_r($entry, true));
				
		$thumbAssets = array();
		$flavorAssets = array();
		$noParamsThumbAssets = array(); //Holds the no flavor params thumb assests
		$noParamsThumbResources = array(); //Holds the no flavor params resources assests
		$noParamsFlavorAssets = array();  //Holds the no flavor params flavor assests
		$noParamsFlavorResources = array(); //Holds the no flavor params flavor resources
		$resource = new KalturaAssetsParamsResourceContainers(); // holds all teh needed resources for the conversion
		$resource->resources = array();

		//For each content in the item element we add a new flavor asset
		if(isset($item->contentAssets))
		{		
			foreach ($item->contentAssets->content as $contentElement)
			{
				$assetResource = $this->getResource($contentElement, $entry->conversionProfileId);
				if(!$assetResource)
					continue;
					
				$assetResourceContainer = new KalturaAssetParamsResourceContainer();
				$flavorAsset = $this->getFlavorAsset($contentElement, $entry->conversionProfileId);
				
				if(is_null($flavorAsset->flavorParamsId))
				{
					KalturaLog::debug("flavorAsset [". print_r($flavorAsset, true) . "]");
					$noParamsFlavorAssets[] = $flavorAsset;
					$noParamsFlavorResources[] = $assetResource;
				}
				else 
				{
					KalturaLog::debug("flavorAsset->flavorParamsId [$flavorAsset->flavorParamsId]");
					$flavorAssets[$flavorAsset->flavorParamsId] = $flavorAsset;
					$assetResourceContainer->assetParamsId = $flavorAsset->flavorParamsId;
					$assetResourceContainer->resource = $assetResource;
					$resource->resources[] = $assetResourceContainer;
				}
			}
		}

		//For each thumbnail in the item element we create a new thumb asset
		if(isset($item->thumbnails))
		{
			foreach ($item->thumbnails->thumbnail as $thumbElement)
			{
				$assetResource = $this->getResource($thumbElement, $entry->conversionProfileId);
				if(!$assetResource)
					continue;
					
				$assetResourceContainer = new KalturaAssetParamsResourceContainer();
				$thumbAsset = $this->getThumbAsset($thumbElement, $entry->conversionProfileId);
				
				if(is_null($thumbAsset->thumbParamsId))
				{
					KalturaLog::debug("thumbAsset [". print_r($thumbAsset, true) . "]");
					$noParamsThumbAssets[] = $thumbAsset;
					$noParamsThumbResources[] = $assetResource;
				}
				else //we have a thumbParamsId so we add to the resources
				{
					KalturaLog::debug("thumbAsset->thumbParamsId [$thumbAsset->thumbParamsId]");
					$thumbAssets[$thumbAsset->thumbParamsId] = $thumbAsset;
					$assetResourceContainer->assetParamsId = $thumbAsset->thumbParamsId;
					$assetResourceContainer->resource = $assetResource;
					$resource->resources[] = $assetResourceContainer;
				}
			}
		}

		if(!count($resource->resources))
		{
			if (count($noParamsFlavorResources) == 1)
			{
				$resource = reset($noParamsFlavorResources);
				$noParamsFlavorResources = array();
				$noParamsFlavorAssets = array();
			}
			else
			{
				$resource = null;
			}
		}

		$createdEntry = $this->sendItemAddData($entry, $resource, $noParamsFlavorAssets, $noParamsFlavorResources, $noParamsThumbAssets, $noParamsThumbResources);
			
		//Updates the bulk upload result for the given entry (with the status and other data)
		$this->updateObjectsResults(array($createdEntry), array($createdEntryBulkUploadResult));
		
		//Adds the additional data for the flavors and thumbs
		$this->handleFlavorAndThumbsAdditionalData($createdEntry->id, $flavorAssets, $thumbAssets);
				
		//Handles the plugin added data
		$pluginsErrorResults = array();
		$pluginsInstances = KalturaPluginManager::getPluginInstances('IKalturaBulkUploadXmlHandler');
		foreach($pluginsInstances as $pluginsInstance)
		{
			/* @var $pluginsInstance IKalturaBulkUploadXmlHandler */
			try {
				$pluginsInstance->configureBulkUploadXmlHandler($this);
				$pluginsInstance->handleItemAdded($createdEntry, $item);
			}catch (Exception $e)
			{
				KalturaLog::err($pluginsInstance->getContainerName() . ' failed: ' . $e->getMessage());
				$pluginsErrorResults[] = $pluginsInstance->getContainerName() . ' failed: ' . $e->getMessage();
			}
		}
		
		if(count($pluginsErrorResults))
			throw new Exception(implode(', ', $pluginsErrorResults));
	
	}
	
	/**
	 * Sends the data using a multi requsest according to the given data
	 * @param KalturaBaseEntry $entry
	 * @param KalturaResource $resource
	 * @param array $noParamsFlavorAssets
	 * @param array $noParamsFlavorResources
	 * @param array $noParamsThumbAssets
	 * @param array $noParamsThumbResources
	 * @return $requestResults - the multi request result
	 */
	protected function sendItemAddData(KalturaBaseEntry $entry ,KalturaResource $resource = null, array $noParamsFlavorAssets, array $noParamsFlavorResources, array $noParamsThumbAssets, array $noParamsThumbResources)
	{	
		$this->impersonate();
		$this->kClient->startMultiRequest();
		
		KalturaLog::debug("Resource is: " . print_r($resource, true));
		
		$this->kClient->baseEntry->add($entry); //Adds the entry 
		$newEntryId = $this->kClient->getMultiRequestResult()->id;							// TODO: use the return value of add instead of getMultiRequestResult
		
		if($resource)
			$this->kClient->baseEntry->addContent($newEntryId, $resource); // adds the entry resources
		
		foreach($noParamsFlavorAssets as $index => $flavorAsset) // Adds all the entry flavors
		{
			$flavorResource = $noParamsFlavorResources[$index];
			$flavor = $this->kClient->flavorAsset->add($newEntryId, $flavorAsset);
			$this->kClient->flavorAsset->setContent($this->kClient->getMultiRequestResult()->id, $flavorResource);			// TODO: use flavor instead of getMultiRequestResult
		}
		
		foreach($noParamsThumbAssets as $index => $thumbAsset) //Adds the entry thumb assests
		{
			
			$thumbResource = $noParamsThumbResources[$index];
			$thumb = $this->kClient->thumbAsset->add($newEntryId, $thumbAsset, $thumbResource);
			$this->kClient->thumbAsset->setContent($this->kClient->getMultiRequestResult()->id, $thumbResource);			// TODO: use thumb instead of getMultiRequestResult
		}
							
		$requestResults = $this->kClient->doMultiRequest();;
		$this->unimpersonate();
		
		foreach($requestResults as $requestResult)
			if($requestResult instanceof Exception)
				throw $requestResult;
		
		$createdEntry = reset($requestResults);
		if(is_null($createdEntry)) //checks that the entry was created
			throw new KalturaBulkUploadXmlException("The entry wasn't created", KalturaBatchJobAppErrors::BULK_ITEM_VALIDATION_FAILED);
		
		if(!($createdEntry instanceof KalturaObjectBase)) // if the entry is not kaltura object (in case of errors)
			throw new KalturaBulkUploadXmlException("Returned type is [" . get_class($createdEntry) . "], KalturaObjectBase was expected", KalturaBatchJobAppErrors::BULK_ITEM_VALIDATION_FAILED);
		
		return $createdEntry;
	}
	
		/**
	 * Handles the adding of additional data to the preciously created flavors and thumbs 
	 * @param int $createdEntryId
	 * @param array $flavorAssets
	 * @param array $thumbAssets
	 */
	protected function handleFlavorAndThumbsAdditionalData($createdEntryId, $flavorAssets, $thumbAssets)
	{
		$this->impersonate();
		$this->kClient->startMultiRequest();
		$this->kClient->flavorAsset->getByEntryId($createdEntryId);
		$this->kClient->thumbAsset->getByEntryId($createdEntryId);
		$result = $this->kClient->doMultiRequest();
		
		foreach($result as $requestResult)
			if($requestResult instanceof Exception)
				throw $requestResult;
		
		$createdFlavorAssets = $result[0]; 
		$createdThumbAssets =  $result[1];
				
		$this->kClient->startMultiRequest();
		///For each flavor asset that we just added without his data then we need to update his additional data
		foreach($createdFlavorAssets as $createdFlavorAsset)
		{
			if(is_null($createdFlavorAsset->flavorParamsId)) //no flavor params to the flavor asset
				continue;
				
			if(!isset($flavorAssets[$createdFlavorAsset->flavorParamsId])) // We don't have the flavor in our dictionary
				continue;
			
			$flavorAsset = $flavorAssets[$createdFlavorAsset->flavorParamsId];
			$this->kClient->flavorAsset->update($createdFlavorAsset->id, $flavorAsset);
		}
		
		foreach($createdThumbAssets as $createdThumbAsset)
		{
			if(is_null($createdThumbAsset->thumbParamsId))
				continue;
				
			if(!isset($thumbAssets[$createdThumbAsset->thumbParamsId]))
				continue;
				
			$thumbAsset = $thumbAssets[$createdThumbAsset->thumbParamsId];
			$this->kClient->thumbAsset->update($createdThumbAsset->id, $thumbAsset);
		}
		
		$requestResults = $this->kClient->doMultiRequest();
		$this->unimpersonate();

		if(is_array($requestResults))
			foreach($requestResults as $requestResult)
				if($requestResult instanceof Exception)
					throw $requestResult;
		
		return $requestResults;
	}
	
	/**
	 * Handles the adding of additional data to the preciously created flavors and thumbs 
	 * @param int $entryId
	 * @param KalturaBaseEntry $entry
	 * @param array $flavorAssets
	 * @param array $flavorAssetsResources
	 * @param array $thumbAssets
	 * @param array $thumbAssetsResources
	 */
	protected function sendItemUpdateData($entryId, $entry, array $flavorAssets, array $flavorAssetsResources, array $thumbAssets, array $thumbAssetsResources)
	{
		$this->impersonate();
		$updateEntry = $this->removeNonUpdatbleFields($entry);
		$updatedEntry = $this->kClient->baseEntry->update($entryId, $updateEntry);
		
		$this->kClient->startMultiRequest();
		$this->kClient->flavorAsset->getByEntryId($entryId);
		$this->kClient->thumbAsset->getByEntryId($entryId);
		$result = $this->kClient->doMultiRequest();
		
		foreach($result as $requestResult)
			if($requestResult instanceof Exception)
				throw $requestResult;
		
		$createdFlavorAssets = $result[0]; 
		$createdThumbAssets =  $result[1];
		$existingflavorAssets = array();
		$existingthumbAssets = array();
				
		foreach($createdFlavorAssets as $createdFlavorAsset)
		{
			if(is_null($createdFlavorAsset->flavorParamsId)) //no flavor params to the flavor asset
				continue;
				
			$existingflavorAssets[$createdFlavorAsset->flavorParamsId] = $createdFlavorAsset->id;
		}
		
		$this->kClient->startMultiRequest();
		foreach ($flavorAssetsResources as $flavorParamsId => $flavorAssetsResource)
		{
			if(!isset($existingflavorAssets[$flavorParamsId]))
			{
				$this->kClient->flavorAsset->add($entryId, $flavorAssets[$flavorParamsId]);
				$this->kClient->flavorAsset->setContent($this->kClient->getMultiRequestResult()->id, $flavorAssetsResource);
			}else{
				$this->kClient->flavorAsset->update($existingflavorAssets[$flavorParamsId], $flavorAssets[$flavorParamsId]);
				$this->kClient->flavorAsset->setContent($existingflavorAssets[$flavorParamsId], $flavorAssetsResource);
			}			
		}
		
		foreach($createdThumbAssets as $createdThumbAsset)
		{
			if(is_null($createdThumbAsset->thumbParamsId))
				continue;
				
			$existingthumbAssets[$createdThumbAsset->thumbParamsId] = $createdThumbAsset->id;
		}
		
		
		foreach($thumbAssetsResources as $thumbParamsId => $thumbAssetsResource)
		{
			if(!isset($existingthumbAssets[$thumbParamsId]))
			{
				$this->kClient->thumbAsset->add($entryId, $thumbAssets[$thumbParamsId]);
				$this->kClient->thumbAsset->setContent($this->kClient->getMultiRequestResult()->id, $thumbAssetsResource);				
			}else{
				$this->kClient->thumbAsset->update($existingthumbAssets[$thumbParamsId], $thumbAssets[$thumbParamsId]);
				$this->kClient->thumbAsset->setContent($existingthumbAssets[$thumbParamsId], $thumbAssetsResource);
			}	
		}
		
		$requestResults = $this->kClient->doMultiRequest();
		$this->unimpersonate();
		
		return $updatedEntry;
	}
	
	/**
	 * returns a flavor asset form the current content element
	 * @param SimpleXMLElement $contentElement
	 * @return KalturaFlavorAsset
	 */
	protected function getFlavorAsset(SimpleXMLElement $contentElement, $conversionProfileId)
	{
		$flavorAsset = new KalturaFlavorAsset(); //we create a new asset (for add)
		$flavorAsset->flavorParamsId = $this->getFlavorParamsId($contentElement, $conversionProfileId, true);
		$flavorAsset->tags = $this->implodeChildElements($contentElement->tags);
			
		return $flavorAsset;
	}
	
	/**
	 * returns a thumbnail asset form the current thumbnail element
	 * @param SimpleXMLElement $thumbElement
	 * @param int $conversionProfileId - The converrsion profile id 
	 * @return KalturaThumbAsset
	 */
	protected function getThumbAsset(SimpleXMLElement $thumbElement, $conversionProfileId)
	{
		$thumbAsset = new KalturaThumbAsset();
		$thumbAsset->thumbParamsId = $this->getThumbParamsId($thumbElement, $conversionProfileId);
		
		if(isset($thumbElement["isDefault"]) && $thumbElement["isDefault"] == 'true') // if the attribute is set to true we add the is default tag to the thumb
			$thumbAsset->tags = self::DEFAULT_THUMB_TAG;
		
		$thumbAsset->tags = $this->implodeChildElements($thumbElement->tags, $thumbAsset->tags);
		
		return $thumbAsset;
	}
	
	/**
	 * Validates if the resource is valid
	 * @param KalturaResource $resource
	 * @param SimpleXMLElement $elementToSearchIn
	 */
	protected function validateResource(KalturaResource $resource = null, SimpleXMLElement $elementToSearchIn)
	{
		if(!$resource)
			return;
			
		//We only check for filesize and check sum in local files 
		if($resource instanceof KalturaServerFileResource)
		{
			$filePath = $resource->localFilePath;
			
			if(is_null($filePath))
			{
				throw new KalturaBulkUploadXmlException("Can't validate file as file path is null", KalturaBatchJobAppErrors::BULK_ITEM_VALIDATION_FAILED);
			}
				
			if(isset($elementToSearchIn->serverFileContentResource->fileChecksum)) //Check checksum if exists
			{
				KalturaLog::debug("Validating checksum");
				if($elementToSearchIn->serverFileContentResource->fileChecksum['type'] == 'sha1')
				{
					 $checksum = sha1_file($filePath);
				}
				else
				{
					$checksum = md5_file($filePath);
				}
				
				$xmlChecksum = (string)$elementToSearchIn->serverFileContentResource->fileChecksum;

				if($xmlChecksum != $checksum)
				{
					throw new KalturaBulkUploadXmlException("File checksum is invalid for file [$filePath], Xml checksum [$xmlChecksum], actual checksum [$checksum]", KalturaBatchJobAppErrors::BULK_ITEM_VALIDATION_FAILED);
				}
			}
			
			if(isset($elementToSearchIn->serverFileContentResource->fileSize)) //Check checksum if exists
			{
				KalturaLog::debug("Validating file size");
				
				$fileSize = kFile::fileSize($filePath);
				$xmlFileSize = (int)$elementToSearchIn->serverFileContentResource->fileSize;
				if($xmlFileSize != $fileSize)
				{
					throw new KalturaBulkUploadXmlException("File size is invalid for file [$filePath], Xml size [$xmlFileSize], actual size [$fileSize]", KalturaBatchJobAppErrors::BULK_ITEM_VALIDATION_FAILED);
				}
			}
		}
	}
	
	/**
	 * Gets an item and returns the resource
	 * @param SimpleXMLElement $elementToSearchIn
	 * @param int $conversionProfileId
	 * @return KalturaResource - the resource located in the given element
	 */
	public function getResource(SimpleXMLElement $elementToSearchIn, $conversionProfileId)
	{
		$resource = $this->getResourceInstance($elementToSearchIn, $conversionProfileId);
		if($resource)
			$this->validateResource($resource, $elementToSearchIn);
										
		return $resource;
	}
	
	/**
	 * Returns the right resource instance for the source content of the item
	 * @param SimpleXMLElement $elementToSearchIn
	 * @param int $conversionProfileId
	 * @return KalturaResource - the resource located in the given element
	 */
	protected function getResourceInstance(SimpleXMLElement $elementToSearchIn, $conversionProfileId)
	{
		$resource = null;
			
		if(isset($elementToSearchIn->serverFileContentResource))
		{
			if($this->allowServerResource)
			{
				KalturaLog::debug("Resource is : serverFileContentResource");
				$resource = new KalturaServerFileResource();
				$localContentResource = $elementToSearchIn->serverFileContentResource;
				$resource->localFilePath = kXml::getXmlAttributeAsString($localContentResource, "filePath");
			}
			else
			{
				KalturaLog::err("serverFileContentResource is not allowed");
			}
		}
		elseif(isset($elementToSearchIn->urlContentResource))
		{
			KalturaLog::debug("Resource is : urlContentResource");
			$resource = new KalturaUrlResource();
			$urlContentResource = $elementToSearchIn->urlContentResource;
			$resource->url = kXml::getXmlAttributeAsString($urlContentResource, "url");
		}
		elseif(isset($elementToSearchIn->sshUrlContentResource))
		{
			KalturaLog::debug("Resource is : sshUrlContentResource");
			$resource = new KalturaSshUrlResource();
			$sshUrlContentResource = $elementToSearchIn->sshUrlContentResource;
			$resource->url = kXml::getXmlAttributeAsString($sshUrlContentResource, "url");
			$resource->privateKey = kXml::getXmlAttributeAsString($sshUrlContentResource, "privateKey");
			$resource->publicKey = kXml::getXmlAttributeAsString($sshUrlContentResource, "publicKey");
			$resource->keyPassphrase = kXml::getXmlAttributeAsString($sshUrlContentResource, "keyPassphrase");
		}
		elseif(isset($elementToSearchIn->remoteStorageContentResource))
		{
			KalturaLog::debug("Resource is : remoteStorageContentResource");
			$resource = new KalturaRemoteStorageResource();
			$remoteContentResource = $elementToSearchIn->remoteStorageContentResource;
			$resource->url = kXml::getXmlAttributeAsString($remoteContentResource, "url");
			$resource->storageProfileId = $this->getStorageProfileId($remoteContentResource);
		}
		elseif(isset($elementToSearchIn->remoteStorageContentResources))
		{
			KalturaLog::debug("Resource is : remoteStorageContentResources");
			$resource = new KalturaRemoteStorageResources();
			$resource->resources = array();
			$remoteContentResources = $elementToSearchIn->remoteStorageContentResources;
			
			foreach($remoteContentResources->remoteStorageContentResource as $remoteContentResource)
			{
				/* @var $remoteContentResource SimpleXMLElement */
				KalturaLog::debug("Resources name [" . $remoteContentResource->getName() . "] url [" . $remoteContentResource['url'] . "] storage [$remoteContentResource->storageProfile]");
				$childResource = new KalturaRemoteStorageResource();
				$childResource->url = kXml::getXmlAttributeAsString($remoteContentResource, "url");
				$childResource->storageProfileId = $this->getStorageProfileId($remoteContentResource);
				$resource->resources[] = $childResource;<commit_msg>qnd: support ssh content resource<commit_after><?php
/**
 * Class for the handling Bulk upload using XML in the system 
 * 
 * @package Scheduler
 * @subpackage Provision
 */
class BulkUploadEngineXml extends KBulkUploadEngine
{
	/**
	 * The defalut thumbnail tag
	 * @var string
	 */
	const DEFAULT_THUMB_TAG = 'default_thumb';
	
	/**
	 * The default ingestion profile id
	 * @var int
	 */
	private $defaultConversionProfileId = null;
	
	/**
	 * Holds the number of the current proccessed item
	 * @var int
	 */
	private $currentItem = 0;
	
	/**
	 * The engine xsd file path
	 * @var string
	 */
	protected $xsdFilePath = null;
	
	/**
	 * Allows the usage of server content resource
	 * @var bool
	 */
	protected $allowServerResource = false;
	
	/**
	 * Maps the flavor params name to id
	 * @var array()
	 */
	private $assetParamsNameToIdPerConversionProfile = null;

	/**
	 * Maps the asset id to flavor params id
	 * @var array()
	 */
	private $assetIdToAssetParamsId = null;
	
	/**
	 * Maps the access control name to id
	 * @var array()
	 */
	private $accessControlNameToId = null;
	
	/**
	 * Maps the converstion profile name to id
	 * @var array()
	 */
	private $conversionProfileNameToId = array();
	
	/**
	 * Maps the storage profile name to id
	 * @var array()
	 */
	private $storageProfileNameToId = null;
	
	/**
	 * Conversion profile xsl file
	 * @var string
	 */
	protected $conversionProfileXsl = null;

	/**
	 * @param KSchedularTaskConfig $taskConfig
	 * @param KalturaClient $kClient
	 * @param KalturaBatchJob $job
	 */
	public function __construct( KSchedularTaskConfig $taskConfig, KalturaClient $kClient, KalturaBatchJob $job)
	{
		parent::__construct($taskConfig, $kClient, $job);
		
		$this->xsdFilePath = 'http://' . kConf::get('www_host') . '/api_v3/index.php/service/schema/action/serve/type/' . KalturaSchemaType::BULK_UPLOAD_XML;
		if($taskConfig->params->xsdFilePath) 
			$this->xsdFilePath = $taskConfig->params->xsdFilePath;
			
		if($taskConfig->params->allowServerResource) 
			$this->allowServerResource = (bool) $taskConfig->params->allowServerResource;
	}
	
	/* (non-PHPdoc)
	 * @see KBulkUploadEngine::HandleBulkUpload()
	 */
	public function handleBulkUpload() 
	{
		$this->validate();
	    $this->parse();
	}
	
	/**
	 * Validates that the xml is valid using the XSD
	 *@return bool - if the validation is ok
	 */
	protected function validate() 
	{
		if(!file_exists($this->data->filePath))
		{
			throw new KalturaBatchException("File doesn't exist [{$this->data->filePath}]", KalturaBatchJobAppErrors::BULK_FILE_NOT_FOUND);
		}
		
		libxml_use_internal_errors(true);
		
		$this->loadXslt();
			
		$xdoc = new DomDocument();
		
		$xmlContent = $this->xslTransform($this->data->filePath);
		libxml_clear_errors();
		if(!$xdoc->loadXML($xmlContent)){
			$errorMessage = kXml::getLibXmlErrorDescription($xmlContent);
			KalturaLog::debug("Could not load xml");
			throw new KalturaBatchException("Could not load xml [{$this->job->id}], $errorMessage", KalturaBatchJobAppErrors::BULK_VALIDATION_FAILED);
		}
		//Validate the XML file against the schema
		libxml_clear_errors();
		if(!$xdoc->schemaValidate($this->xsdFilePath)) 
		{
			$errorMessage = kXml::getLibXmlErrorDescription($xmlContent);
			KalturaLog::debug("XML is invalid:\n$errorMessage");
			throw new KalturaBatchException("Validate files failed on job [{$this->job->id}], $errorMessage", KalturaBatchJobAppErrors::BULK_VALIDATION_FAILED);
		}
		
		return true;
	}
	
	/**
	 * Load xsl transform
	 */
	protected function loadXslt() 
	{
		$data = self::getData();
		$conversionProfileId = $data->conversionProfileId;
		if($data->conversionProfileId == -1){
			$conversionProfileId = PartnerPeer::retrieveByPK($this->currentPartnerId)->getDefaultConversionProfileId();
		}
		
		$this->impersonate();
		$conversionProfile = $this->kClient->conversionProfile->get($conversionProfileId);
		$this->unimpersonate();
		if(!$conversionProfile || !$conversionProfile->xslTransformation)
			return false;
		$this->conversionProfileXsl = $conversionProfile->xslTransformation;
		return true;
	}

	/**
	 * Transform Xml file with conversion profile xsl
	 * If xsl is not found, original Xml returned
	 * @param string $filePath the original xml that was taken from partner file path 
	 * @return string - transformed Xml
	 */
	protected function xslTransform($filePath)
	{
		$xdoc = file_get_contents($filePath);
		if(is_null($xdoc) || is_null($this->conversionProfileXsl))
			return $xdoc;
		
		libxml_clear_errors();
		$xml = new DOMDocument();
		if(!$xml->loadXML($xdoc)){
			KalturaLog::debug("Could not load xml");
			$errorMessage = kXml::getLibXmlErrorDescription($xdoc);
			throw new KalturaBatchException("Could not load xml [{$this->job->id}], $errorMessage", KalturaBatchJobAppErrors::BULK_VALIDATION_FAILED);
		}
		
		libxml_clear_errors();
		$proc = new XSLTProcessor;
		$xsl = new DOMDocument();
		if(!$xsl->loadXML($this->conversionProfileXsl)){
			KalturaLog::debug("Could not load xsl".$this->conversionProfileXsl);
			$errorMessage = kXml::getLibXmlErrorDescription($this->conversionProfileXsl);
			throw new KalturaBatchException("Could not load xsl [{$this->job->id}], $errorMessage", KalturaBatchJobAppErrors::BULK_VALIDATION_FAILED);
		}
		$proc->importStyleSheet($xsl);
		libxml_clear_errors();
		$transformedXml = $proc->transformToXML($xml);
		if(!$transformedXml){
			KalturaLog::debug("Could not transform xml".$this->conversionProfileXsl);
			$errorMessage = kXml::getLibXmlErrorDescription($this->conversionProfileXsl);
			throw new KalturaBatchException("Could not transform xml [{$this->job->id}], $errorMessage", KalturaBatchJobAppErrors::BULK_VALIDATION_FAILED);
		}
		return $transformedXml;
	}
	
	/**
	 * Parses the Xml file lines and creates the right actions in the system
	 */
	protected function parse()
	{
		$this->currentItem = 0;
		
		$xdoc = new SimpleXMLElement($this->xslTransform($this->data->filePath));
		
		foreach( $xdoc->channel as $channel)
		{
			$this->handleChannel($channel);
			if($this->exceededMaxRecordsEachRun) // exit if we have proccessed max num of items
				return;
		}
	}

	/**
	 * @param string $referenceId
	 * @return string entry id 
	 */
	protected function getEntryIdFromReference($referenceId)
	{
		$existingEntry = $this->getEntryFromReference($referenceId);
		if($existingEntry)
			return $existingEntry->id;
			
		return null;
	}

	/**
	 * @param string $referenceId
	 * @return KalturaBaseEntry
	 */
	protected function getEntryFromReference($referenceId)
	{
		$filter = new KalturaBaseEntryFilter();
		$filter->referenceIdEqual = $referenceId;
		$filter->statusIn = implode(',', array(
			KalturaEntryStatus::ERROR_IMPORTING,
			KalturaEntryStatus::ERROR_CONVERTING,
			KalturaEntryStatus::IMPORT,
			KalturaEntryStatus::PRECONVERT,
			KalturaEntryStatus::READY,
			KalturaEntryStatus::PENDING,
			KalturaEntryStatus::NO_CONTENT,
		));
		$pager = new KalturaFilterPager();
		$pager->pageSize = 1;
		
		$this->impersonate();
		$entries = null;
		try
		{
			$entries = $this->kClient->baseEntry->listAction($filter, $pager);
		}
		catch (KalturaException $e)
		{
			KalturaLog::err($e->getMessage());
		}
		$this->unimpersonate();
		
		/* @var $entries KalturaBaseEntryListResponse */
		if(!$entries || !$entries->totalCount)
			return null;
		
		return reset($entries->objects);
	}

	/**
	 * @param string $entryId
	 * @return KalturaBaseEntry
	 */
	protected function getEntry($entryId)
	{
		$entry = null;
		$this->impersonate();
		try
		{
			$entry = $this->kClient->baseEntry->get($entryId);
		}
		catch (KalturaException $e)
		{
			KalturaLog::err($e->getMessage());
		}
		$this->unimpersonate();
		
		return $entry;
	}

	/**
	 * Gets and handles a channel from the mrss
	 * @param SimpleXMLElement $channel 
	 */
	protected function handleChannel(SimpleXMLElement $channel)
	{
		$startIndex = $this->getStartIndex();
		KalturaLog::debug("startIndex [$startIndex]");
		
		//Gets all items from the channel
		foreach( $channel->item as $item)
		{
			
			if($this->currentItem < $startIndex)
			{
				$this->currentItem++;
				continue;
			}
				
			
			if($this->exceededMaxRecordsEachRun) // exit if we have proccessed max num of items
				return;
			
			$this->currentItem++; //move to the next item (first item is 1)
			try
			{
				$this->checkAborted();
				
				$actionToPerform = self::$actionsMap[KalturaBulkUploadAction::ADD];
						
				$action = KalturaBulkUploadAction::ADD;
				if(isset($item->action))
				{
					$actionToPerform = strtolower($item->action);
				}
				elseif(isset($item->entryId))
				{
					$actionToPerform = self::$actionsMap[KalturaBulkUploadAction::UPDATE];
				}
				elseif(isset($item->referenceId))
				{
					if($this->getEntryIdFromReference("{$item->referenceId}"))
						$actionToPerform = self::$actionsMap[KalturaBulkUploadAction::UPDATE];
				}
				
				switch($actionToPerform)
				{
					case self::$actionsMap[KalturaBulkUploadAction::ADD]:
						$action = KalturaBulkUploadAction::ADD;
						$this->validateItem($item);
						$this->handleItemAdd($item);
						break;
					case self::$actionsMap[KalturaBulkUploadAction::UPDATE]:
						$action = KalturaBulkUploadAction::UPDATE;
						$this->handleItemUpdate($item);						
						break;
					case self::$actionsMap[KalturaBulkUploadAction::DELETE]:
						$action = KalturaBulkUploadAction::DELETE;
						$this->handleItemDelete($item);					
						break;
					default :
						throw new KalturaBatchException("Action: {$actionToPerform} is not supported", KalturaBatchJobAppErrors::BULK_ACTION_NOT_SUPPORTED);
				}
			}
			catch (Exception $e)
			{
				KalturaLog::err('Item failed (' . get_class($e) . '): ' . $e->getMessage());
				$bulkUploadResult = $this->createUploadResult($item, $action);
				$bulkUploadResult->errorDescription = $e->getMessage();
				$bulkUploadResult->entryStatus = KalturaEntryStatus::ERROR_IMPORTING;
				$this->addBulkUploadResult($bulkUploadResult);
			}
		}
	}
	
	/**
	 * Validates the given item so it's valid (some validation can't be enforced in the schema)
	 * @param SimpleXMLElement $item
	 */
	protected function validateItem(SimpleXMLElement $item)
	{
		//Validates that the item type has a matching type element
		$this->validateTypeToTypedElement($item);
	}		
	
	/**
	 * Gets the flavor params from the given flavor asset
	 * @param string $assetId
	 */
	protected function getAssetParamsIdFromAssetId($assetId, $entryId)
	{
		if(is_null($this->assetIdToAssetParamsId[$entryId]))
		{
			$this->initAssetIdToAssetParamsId($entryId);
		}
		
		if(isset($this->assetIdToAssetParamsId[$entryId][$assetId]))
		{
			return $this->assetIdToAssetParamsId[$entryId][$assetId];
		}
		else //The asset wasn't found on the entry
		{
			throw new KalturaBatchException("Asset Id [$assetId] not found on entry [$entryId]", KalturaBatchJobAppErrors::BULK_ITEM_VALIDATION_FAILED);
		}
	}
	
	/**
	 * Removes all non updatble fields from the entry
	 * @param KalturaBaseEntry $entry
	 */
	protected function removeNonUpdatbleFields(KalturaBaseEntry $entry)
	{
		$retEntry = clone $entry;
		$retEntry->conversionProfileId = null;
		return $retEntry;
	}
	
	/**
	 * Handles xml bulk upload update
	 * @param SimpleXMLElement $item
	 * @throws KalturaException
	 */
	protected function handleItemUpdate(SimpleXMLElement $item)
	{
		KalturaLog::debug("xml [" . $item->asXML() . "]");
		
		$entryId = null;
		$conversionProfileId = null;
		if(isset($item->entryId))
		{
			$entryId = "{$item->entryId}";
			
			$existingEntry = $this->getEntry($entryId);
			if(!$existingEntry)
				throw new KalturaBatchException("Entry id [$entryId] not found", KalturaBatchJobAppErrors::BULK_ITEM_NOT_FOUND);
				
			$conversionProfileId = $existingEntry->conversionProfileId;
		}
		elseif(isset($item->referenceId))
		{
			$existingEntry = $this->getEntryFromReference("{$item->referenceId}");
			if(!$existingEntry)
				throw new KalturaBatchException("Reference id [{$item->referenceId}] not found", KalturaBatchJobAppErrors::BULK_ITEM_NOT_FOUND);
				
			$entryId = $existingEntry->id;
			$conversionProfileId = $existingEntry->conversionProfileId;
		}
		else
		{
			throw new KalturaBatchException("Missing entry id element", KalturaBatchJobAppErrors::BULK_MISSING_MANDATORY_PARAMETER);
		}
		
		// Overwriting conversionProfileId if one is supplied in the XML
		if(isset($item->conversionProfileId) || isset($item->conversionProfile))
			$conversionProfileId = $this->getConversionProfileId($item);
		KalturaLog::DEBUG("Conversion profile found within XML - setting to [ $conversionProfileId ]");
		
		//Throw exception in case of max proccessed items and handle all exceptions there
		$updatedEntryBulkUploadResult = $this->createUploadResult($item, KalturaBulkUploadAction::UPDATE);
		
		if($this->exceededMaxRecordsEachRun) // exit if we have proccessed max num of items
			return;

		$entry = $this->createEntryFromItem($item, $existingEntry->type); //Creates the entry from the item element
		
		$this->handleTypedElement($entry, $item); //Sets the typed element values (Mix, Media, ...)
		KalturaLog::debug("current entry is: " . print_r($entry, true));
				
		$thumbAssets = array();
		$thumbAssetsResources = array();
		$flavorAssets = array();
		$flavorAssetsResources = array();
		$noParamsThumbAssets = array(); //Holds the no flavor params thumb assests
		$noParamsThumbResources = array(); //Holds the no flavor params resources assests
		$noParamsFlavorAssets = array();  //Holds the no flavor params flavor assests
		$noParamsFlavorResources = array(); //Holds the no flavor params flavor resources
		$flavorAssetsForUpdate = array();
		$flavorResources = array();
		$thumbAssetsForUpdate = array();
		$thumbResources = array();
		$resource = new KalturaAssetsParamsResourceContainers(); // holds all teh needed resources for the conversion
		$resource->resources = array();
		
		
		if(isset($item->contentAssets->action) && (isset($item->thumbnails->action)))
		{
			$contentAssetsAction = strtolower($item->contentAssets->action);
			$thumbnailsAction = strtolower($item->thumbnails->action);
		}
		elseif (isset($item->contentAssets->action))
		{
			$contentAssetsAction = strtolower($item->contentAssets->action);
			$thumbnailsAction = strtolower($item->contentAssets->action);
		}
		elseif (isset($item->thumbnails->action))
		{
			$contentAssetsAction = strtolower($item->thumbnails->action);
			$thumbnailsAction = strtolower($item->thumbnails->action);
		}
		else
		{
			//default action to perfom for assets and thumbnails is replace
			$contentAssetsAction = self::$actionsMap[KalturaBulkUploadAction::REPLACE];
			$thumbnailsAction = self::$actionsMap[KalturaBulkUploadAction::REPLACE];
		}
		
		
		
		if (isset($item->contentAssets->action) && isset($item->thumbnails->action) && ($contentAssetsAction != $thumbnailsAction))
			throw new KalturaBatchException("ContentAsset->action: {$contentAssetsAction} must be the same as thumbnails->action: {$thumbnailsAction}", KalturaBatchJobAppErrors::BULK_ACTION_NOT_SUPPORTED);
		
		//For each content in the item element we add a new flavor asset
		if(isset($item->contentAssets))
		{		
			foreach ($item->contentAssets->content as $contentElement)
			{
				KalturaLog::debug("contentElement [" . print_r($contentElement->asXml(), true). "]");
				
				if(empty($contentElement)) // if the content is empty skip
				{
					continue;
				}
								
				$flavorAsset = $this->getFlavorAsset($contentElement, $conversionProfileId);
				$flavorAssetResource = $this->getResource($contentElement, $conversionProfileId);
				if(!$flavorAssetResource)
					continue;
				
				$assetParamsId = $flavorAsset->flavorParamsId;
	
				$assetId = kXml::getXmlAttributeAsString($contentElement, "assetId");
				if($assetId) // if we have an asset id then we need to update the asset
				{
					KalturaLog::debug("Asset id [ $assetId]");
					$assetParamsId = $this->getAssetParamsIdFromAssetId($assetId, $entryId);
				}
			
				KalturaLog::debug("assetParamsId [$assetParamsId]");
							
				if(is_null($assetParamsId)) // no params resource
				{
					$noParamsFlavorAssets[] = $flavorAsset;
					$noParamsFlavorResources[] = $flavorAssetResource;
					continue;
				}
				else 
				{
					$flavorAssetsResources[$flavorAsset->flavorParamsId] = $flavorAssetResource;
				}
				
				$flavorAssets[$flavorAsset->flavorParamsId] = $flavorAsset;
				$assetResource = new KalturaAssetParamsResourceContainer();
				$assetResource->resource = $flavorAssetResource;
				$assetResource->assetParamsId = $assetParamsId;
				$resource->resources[] = $assetResource;
			}
		}
		
		//For each thumbnail in the item element we create a new thumb asset
		if(isset($item->thumbnails))
		{
			foreach ($item->thumbnails->thumbnail as $thumbElement)
			{
				if(empty($thumbElement)) // if the content is empty
				{
					continue;
				}
				
				KalturaLog::debug("thumbElement [" . print_r($thumbElement->asXml(), true). "]");
							
				$thumbAsset = $this->getThumbAsset($thumbElement, $conversionProfileId);
				$thumbAssetResource = $this->getResource($thumbElement, $conversionProfileId);
				if(!$thumbAssetResource)
					continue;
										
				$assetParamsId = $thumbAsset->thumbParamsId;
	
				$assetId = kXml::getXmlAttributeAsString($thumbElement, "assetId");
				if($assetId) // if we have an asset id then we need to update the asset
				{
					KalturaLog::debug("Asset id [ $assetId]");
					$assetParamsId = $this->getAssetParamsIdFromAssetId($assetId, $entryId);
				}
							
				KalturaLog::debug("assetParamsId [$assetParamsId]");
				
				if(is_null($assetParamsId))
				{
					$noParamsThumbAssets[] = $thumbAsset;
					$noParamsThumbResources[] = $thumbAssetResource;
					continue;
				}
				else
				{
					$thumbAssetsResources[$thumbAsset->thumbParamsId] = $thumbAssetResource;
				}
				
				$thumbAssets[$thumbAsset->thumbParamsId] = $thumbAsset;
				$assetResource = new KalturaAssetParamsResourceContainer();
				$assetResource->resource = $thumbAssetResource;
				$assetResource->assetParamsId = $assetParamsId;
				$resource->resources[] = $assetResource;
			}
		}
		
		if(!count($resource->resources))
		{
			if (count($noParamsFlavorResources) == 1)
			{
				$resource = reset($noParamsFlavorResources);
				$noParamsFlavorResources = array();
				$noParamsFlavorAssets = array();
			}
			else
			{
				$resource = null;
			}
		}
		
		switch($contentAssetsAction)
		{
			case self::$actionsMap[KalturaBulkUploadAction::UPDATE]:
				$entry = $this->sendItemUpdateData($entryId, $entry, $flavorAssets, $flavorAssetsResources, $thumbAssets, $thumbAssetsResources);
				break;
			case self::$actionsMap[KalturaBulkUploadAction::REPLACE]:
				$entry = $this->sendItemReplaceData($entryId, $entry, $resource, 
												  $noParamsFlavorAssets, $noParamsFlavorResources, 
												  $noParamsThumbAssets, $noParamsThumbResources);
				$entryId = $entry->id;
				break;
			default :
				throw new KalturaBatchException("Action: {$contentAssetsAction} is not supported", KalturaBatchJobAppErrors::BULK_ACTION_NOT_SUPPORTED);
		}
							  
		//Adds the additional data for the flavors and thumbs
		$this->handleFlavorAndThumbsAdditionalData($entryId, $flavorAssets, $thumbAssets);
				
		//Handles the plugin added data
		$pluginsErrorResults = array();
		$pluginsInstances = KalturaPluginManager::getPluginInstances('IKalturaBulkUploadXmlHandler');
		foreach($pluginsInstances as $pluginsInstance)
		{
			/* @var $pluginsInstance IKalturaBulkUploadXmlHandler */
			try {
				$pluginsInstance->configureBulkUploadXmlHandler($this);
				$pluginsInstance->handleItemUpdated($entry, $item);
			}catch (Exception $e)
			{
				KalturaLog::err($pluginsInstance->getContainerName() . ' failed: ' . $e->getMessage());
				$pluginsErrorResults[] = $pluginsInstance->getContainerName() . ' failed: ' . $e->getMessage();
			}
		}
		
		if(count($pluginsErrorResults))
			throw new Exception(implode(', ', $pluginsErrorResults));
	
		//Updates the bulk upload result for the given entry (with the status and other data)
		$this->updateObjectsResults(array($entry), array($updatedEntryBulkUploadResult));
	}

	/**
	 * (non-PHPdoc)
	 * @see KBulkUploadEngine::addBulkUploadResult()
	 */
	protected function addBulkUploadResult(KalturaBulkUploadResult $bulkUploadResult)
	{
		parent::addBulkUploadResult($bulkUploadResult);
					
		$this->handledRecordsThisRun++; //adds one to the count of handled records
	}
	
	/**
	 * Sends the data using a multi requsest according to the given data
	 * @param int $entryID
	 * @param KalturaBaseEntry $entry
	 * @param KalturaResource $resource - the main resource collection for the entry
	 * @param array $noParamsFlavorAssets - Holds the no flavor params flavor assets 
	 * @param array $noParamsFlavorResources - Holds the no flavor params flavor resources
	 * @param array $noParamsThumbAssets - Holds the no flavor params thumb assets
	 * @param array $noParamsThumbResources - Holds the no flavor params thumb resources
	 * @return $requestResults - the multi request result
	 */
	protected function sendItemReplaceData($entryId, KalturaBaseEntry $entry ,KalturaResource $resource = null, 
										array $noParamsFlavorAssets, array $noParamsFlavorResources, 
										array $noParamsThumbAssets, array $noParamsThumbResources)
	{
		
		KalturaLog::debug("Resource is: " . print_r($resource, true));
		
		$this->impersonate();
		$updateEntry = $this->removeNonUpdatbleFields($entry);
		$updatedEntry = $this->kClient->baseEntry->get($entryId);
		
		$this->kClient->startMultiRequest();
		
		$updatedEntryId = $updatedEntry->id;   	
		if(!is_null($updatedEntry->replacingEntryId))
			$updatedEntryId = $updatedEntry->replacingEntryId;
					
		if($resource)
			$this->kClient->baseEntry->updateContent($updatedEntryId ,$resource, $entry->conversionProfileId); //to create a temporery entry.
		
		foreach($noParamsFlavorAssets as $index => $flavorAsset) // Adds all the entry flavors
		{
			$flavorResource = $noParamsFlavorResources[$index];
			$flavor = $this->kClient->flavorAsset->add($updatedEntryId, $flavorAsset);
			$this->kClient->flavorAsset->setContent($this->kClient->getMultiRequestResult()->id, $flavorResource);		// TODO: use flavor instead of getMultiRequestResult
		}
		
		foreach($noParamsThumbAssets as $index => $thumbAsset) //Adds the entry thumb assests
		{
			$thumbResource = $noParamsThumbResources[$index];
			$thumb = $this->kClient->thumbAsset->add($updatedEntryId, $thumbAsset);
			$this->kClient->thumbAsset->setContent($this->kClient->getMultiRequestResult()->id, $thumbResource);		// TODO: use thumb instead of getMultiRequestResult
		}
		
		$requestResults = $this->kClient->doMultiRequest();
		
		//update is after add content since in case entry replacement we want the duration to be set on the new entry.
		$updatedEntry = $this->kClient->baseEntry->update($entryId, $updateEntry);
		
		$this->unimpersonate();
		
		if(is_array($requestResults))
			foreach($requestResults as $requestResult)
				if($requestResult instanceof Exception)
					throw $requestResult;
		
		return $updatedEntry;
	}

	/**
	 * Handles xml bulk upload delete
	 * @param SimpleXMLElement $item
	 * @throws KalturaException
	 */
	protected function handleItemDelete(SimpleXMLElement $item)
	{
		$entryId = null;
		if(isset($item->entryId))
		{
			$entryId = "{$item->entryId}";
		}
		elseif(isset($item->referenceId))
		{
			$entryId = $this->getEntryIdFromReference("{$item->referenceId}");
			if(!$entryId)
				throw new KalturaBatchException("Reference id [{$item->referenceId}] not found", KalturaBatchJobAppErrors::BULK_ITEM_NOT_FOUND);
		}
		else
		{
			throw new KalturaBatchException("Missing entry id element", KalturaBatchJobAppErrors::BULK_MISSING_MANDATORY_PARAMETER);
		}
		
		$this->impersonate();
		$result = $this->kClient->baseEntry->delete($entryId);
		$this->unimpersonate();
		
		$bulkUploadResult = $this->createUploadResult($item, KalturaBulkUploadAction::DELETE);
		
		if($this->exceededMaxRecordsEachRun) // exit if we have proccessed max num of items
			return;
		
		$bulkUploadResult->entryId = $entryId;
		$this->addBulkUploadResult($bulkUploadResult);
	}

	/**
	 * Gets an item and insert it into the system
	 * @param SimpleXMLElement $item
	 */
	protected function handleItemAdd(SimpleXMLElement $item)
	{
		KalturaLog::debug("xml [" . $item->asXML() . "]");
		
		//Throw exception in case of  max proccessed items and handle all exceptions there
		$createdEntryBulkUploadResult = $this->createUploadResult($item, KalturaBulkUploadAction::ADD);

		if($this->exceededMaxRecordsEachRun) // exit if we have proccessed max num of items
			return;
		
		$entry = $this->createEntryFromItem($item); //Creates the entry from the item element
		$this->handleTypedElement($entry, $item); //Sets the typed element values (Mix, Media, ...)
		KalturaLog::debug("current entry is: " . print_r($entry, true));
				
		$thumbAssets = array();
		$flavorAssets = array();
		$noParamsThumbAssets = array(); //Holds the no flavor params thumb assests
		$noParamsThumbResources = array(); //Holds the no flavor params resources assests
		$noParamsFlavorAssets = array();  //Holds the no flavor params flavor assests
		$noParamsFlavorResources = array(); //Holds the no flavor params flavor resources
		$resource = new KalturaAssetsParamsResourceContainers(); // holds all teh needed resources for the conversion
		$resource->resources = array();

		//For each content in the item element we add a new flavor asset
		if(isset($item->contentAssets))
		{		
			foreach ($item->contentAssets->content as $contentElement)
			{
				$assetResource = $this->getResource($contentElement, $entry->conversionProfileId);
				if(!$assetResource)
					continue;
					
				$assetResourceContainer = new KalturaAssetParamsResourceContainer();
				$flavorAsset = $this->getFlavorAsset($contentElement, $entry->conversionProfileId);
				
				if(is_null($flavorAsset->flavorParamsId))
				{
					KalturaLog::debug("flavorAsset [". print_r($flavorAsset, true) . "]");
					$noParamsFlavorAssets[] = $flavorAsset;
					$noParamsFlavorResources[] = $assetResource;
				}
				else 
				{
					KalturaLog::debug("flavorAsset->flavorParamsId [$flavorAsset->flavorParamsId]");
					$flavorAssets[$flavorAsset->flavorParamsId] = $flavorAsset;
					$assetResourceContainer->assetParamsId = $flavorAsset->flavorParamsId;
					$assetResourceContainer->resource = $assetResource;
					$resource->resources[] = $assetResourceContainer;
				}
			}
		}

		//For each thumbnail in the item element we create a new thumb asset
		if(isset($item->thumbnails))
		{
			foreach ($item->thumbnails->thumbnail as $thumbElement)
			{
				$assetResource = $this->getResource($thumbElement, $entry->conversionProfileId);
				if(!$assetResource)
					continue;
					
				$assetResourceContainer = new KalturaAssetParamsResourceContainer();
				$thumbAsset = $this->getThumbAsset($thumbElement, $entry->conversionProfileId);
				
				if(is_null($thumbAsset->thumbParamsId))
				{
					KalturaLog::debug("thumbAsset [". print_r($thumbAsset, true) . "]");
					$noParamsThumbAssets[] = $thumbAsset;
					$noParamsThumbResources[] = $assetResource;
				}
				else //we have a thumbParamsId so we add to the resources
				{
					KalturaLog::debug("thumbAsset->thumbParamsId [$thumbAsset->thumbParamsId]");
					$thumbAssets[$thumbAsset->thumbParamsId] = $thumbAsset;
					$assetResourceContainer->assetParamsId = $thumbAsset->thumbParamsId;
					$assetResourceContainer->resource = $assetResource;
					$resource->resources[] = $assetResourceContainer;
				}
			}
		}

		if(!count($resource->resources))
		{
			if (count($noParamsFlavorResources) == 1)
			{
				$resource = reset($noParamsFlavorResources);
				$noParamsFlavorResources = array();
				$noParamsFlavorAssets = array();
			}
			else
			{
				$resource = null;
			}
		}

		$createdEntry = $this->sendItemAddData($entry, $resource, $noParamsFlavorAssets, $noParamsFlavorResources, $noParamsThumbAssets, $noParamsThumbResources);
			
		//Updates the bulk upload result for the given entry (with the status and other data)
		$this->updateObjectsResults(array($createdEntry), array($createdEntryBulkUploadResult));
		
		//Adds the additional data for the flavors and thumbs
		$this->handleFlavorAndThumbsAdditionalData($createdEntry->id, $flavorAssets, $thumbAssets);
				
		//Handles the plugin added data
		$pluginsErrorResults = array();
		$pluginsInstances = KalturaPluginManager::getPluginInstances('IKalturaBulkUploadXmlHandler');
		foreach($pluginsInstances as $pluginsInstance)
		{
			/* @var $pluginsInstance IKalturaBulkUploadXmlHandler */
			try {
				$pluginsInstance->configureBulkUploadXmlHandler($this);
				$pluginsInstance->handleItemAdded($createdEntry, $item);
			}catch (Exception $e)
			{
				KalturaLog::err($pluginsInstance->getContainerName() . ' failed: ' . $e->getMessage());
				$pluginsErrorResults[] = $pluginsInstance->getContainerName() . ' failed: ' . $e->getMessage();
			}
		}
		
		if(count($pluginsErrorResults))
			throw new Exception(implode(', ', $pluginsErrorResults));
	
	}
	
	/**
	 * Sends the data using a multi requsest according to the given data
	 * @param KalturaBaseEntry $entry
	 * @param KalturaResource $resource
	 * @param array $noParamsFlavorAssets
	 * @param array $noParamsFlavorResources
	 * @param array $noParamsThumbAssets
	 * @param array $noParamsThumbResources
	 * @return $requestResults - the multi request result
	 */
	protected function sendItemAddData(KalturaBaseEntry $entry ,KalturaResource $resource = null, array $noParamsFlavorAssets, array $noParamsFlavorResources, array $noParamsThumbAssets, array $noParamsThumbResources)
	{	
		$this->impersonate();
		$this->kClient->startMultiRequest();
		
		KalturaLog::debug("Resource is: " . print_r($resource, true));
		
		$this->kClient->baseEntry->add($entry); //Adds the entry 
		$newEntryId = $this->kClient->getMultiRequestResult()->id;							// TODO: use the return value of add instead of getMultiRequestResult
		
		if($resource)
			$this->kClient->baseEntry->addContent($newEntryId, $resource); // adds the entry resources
		
		foreach($noParamsFlavorAssets as $index => $flavorAsset) // Adds all the entry flavors
		{
			$flavorResource = $noParamsFlavorResources[$index];
			$flavor = $this->kClient->flavorAsset->add($newEntryId, $flavorAsset);
			$this->kClient->flavorAsset->setContent($this->kClient->getMultiRequestResult()->id, $flavorResource);			// TODO: use flavor instead of getMultiRequestResult
		}
		
		foreach($noParamsThumbAssets as $index => $thumbAsset) //Adds the entry thumb assests
		{
			
			$thumbResource = $noParamsThumbResources[$index];
			$thumb = $this->kClient->thumbAsset->add($newEntryId, $thumbAsset, $thumbResource);
			$this->kClient->thumbAsset->setContent($this->kClient->getMultiRequestResult()->id, $thumbResource);			// TODO: use thumb instead of getMultiRequestResult
		}
							
		$requestResults = $this->kClient->doMultiRequest();;
		$this->unimpersonate();
		
		foreach($requestResults as $requestResult)
			if($requestResult instanceof Exception)
				throw $requestResult;
		
		$createdEntry = reset($requestResults);
		if(is_null($createdEntry)) //checks that the entry was created
			throw new KalturaBulkUploadXmlException("The entry wasn't created", KalturaBatchJobAppErrors::BULK_ITEM_VALIDATION_FAILED);
		
		if(!($createdEntry instanceof KalturaObjectBase)) // if the entry is not kaltura object (in case of errors)
			throw new KalturaBulkUploadXmlException("Returned type is [" . get_class($createdEntry) . "], KalturaObjectBase was expected", KalturaBatchJobAppErrors::BULK_ITEM_VALIDATION_FAILED);
		
		return $createdEntry;
	}
	
		/**
	 * Handles the adding of additional data to the preciously created flavors and thumbs 
	 * @param int $createdEntryId
	 * @param array $flavorAssets
	 * @param array $thumbAssets
	 */
	protected function handleFlavorAndThumbsAdditionalData($createdEntryId, $flavorAssets, $thumbAssets)
	{
		$this->impersonate();
		$this->kClient->startMultiRequest();
		$this->kClient->flavorAsset->getByEntryId($createdEntryId);
		$this->kClient->thumbAsset->getByEntryId($createdEntryId);
		$result = $this->kClient->doMultiRequest();
		
		foreach($result as $requestResult)
			if($requestResult instanceof Exception)
				throw $requestResult;
		
		$createdFlavorAssets = $result[0]; 
		$createdThumbAssets =  $result[1];
				
		$this->kClient->startMultiRequest();
		///For each flavor asset that we just added without his data then we need to update his additional data
		foreach($createdFlavorAssets as $createdFlavorAsset)
		{
			if(is_null($createdFlavorAsset->flavorParamsId)) //no flavor params to the flavor asset
				continue;
				
			if(!isset($flavorAssets[$createdFlavorAsset->flavorParamsId])) // We don't have the flavor in our dictionary
				continue;
			
			$flavorAsset = $flavorAssets[$createdFlavorAsset->flavorParamsId];
			$this->kClient->flavorAsset->update($createdFlavorAsset->id, $flavorAsset);
		}
		
		foreach($createdThumbAssets as $createdThumbAsset)
		{
			if(is_null($createdThumbAsset->thumbParamsId))
				continue;
				
			if(!isset($thumbAssets[$createdThumbAsset->thumbParamsId]))
				continue;
				
			$thumbAsset = $thumbAssets[$createdThumbAsset->thumbParamsId];
			$this->kClient->thumbAsset->update($createdThumbAsset->id, $thumbAsset);
		}
		
		$requestResults = $this->kClient->doMultiRequest();
		$this->unimpersonate();

		if(is_array($requestResults))
			foreach($requestResults as $requestResult)
				if($requestResult instanceof Exception)
					throw $requestResult;
		
		return $requestResults;
	}
	
	/**
	 * Handles the adding of additional data to the preciously created flavors and thumbs 
	 * @param int $entryId
	 * @param KalturaBaseEntry $entry
	 * @param array $flavorAssets
	 * @param array $flavorAssetsResources
	 * @param array $thumbAssets
	 * @param array $thumbAssetsResources
	 */
	protected function sendItemUpdateData($entryId, $entry, array $flavorAssets, array $flavorAssetsResources, array $thumbAssets, array $thumbAssetsResources)
	{
		$this->impersonate();
		$updateEntry = $this->removeNonUpdatbleFields($entry);
		$updatedEntry = $this->kClient->baseEntry->update($entryId, $updateEntry);
		
		$this->kClient->startMultiRequest();
		$this->kClient->flavorAsset->getByEntryId($entryId);
		$this->kClient->thumbAsset->getByEntryId($entryId);
		$result = $this->kClient->doMultiRequest();
		
		foreach($result as $requestResult)
			if($requestResult instanceof Exception)
				throw $requestResult;
		
		$createdFlavorAssets = $result[0]; 
		$createdThumbAssets =  $result[1];
		$existingflavorAssets = array();
		$existingthumbAssets = array();
				
		foreach($createdFlavorAssets as $createdFlavorAsset)
		{
			if(is_null($createdFlavorAsset->flavorParamsId)) //no flavor params to the flavor asset
				continue;
				
			$existingflavorAssets[$createdFlavorAsset->flavorParamsId] = $createdFlavorAsset->id;
		}
		
		$this->kClient->startMultiRequest();
		foreach ($flavorAssetsResources as $flavorParamsId => $flavorAssetsResource)
		{
			if(!isset($existingflavorAssets[$flavorParamsId]))
			{
				$this->kClient->flavorAsset->add($entryId, $flavorAssets[$flavorParamsId]);
				$this->kClient->flavorAsset->setContent($this->kClient->getMultiRequestResult()->id, $flavorAssetsResource);
			}else{
				$this->kClient->flavorAsset->update($existingflavorAssets[$flavorParamsId], $flavorAssets[$flavorParamsId]);
				$this->kClient->flavorAsset->setContent($existingflavorAssets[$flavorParamsId], $flavorAssetsResource);
			}			
		}
		
		foreach($createdThumbAssets as $createdThumbAsset)
		{
			if(is_null($createdThumbAsset->thumbParamsId))
				continue;
				
			$existingthumbAssets[$createdThumbAsset->thumbParamsId] = $createdThumbAsset->id;
		}
		
		
		foreach($thumbAssetsResources as $thumbParamsId => $thumbAssetsResource)
		{
			if(!isset($existingthumbAssets[$thumbParamsId]))
			{
				$this->kClient->thumbAsset->add($entryId, $thumbAssets[$thumbParamsId]);
				$this->kClient->thumbAsset->setContent($this->kClient->getMultiRequestResult()->id, $thumbAssetsResource);				
			}else{
				$this->kClient->thumbAsset->update($existingthumbAssets[$thumbParamsId], $thumbAssets[$thumbParamsId]);
				$this->kClient->thumbAsset->setContent($existingthumbAssets[$thumbParamsId], $thumbAssetsResource);
			}	
		}
		
		$requestResults = $this->kClient->doMultiRequest();
		$this->unimpersonate();
		
		return $updatedEntry;
	}
	
	/**
	 * returns a flavor asset form the current content element
	 * @param SimpleXMLElement $contentElement
	 * @return KalturaFlavorAsset
	 */
	protected function getFlavorAsset(SimpleXMLElement $contentElement, $conversionProfileId)
	{
		$flavorAsset = new KalturaFlavorAsset(); //we create a new asset (for add)
		$flavorAsset->flavorParamsId = $this->getFlavorParamsId($contentElement, $conversionProfileId, true);
		$flavorAsset->tags = $this->implodeChildElements($contentElement->tags);
			
		return $flavorAsset;
	}
	
	/**
	 * returns a thumbnail asset form the current thumbnail element
	 * @param SimpleXMLElement $thumbElement
	 * @param int $conversionProfileId - The converrsion profile id 
	 * @return KalturaThumbAsset
	 */
	protected function getThumbAsset(SimpleXMLElement $thumbElement, $conversionProfileId)
	{
		$thumbAsset = new KalturaThumbAsset();
		$thumbAsset->thumbParamsId = $this->getThumbParamsId($thumbElement, $conversionProfileId);
		
		if(isset($thumbElement["isDefault"]) && $thumbElement["isDefault"] == 'true') // if the attribute is set to true we add the is default tag to the thumb
			$thumbAsset->tags = self::DEFAULT_THUMB_TAG;
		
		$thumbAsset->tags = $this->implodeChildElements($thumbElement->tags, $thumbAsset->tags);
		
		return $thumbAsset;
	}
	
	/**
	 * Validates if the resource is valid
	 * @param KalturaResource $resource
	 * @param SimpleXMLElement $elementToSearchIn
	 */
	protected function validateResource(KalturaResource $resource = null, SimpleXMLElement $elementToSearchIn)
	{
		if(!$resource)
			return;
			
		//We only check for filesize and check sum in local files 
		if($resource instanceof KalturaServerFileResource)
		{
			$filePath = $resource->localFilePath;
			
			if(is_null($filePath))
			{
				throw new KalturaBulkUploadXmlException("Can't validate file as file path is null", KalturaBatchJobAppErrors::BULK_ITEM_VALIDATION_FAILED);
			}
				
			if(isset($elementToSearchIn->serverFileContentResource->fileChecksum)) //Check checksum if exists
			{
				KalturaLog::debug("Validating checksum");
				if($elementToSearchIn->serverFileContentResource->fileChecksum['type'] == 'sha1')
				{
					 $checksum = sha1_file($filePath);
				}
				else
				{
					$checksum = md5_file($filePath);
				}
				
				$xmlChecksum = (string)$elementToSearchIn->serverFileContentResource->fileChecksum;

				if($xmlChecksum != $checksum)
				{
					throw new KalturaBulkUploadXmlException("File checksum is invalid for file [$filePath], Xml checksum [$xmlChecksum], actual checksum [$checksum]", KalturaBatchJobAppErrors::BULK_ITEM_VALIDATION_FAILED);
				}
			}
			
			if(isset($elementToSearchIn->serverFileContentResource->fileSize)) //Check checksum if exists
			{
				KalturaLog::debug("Validating file size");
				
				$fileSize = kFile::fileSize($filePath);
				$xmlFileSize = (int)$elementToSearchIn->serverFileContentResource->fileSize;
				if($xmlFileSize != $fileSize)
				{
					throw new KalturaBulkUploadXmlException("File size is invalid for file [$filePath], Xml size [$xmlFileSize], actual size [$fileSize]", KalturaBatchJobAppErrors::BULK_ITEM_VALIDATION_FAILED);
				}
			}
		}
	}
	
	/**
	 * Gets an item and returns the resource
	 * @param SimpleXMLElement $elementToSearchIn
	 * @param int $conversionProfileId
	 * @return KalturaResource - the resource located in the given element
	 */
	public function getResource(SimpleXMLElement $elementToSearchIn, $conversionProfileId)
	{
		$resource = $this->getResourceInstance($elementToSearchIn, $conversionProfileId);
		if($resource)
			$this->validateResource($resource, $elementToSearchIn);
										
		return $resource;
	}
	
	/**
	 * Returns the right resource instance for the source content of the item
	 * @param SimpleXMLElement $elementToSearchIn
	 * @param int $conversionProfileId
	 * @return KalturaResource - the resource located in the given element
	 */
	protected function getResourceInstance(SimpleXMLElement $elementToSearchIn, $conversionProfileId)
	{
		$resource = null;
			
		if(isset($elementToSearchIn->serverFileContentResource))
		{
			if($this->allowServerResource)
			{
				KalturaLog::debug("Resource is : serverFileContentResource");
				$resource = new KalturaServerFileResource();
				$localContentResource = $elementToSearchIn->serverFileContentResource;
				$resource->localFilePath = kXml::getXmlAttributeAsString($localContentResource, "filePath");
			}
			else
			{
				KalturaLog::err("serverFileContentResource is not allowed");
			}
		}
		elseif(isset($elementToSearchIn->urlContentResource))
		{
			KalturaLog::debug("Resource is : urlContentResource");
			$resource = new KalturaUrlResource();
			$urlContentResource = $elementToSearchIn->urlContentResource;
			$resource->url = kXml::getXmlAttributeAsString($urlContentResource, "url");
		}
		elseif(isset($elementToSearchIn->sshUrlContentResource))
		{
			KalturaLog::debug("Resource is : sshUrlContentResource");
			$resource = new KalturaSshUrlResource();
			$sshUrlContentResource = $elementToSearchIn->sshUrlContentResource;
			$resource->url = kXml::getXmlAttributeAsString($sshUrlContentResource, "url");
			$resource->keyPassphrase = kXml::getXmlAttributeAsString($sshUrlContentResource, "keyPassphrase");
			$resource->privateKey = strval($sshUrlContentResource->privateKey);
			$resource->publicKey = strval($sshUrlContentResource->publicKey);
		}
		elseif(isset($elementToSearchIn->remoteStorageContentResource))
		{
			KalturaLog::debug("Resource is : remoteStorageContentResource");
			$resource = new KalturaRemoteStorageResource();
			$remoteContentResource = $elementToSearchIn->remoteStorageContentResource;
			$resource->url = kXml::getXmlAttributeAsString($remoteContentResource, "url");
			$resource->storageProfileId = $this->getStorageProfileId($remoteContentResource);
		}
		elseif(isset($elementToSearchIn->remoteStorageContentResources))
		{
			KalturaLog::debug("Resource is : remoteStorageContentResources");
			$resource = new KalturaRemoteStorageResources();
			$resource->resources = array();
			$remoteContentResources = $elementToSearchIn->remoteStorageContentResources;
			
			foreach($remoteContentResources->remoteStorageContentResource as $remoteContentResource)
			{
				/* @var $remoteContentResource SimpleXMLElement */
				KalturaLog::debug("Resources name [" . $remoteContentResource->getName() . "] url [" . $remoteContentResource['url'] . "] storage [$remoteContentResource->storageProfile]");
				$childResource = new KalturaRemoteStorageResource();
				$childResource->url = kXml::getXmlAttributeAsString($remoteContentResource, "url");
				$childResource->storageProfileId = $this->getStorageProfileId($remoteContentResource);
				$resource->resources[] = $childResource;
{'fraction_non_alphanumeric': 0.12774785603661495, 'fraction_numerical': 0.00034673262291671483, 'mean_word_length': 4.673267326732673, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 953, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 62}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1082103', 'n_tokens_mistral': 30664, 'n_tokens_neox': 25975, 'n_words': 5265}