<?php

namespace App\Config;

/**
 * Class is used for managing the services and service groups. Also it used for saving the attributes and all offer details.
 * When calling the "save" method all basic service details (attribute, offers, etc) are also saved.
 * @author Bogdan
 * @static \App\Config\Services_Basic getAdmin()
 * @static \App\Config\Services_Basic getInstance()
 */
class Services_Basic extends XmlDynamicRecordsAbstract
{


	/**
	 * Stores the configuration file (relative to the "files/config/" dir). For config files stored
	 * inside subdirectories, the subdirectory is included (Ex: services/servicesList.xml).
	 * @var String
	 */
	protected $fileName=CONFIG_FILE_SERVICE_LIST;

	/**
	 * Used only for UnitTests when overwriting a method
	 *
	 * @param $instance
	 */
	static public function setInstance($instance)
	{
		// the instantiated class
		$extClassName = get_called_class();
		static::$instance[$extClassName] = $instance;
	}


	/**
	 * Rewrite this method so it is never used.
	 */
	public function get($item)
	{
		throw new \Exception("Don't use this method. You must use the methods: getGroupName(code) or getServiceName(code)");
	}

	/**
	 * (non-PHPdoc)
	 * @see \App\Config\XmlDynamicRecordsAbstract::getAll_rawData_extractDataFromFile_list()
	 */
	protected function getAll_rawData_extractDataFromFile_list(\SimpleXMLElement $xml)
	{

		$serviceGroupList=[];

		// scan each service and group
		foreach ($xml as $serviceGroup) {
			$list=[];

			// there is a group
			if ((string)$serviceGroup->getName()=='serviceGroup') {

					// scan each services from this group
				foreach ($serviceGroup as $service) {
					$list[(string)$service['code']] = ['type' => 'service', 'name' => (string)$service['name'], 'category' => (string)$service['category']];
				}
				$serviceGroupList[(string)$serviceGroup['code']]=[
					'type' => 'group',
					'name' => (string)$serviceGroup['name'],
					'list' => $list
				];

			}

			// if this group is in fact a service
			if ((string)$serviceGroup->getName()=='service')
				$serviceGroupList[(string)$serviceGroup['code']]=[
					'type' 		=> 'service',
					'name' 		=> (string)$serviceGroup['name'],
					'category' 	=> (string)$serviceGroup['category'],
				];
		}
		return $serviceGroupList;
	}

	/**
	 * Returns the extracted data (default item) after the XML content is parsed (from $this->configFileXmlGet).
	 * @return Array
	 */
	protected function getAll_rawData_extractDataFromFile_default(\SimpleXMLElement $xml)
	{
		return '';
	}


	/**
	 * (non-PHPdoc)
	 * @see \App\Config\XmlDynamicRecordsAbstract::getAll_rawData_extractDataFromFile_mandatory()
	 */
	protected function getAll_rawData_extractDataFromFile_mandatory(\SimpleXMLElement $xml)
	{
		return true;
	}


	/**
	 * This method gets a list with all services having the key from first level `group code`. So the groups and services without
	 * a group are on first level; the services with group are on second level. The method must be used only with `instance` constructor
	 * @return array
	 */
	public function getListGrouped()
	{
		return $this->getAll();
	}


	/**
	 * Gets a list with all services.
	 * The method returns an array with all services having the key `service code` and value `service details'
	 * @return array
	 */
	public function getListLinear()
	{
		$linearList = [];

		// scan each items grouped by category
		foreach ($this->getAll() as $groupCode => $groupDetails) {

			// find services on second level
			if ($groupDetails['type'] == 'group' ) {
				if ($groupDetails['list']) {
					foreach ($groupDetails['list'] as $serviceCode => $serviceDetails) {
						$linearList[$serviceCode] =
							[
								'name' => $serviceDetails['name'],
								'category' => $serviceDetails['category'],
								'group' => [
									'code' => $groupCode,
									'name' => $groupDetails['name'],
								]
							]
						;
					}
				}
			}
			// find services on first level
			else {
				$linearList[$groupCode] = ['name' => $groupDetails['name'], 'category' => $groupDetails['category']];
			}
		}
		return $linearList;
	}

	/**
	 * Gets as associative array of serviceCode=>serviceName (does not include groups)
	 */
	public function getListLinearSimple()
	{
		$return = [];
		foreach($this->getListLinear() as $serviceCode=>$serviceDetails) {
			$return[$serviceCode] = $serviceDetails['name'];
		}
		return $return;
	}

