<?php
namespace SabaiApps\Directories\Component\Entity\Type;

abstract class AbstractEntity implements IEntity, \ArrayAccess {

	public $data = array();
	protected $_bundleName, $_bundleType, $_properties, $_fieldValues = array(), $_fieldsLoaded = false, $_fromCache = false,
		$_extraFieldValues        = array();
	protected static $_fieldTypes = array();

	public function __construct( $bundleName, $bundleType, array $properties ) {
		$this->_bundleName = $bundleName;
		$this->_bundleType = $bundleType;
		$this->_properties = $properties;
	}

	public function getBundleName() {
		return $this->_bundleName;
	}

	public function getBundleType() {
		return $this->_bundleType;
	}

	public function getProperties() {
		return $this->_properties;
	}

	public function getFieldValue( $name ) {
		return isset( $this->_fieldValues[ $name ] ) ? $this->_fieldValues[ $name ] : ( isset( $this->_properties[ $name ] ) ? array( $this->_properties[ $name ] ) : null );
	}

	public function setFieldValue( $name, $value ) {
		$this->_fieldValues[ $name ] = $value;
		return $this;
	}

	public function getSingleFieldValue( $name, $key = null, $index = 0 ) {
		if ( ( null === $value = $this->getFieldValue( $name ) )
			|| ! isset( $value[ $index ] )
		) {
			return null;
		}

		$ret = $value[ $index ];
		if ( isset( $key ) ) {
			foreach ( (array) $key as $_key ) {
				if ( ! isset( $ret[ $_key ] ) ) {
					return null; // invalid key
				}

				$ret = $ret[ $_key ];
			}
		}
		return $ret;
	}

	public function getFieldValues( $withProperty = false ) {
		return $withProperty ? $this->_properties + $this->_fieldValues : $this->_fieldValues;
	}

	public function getFieldType( $fieldName ) {
		return self::$_fieldTypes[ $this->_bundleName ][ $fieldName ] ?? null;
	}

	public function getFieldTypes() {
		return self::$_fieldTypes[ $this->_bundleName ] ?? null;
	}

	public function getFieldNamesByType( $type ) {
		return isset( self::$_fieldTypes[ $this->_bundleName ] ) ? array_keys( self::$_fieldTypes[ $this->_bundleName ], $type ) : array();
	}

	public function initFields( array $values, array $types, $markLoaded = true ) {
		$this->_fieldValues  = $values;
		$this->_fieldsLoaded = $markLoaded;
		if ( ! isset( self::$_fieldTypes[ $this->_bundleName ] ) ) {
			self::$_fieldTypes[ $this->_bundleName ] = $types;
		}

		return $this;
	}

	public function isFieldsLoaded() {
		return $this->_fieldsLoaded;
	}

	public function setExtraFields( array $values ) {
		$this->_extraFieldValues = $values;
		return $this;
	}

	public function getExtraFieldValue( $name, $default = null ) {
		return $this->_extraFieldValues[ $name ] ?? $default;
	}

	public function __get( $name ) {
		return $this->getFieldValue( $name );
	}

	public function __isset( $name ) {
		return isset( $this->_fieldValues[ $name ] ) || isset( $this->_properties[ $name ] );
	}

	public function __unset( $name ) {
		unset( $this->_fieldValues[ $name ] );
	}

	public function __toString() {
		return $this->getTitle();
	}

	final public function serialize() {
		return serialize( $this->_onSerialize() );
	}

	final public function unserialize( $serialized ) {
		$this->_onUnserialize( unserialize( $serialized ) );
		$this->_fromCache = true;
	}

	public function __serialize() {
		return $this->_onSerialize();
	}

	public function __unserialize( $serialized ) {
		$this->_onUnserialize( $serialized );
		$this->_fromCache = true;
	}

	protected function _onSerialize() {
		return array( $this->_bundleName, $this->_bundleType, $this->_properties );
	}

	protected function _onUnserialize( $values ) {
		$this->_bundleName = $values[0];
		$this->_bundleType = $values[1];
		$this->_properties = $values[2];
	}

	public function isFromCache() {
		return $this->_fromCache;
	}

	public function getUniqueId( $prefix = null ) {
		if ( ! isset( $prefix ) ) {
			$prefix = 'drts-entity';
		}
		return $prefix . '-' . $this->getType() . '-' . $this->getId();
	}

	public function setCustomProperty( $name, $value ) {
		$this->_properties[ '_' . $name ] = $value;
		return $this;
	}

	public function getCustomProperty( $name ) {
		$name = '_' . $name;
		return isset( $this->_properties[ $name ] ) ? $this->_properties[ $name ] : null;
	}

	public function isPropertyModified( $name, $value ) {
		return array_key_exists( $name, $this->_properties )
			&& $value != $this->_properties[ $name ];
	}

	public function getStatus() {}

	public function getModified() {
		return $this->getTimestamp();
	}

	public function isFeatured() {
		return (int) $this->getSingleFieldValue( 'entity_featured', 'value' );
	}

	public function isOnParentPage() {
		return isset( $GLOBALS['drts_entity'] ) && $this->getParentId() === $GLOBALS['drts_entity']->getId();
	}

	public function getAuthorId() {}

	public function getAuthor() {}

	public function getParentId() {}

	public function setParent( IEntity $parent ) {}

	public function setStatus( $status ) {}

	public function isTaxonomyTerm() {
		return false;
	}

	public function isPublished() {
		return true;
	}

	public function isDraft() {
		return false;
	}

	public function isPending() {
		return false;
	}

	public function isPrivate() {
		return false;
	}

	public function isScheduled() {
		return false;
	}

	#[\ReturnTypeWillChange]
	public function offsetExists( $offset ) {
		return isset( $this->_fieldValues[ $offset ] ) || isset( $this->_properties[ $offset ] );
	}

	#[\ReturnTypeWillChange]
	public function offsetGet( $offset ) {
		return $this->getFieldValue( $offset );
	}

	#[\ReturnTypeWillChange]
	public function offsetSet( $offset, $value ) {
		$this->_fieldValues[ $offset ] = $value;
	}

	#[\ReturnTypeWillChange]
	public function offsetUnset( $offset ) {
		unset( $this->_fieldValues[ $offset ] );
	}
}
