<?php

/**
 * Vlastní SOAP klient pro práci s reality.sk
 * Formátuje specifcká data podle naší potřeby
 */
class Dalten_Export_Api_Backend_RealitySk_Soap extends \SoapClient
{
	const XSI_NS = "http://www.w3.org/2001/XMLSchema-instance";
	const XSD_NS = "http://www.w3.org/2001/XMLSchema";

	/**
	 * Datove typy pro hodnoty 'characteristics'
	 * nutné pro nastavení xsd pro node v DOMu.
	 *
	 * @var array
	 */
	private static $dataTypes = array(
		'amountOfUnpaidCreadit' => 'decimal',
		'approvalWithExtractionOfAgriculturalLand' => 'boolean',
		'approvedBuildingHeight' => 'decimal',
		'apron' => 'decimal',
		'areaForSport' => 'decimal',
		'balcony' => 'boolean',
		'balconyArea' => 'decimal',
		'basin' => 'boolean',
		'basinLength' => 'decimal',
		'bulkOfBuiding' => 'decimal',
		'busStation' => 'decimal',
		'cableTV' => 'boolean',
		'coniferousForest' => 'decimal',
		'consolidatedDumpingArea' => 'decimal',
		'consolidatedGround' => 'decimal',
		'deciduousForest' => 'decimal',
		'drivewayHeight' => 'integer',
		'drivewayWidth' => 'integer',
		'dwellingPartArea' => 'decimal',
		'elevator' => 'boolean',
		'elevatorLoadRating' => 'integer',
		'entireEstateArea' => 'decimal',
		'entireFloorArea' => 'decimal',
		'entireUsageArea' => 'decimal',
		'expertReport' => 'decimal',
		'fireplace' => 'boolean',
		'firstFloorLoadCapacity' => 'decimal',
		'fitness' => 'boolean',
		'fitnessArea' => 'decimal',
		'floor' => 'integer',
		'floorFrom' => 'integer',
		'frontageWidth' => 'decimal',
		'garage' => 'boolean',
		'gardenHouse' => 'boolean',
		'gardenHouseArea' => 'decimal',
		'greenery' => 'boolean',
		'greeneryArea' => 'decimal',
		'groundInvestigation' => 'boolean',
		'groundOfCovarage' => 'decimal',
		'highway' => 'decimal',
		'installedOutput' => 'integer',
		'internet' => 'boolean',
		'landQuality' => 'integer',
		'liftingCapacityOfCraneBridge' => 'decimal',
		'loadingPlatform' => 'decimal',
		'loggia' => 'boolean',
		'loggiaArea' => 'decimal',
		'lot' => 'decimal',
		'mainRoad' => 'decimal',
		'mixedForest' => 'decimal',
		'natureReservation' => 'boolean',
		'nonResidentialArea' => 'decimal',
		'numberOfAboveGroundFloors' => 'integer',
		'numberOfApartments' => 'integer',
		'numberOfBedrooms' => 'integer',
		'numberOfEmployees' => 'integer',
		'numberOfGarageParkingSpots' => 'integer',
		'numberOfLandParts' => 'integer',
		'numberOfParkingSpots' => 'integer',
		'numberOfRooms' => 'integer',
		'numberOfSublevels' => 'integer',
		'numberOfVacationFlats' => 'integer',
		'onusOfRent' => 'boolean',
		'premisesForBreedingOfAnimals' => 'decimal',
		'preservationOfMonuments' => 'boolean',
		'priceOfBuilding' => 'decimal',
		'priceOfLot' => 'decimal',
		'productionArea' => 'decimal',
		'propellantOutlayPerYear' => 'decimal',
		'protectedZone' => 'decimal',
		'railwayStation' => 'decimal',
		'rentalReturn' => 'decimal',
		'riverPort' => 'decimal',
		'safetyEquipment' => 'boolean',
		'saleSpace' => 'decimal',
		'sauna' => 'boolean',
		'secondFloorLoadCapacity' => 'decimal',
		'separateAccess' => 'boolean',
		'serviceAndPowerCosts' => 'decimal',
		'storageSpace' => 'decimal',
		'technicalBackgroundArea' => 'decimal',
		'terrace' => 'boolean',
		'terraceArea' => 'decimal',
		'thermalInsulationOfBuilding' => 'boolean',
		'thirdFloorLoadCapacity' => 'decimal',
		'totalNumberOfObjects' => 'integer',
		'tramStation' => 'decimal',
		'winterGarden' => 'boolean',
		'winterGardenArea' => 'decimal',
		'workshop' => 'boolean',
		'workshopArea' => 'decimal',
		'yearOfConstruction' => 'integer',
		'yearOfLastReconstruction' => 'integer',
	);