	/**
	 * The method sets a new group if the second parameter $itemDetails has one key type equals 'group'
	 * or sets a new service if the key groupCode exists and type = 'service'.
	 * So if you set a service must have the key 'groupCode'
	 * @see \App\Config\XmlDynamicRecordsAbstract::doItemInsert()
	 * @param string $code
	 * @param array $itemDetails
	 */
	protected function doItemInsert($code, $itemDetails)
	{
		// insert a group or a service without group
		if ($itemDetails['type'] == 'group' or $itemDetails['groupCode'] == '') {
			parent::doItemInsert($code, $itemDetails);
		}

		// insert a new service in a group
		else {
			$this->itemsList[$itemDetails['groupCode']]['list'][$code]=[
				'name' 		=> $itemDetails['name'],
				'type' 		=> $itemDetails['type'],
				'category' 	=> $itemDetails['category'],
			];
		}
	}


	/**
	 * Rewrite this method because must check if code exist on second level
	 * @see \App\Config\XmlDynamicRecordsAbstract::itemUpdate()
	 */
	public function itemUpdate($code, $itemDetails)
	{
		// check constructor type
		if ($this->constructType!='admin') throw new \Exception("You can use the method `".get_called_class().'::'.__FUNCTION__."` only if the constructor type is `admin`.");
		// itemCheck - to throw more messages (extended class specific)
		$itemDetailsCheck=$itemDetails;
		$itemDetailsCheck['operation']='update';
		$this->itemCheck($code, $itemDetailsCheck);

		// updates the item in the list
		$this->doItemUpdate($code, $itemDetails);

		$this->changedFlag=true;
		return $this;
	}


	/**
	 * To update a group - first param is the group code and second param. must have the key 'name' with the new name of group
	 * To update a service first param is service code and in second param must have a key 'name' with the new name of service
	 * and another key 'groupCode' with the code indicating where to move this service
	 * @see \App\Config\XmlDynamicRecordsAbstract::doItemUpdate()
	 * @param string $code
	 * @param array $itemDetails
	 */
	protected function doItemUpdate($code, $itemDetails)
	{

		// update a group
		if ($this->getItemType($code) == 'group') {
			$this->itemsList[$code]['name']=$itemDetails['name'];
		}

		// update a service
		else {

			// serv. without group -> serv. without group
			if ($this->getServiceGroupCode($code)=='' and $itemDetails['groupCode']=='') {
				$this->itemsList[$code]['name']=$itemDetails['name'];
			}

			// serv. without group -> serv. with group
			if ($this->getServiceGroupCode($code)=='' and $itemDetails['groupCode']!='') {
				unset($this->itemsList[$code]);
				$this->itemsList[$itemDetails['groupCode']]['list'][$code]=$itemDetails;
			}

			// serv. with group
			if ($this->getServiceGroupCode($code)) {

				// serv with group -> serv without group
				if ($itemDetails['groupCode']=='') {
					unset($this->itemsList[$this->getServiceGroupCode($code)]['list'][$code]);
					$this->itemsList[$code]=$itemDetails;
				}

				// serv with group -> serv with group
				else {

					// in the same group
					if ($itemDetails['groupCode'] == $this->getServiceGroupCode($code)) {
						$this->itemsList[$itemDetails['groupCode']]['list'][$code]=$itemDetails;
					}
					// in another group
					else {
						unset($this->itemsList[$this->getServiceGroupCode($code)]['list'][$code]);
						$this->itemsList[$itemDetails['groupCode']]['list'][$code]=$itemDetails;
					}
				}
			}
		}
	}


	/**
	 * Deletes an element from the list of items.
	 * @param String $code
	 * @throws \App\Config\MessageException - if input is not okay
	 * @return self
	 */
	public function itemDelete($code)
	{

		// check constructor type
		if ($this->constructType!='admin') throw new \Exception("You can use the method `".get_called_class().'::'.__FUNCTION__."` only if the constructor type is `admin`.");
		// check input
		if (!$code) $this->addErrorMessage('The code of the deleting item is not valid.');

		// deleted the item in the list
		$this->doItemDelete($code);

		$this->changedFlag=true;

		return $this;
	}


