<?php

// ##########################################################################

/**
* Abstract class for handling tags found by vB_TemplateParser.
*/
class vB_TemplateParser_Curly
{
	/**
	* Validate the use of this tag. Can validate any aspects of the tag,
	* including attributes, siblings, parents, and children
	*
	* @param	object	DOM Node of type text
	* @param	object	vB_TemplateParser object
	*
	* @return	array	Array of errors
	*/
	public static function validate(vB_Node $main_node, vB_TemplateParser $parser)
	{
		return array();
	}

	/**
	* Compile this tag. Note that you must account for children as well.
	*
	* @param	object	DOM Node of type text
	* @param	object	vB_TemplateParser object
	*
	* @return	string	Evalable string
	*/
	public static function compile(vB_Node $main_node, vB_TemplateParser $parser)
	{
		return $parser->_parse_nodes($main_node->childNodes());
	}
		
	/**
	* Converts a single attribute to an argument string
	*
	* @param	array	the attribute
	* @param	object	the parser object
	*
	* @return	string	string version of attribute
	*/
	protected static function attributeToString($attribute, $parser)
	{
		if ($attribute instanceof vB_CurlyNode AND in_array($attribute->value, array('raw', 'var')))
		{
			//The substr is used to strip the two single quotes and period before and after the variable
			//'' . $block_data['pageinfo_vcard'] . '')' changed to $block_data['pageinfo_vcard']
			//This allows for an array in an array to be passed in through the link function
			//{vb:link member, {vb:raw array_variable}, {vb:raw array_variable.array_variable}}
			return substr($parser->_default_node_handler($attribute), 4, -4);
		}
		else
		{				
			return '"' . $attribute . '"';
			
			//TODO: change to the following line when we want to enforce
			//no explicit variables as curly brace parameters
			//	$arguments .= "'" . $attribute . "'";
		}
	}
	
	/**
	* Compiles an array of attributes into an escaped argument string
	* for use by the template eval engine at runtime
	*
	* @param	array	list of attributes
	* @param	object	the parser object
	*
	* @return	string	argument portion for runtime engine call
	*/
	protected static function getArgumentsFromAttributes($attribute_list, $parser)
	{
		$arguments = '';
		foreach ($attribute_list AS $attribute)
		{
			$arguments .= self::attributeToString($attribute, $parser) . ', ';
		}
		// remove trailing comma and space
		$arguments = substr_replace($arguments ,'',-2);
	
		return $arguments;
	}
}

// ##########################################################################

class vB_TemplateParser_CurlyDate extends vB_TemplateParser_Curly
{
	public static function validate(vB_Node $main_node, vB_TemplateParser $parser)
	{
		$errors = array();

		if (!array_key_exists(0, $main_node->attributes))
		{
			$errors[] = 'no_timestamp_specified';
		}

		if (sizeof($main_node->attributes) > 2)
		{
			$errors[] = 'too_many_attributes';
		}

		return $errors;
	}

	public static function compile(vB_Node $main_node, vB_TemplateParser $parser)
	{
		$arguments = self::getArgumentsFromAttributes($main_node->attributes, $parser);
		
		return 'vB_Template_Runtime::date(' .$arguments . ')';
	}
}

// ##########################################################################

class vB_TemplateParser_CurlyEscapeJS extends vB_TemplateParser_Curly
{
	public static function validate(vB_Node $main_node, vB_TemplateParser $parser)
	{
		$errors = array();

		if (!array_key_exists(0, $main_node->attributes))
		{
			$errors[] = 'no_variable_specified';
		}

		if (sizeof($main_node->attributes) > 1)
		{
			$errors[] = 'too_many_attributes';
		}
		return $errors;
	}

	public static function compile(vB_Node $main_node, vB_TemplateParser $parser)
	{
		$arguments = self::getArgumentsFromAttributes($main_node->attributes, $parser);

		return 'vB_Template_Runtime::escapeJS(' .$arguments . ')';
	}
}

