<?php

/**
 * @package         Convert Forms
 * @version         4.4.10 Pro
 *
 * @author          Tassos Marinos <info@tassos.gr>
 * @link            https://www.tassos.gr
 * @copyright       Copyright © 2024 Tassos All Rights Reserved
 * @license         GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> or later
 */

// No direct access
defined('_JEXEC') or die('Restricted access');

class AWeberEntry extends AWeberResponse
{

	/**
	 * @var array Holds list of data keys that are not publicly accessible
	 */
	protected $_privateData = array(
		'resource_type_link',
		'http_etag',
	);

	/**
	 * @var array   Stores local modifications that have not been saved
	 */
	protected $_localDiff = array();

	/**
	 * @var array Holds AWeberCollection objects already instantiated, keyed by
	 *      their resource name (plural)
	 */
	protected $_collections = array();

	/**
	 * attrs
	 *
	 * Provides a simple array of all the available data (and collections) available
	 * in this entry.
	 *
	 * @access public
	 * @return array
	 */
	public function attrs()
	{
		$attrs = array();
		foreach ($this->data as $key => $value)
		{
			if (!in_array($key, $this->_privateData) && !strpos($key, 'collection_link'))
			{
				$attrs[$key] = $value;
			}
		}
		if (!empty(AWeberAPI::$_collectionMap[$this->type]))
		{
			foreach (AWeberAPI::$_collectionMap[$this->type] as $child)
			{
				$attrs[$child] = 'collection';
			}
		}
		return $attrs;
	}

	/**
	 * _type
	 *
	 * Used to pull the name of this resource from its resource_type_link
	 * @access protected
	 * @return String
	 */
	protected function _type()
	{
		if (empty($this->type))
		{
			if (!empty($this->data['resource_type_link']))
			{
				list($url, $type) = explode('#', $this->data['resource_type_link']);
				$this->type       = $type;
			}
			elseif (!empty($this->data['broadcast_id']))
			{
				$this->type = 'broadcast';
			}
			else
			{
				return null;
			}
		}
		return $this->type;
	}

	/**
	 * delete
	 *
	 * Delete this object from the AWeber system.  May not be supported
	 * by all entry types.
	 * @access public
	 * @return boolean  Returns true if it is successfully deleted, false
	 *      if the delete request failed.
	 */
	public function delete()
	{
		$this->adapter->request('DELETE', $this->url, array(), array('return' => 'status'));
		return true;
	}

	/**
	 * move
	 *
	 * Invoke the API method to MOVE an entry resource to a different List.
	 *
	 * Note: Not all entry resources are eligible to be moved, please
	 *       refer to the AWeber API Reference Documentation at
	 *       https://labs.aweber.com/docs/reference/1.0 for more
	 *       details on which entry resources may be moved and if there
	 *       are any requirements for moving that resource.
	 *
	 * @access public
	 * @param AWeberEntry(List)   List to move Resource (this) too.
	 * @return mixed AWeberEntry(Resource) Resource created on List ($list)
	 *                                     or False if resource was not created.
	 */
	public function move($list, $last_followup_message_number_sent = NULL)
	{
		# Move Resource
		$params = array(
			'ws.op'     => 'move',
			'list_link' => $list->self_link,
		);
		if (isset($last_followup_message_number_sent))
		{
			$params['last_followup_message_number_sent'] = $last_followup_message_number_sent;
		}

		$data = $this->adapter->request('POST', $this->url, $params, array('return' => 'headers'));

		# Return new Resource
		$url           = $data['Location'];
		$resource_data = $this->adapter->request('GET', $url);
		return new AWeberEntry($resource_data, $url, $this->adapter);
	}

	/**
	 * save
	 *
	 * Saves the current state of this object if it has been changed.
	 * @access public
	 * @return void
	 */
	public function save()
	{
		if (!empty($this->_localDiff))
		{
			$data = $this->adapter->request('PATCH', $this->url, $this->_localDiff, array('return' => 'status'));
		}
		$this->_localDiff = array();
		return true;

	}

