<?php 

if( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly.

if( ! class_exists('ACF_Data') ) :

class ACF_Data {
	
	/** @var string Unique identifier. */
	var $cid = '';
	
	/** @var array Storage for data. */
	var $data = array();
	
	/** @var array Storage for data aliases. */
	var $aliases = array();
	
	/** @var bool Enables unique data per site. */
	var $multisite = false;
	
	/**
	 * __construct
	 *
	 * Sets up the class functionality.
	 *
	 * @date	9/1/19
	 * @since	5.7.10
	 *
	 * @param	array $data Optional data to set.
	 * @return	void
	 */
	function __construct( $data = false ) {
		
		// Set cid.
		$this->cid = acf_uniqid();
		
		// Set data.
		if( $data ) {
			$this->set( $data );
		}
		
		// Initialize.
		$this->initialize();
	}
	
	/**
	 * initialize
	 *
	 * Called during constructor to setup class functionality.
	 *
	 * @date	9/1/19
	 * @since	5.7.10
	 *
	 * @param	void
	 * @return	void
	 */
	function initialize() {
		// Do nothing.
	}
	
	/**
	 * prop
	 *
	 * Sets a property for the given name and returns $this for chaining.
	 *
	 * @date	9/1/19
	 * @since	5.7.10
	 *
	 * @param	(string|array) $name The data name or an array of data.
	 * @param	mixed $value The data value.
	 * @return	ACF_Data
	 */
	function prop( $name = '', $value = null ) {
		
		// Update property.
		$this->{$name} = $value;
		
		// Return this for chaining.
		return $this;
	}
	
	/**
	 * _key
	 *
	 * Returns a key for the given name allowing aliasses to work.
	 *
	 * @date	18/1/19
	 * @since	5.7.10
	 *
	 * @param	type $var Description. Default.
	 * @return	type Description.
	 */
	function _key( $name = '' ) {
		return isset($this->aliases[ $name ]) ? $this->aliases[ $name ] : $name;
	}
	
	/**
	 * has
	 *
	 * Returns true if this has data for the given name.
	 *
	 * @date	9/1/19
	 * @since	5.7.10
	 *
	 * @param	string $name The data name.
	 * @return	boolean
	 */
	function has( $name = '' ) {
		$key = $this->_key($name);
		return isset($this->data[ $key ]);
	}
	
	/**
	 * is
	 *
	 * Similar to has() but does not check aliases.
	 *
	 * @date	7/2/19
	 * @since	5.7.11
	 *
	 * @param	type $var Description. Default.
	 * @return	type Description.
	 */
	function is( $key = '' ) {
		return isset($this->data[ $key ]);
	}
	
	/**
	 * get
	 *
	 * Returns data for the given name of null if doesn't exist.
	 *
	 * @date	9/1/19
	 * @since	5.7.10
	 *
	 * @param	string $name The data name.
	 * @return	mixed
	 */
	function get( $name = false ) {
		
		// Get all.
		if( $name === false ) {
			return $this->data;
		
		// Get specific.
		} else {
			$key = $this->_key($name);
			return isset($this->data[ $key ]) ? $this->data[ $key ] : null;
		}
	}
	
	/**
	 * get_data
	 *
	 * Returns an array of all data.
	 *
	 * @date	9/1/19
	 * @since	5.7.10
	 *
	 * @param	void
	 * @return	array
	 */
	function get_data() {
		return $this->data;
	}
	
	/**
	 * set
	 *
	 * Sets data for the given name and returns $this for chaining.
	 *
	 * @date	9/1/19
	 * @since	5.7.10
	 *
	 * @param	(string|array) $name The data name or an array of data.
	 * @param	mixed $value The data value.
	 * @return	ACF_Data
	 */
	function set( $name = '', $value = null ) {
		
		// Set multiple.
		if( is_array($name) ) {
			$this->data = array_merge($this->data, $name);
			
		// Set single.	
		} else {
			$this->data[ $name ] = $value;
		}
		
		// Return this for chaining.
		return $this;
	}
	
	/**
	 * append
	 *
	 * Appends data for the given name and returns $this for chaining.
	 *
	 * @date	9/1/19
	 * @since	5.7.10
	 *
	 * @param	mixed $value The data value.
	 * @return	ACF_Data
	 */
	function append( $value = null ) {
		
		// Append.
		$this->data[] = $value;
		
		// Return this for chaining.
		return $this;
	}
	
	/**
	 * remove
	 *
	 * Removes data for the given name.
	 *
	 * @date	9/1/19
	 * @since	5.7.10
	 *
	 * @param	string $name The data name.
	 * @return	ACF_Data
	 */
	function remove( $name = '' ) {
		
		// Remove data.
		unset( $this->data[ $name ] );
		
		// Return this for chaining.
		return $this;
	}
	
	/**
	 * reset
	 *
	 * Resets the data.
	 *
	 * @date	22/1/19
	 * @since	5.7.10
	 *
	 * @param	void
	 * @return	void
	 */
	function reset() {
		$this->data = array();
		$this->aliases = array();
	}
	
	/**
	 * count
	 *
	 * Returns the data count.
	 *
	 * @date	23/1/19
	 * @since	5.7.10
	 *
	 * @param	void
	 * @return	int
	 */
	function count() {
		return count( $this->data );
	}
	
	/**
	 * query
	 *
	 * Returns a filtered array of data based on the set of key => value arguments.
	 *
	 * @date	23/1/19
	 * @since	5.7.10
	 *
	 * @param	void
	 * @return	int
	 */
	function query( $args, $operator = 'AND' ) {
		return wp_list_filter( $this->data, $args, $operator );
	}
	
	/**
	 * alias
	 *
	 * Sets an alias for the given name allowing data to be found via multiple identifiers.
	 *
	 * @date	18/1/19
	 * @since	5.7.10
	 *
	 * @param	type $var Description. Default.
	 * @return	type Description.
	 */
	function alias( $name = '' /*, $alias, $alias2, etc */ ) {
		
		// Get all aliases.
		$args = func_get_args();
		array_shift( $args );
		
		// Loop over aliases and add to data.
		foreach( $args as $alias ) {
			$this->aliases[ $alias ] = $name;
		}
		
		// Return this for chaining.
		return $this;
	}
	
	/**
	 * switch_site
	 *
	 * Triggered when switching between sites on a multisite installation.
	 *
	 * @date	13/2/19
	 * @since	5.7.11
	 *
	 * @param	int $site_id New blog ID.
	 * @param	int prev_blog_id Prev blog ID.
	 * @return	void
	 */
	function switch_site( $site_id, $prev_site_id ) {
		
		// Bail early if not multisite compatible.
		if( !$this->multisite ) {
			return;
		}
		
		// Bail early if no change in blog ID.
		if( $site_id === $prev_site_id ) {
			return;
		}
		
		// Create storage.
		if( !isset($this->site_data) ) {
			$this->site_data = array();
			$this->site_aliases = array();
		}
		
		// Save state.
		$this->site_data[ $prev_site_id ] = $this->data;
		$this->site_aliases[ $prev_site_id ] = $this->aliases;
		
		// Reset state.
		$this->data = array();
		$this->aliases = array();
		
		// Load state.
		if( isset($this->site_data[ $site_id ]) ) {
			$this->data = $this->site_data[ $site_id ];
			$this->aliases = $this->site_aliases[ $site_id ];
			unset( $this->site_data[ $site_id ] );
			unset( $this->site_aliases[ $site_id ] );
		}
	}
}

endif; // class_exists check