// ##########################################################################

class vB_TemplateParser_CurlyIf extends vB_TemplateParser_Curly
{
	public static function validate(vB_Node $main_node, vB_TemplateParser $parser)
	{
		$errors = array();

		if (!array_key_exists(0, $main_node->attributes))
		{
			$errors[] = 'no_condition_specified';
		}

		if (!array_key_exists(1, $main_node->attributes))
		{
			$errors[] = 'no_true_expression_specified';
		}

		if (sizeof($main_node->attributes) > 3)
		{
			$errors[] = 'too_many_attributes';
		}
		return $errors;
	}

	public static function compile(vB_Node $main_node, vB_TemplateParser $parser)
	{
		$trueval = self::attributeToString($main_node->attributes[1], $parser);
		$falseval = (!empty($main_node->attributes[2]) ? self::attributeToString($main_node->attributes[2], $parser) : '""');
		
		return '((' . $main_node->attributes[0] . ') ? ' . $trueval . ' : ' . $falseval . ') ';
	}
}

// ##########################################################################

class vB_TemplateParser_CurlyLink extends vB_TemplateParser_Curly
{
	public static function validate(vB_Node $main_node, vB_TemplateParser $parser)
	{
		$errors = array();

		if (!array_key_exists(0, $main_node->attributes))
		{
			$errors[] = 'no_type_specified';
		}

		if (!array_key_exists(1, $main_node->attributes))
		{
			$errors[] = 'no_info_specified';
		}

		$argument_list = array_slice($main_node->attributes, 1);
		foreach ($argument_list AS $attribute)
		{
			if ($attribute instanceof vB_CurlyNode AND !in_array($attribute->value, array('raw', 'var')))
			{
				$errors[] = 'link_only_accepts_vars';
			}
		}

		if (sizeof($main_node->attributes) > 5)
		{
			$errors[] = 'too_many_attributes';
		}

		return $errors;
	}

	public static function compile(vB_Node $main_node, vB_TemplateParser $parser)
	{
		$argument_list = array_slice($main_node->attributes, 1);
		$arguments = '';
		foreach ($argument_list AS $attribute)
		{
			if ($attribute instanceof vB_CurlyNode)
			{
				$arguments .= ", " .  self::attributeToString($attribute, $parser);
			}
			else if ($attribute === NULL)
			{
				$arguments .= ', NULL';
			}
			else
			{
				$arguments .= ", '" . $attribute . "'";
			}
		}

		return 'vB_Template_Runtime::linkBuild("' . $main_node->attributes[0] . "\"$arguments" . ')';
	}
}

// ##########################################################################

class vB_TemplateParser_CurlyNumber extends vB_TemplateParser_Curly
{
	public static function validate(vB_Node $main_node, vB_TemplateParser $parser)
	{
		$errors = array();

		if (!array_key_exists(0, $main_node->attributes))
		{
			$errors[] = 'no_number_specified';
		}

		if (sizeof($main_node->attributes) > 2)
		{
			$errors[] = 'too_many_attributes';
		}

		return $errors;
	}

	public static function compile(vB_Node $main_node, vB_TemplateParser $parser)
	{
		$arguments = self::getArgumentsFromAttributes($main_node->attributes, $parser);
		
		return 'vB_Template_Runtime::numberFormat(' .$arguments . ')';
	}
}

// ##########################################################################

class vB_TemplateParser_CurlyPhrase extends vB_TemplateParser_Curly
{
	public static function validate(vB_Node $main_node, vB_TemplateParser $parser)
	{
		$errors = array();

		if (!array_key_exists(0, $main_node->attributes))
		{
			$errors[] = 'no_phrase_specified';
		}

		return $errors;
	}

