<?php

/**
 * Base Object
 * @package Simple Lightbox
 * @subpackage Base
 * @author Archetyped
 */
class SLB_Base_Object extends SLB_Base {
	/* Configuration */

	/**
	 * @var string
	 * @see Base::$mode
	 */
	protected $mode = 'object';

	/*-** Properties **-*/

	/**
	 * Unique ID
	 * @var string
	 */
	protected $id = '';

	/**
	 * Parent object
	 * @var Base_Object
	 */
	protected $parent = null;

	/**
	 * Attached files
	 * @var array
	 * > scripts    array JS scripts
	 * > styles     array Stylesheets
	 */
	protected $files = array(
		'scripts' => array(),
		'styles'  => array(),
	);

	/**
	 * Properties that can be inherited from parent
	 * @var array
	 */
	protected $parent_props = array();

	/*-** Methods **-*/

	/**
	 * Constructor
	 * @param string $id Unique ID for content type
	 * @param array $props (optional) Type properties (optional because props can be set post-init)
	 */
	public function __construct( $id, $props = null ) {
		parent::__construct();
		$this
			->set_id( $id )
			->set_props( $props );
	}

	/**
	 * Checks if object is valid
	 * To be overriden by child classes
	 */
	public function is_valid() {
		return true;
	}

	/*-** Getters/Setters **-*/

	/**
	 * Get ID
	 * @return string ID
	 */
	public function get_id() {
		return $this->id;
	}

	/**
	 * Set ID
	 * @param string $id ID
	 * @return object Current instance
	 */
	public function set_id( $id ) {
		$id = ( is_string( $id ) ) ? trim( $id ) : '';
		if ( ! empty( $id ) ) {
			$this->id = $id;
		}
		return $this;
	}

	/**
	 * Set type properties
	 * @param array $props Type properties to set
	 */
	protected function set_props( $props ) {
		if ( is_array( $props ) && ! empty( $props ) ) {
			foreach ( $props as $key => $val ) {
				// Check for setter method
				$m = 'set_' . $key;
				if ( method_exists( $this, $m ) ) {
					$this->{$m}( $val );
				}
			}
		}
		return $this;
	}

	/**
	 * Get parent
	 * @return object|null Parent
	 */
	public function get_parent() {
		return $this->parent;
	}

	/**
	 * Set parent
	 * @param object $parent Parent object
	 * @return object Current instance
	 */
	public function set_parent( $parent ) {
		$this->parent = ( $parent instanceof $this ) ? $parent : null;
		return $this;
	}

	/**
	 * Check if parent is set
	 * @return bool TRUE if parent is set
	 */
	public function has_parent() {
		return ( is_null( $this->parent ) ) ? false : true;
	}

	/**
	 * Retrieve all ancestors
	 * @return array Ancestors
	 */
	public function get_ancestors() {
		$ret  = array();
		$curr = $this;
		while ( $curr->has_parent() ) {
			// Get next ancestor.
			$curr = $curr->get_parent();
			// Add ancestor.
			$ret[] = $curr;
		}

		return $ret;
	}

	/* Files */

	/**
	 * Add file
	 * @param string $type Group to add file to
	 * @param string $handle Name for resource
	 * @param string $src File URI
	 * @return object Current instance
	 */
	protected function add_file( $type, $handle, $src, $deps = array() ) {
		if ( is_string( $type ) && is_string( $handle ) && is_string( $src ) ) {
			// Validate dependencies
			if ( ! is_array( $deps ) ) {
				$deps = array();
			}
			// Init file group
			if ( ! isset( $this->files[ $type ] ) || ! is_array( $this->files[ $type ] ) ) {
				$this->files[ $type ] = array();
			}
			// Add file to group
			$this->files[ $type ][ $handle ] = array(
				'handle' => $handle,
				'uri'    => $src,
				'deps'   => $deps,
			);
		}
		return $this;
	}

	/**
	 * Add multiple files
	 * @param string $type Group to add files to
	 * @param array $files Files to add
	 * @see add_file() for file parameters
	 * @return object Current instance
	 */
	protected function add_files( $type, $files ) {
		if ( ! is_array( $files ) || empty( $files ) ) {
			return false;
		}
		$m = $this->m( 'add_file' );
		foreach ( $files as $file ) {
			if ( ! is_array( $file ) || empty( $file ) ) {
				continue;
			}
			array_unshift( $file, $type );
			call_user_func_array( $m, $file );
		}
		return $this;
	}

