<?php

namespace SMW\Exporter\Element;

use InvalidArgumentException;
use RuntimeException;
use SMWDataItem as DataItem;

/**
 * A single resource (individual) for export, as defined by a URI.
 * This class can also be used to represent blank nodes: It is assumed that all
 * objects of class ExpElement or any of its subclasses represent a blank
 * node if their name is empty or of the form "_id" where "id" is any
 * identifier string. IDs are local to the current context, such as a list of
 * triples or an SMWExpData container.
 *
 * @license GPL-2.0-or-later
 * @since 2.2
 *
 * @author Markus Krötzsch
 * @author mwjames
 */
class ExpResource extends ExpElement {

	/**
	 * @var string
	 */
	private $uri;

	/**
	 * @var bool
	 */
	public $isImported = false;

	/**
	 * @note The given URI must not contain serialization-specific
	 * abbreviations or escapings, such as XML entities.
	 *
	 * @param string $uri The full URI
	 * @param DataItem|null $dataItem
	 *
	 * @throws InvalidArgumentException
	 */
	public function __construct( $uri, ?DataItem $dataItem = null ) {
		if ( !is_string( $uri ) ) {
			throw new InvalidArgumentException( '$uri needs to be a string' );
		}

		parent::__construct( $dataItem );

		// https://www.w3.org/2011/rdf-wg/wiki/IRIs/RDFConceptsProposal
		// "... characters “<”, “>”, “{”, “}”, “|”, “\”, “^”, “`”, ‘“’ (double quote),
		// and “ ” (space) were allowed ... are not allowed in IRIs, Data
		// containing these characters in %-encoded form is fine ..."
		$this->uri = str_replace( [ '"' ], [ '%22' ], $uri );
	}

	/**
	 * Return true if this resource represents a blank node.
	 *
	 * @return bool
	 */
	public function isBlankNode() {
		return $this->uri === '' || $this->uri[0] == '_';
	}

	/**
	 * @since 2.5
	 *
	 * @return bool
	 */
	public function isImported() {
		return $this->isImported;
	}

	/**
	 * Get the URI of this resource. The result is a UTF-8 encoded URI (or
	 * IRI) without any escaping.
	 *
	 * @return string
	 */
	public function getUri() {
		return $this->uri;
	}

	/**
	 * @since  2.2
	 *
	 * @return array
	 */
	public function getSerialization() {
		$serialization = [
			'type' => self::TYPE_RESOURCE,
			'uri'  => $this->getUri()
		];

		return $serialization + parent::getSerialization();
	}

	/**
	 * @see ExpElement::newFromSerialization
	 */
	protected static function deserialize( $serialization ) {
		if ( !isset( $serialization['uri'] ) ) {
			throw new RuntimeException( "Invalid serialization format" );
		}

		return new self(
			$serialization['uri'],
			$serialization['dataitem']
		);
	}

}