	public static function compile(vB_Node $main_node, vB_TemplateParser $parser)
	{
		$argument_list = array_slice($main_node->attributes, 1);
		$arguments = '';
		foreach ($argument_list AS $attribute)
		{
			if ($attribute instanceof vB_CurlyNode)
			{
				$attribute = $parser->_default_node_handler($attribute);
			}
			$arguments .= ", htmlspecialchars('" . $attribute . "')";
		}

		if ($main_node->attributes[0] instanceof vB_CurlyNode AND in_array($main_node->attributes[0]->value, array('raw', 'var')))
		{
			$string = '$' . $main_node->attributes[0]->attributes[0];
		}
		else
		{
			$string = $main_node->attributes[0];
		}
		return 'vB_Template_Runtime::parsePhrase("' . $string . "\"$arguments" . ')';
	}
}


// ##########################################################################

class vB_TemplateParser_CurlyRawPhrase extends vB_TemplateParser_Curly
{
	public static function validate(vB_Node $main_node, vB_TemplateParser $parser)
	{
		$errors = array();

		if (!array_key_exists(0, $main_node->attributes))
		{
			$errors[] = 'no_phrase_specified';
		}

		return $errors;
	}

	public static function compile(vB_Node $main_node, vB_TemplateParser $parser)
	{
		$argument_list = array_slice($main_node->attributes, 1);
		$arguments = '';
		foreach ($argument_list AS $attribute)
		{
			if ($attribute instanceof vB_CurlyNode)
			{
				$arguments .= ", '" . $parser->_default_node_handler($attribute) . "'";
			}
			else
			{
				$arguments .= ", '" . $attribute . "'";
			}
		}

		if ($main_node->attributes[0] instanceof vB_CurlyNode AND in_array($main_node->attributes[0]->value, array('raw', 'var')))
		{
			$string = $main_node->attributes[0]->attributes[0];
			$string = ($string[0] !== '$' ? '$' : '') . $string;
		}
		else
		{
			$string = $main_node->attributes[0];
		}
		
		return 'vB_Template_Runtime::parsePhrase("' . $string . "\"$arguments" . ')';
	}
}

// ##########################################################################

class vB_TemplateParser_CurlyTime extends vB_TemplateParser_Curly
{
	public static function validate(vB_Node $main_node, vB_TemplateParser $parser)
	{
		$errors = array();

		if (!array_key_exists(0, $main_node->attributes))
		{
			$errors[] = 'no_time_specified';
		}

		if (sizeof($main_node->attributes) > 1)
		{
			$errors[] = 'too_many_attributes';
		}

		return $errors;
	}

	public static function compile(vB_Node $main_node, vB_TemplateParser $parser)
	{
		$arguments = self::getArgumentsFromAttributes($main_node->attributes, $parser);
		
		return 'vB_Template_Runtime::time(' .$arguments . ')';
	}
}

// ##########################################################################

class vB_TemplateParser_CurlyUrlencode extends vB_TemplateParser_Curly
{
	public static function validate(vB_Node $main_node, vB_TemplateParser $parser)
	{
		$errors = array();

		if (!array_key_exists(0, $main_node->attributes))
		{
			$errors[] = 'no_variable_specified';
		}

		if (sizeof($main_node->attributes) > 1)
		{
			$errors[] = 'too_many_attributes';
		}

		return $errors;
	}

	public static function compile(vB_Node $main_node, vB_TemplateParser $parser)
	{
		$arguments = self::getArgumentsFromAttributes($main_node->attributes, $parser);
		
		return 'vB_Template_Runtime::urlEncode(' .$arguments . ')';
	}
}

// ##########################################################################

class vB_TemplateParser_CurlyStylevar extends vB_TemplateParser_Curly
{
	public static function validate(vB_Node $main_node, vB_TemplateParser $parser)
	{
		$errors = array();

		if (!array_key_exists(0, $main_node->attributes))
		{
			$errors[] = 'no_variable_specified';
		}

		if (sizeof($main_node->attributes) > 1)
		{
			$errors[] = 'too_many_attributes';
		}

		return $errors;
	}