	/**
	 * Retrieve files
	 * All files or a specific group of files can be retrieved
	 * @param string $type (optional) File group to retrieve
	 * @return array Files
	 */
	protected function get_files( $type = null ) {
		$ret = $this->files;
		if ( is_string( $type ) ) {
			$ret = ( isset( $ret[ $type ] ) ) ? $ret[ $type ] : array();
		}
		if ( ! is_array( $ret ) ) {
			$ret = array();
		}
		return $ret;
	}

	/**
	 * Retrieve file
	 * @param string $type Group to retrieve file from
	 * @param string $handle
	 * @param string $format (optional) Format of return value (Default: array)
	 * @return array|null File properties (Default: NULL)
	 */
	protected function get_file( $type, $handle, $format = null ) {
		// Get files
		$files = $this->get_files( $type );
		// Get specified file
		$ret = ( is_string( $type ) && isset( $files[ $handle ] ) ) ? $files[ $handle ] : null;
		// Format return value
		if ( ! empty( $ret ) && ! ! $format ) {
			switch ( $format ) {
				case 'uri':
					$ret = $ret['uri'];
					// Normalize URI
					if ( ! $this->util->is_uri( $ret ) ) {
						$ret = $this->util->normalize_path( site_url(), $ret );
					}
					break;
				case 'path':
					$ret = $ret['uri'];
					// Normalize path
					if ( ! $this->util->is_uri( $ret ) ) {
						$ret = $this->util->get_relative_path( $ret );
						$ret = $this->util->normalize_path( ABSPATH, $ret );
					}
					break;
				case 'object':
					$ret = (object) $ret;
					break;
				case 'contents':
					$ret = $ret['uri'];
					if ( ! $this->util->is_uri( $ret ) ) {
						$ret = $this->util->normalize_path( site_url(), $ret );
					}
					$get = wp_safe_remote_get( $ret );
					$ret = ( ! is_wp_error( $get ) && 200 === $get['response']['code'] ) ? $get['body'] : '';
					break;
			}
		}
		return $ret;
	}

	/**
	 * Add stylesheet
	 * @param string $handle Name of the stylesheet
	 * @param string $src Stylesheet URI
	 * @return object Current instance
	 */
	public function add_style( $handle, $src, $deps = array() ) {
		return $this->add_file( 'styles', $handle, $src, $deps );
	}

	/**
	 * Retrieve stylesheet files
	 * @return array Stylesheet files
	 */
	public function get_styles( $opts = null ) {
		$files = $this->get_files( 'styles' );
		if ( is_array( $opts ) ) {
			$opts = (object) $opts;
		}
		if ( is_object( $opts ) && ! empty( $opts ) ) {
			// Parse options
			// URI Format
			if ( isset( $opts->uri_format ) ) {
				foreach ( $files as $hdl => $props ) {
					switch ( $opts->uri_format ) {
						case 'full':
							if ( ! $this->util->is_uri( $props['uri'] ) ) {
								$files[ $hdl ]['uri'] = $this->util->normalize_path( site_url(), $props['uri'] );
							}
							break;
					}
				}
			}
		}
		return $files;
	}

	/**
	 * Retrieve stylesheet file
	 * @param string $handle Name of stylesheet
	 * @param string $format (optional) Format of return value (@see `get_file()`)
	 * @return array|null File properties (Default: NULL)
	 */
	public function get_style( $handle, $format = null ) {
		return $this->get_file( 'styles', $handle, $format );
	}

	/**
	 * Add script
	 * @param string $handle Name of the script
	 * @param string $src Script URI
	 * @return object Current instance
	 */
	public function add_script( $handle, $src, $deps = array() ) {
		return $this->add_file( 'scripts', $handle, $src, $deps );
	}

	/**
	 * Retrieve script files
	 * @return array Script files
	 */
	public function get_scripts() {
		return $this->get_files( 'scripts' );
	}

	/**
	 * Retrieve script file
	 * @param string $handle Name of script
	 * @param string $format (optional) Format of return value (@see `get_file()`)
	 * @return array|null File properties (Default: NULL)
	 */
	public function get_script( $handle, $format = null ) {
		return $this->get_file( 'scripts', $handle, $format );
	}

}
