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

use SabaiApps\Directories\Application;
use SabaiApps\Directories\Component\Entity\Feature\IFeature;
use SabaiApps\Directories\Exception;
use SabaiApps\Directories\Component\Entity\Model\Bundle;

class FeaturesHelper {

	private $_impls = array();

	public function help( Application $application, $useCache = true ) {
		if ( ! $useCache
			|| ( ! $features = $application->getPlatform()->getCache( 'entity_features' ) )
		) {
			$features = array();
			foreach ( $application->InstalledComponentsByInterface( 'Entity\IFeatures' ) as $component_name ) {
				if ( ! $application->isComponentLoaded( $component_name )
					|| ( ! $feature_names = $application->getComponent( $component_name )->entityGetFeatureNames() )
				) {
					continue;
				}

				foreach ( $feature_names as $feature_name ) {
					if ( $feature = $application->getComponent( $component_name )->entityGetFeature( $feature_name ) ) {
						if ( ! $weight = $feature->entityFeatureInfo( 'weight' ) ) {
							$weight = 99;
						}
						$features[ $weight ][ $feature_name ] = $component_name;
					}
				}
			}
			if ( ! empty( $features ) ) {
				ksort( $features );
				$_features = array();
				foreach ( array_keys( $features ) as $weight ) {
					$_features += $features[ $weight ];
				}
				$features = $_features;
			}
			$application->getPlatform()->setCache( $features, 'entity_features' );
		}

		return $features;
	}

	/**
	 * Gets an implementation of IFeature interface for a given feature name
	 *
	 * @param Application $application
	 * @param string      $featureName
	 * @return IFeature
	 */
	public function impl( Application $application, $featureName, $returnFalse = false ) {
		if ( ! isset( $this->_impls[ $featureName ] ) ) {
			if ( ( ! $features = $this->help( $application ) )
				|| ! isset( $features[ $featureName ] )
				|| ! $application->isComponentLoaded( $features[ $featureName ] )
			) {
				if ( $returnFalse ) {
					return false;
				}
				throw new Exception\UnexpectedValueException( sprintf( 'Invalid feature: %s', $featureName ) );
			}
			$this->_impls[ $featureName ] = $application->getComponent( $features[ $featureName ] )->entityGetFeature( $featureName );
		}

		return $this->_impls[ $featureName ];
	}

	public function form( Application $application, Bundle $bundle, array $settings = array(), array $parents = array() ) {
		$form = array(
			'#tree'             => true,
			'#element_validate' => array(
				array( array( $this, '_validateForm' ), array( $application, $bundle ) ),
			),
		);
		foreach ( array_keys( $this->help( $application ) ) as $feature_name ) {
			if ( ( ! $feature = $this->impl( $application, $feature_name, true ) )
				|| ! $feature->entityFeatureSupports( $bundle )
			) {
				continue;
			}

			$feature_info     = $feature->entityFeatureInfo();
			$feature_settings = isset( $settings[ $feature_name ] ) ? $settings[ $feature_name ] : array();
			if ( false === $feature_default_settings = $feature->entityFeatureDefaultSettings( $bundle ) ) {
				$feature_default_settings = isset( $feature_info['default_settings'] ) ? (array) $feature_info['default_settings'] : array();
			}
			$feature_settings += $feature_default_settings;
			if ( ! $feature_settings_form = $feature->entityFeatureSettingsForm( $bundle, $feature_settings, array_merge( $parents, array( $feature_name ) ) ) ) {
				continue;
			}

			$form[ $feature_name ]            = $feature_settings_form;
			$form[ $feature_name ]['#weight'] = isset( $feature_info['weight'] ) ? $feature_info['weight'] : 10;
			$form[ $feature_name ]['#title']  = $feature_info['label'];
			$form[ $feature_name ]['#class']  = 'drts-form-label-lg';
		}
		return $form;
	}

	public function _validateForm( $form, &$value, $element, Application $application, Bundle $bundle ) {
		// Extract settings for both features enabled and disabled as separate arrays
		$enabled = $disabled = array();
		foreach ( $value as $feature_name => $feature_settings ) {
			if ( ! $feature = $application->Entity_Features_impl( $feature_name, true ) ) {
				continue;
			}

			$_feature_settings = $feature->entityFeatureIsEnabled( $bundle, $feature_settings );
			if ( false !== $_feature_settings ) {
				$enabled[ $feature_name ] = is_array( $_feature_settings ) ? $_feature_settings : $feature_settings;
			} else {
				$disabled[ $feature_name ] = $feature_settings;
			}
		}
		$value = array(
			'enabled'  => $enabled,
			'disabled' => $disabled,
		);
	}
}