	/**
	 * __get
	 *
	 * Used to look up items in data, and special properties like type and
	 * child collections dynamically.
	 *
	 * @param String $value     Attribute being accessed
	 * @access public
	 * @throws AWeberResourceNotImplemented
	 * @return mixed
	 */
	public function __get($value)
	{
		if (in_array($value, $this->_privateData))
		{
			return null;
		}
		if (!empty($this->data) && array_key_exists($value, $this->data))
		{
			if (is_array($this->data[$value]))
			{
				$array              = new AWeberEntryDataArray($this->data[$value], $value, $this);
				$this->data[$value] = $array;
			}
			return $this->data[$value];
		}
		if ($value == 'type')
		{
			return $this->_type();
		}

		if ($this->_isChildCollection($value))
		{
			return $this->_getCollection($value);
		}
		throw new AWeberResourceNotImplemented($this, $value);
	}

	/**
	 * __set
	 *
	 * If the key provided is part of the data array, then update it in the
	 * data array.  Otherwise, use the default __set() behavior.
	 *
	 * @param mixed $key        Key of the attr being set
	 * @param mixed $value      Value being set to the $key attr
	 * @access public
	 */
	public function __set($key, $value)
	{
		if (array_key_exists($key, $this->data))
		{
			$this->_localDiff[$key]  = $value;
			return $this->data[$key] = $value;
		}
		else
		{
			return parent::__set($key, $value);
		}
	}

	/** getParentEntry
	 *
	 * Gets an entry's parent entry
	 * Returns NULL if no parent entry
	 */
	public function getParentEntry()
	{
		$url_parts = explode('/', $this->url);
		$size      = count($url_parts);

		#Remove entry id and slash from end of url
		$url = substr($this->url, 0, -strlen($url_parts[$size - 1]) - 1);

		#Remove collection name and slash from end of url
		$url = substr($url, 0, -strlen($url_parts[$size - 2]) - 1);

		try {
			$data = $this->adapter->request('GET', $url);
			return new AWeberEntry($data, $url, $this->adapter);
		}
		catch (Exception $e)
		{
			return NULL;
		}
	}

	/**
	 * _parseNamedOperation
	 *
	 * Turns a dumb array of json into an array of Entries.  This is NOT
	 * a collection, but simply an array of entries, as returned from a
	 * named operation.
	 *
	 * @param array $data
	 * @access protected
	 * @return array
	 */
	protected function _parseNamedOperation($data)
	{
		$results = array();
		foreach ($data as $entryData)
		{
			$results[] = new AWeberEntry($entryData, str_replace($this->adapter->app->getBaseUri(), '',
				$entryData['self_link']), $this->adapter);
		}
		return $results;
	}

	/**
	 * _methodFor
	 *
	 * Raises exception if $this->type is not in array entryTypes.
	 * Used to restrict methods to specific entry type(s).
	 * @param mixed $entryTypes Array of entry types as strings, ie array('account')
	 * @access protected
	 * @return void
	 */
	protected function _methodFor($entryTypes)
	{
		if (in_array($this->type, $entryTypes))
		{
			return true;
		}

		throw new AWeberMethodNotImplemented($this);
	}

	/**
	 * _getCollection
	 *
	 * Returns the AWeberCollection object representing the given
	 * collection name, relative to this entry.
	 *
	 * @param String $value The name of the sub-collection
	 * @access protected
	 * @return AWeberCollection
	 */
	protected function _getCollection($value)
	{
		if (empty($this->_collections[$value]))
		{
			$url                        = "{$this->url}/{$value}";
			$data                       = $this->adapter->request('GET', $url);
			$this->_collections[$value] = new AWeberCollection($data, $url, $this->adapter);
		}
		return $this->_collections[$value];
	}

	/**
	 * _isChildCollection
	 *
	 * Is the given name of a collection a child collection of this entry?
	 *
	 * @param String $value The name of the collection we are looking for
	 * @access protected
	 * @return boolean
	 * @throws AWeberResourceNotImplemented
	 */
	protected function _isChildCollection($value)
	{
		$this->_type();
		if (!empty(AWeberAPI::$_collectionMap[$this->type]) &&
			in_array($value, AWeberAPI::$_collectionMap[$this->type]))
		{
			return true;
		}

		return false;
	}

}