	/**
	 * The method delete a group or a service wthout a group if the received code exists on first level
	 * and a service with group if the receved code is on second level
	 * @see \App\Config\XmlDynamicRecordsAbstract::doItemDelete()
	 */
	protected function doItemDelete($code)
	{

		// delete a service without a group or a group
		if (array_key_exists($code, $this->itemsList)) {
			parent::doItemDelete($code);
		}
		// delete service with group
		else {
			unset($this->itemsList[$this->getServiceGroupCode($code)]['list'][$code]);
		}
	}


	/**
	 * Rewrite this method because in abstract class this method check if received code exists in first level.
	 * Now the received code may be on the second level
	 * Moves an item up in the list.
	 * @param String $code
	 * @return @self
	 */
	public function itemMoveUp($code)
	{

		// check constructor type
		if ($this->constructType!='admin') throw new \Exception("You can use the method `".get_called_class().'::'.__FUNCTION__."` only if the constructor type is `admin`.");
		// at least two elements must be present in the array
		if (count($this->itemsList)<2) $this->addErrorMessage('There has to be at least two elements so that moving them would make sense.');

		// move up a group or a service without group
		if ($this->getItemType($code)=='group' or ($this->getItemType($code)=='service' and $this->getServiceGroupCode($code)=='')) {
			// move the element up
			$codesList=array_keys($this->itemsList);
			$detailsList=array_values($this->itemsList);
			// get the position of the moving item
			$pos=array_search($code, $codesList);
			// if this is the first position - do not do anything
			if (!$pos) return $this;
			// interchange variables
			interchangeVariables($codesList[$pos-1], $codesList[$pos]);
			interchangeVariables($detailsList[$pos-1], $detailsList[$pos]);
			// save the new list after the two items were replaced
			$this->itemsList=array_combine($codesList, $detailsList);
		}

		// move up a service with group
		else {
			$groupCode=$this->getServiceGroupCode($code);

			// move the element up
			$codesList=array_keys($this->itemsList[$groupCode]['list']);
			$detailsList=array_values($this->itemsList[$groupCode]['list']);
			// get the position of the moving item
			$pos=array_search($code, $codesList);
			// if this is the first position - do not do anything
			if (!$pos) return $this;
			// interchange variables
			interchangeVariables($codesList[$pos-1], $codesList[$pos]);
			interchangeVariables($detailsList[$pos-1], $detailsList[$pos]);
			// save the new list after the two items were replaced
			$this->itemsList[$groupCode]['list']=array_combine($codesList, $detailsList);
		}
		$this->changedFlag=true;
		return $this;
	}


	/**
	 * Rewrite this method because in abstract class this method check if received code exists in first level.
	 * Now the received code may be on the second level
	 * Moves an item up in the list.
	 * Moves an item down in the list.
	 * @param String $code
	 * @return @self
	 */
	public function itemMoveDown($code)
	{

		// check constructor type
		if ($this->constructType!='admin') throw new \Exception("You can use the method `".get_called_class().'::'.__FUNCTION__."` only if the constructor type is `admin`.");
		// at least two elements must be present in the array
		if (count($this->itemsList)<2) $this->addErrorMessage('There has to be at least two elements so that moving them would make sense.');

		// move down a group or a service without group
		if ($this->getItemType($code)=='group' or ($this->getItemType($code)=='service' and $this->getServiceGroupCode($code)=='')) {
			// move the element up
			$codesList=array_keys($this->itemsList);
			$detailsList=array_values($this->itemsList);
			// get the position of the moving item
			$pos=array_search($code, $codesList);
			// if this is the first position - do not do anything
			if ($pos==count($this->itemsList)-1) return $this;
			// interchange variables
			interchangeVariables($codesList[$pos+1], $codesList[$pos]);
			interchangeVariables($detailsList[$pos+1], $detailsList[$pos]);
			// save the new list after the two items were replaced
			$this->itemsList=array_combine($codesList, $detailsList);
		}

		// move down a service with group
		else {
			$groupCode=$this->getServiceGroupCode($code);
			// move the element up
			$codesList=array_keys($this->itemsList[$groupCode]['list']);
			$detailsList=array_values($this->itemsList[$groupCode]['list']);
			// get the position of the moving item
			$pos=array_search($code, $codesList);
			// if this is the first position - do not do anything
			if ($pos==count($this->itemsList)-1) return $this;
			// interchange variables
			interchangeVariables($codesList[$pos+1], $codesList[$pos]);
			interchangeVariables($detailsList[$pos+1], $detailsList[$pos]);
			// save the new list after the two items were replaced
			$this->itemsList[$groupCode]['list']=array_combine($codesList, $detailsList);
		}

		$this->changedFlag=true;
		return $this;

	}


