<?php
/**
 * @brief		Customization AJAX actions
 * @since		07 May 2013
 */

namespace IPS\core\modules\admin\customization;

/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
	header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
	exit;
}

/**
 * Members AJAX actions
 */
class _ajax extends \IPS\Dispatcher\Controller
{
	/**
	 * @brief	Has been CSRF-protected
	 */
	public static $csrfProtected = TRUE;
	
	/**
	 * Return a CSS or HTML menu
	 *
	 * @return	html
	 */
	public function loadMenu()
	{
		$id	        = \IPS\Request::i()->id;
		$t_type 	= \IPS\Request::i()->t_type     ?: 'templates';
		$t_app      = \IPS\Request::i()->t_app		?: 'core';
		$t_location = \IPS\Request::i()->t_location ?: ( ( \IPS\Request::i()->t_app ) ? false : 'front' );
		
		if ( $t_type == 'templates' )
		{
			$t_group    = \IPS\Request::i()->t_group ?: ( ( \IPS\Request::i()->t_app ) ? false : 'global' );
			$t_template = \IPS\Request::i()->t_name  ?: ( ( \IPS\Request::i()->t_app ) ? false : 'globalTemplate' );
		}
		else
		{
			$t_group    = \IPS\Request::i()->t_group ?: ( ( \IPS\Request::i()->t_app ) ? false : 'custom' );
			$t_template = \IPS\Request::i()->t_name  ?: ( ( \IPS\Request::i()->t_app ) ? false : 'custom.css' );
		}
		
		$theme = \IPS\Theme::load( $id );

		if ( $t_type == 'templates' )
		{
			$templateNames = $theme->getRawTemplates( '', '', '', \IPS\Theme::RETURN_ALL_NO_CONTENT );
		}
		else
		{
			$templateNames = $theme->getRawCss( '', '', '', \IPS\Theme::RETURN_ALL_NO_CONTENT );
		}
		
		if ( $t_type === 'templates' )
		{
			/* Remove Admin Templates */
			foreach( $templateNames as $app => $items )
			{
				foreach( $templateNames[ $app ] as $location => $items )
				{
					if ( $location == 'admin' )
					{
						unset( $templateNames[ $app ][ $location ] );
					}
				}
			}
		}
		else
		{
			$cssFiles = [];
			/* Remove all but custom/custom.css */
			foreach ( $templateNames as $app => $items )
			{
				foreach ( $templateNames[$app] as $location => $items )
				{
					if ( $location === 'front' or $location === 'global' )
					{
						foreach ( $templateNames[$app][$location] as $path => $items )
						{
							if ( $path == 'custom' )
							{
								$cssFiles[ $app ][ $location ][ $path ] = $items;
							}
							else
							{
								foreach( $items as $item )
								{
									if ( $item['css_added_to'] == $theme->_id or $item['css_user_edited'] )
									{
										$cssFiles[ $app ][ $location ][ $path ][ $item['css_name'] ] = $item;
									}
								}
							}
						}
					}
				}
			}

			$templateNames = $cssFiles;
		}

		\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'customization' )->templateEditorMenu( $theme, $templateNames, array( 'app' => $t_app, 'location' => $t_location, 'group' => $t_group, 'template' => $t_template, 'type' => $t_type) );
	}
	
	/**
	 * Return a CSS or HTML template as JSON
	 *
	 * @return	json
	 */
	public function loadTemplate()
	{
		$t_type 	= \IPS\Request::i()->t_type;
		$t_app      = \IPS\Request::i()->t_app;
		$t_location = \IPS\Request::i()->t_location;
		$t_group	= ( \IPS\Request::i()->t_group ) ?: '.';
		$t_name     = \IPS\Request::i()->t_name;
		$id	        = \IPS\Request::i()->id;
		
		$skinSet       = \IPS\Theme::load( $id );
	
		if ( $t_type == 'templates' )
		{
			$templateBits  = $skinSet->getRawTemplates( $t_app, $t_location, $t_group, \IPS\Theme::RETURN_ALL );
			$templateBit   = ( ! empty( $t_name ) ) ? $templateBits[ $t_app ][ $t_location ][ $t_group ][ $t_name ] : null;
			$templateBit['template_content'] = htmlentities( $templateBit['template_content'], ENT_DISALLOWED, 'UTF-8', TRUE );
		}
		else
		{
			$templateNames = $skinSet->getRawCss( '', '', '', \IPS\Theme::RETURN_ALL_NO_CONTENT );
			$templateBits  = $skinSet->getRawCss( $t_app, ['global', 'front'], NULL, \IPS\Theme::RETURN_ALL );
			$templateBit   = ( ! empty( $t_name ) ) ? $templateBits[ $t_app ][ $t_location ][ $t_group ][ $t_name ] : null;
			$templateBit['css_content'] = htmlentities( $templateBit['css_content'], ENT_DISALLOWED, 'UTF-8', TRUE );
		}
		
		if ( $templateBit !== null )
		{
			\IPS\Output::i()->json( $templateBit );
		}
		else
		{
			\IPS\Output::i()->json( array( 'error' => true ) );
		}
	}
	
	/**
	 * [AJAX] Search templates
	 *
	 * @return	void
	 */
	public function searchtemplates()
	{
		\IPS\Dispatcher::i()->checkAcpPermission( 'theme_templates_manage' );
		
		$theme = \IPS\Theme::load( \IPS\Request::i()->id );
		$parents = array( $theme->_id );
		
		$where = array();
		if ( \IPS\Request::i()->term )
		{
			$where[] = array( '( LOWER(template_name) LIKE ? OR LOWER(template_content) LIKE ? )', '%' . mb_strtolower( \IPS\Request::i()->term ) . '%', '%' . mb_strtolower( \IPS\Request::i()->term ) . '%' );
			
			/* If searching content we need to specifically only search the templates *actually* being used */
			$uniqueIds = array();
			foreach ( $theme->getRawTemplates( '', '', '', \IPS\Theme::RETURN_ALL_NO_CONTENT ) as $locations )
			{
				foreach ( $locations as $groups )
				{
					foreach ( $groups as $templates )
					{
						foreach ( $templates as $template )
						{
							$uniqueIds[] = md5( $template['template_app'] . ',' . $template['template_location'] . ',' . $template['template_group'] . ',' . $template['template_name'] );
						}
					}
				}
			}
			$where[] = array( \IPS\Db::i()->in( "MD5( CONCAT_WS( ',', template_app, template_location, template_group, template_name ) )", $uniqueIds ) );
		}
		if ( \in_array( 'inherited', explode( ',', \IPS\Request::i()->filters ) ) )
		{
			try
			{
				foreach( $theme->parents() as $parent )
				{
					$parents[] = $parent->_id;
				}
			}
			catch( \OutOfRangeException $e ) { }
		}
		array_push( $parents, 0 );
		if ( !\in_array( 'unique', explode( ',', \IPS\Request::i()->filters ) ) )
		{
			$where[] = array( 'template_user_added=0' );
		}
		if ( !\in_array( 'unmodified', explode( ',', \IPS\Request::i()->filters ) ) )
		{
			$where[] = array( 'template_user_edited>0 or template_added_to > 0' );
		}
		if ( !\in_array( 'modified', explode( ',', \IPS\Request::i()->filters ) ) )
		{
			$where[] = array( 'template_added_to=0' );
		}
		$where[] = array( 'template_set_id IN (' . implode( ',' , $parents ) . ')' );
		
		$select = \IPS\Db::i()->select(
			'*, INSTR(\',' . implode( ',' , $parents ) . ',\', CONCAT(\',\',template_set_id,\',\') ) as theorder',
			'core_theme_templates',
			$where,
			'template_location, template_group, template_name, theorder desc'
		);

		$return = array();
		foreach( $select as $result )
		{
			if ( $result['template_user_edited'] )
			{
				try
				{
					$outOfDate = $result['template_user_edited'] < \IPS\Application::load( $result['template_app'] )->long_version;
				}
				catch( \UnexpectedValueException | \OutOfRangeException $e )
				{
					unset( $return[ $result['template_app'] ][ $result['template_location'] ][ $result['template_group'] ][ $result['template_name'] ] );
					continue;
				}
				
				if ( ( $outOfDate and !\in_array( 'outofdate', explode( ',', \IPS\Request::i()->filters ) ) ) or ( !$outOfDate and !\in_array( 'modified', explode( ',', \IPS\Request::i()->filters ) ) ) )
				{
					unset( $return[ $result['template_app'] ][ $result['template_location'] ][ $result['template_group'] ][ $result['template_name'] ] );
					continue;
				}
			}

			$return[ $result['template_app'] ][ $result['template_location'] ][ $result['template_group'] ][ $result['template_name'] ] = $result['template_name'];
		}
		
		\IPS\Output::i()->json( $return );
	}
	
	/**
	 * [AJAX] Search CSS
	 *
	 * @return	void
	 */
	public function searchcss()
	{
		\IPS\Dispatcher::i()->checkAcpPermission( 'theme_templates_manage' );
		
		$theme = \IPS\Theme::load( \IPS\Request::i()->id );
		$parents = array( $theme->_id );

		$where = array();
		if ( \IPS\Request::i()->term )
		{
			$where[] = array( '( LOWER(css_name) LIKE ? OR LOWER(css_content) LIKE ? )', '%' . mb_strtolower( \IPS\Request::i()->term ) . '%', '%' . mb_strtolower( \IPS\Request::i()->term ) . '%' );
			
			/* If searching content we need to specifically only search the css files *actually* being used */
			$uniqueIds = array();
			foreach ( $theme->getRawCss( '', '', '', \IPS\Theme::RETURN_ALL_NO_CONTENT ) as $locations )
			{
				foreach ( $locations as $groups )
				{
					foreach ( $groups as $templates )
					{
						foreach ( $templates as $template )
						{
							$uniqueIds[] = md5( $template['css_app'] . ',' . $template['css_location'] . ',' . $template['css_path'] . ',' . $template['css_name'] );
						}
					}
				}
			}
			$where[] = array( \IPS\Db::i()->in( "MD5( CONCAT_WS( ',', css_app, css_location, css_path, css_name ) )", $uniqueIds ) );
		}
		if ( \in_array( 'inherited', explode( ',', \IPS\Request::i()->filters ) ) )
		{
			try
			{
				foreach( $theme->parents() as $parent )
				{
					$parents[] = $parent->_id;
				}
			}
			catch( \OutOfRangeException $e ) { }
		}
		array_push( $parents, 0 );
		if ( !\in_array( 'unique', explode( ',', \IPS\Request::i()->filters ) ) )
		{
			$where[] = array( 'css_added_to=?', \IPS\Request::i()->id );
		}
		if ( !\in_array( 'unmodified', explode( ',', \IPS\Request::i()->filters ) ) )
		{
			$where[] = array( 'css_user_edited>0' );
		}
		$where[] = array( 'css_set_id IN (' . implode( ',' , $parents ) . ')' );

		$return = array();
		foreach( \IPS\Db::i()->select(
			'*, INSTR(\',' . implode( ',' , $parents ) . ',\', CONCAT(\',\',css_set_id,\',\') ) as theorder',
			'core_theme_css',
			$where,
			'css_location, css_path, css_name, theorder desc'
		) as $result )
		{
			if ( $result['css_user_edited'] )
			{
				try
				{
					$outOfDate = $result['css_user_edited'] < \IPS\Application::load( $result['css_app'] )->long_version;
				}
				catch( \UnexpectedValueException | \OutOfRangeException $e )
				{
					unset( $return[ $result['css_app'] ][ $result['css_location'] ][ $result['css_path'] ][ $result['css_name'] ] );
					continue;
				}

				if ( !$result['css_added_to'] and ( ( $outOfDate and !\in_array( 'outofdate', explode( ',', \IPS\Request::i()->filters ) ) ) or ( !$outOfDate and !\in_array( 'modified', explode( ',', \IPS\Request::i()->filters ) ) ) ) )
				{
					unset( $return[ $result['css_app'] ][ $result['css_location'] ][ $result['css_path'] ][ $result['css_name'] ] );
					continue;
				}
			}

			$return[ $result['css_app'] ][ $result['css_location'] ][ $result['css_path'] ][ $result['css_name'] ] = $result['css_name'];
		}
		
		\IPS\Output::i()->json( $return );
	}
}