	/**
	 * Vrati datovy typ podle nazvu paramtru. Pokud neexistuje vrátí 'string'.
	 *
	 * @param string $paramName Jméno parametru.
	 *
	 * @return string
	 */
	private static function getType($paramName)
	{
		if (isset(self::$dataTypes[$paramName])) {
			return self::$dataTypes[$paramName];
		}
		return 'string';
	}

	public function __doRequest($request, $location, $action, $version, $one_way = null)
	{
		$request = preg_replace('/(<SOAP-ENV:Envelope )/',
                    '\\1 xmlns:xsi="' . self::XSI_NS . '" xmlns:xsd="' . self::XSD_NS . '" ',
                    $request);

		return parent::__doRequest($request, $location, $action, $version, $one_way);
	}

	/**
	 * Volá danou metodu s danymi parametry.
	 *
	 * @param string $method Volaná metoda.
	 * @param array  $params Parametry metody.
     *
     * @return string
	 */
	public function call($method, array $params = array())
	{
		$doc = new \DOMDocument();
		$root = $doc->createElement('ns1:' . $method);

		self::_toXml($params, $root, $doc);

		$xml = $doc->saveXML($root);

		$var = new \SoapVar($xml, XSD_ANYXML);
		$param = new \SoapParam($var, 'tojeuplnejedno');

		$response = $this->__soapCall($method, array($param));

		if (isset($response->return)) {
			return $response->return;
		}
	}

	/**
	 * Pomocná rekurzivní metoda zpracovávající specifické požadavky.
     * Vyjímka ve zpracování hodnoty pro klíč descriptions.
	 *
	 * @param array $data
	 * @param DOMElement $el
	 * @param DOMDocument $doc
     *
	 * @return DOMElement
	 */
	private static function _toXml(array $data, DOMElement &$el, DOMDocument &$doc)
	{
		foreach ($data as $k => $v) {

			if (is_array($v)) {

				// descriptions maji malou vyjimku
				if ($k === 'descriptions') {

					$child = $doc->createElement($k);
					$el->appendChild($child);
					self::_toXML($v[0], $child, $doc);

					continue;
				}

				// characteristics potrebuji k parametrumnastavid atribut xsd
				if ($k === 'characteristics') {

					$characs = $doc->createElement('characteristics');
					foreach ($v as $key => $value) {
						$characNode = $doc->createElement('entry');
						$keyNode = $doc->createElement('key', $key);
						$valueNode = $doc->createElement('value', $value);
						$valueNode->setAttribute('xsi:type', 'xsd:' . self::getType($key));

						$characNode->appendChild($keyNode);
						$characNode->appendChild($valueNode);
						$characs->appendChild($characNode);
					}

					$el->appendChild($characs);
					continue;
				}

				// pokud jsou data cislovane pole, pak se vytvari elementy podle klice
				if (isset($v[0])) {
					foreach($v as $key => $value) {
						$node = $doc->createElement($k);
						$el->appendChild($node);
						self::_toXML($value, $node, $doc);
					}
					continue;
				}

				$child = $doc->createElement($k);
				$el->appendChild($child);
				self::_toXML($v, $child, $doc);

			} else {

				$newEl = $doc->createElement($k, $v);
				$el->appendChild($newEl);
			}
		}
		return $el;
	}
}