	/**
	 * Checks an item and throws an \App\Config\MessageException exception if anything goes wrong.
	 * @param String $code
	 * @param Mixed $itemDetails
	 * @throws \App\Config\MessageException - if anything goes wrong
	 */
	protected function itemCheck($code, $itemDetails)
	{

		// CODE ////////////////////////////////////////////////////////////////////////////////////
		// check if the code is set
		if (!$code) {
			$this->addErrorMessage('The code was not defined.');
		}

		// check code length
		if (mb_strlen($code)>2) {
			$this->addErrorMessage("The code length must be smaller than 2 chars.");
		}

		// DETAILS /////////////////////////////////////////////////////////////////////////////////
		// check if details list is an array
		if (!is_array($itemDetails)) {
			$this->addErrorMessage('Details were not defined.');
		}

		// check if the group name or service name is set
		if (!($itemDetails['name'])) {
			$this->addErrorMessage('The name was not defined.');
		}
		// check name length
		if (mb_strlen($itemDetails['name'])>50) {
			$this->addErrorMessage('The name length must be smaller than 50 chars.');
		}

		// check the service category
		$CFG = \Engine\Loader_Cfg::getInstance()->getGlobal();
		if ($itemDetails['category'] and !in_array($itemDetails['category'], $CFG['travel']['servicesCategory']) ) {
			$this->addErrorMessage('The service category is not valid.');
		}

		// THE CODE MUST EXIST FOR UPDATE OPERATION AND THROW EXCEPTION IF IT DOES NOT EXIST
		if ($itemDetails['operation']) {
			$ok=false;
			if (array_key_exists($code, $this->itemsList)) {
				$ok=true;
			}
			foreach ($this->itemsList as $grDetails) {
				if (is_array($grDetails['list']) and in_array( mb_strtoupper($code), array_map('mb_strtoupper', array_keys($grDetails['list'])) ) ) {
					$ok=true;
					break;
				}
			}
			// did not find code
			if (!$ok) {
				$this->addErrorMessage('The item code does not exist.');
			}
		}

		// CHECK IF THE CODE EXISTS ON SECOND LEVEL -  FOR INSERT OPERATION
		else {
			foreach($this->itemsList as $groupDetails) {
				if ( $groupDetails['list'] and in_array( mb_strtoupper($code), array_map('mb_strtoupper', array_keys($groupDetails['list'])) ) ) {
					$this->addErrorMessage('This item code already exists for a service.');
				}
			}
		}


		// CHECK IF THE NAME ALREADY EXISTS
		foreach($this->itemsList as $groupCode => $groupDetails) {

			// check if the name exists
			if ( $groupCode!=$code and mb_strtoupper($itemDetails['name']) == mb_strtoupper($groupDetails['name'])) {
				$this->addErrorMessage('This `name` already exists for a group.');
			}

			// check if the name exists for a service in a group
			if ($groupDetails['list']) {
				foreach ($groupDetails['list'] as $serviceCode => $serviceDetails) {
					if ( $serviceCode!=$code and mb_strtoupper($itemDetails['name'])==mb_strtoupper($serviceDetails['name'])) {
						$this->addErrorMessage('This `name` already exists for a service.');
					}
				}
			}
		}

	}