	public static function compile(vB_Node $main_node, vB_TemplateParser $parser)
	{
		return 'vB_Template_Runtime::fetchStylevar("' . $main_node->attributes[0] . '")';
	}
}

// ##########################################################################

class vB_TemplateParser_CurlyMath extends vB_TemplateParser_Curly
{
	public static function validate(vB_Node $main_node, vB_TemplateParser $parser)
	{
		$errors = array();

		if (!array_key_exists(0, $main_node->attributes))
		{
			$errors[] = 'no_variable_specified';
		}

		return $errors;
	}

	public static function compile(vB_Node $main_node, vB_TemplateParser $parser)
	{

		$argument_list = $main_node->attributes;
		$arguments = array();
		foreach ($argument_list AS $attribute)
		{
			if ($attribute instanceof vB_CurlyNode)
			{
				$attribute = "'" . $parser->_default_node_handler($attribute) . "'";
			}
			else
			{
				$attribute = "'$attribute'";
			}
			$arguments[] =  $attribute;
		}
		$arguments = implode(".", $arguments);
		return 'vB_Template_Runtime::runMaths(' . $arguments . ')';
	}
}

// ##########################################################################

class vB_TemplateParser_CurlyVar extends vB_TemplateParser_Curly
{
	public static function validate(vB_Node $main_node, vB_TemplateParser $parser)
	{
		return vB_TemplateParser_CurlyRaw::validate($main_node, $parser);
	}

	public static function compile(vB_Node $main_node, vB_TemplateParser $parser)
	{
		return 'htmlspecialchars(' . vB_TemplateParser_CurlyRaw::compile($main_node, $parser) . ')';
	}
}

class vB_TemplateParser_CurlyRaw extends vB_TemplateParser_Curly
{
	public static function validate(vB_Node $main_node, vB_TemplateParser $parser)
	{
		$errors = array();

		if (!array_key_exists(0, $main_node->attributes))
		{
			$errors[] = 'no_variable_specified';
		}
		else if (!preg_match('#\$?([a-z_][a-z0-9_]*)(\.([a-z0-9_]+|\$([a-z_][a-z0-9_]*))+)*#i', $main_node->attributes[0]))
		{
			$errors[] = 'invalid_variable_name';
		}

		return $errors;
	}

	public static function compile(vB_Node $main_node, vB_TemplateParser $parser)
	{
		$parts = explode('.', $main_node->attributes[0]);
		// first part is always the variable or array value
		$output = $parts[0];

		if (isset($parts[1]))
		{
			if ($main_node->attributes[1] instanceof vB_CurlyNode AND in_array($main_node->attributes[1]->value, array('raw', 'var')))
			{
				$parts[1] = '$' . $main_node->attributes[1]->attributes[0];
			}
    	for ($i = 1; $i < sizeof($parts); $i++)
    	{
				if ($parts[$i][0] == '$')
				{
	        		$output .= '[' . $parts[$i] . ']';
				}
				else if (strpos($parts[$i], '$') !== false)
				{
	        		$output .= '["' . $parts[$i] . '"]';
				}
				else
				{
	        		$output .= "['" . $parts[$i] . "']";
				}
    	}
		}

		return ($output[0] !== '$' ? '$' : '') . $output;
	}
}

/*
//keep this in our back pocket --
//The curly parser currently requires arguments to be either a string or a curly
//tag.  However in some cases, most notably params to phrases, we'd like to be
//able to pass such a combination.  This fakes it by converting a combination into
//a single curly tag.
class vB_TemplateParser_CurlyCat extends vB_TemplateParser_Curly
{
	public static function compile(vB_Node $main_node, vB_TemplateParser $parser)
	{
		$string = "";
		foreach ($main_node->attributes AS $attribute)
		{
			if ($attribute instanceof vB_CurlyNode)
			{
				$string .= $parser->_default_node_handler($attribute);
			}
			else
			{
				$string .= $attribute;
			}
		}
		return "'$string'";
	}
}
*/