	/**
	 * Checks the input  for `save()` operation. Method checks that the groups to have a services list (at least one service)
	 * then calls the method from attributes config to check the attributes from session
	 * then calls the method from services offer config  - row types - to check the row types from session.
	 * the method from service offer config - offer types - to check the offer types
	 * then calls the method from service offer config - confirmations
	 * and then calls the method from services offer config  - offer details - to check the quantity type, valability and ignoreSupplierOnDocuments from session.
	 * @throws \App\Config\MessageException - the error message in case something is wrong.
	 */
	protected function save_check()
	{

		// if an item was deleted, check if that particular item is used inside orders
		$oldItemsList = \App\Config\Services_Basic::getInstance()->getListLinear();
		$newItemsList = \App\Config\Services_Basic::getAdmin()->getListLinear();
		$deletedServices = array_diff_key($oldItemsList, $newItemsList);
		$deletedCodes = array_keys($deletedServices);

		if($oldItemsList !== $newItemsList) {
			if (!empty($deletedCodes) && $code = $this->isUsed($deletedCodes)) {
				$this->addErrorMessage(sprintf("At least one of the deleted services (`%s`) is already used in order services.", $code));
			}
		}

		// check services //////////////////////////////////////////////////////////////////////////
		// check if itemsList has set a group with no one service
		foreach ($this->itemsList as $groupDetails) {
			if ( $groupDetails['type'] == 'group' and !($groupDetails['list']) ) {
				$this->addErrorMessage(sprintf("The group `%s` does not have any service defined", $groupDetails['name'] ));
			}
		}

		// check that service code does not contain special chars
		foreach($this->itemsList as $code1=>$list1) {
			if (!preg_match("/[a-zA-Z0-9]{1,2}/", $code1)) {
				$this->addErrorMessage(sprintf("You cannot use special chars in the service/category code. Please check the code of '%s'.", $groupDetails['name'] ));
			}
			if ($list1['list']) {
				foreach($list1['list'] as $code2=>$serv2) {
					if (!preg_match("/[a-zA-Z0-9]{1,2}/", $code2)) {
						$this->addErrorMessage(sprintf("You cannot use special chars in the service/category code. Please check the code of '%s'.", $serv2['name'] ));
					}
				}
			}
		}

		// check the attributes ////////////////////////////////////////////////////////////////////
		Services_Fields::getAdmin()->check();

		// check the service offer /////////////////////////////////////////////////////////////////

		// check row types
		Services_OfferRowTypes::getAdmin()->check();

		// check service offer details - quantity type, valability and ignoreSupplierOnDocuments
		Services_OfferDetails::getAdmin()->check();

		// check offer types
		Services_OfferTypes::getAdmin()->check();

		//check offer confirmation mode
		Services_OfferConfirmations::getAdmin()->check();

		// check offer fields
		Services_OfferFields::getAdmin()->check();

	}


	/**
	 * Writes in `xml` file the attributes (only those who have services in session)
	 * Then writes service offer : row types, offer details , offer types and offer confirmations
	 * In the end it writes on disk the services from session
	 * Returns the simplexml object so it can be written on disk.
	 * @see \App\Config\BaseAbstract::save_write_do_getXml()
	 */
	protected function save_write_do_getXml()
	{

		// WRITES THE STRANDARD FIELDS ////////////////////////////////////////////////////////////
		Services_Fields::getAdmin()->save_write();

		// WRITES THE SERVICE OFFER ////////////////////////////////////////////////////////////////

		// writes the row types from service offer
		Services_OfferRowTypes::getAdmin()->save_write();

		// writes the offer details
		Services_OfferDetails::getAdmin()->save_write();

		// writes the offer types
		Services_OfferTypes::getAdmin()->save_write();

		// writes the offer confirmations
		Services_OfferConfirmations::getAdmin()->save_write();

		// writes the offer fields
		Services_OfferFields::getAdmin()->save_write();

		// WRITES THE SERVICES /////////////////////////////////////////////////////////////////////
		$xml=simplexml_load_string('<?xml version="1.0" encoding="UTF-8"?><services />');

		// scan each form of payment
		foreach ($this->itemsList as $groupCode => $groupDetails) {

			// if type is category add a group
			if ($groupDetails['type'] == 'group') {
				$serviceGroup = $xml->addChild('serviceGroup');
				$serviceGroup['code'] = $groupCode;
				$serviceGroup['name'] = $groupDetails['name'];
				foreach ($groupDetails['list'] as $serviceCode => $serviceDetails ) {

					// add service for this group
					$service = $serviceGroup->addChild('service');
					$service['code']=$serviceCode;
					$service['name']=$serviceDetails['name'];
					if ($serviceDetails['category']) {
						$service['category']=$serviceDetails['category'];
					}
				}
			}

			//	if type is service add a service without group
			if ($groupDetails['type'] == 'service') {
				$serviceWithoutGroup = $xml->addChild('service');
				$serviceWithoutGroup['code'] = $groupCode;
				$serviceWithoutGroup['name'] = $groupDetails['name'];
				if ($groupDetails['category']) {
					$serviceWithoutGroup['category']=$groupDetails['category'];
				}

			}
		}

		// return the xml content of the current object
		return $xml;

	}


	/**
	 * Method finds and returns group code for a service code
	 * @param string $serviceCode
	 * @return  string groupCode
	 */
	public function getServiceGroupCode($serviceCode)
	{

		// constructor type = admin
		if ($this->constructType=='admin') {
			if ($this->itemsList[$serviceCode]) { // service is on the first level (no category)
				return null;
			}
			else {
				foreach ($this->itemsList as $groupCode => $groupDetails) {
					if ($groupDetails['list'][$serviceCode]) {
						return  $groupCode;
					}
				}
				return null;
			}
		}
		// constructor type = instance
		else {
			$servList = $this->getListLinear();
			if ($servList[$serviceCode] and $servList[$serviceCode]['group']) {
				return $servList[$serviceCode]['group']['code'];
			} else {
				return null;
			}
		}

	}


	/**
	 * Return the type of element (service or group) else if the code is not valid throw an exception
	 * @param string $code
	 * @return ?string 'service' if this code is for a service and 'group' if this code is for a group
	*/
	private function getItemType($code)
	{

		// check constructor type
		if ($this->constructType!='admin') throw new \Exception("You can use the method `".get_called_class().'::'.__FUNCTION__."` only if the constructor type is `admin`.");

		// scan on first level
		if (array_key_exists($code, $this->itemsList)) {
			if ($this->itemsList[$code]['type'] == 'group') {
				return 'group';
			}
			else {
				return 'service';
			}
		}

		// scan itemsList on second level
		else {
			foreach ($this->itemsList as $groupDetails) {
				if ($groupDetails['list'] and array_key_exists($code, $groupDetails['list'])) {
					return 'service';
				}
			}
		}
		$this->addErrorMessage(sprintf('The code `%s` is not valid.',$code));
		return null;
	}


	/**
	 * This method returns the name of group or throw a exception if param code is not valid
	 * @param string $code
	 * @throws \App\Config\MessageException
	 */
	public function getGroupName($code)
	{

		// check constructor type
		if ($this->constructType!='instance') {
			throw new \Exception("You can use the method `".get_called_class().'::'.__FUNCTION__."` only if the constructor type is `instance`.");
		}

		$groupsList=$this->getAll();
		// return the group name
		if ($groupsList[$code]['type']=='group') {
			return $groupsList[$code]['name'];
		}
		return ;
	}


	/**
	 * This method returns the name of service - works with both getAdmin and getInstance.
	 * @param string $code
	 * @throws \App\Config\MessageException
	 */
	public function getServiceName($code)
	{

		// gets services list
		$servicesList=$this->getListLinear();

		if ($servicesList[$code]) {
			return $servicesList[$code]['name'];
		}
		return ;
	}

	/**
	 * This method returns the cateory of service - works with both getAdmin and getInstance.
	 * @param String $code
	 * @throws \App\Config\MessageException
	 */
	public function getServiceCategory($code)
	{

		// gets services list
		$servicesList=$this->getListLinear();
		if ($servicesList[$code]) {
			return $servicesList[$code]['category'];
		}
		return ;
	}

	/**
	 * Method ckecks if exists a group with this code
	 * @param string $code
	 * @throws \Exception
	 * @return boolean
	 */
	public function checkGroup($code)
	{
		// check constructor type
		if ($this->constructType!='instance') {
			throw new \Exception("You can use the method `".get_called_class().'::'.__FUNCTION__."` only if the constructor type is `instance`.");
		}
		// get the groups list
		$groupsList = $this->getAll();
		if( $groupsList[$code]['type']=='group' and array_key_exists($code, $groupsList) ) {
			return  true;
		}
		return false;
	}

	/**
	 * Method ckecks if a service with this code exists.
	 * @param string $code
	 * @throws \Exception
	 * @return boolean
	 */
	public function checkService($code)
	{
		// check constructor type
		if ($this->constructType!='instance') {
			throw new \Exception("You can use the method `".get_called_class().'::'.__FUNCTION__."` only if the constructor type is `instance`.");
		}
		// gets the service list
		$servicesList=$this->getListLinear();
		// return true if the group exists
		if ($servicesList[$code]) {
			return true;
		}
		return false;
	}


	/**
	 * Verify if the the service code is used
	 * @param array $codes
	 * @return boolean
	 */
	public function isUsed(Array $codesArr)
	{
		if (!$codesArr) {
			return false;
		}

		$ordersListObj = new \App\EntityList\OrderServices();
		$ordersListObj->setColumn('serviceCode');
		$ordersListObj->applyUserRestriction(false);
		$ordersListObj->setCustomFilter('BINARY `serviceCode` IN ('.implode(', ', array_fill(0, count($codesArr), '?')).')', $codesArr);
		$ordersListObj->setLimit(1);

		$recordsArr = $ordersListObj->exportRecords();
		if ($recordsArr) {
			return $recordsArr[0]['serviceCode'];
		}
		return false;
	}

}

