<?php
/**
 * PHPExcel
 *
 * Copyright (c) 2006 - 2014 PHPExcel
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 *
 * @category	PHPExcel
 * @package		PHPExcel_Worksheet
 * @copyright	Copyright (c) 2006 - 2014 PHPExcel (http://www.codeplex.com/PHPExcel)
 * @license		http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt	LGPL
 * @version		##VERSION##, ##DATE##
 */


/**
 * PHPExcel_Worksheet_AutoFilter_Column_Rule
 *
 * @category	PHPExcel
 * @package		PHPExcel_Worksheet
 * @copyright	Copyright (c) 2006 - 2014 PHPExcel (http://www.codeplex.com/PHPExcel)
 */
class PHPExcel_Worksheet_AutoFilter_Column_Rule
{
	const AUTOFILTER_RULETYPE_FILTER		= 'filter';
	const AUTOFILTER_RULETYPE_DATEGROUP		= 'dateGroupItem';
	const AUTOFILTER_RULETYPE_CUSTOMFILTER	= 'customFilter';
	const AUTOFILTER_RULETYPE_DYNAMICFILTER	= 'dynamicFilter';
	const AUTOFILTER_RULETYPE_TOPTENFILTER	= 'top10Filter';

	private static $_ruleTypes = array(
		//	Currently we're not handling
		//		colorFilter
		//		extLst
		//		iconFilter
		self::AUTOFILTER_RULETYPE_FILTER,
		self::AUTOFILTER_RULETYPE_DATEGROUP,
		self::AUTOFILTER_RULETYPE_CUSTOMFILTER,
		self::AUTOFILTER_RULETYPE_DYNAMICFILTER,
		self::AUTOFILTER_RULETYPE_TOPTENFILTER,
	);

	const AUTOFILTER_RULETYPE_DATEGROUP_YEAR	= 'year';
	const AUTOFILTER_RULETYPE_DATEGROUP_MONTH	= 'month';
	const AUTOFILTER_RULETYPE_DATEGROUP_DAY		= 'day';
	const AUTOFILTER_RULETYPE_DATEGROUP_HOUR	= 'hour';
	const AUTOFILTER_RULETYPE_DATEGROUP_MINUTE	= 'minute';
	const AUTOFILTER_RULETYPE_DATEGROUP_SECOND	= 'second';

	private static $_dateTimeGroups = array(
		self::AUTOFILTER_RULETYPE_DATEGROUP_YEAR,
		self::AUTOFILTER_RULETYPE_DATEGROUP_MONTH,
		self::AUTOFILTER_RULETYPE_DATEGROUP_DAY,
		self::AUTOFILTER_RULETYPE_DATEGROUP_HOUR,
		self::AUTOFILTER_RULETYPE_DATEGROUP_MINUTE,
		self::AUTOFILTER_RULETYPE_DATEGROUP_SECOND,
	);

	const AUTOFILTER_RULETYPE_DYNAMIC_YESTERDAY		= 'yesterday';
	const AUTOFILTER_RULETYPE_DYNAMIC_TODAY			= 'today';
	const AUTOFILTER_RULETYPE_DYNAMIC_TOMORROW		= 'tomorrow';
	const AUTOFILTER_RULETYPE_DYNAMIC_YEARTODATE	= 'yearToDate';
	const AUTOFILTER_RULETYPE_DYNAMIC_THISYEAR		= 'thisYear';
	const AUTOFILTER_RULETYPE_DYNAMIC_THISQUARTER	= 'thisQuarter';
	const AUTOFILTER_RULETYPE_DYNAMIC_THISMONTH		= 'thisMonth';
	const AUTOFILTER_RULETYPE_DYNAMIC_THISWEEK		= 'thisWeek';
	const AUTOFILTER_RULETYPE_DYNAMIC_LASTYEAR		= 'lastYear';
	const AUTOFILTER_RULETYPE_DYNAMIC_LASTQUARTER	= 'lastQuarter';
	const AUTOFILTER_RULETYPE_DYNAMIC_LASTMONTH		= 'lastMonth';
	const AUTOFILTER_RULETYPE_DYNAMIC_LASTWEEK		= 'lastWeek';
	const AUTOFILTER_RULETYPE_DYNAMIC_NEXTYEAR		= 'nextYear';
	const AUTOFILTER_RULETYPE_DYNAMIC_NEXTQUARTER	= 'nextQuarter';
	const AUTOFILTER_RULETYPE_DYNAMIC_NEXTMONTH		= 'nextMonth';
	const AUTOFILTER_RULETYPE_DYNAMIC_NEXTWEEK		= 'nextWeek';
	const AUTOFILTER_RULETYPE_DYNAMIC_MONTH_1		= 'M1';
	const AUTOFILTER_RULETYPE_DYNAMIC_JANUARY		= self::AUTOFILTER_RULETYPE_DYNAMIC_MONTH_1;
	const AUTOFILTER_RULETYPE_DYNAMIC_MONTH_2		= 'M2';
	const AUTOFILTER_RULETYPE_DYNAMIC_FEBRUARY		= self::AUTOFILTER_RULETYPE_DYNAMIC_MONTH_2;
	const AUTOFILTER_RULETYPE_DYNAMIC_MONTH_3		= 'M3';
	const AUTOFILTER_RULETYPE_DYNAMIC_MARCH			= self::AUTOFILTER_RULETYPE_DYNAMIC_MONTH_3;
	const AUTOFILTER_RULETYPE_DYNAMIC_MONTH_4		= 'M4';
	const AUTOFILTER_RULETYPE_DYNAMIC_APRIL			= self::AUTOFILTER_RULETYPE_DYNAMIC_MONTH_4;
	const AUTOFILTER_RULETYPE_DYNAMIC_MONTH_5		= 'M5';
	const AUTOFILTER_RULETYPE_DYNAMIC_MAY			= self::AUTOFILTER_RULETYPE_DYNAMIC_MONTH_5;
	const AUTOFILTER_RULETYPE_DYNAMIC_MONTH_6		= 'M6';
	const AUTOFILTER_RULETYPE_DYNAMIC_JUNE			= self::AUTOFILTER_RULETYPE_DYNAMIC_MONTH_6;
	const AUTOFILTER_RULETYPE_DYNAMIC_MONTH_7		= 'M7';
	const AUTOFILTER_RULETYPE_DYNAMIC_JULY			= self::AUTOFILTER_RULETYPE_DYNAMIC_MONTH_7;
	const AUTOFILTER_RULETYPE_DYNAMIC_MONTH_8		= 'M8';
	const AUTOFILTER_RULETYPE_DYNAMIC_AUGUST		= self::AUTOFILTER_RULETYPE_DYNAMIC_MONTH_8;
	const AUTOFILTER_RULETYPE_DYNAMIC_MONTH_9		= 'M9';
	const AUTOFILTER_RULETYPE_DYNAMIC_SEPTEMBER		= self::AUTOFILTER_RULETYPE_DYNAMIC_MONTH_9;
	const AUTOFILTER_RULETYPE_DYNAMIC_MONTH_10		= 'M10';
	const AUTOFILTER_RULETYPE_DYNAMIC_OCTOBER		= self::AUTOFILTER_RULETYPE_DYNAMIC_MONTH_10;
	const AUTOFILTER_RULETYPE_DYNAMIC_MONTH_11		= 'M11';
	const AUTOFILTER_RULETYPE_DYNAMIC_NOVEMBER		= self::AUTOFILTER_RULETYPE_DYNAMIC_MONTH_11;
	const AUTOFILTER_RULETYPE_DYNAMIC_MONTH_12		= 'M12';
	const AUTOFILTER_RULETYPE_DYNAMIC_DECEMBER		= self::AUTOFILTER_RULETYPE_DYNAMIC_MONTH_12;
	const AUTOFILTER_RULETYPE_DYNAMIC_QUARTER_1		= 'Q1';
	const AUTOFILTER_RULETYPE_DYNAMIC_QUARTER_2		= 'Q2';
	const AUTOFILTER_RULETYPE_DYNAMIC_QUARTER_3		= 'Q3';
	const AUTOFILTER_RULETYPE_DYNAMIC_QUARTER_4		= 'Q4';
	const AUTOFILTER_RULETYPE_DYNAMIC_ABOVEAVERAGE	= 'aboveAverage';
	const AUTOFILTER_RULETYPE_DYNAMIC_BELOWAVERAGE	= 'belowAverage';

	private static $_dynamicTypes = array(
		self::AUTOFILTER_RULETYPE_DYNAMIC_YESTERDAY,
		self::AUTOFILTER_RULETYPE_DYNAMIC_TODAY,
		self::AUTOFILTER_RULETYPE_DYNAMIC_TOMORROW,
		self::AUTOFILTER_RULETYPE_DYNAMIC_YEARTODATE,
		self::AUTOFILTER_RULETYPE_DYNAMIC_THISYEAR,
		self::AUTOFILTER_RULETYPE_DYNAMIC_THISQUARTER,
		self::AUTOFILTER_RULETYPE_DYNAMIC_THISMONTH,
		self::AUTOFILTER_RULETYPE_DYNAMIC_THISWEEK,
		self::AUTOFILTER_RULETYPE_DYNAMIC_LASTYEAR,
		self::AUTOFILTER_RULETYPE_DYNAMIC_LASTQUARTER,
		self::AUTOFILTER_RULETYPE_DYNAMIC_LASTMONTH,
		self::AUTOFILTER_RULETYPE_DYNAMIC_LASTWEEK,
		self::AUTOFILTER_RULETYPE_DYNAMIC_NEXTYEAR,
		self::AUTOFILTER_RULETYPE_DYNAMIC_NEXTQUARTER,
		self::AUTOFILTER_RULETYPE_DYNAMIC_NEXTMONTH,
		self::AUTOFILTER_RULETYPE_DYNAMIC_NEXTWEEK,
		self::AUTOFILTER_RULETYPE_DYNAMIC_MONTH_1,
		self::AUTOFILTER_RULETYPE_DYNAMIC_MONTH_2,
		self::AUTOFILTER_RULETYPE_DYNAMIC_MONTH_3,
		self::AUTOFILTER_RULETYPE_DYNAMIC_MONTH_4,
		self::AUTOFILTER_RULETYPE_DYNAMIC_MONTH_5,
		self::AUTOFILTER_RULETYPE_DYNAMIC_MONTH_6,
		self::AUTOFILTER_RULETYPE_DYNAMIC_MONTH_7,
		self::AUTOFILTER_RULETYPE_DYNAMIC_MONTH_8,
		self::AUTOFILTER_RULETYPE_DYNAMIC_MONTH_9,
		self::AUTOFILTER_RULETYPE_DYNAMIC_MONTH_10,
		self::AUTOFILTER_RULETYPE_DYNAMIC_MONTH_11,
		self::AUTOFILTER_RULETYPE_DYNAMIC_MONTH_12,
		self::AUTOFILTER_RULETYPE_DYNAMIC_QUARTER_1,
		self::AUTOFILTER_RULETYPE_DYNAMIC_QUARTER_2,
		self::AUTOFILTER_RULETYPE_DYNAMIC_QUARTER_3,
		self::AUTOFILTER_RULETYPE_DYNAMIC_QUARTER_4,
		self::AUTOFILTER_RULETYPE_DYNAMIC_ABOVEAVERAGE,
		self::AUTOFILTER_RULETYPE_DYNAMIC_BELOWAVERAGE,
	);

	/*
	 *	The only valid filter rule operators for filter and customFilter types are:
	 *		<xsd:enumeration value="equal"/>
	 *		<xsd:enumeration value="lessThan"/>
	 *		<xsd:enumeration value="lessThanOrEqual"/>
	 *		<xsd:enumeration value="notEqual"/>
	 *		<xsd:enumeration value="greaterThanOrEqual"/>
	 *		<xsd:enumeration value="greaterThan"/>
	 */
	const AUTOFILTER_COLUMN_RULE_EQUAL				= 'equal';
	const AUTOFILTER_COLUMN_RULE_NOTEQUAL			= 'notEqual';
	const AUTOFILTER_COLUMN_RULE_GREATERTHAN		= 'greaterThan';
	const AUTOFILTER_COLUMN_RULE_GREATERTHANOREQUAL	= 'greaterThanOrEqual';
	const AUTOFILTER_COLUMN_RULE_LESSTHAN			= 'lessThan';
	const AUTOFILTER_COLUMN_RULE_LESSTHANOREQUAL	= 'lessThanOrEqual';

	private static $_operators = array(
		self::AUTOFILTER_COLUMN_RULE_EQUAL,
		self::AUTOFILTER_COLUMN_RULE_NOTEQUAL,
		self::AUTOFILTER_COLUMN_RULE_GREATERTHAN,
		self::AUTOFILTER_COLUMN_RULE_GREATERTHANOREQUAL,
		self::AUTOFILTER_COLUMN_RULE_LESSTHAN,
		self::AUTOFILTER_COLUMN_RULE_LESSTHANOREQUAL,
	);

	const AUTOFILTER_COLUMN_RULE_TOPTEN_BY_VALUE	= 'byValue';
	const AUTOFILTER_COLUMN_RULE_TOPTEN_PERCENT		= 'byPercent';

	private static $_topTenValue = array(
		self::AUTOFILTER_COLUMN_RULE_TOPTEN_BY_VALUE,
		self::AUTOFILTER_COLUMN_RULE_TOPTEN_PERCENT,
	);

	const AUTOFILTER_COLUMN_RULE_TOPTEN_TOP			= 'top';
	const AUTOFILTER_COLUMN_RULE_TOPTEN_BOTTOM		= 'bottom';

	private static $_topTenType = array(
		self::AUTOFILTER_COLUMN_RULE_TOPTEN_TOP,
		self::AUTOFILTER_COLUMN_RULE_TOPTEN_BOTTOM,
	);


	/* Rule Operators (Numeric, Boolean etc) */
//	const AUTOFILTER_COLUMN_RULE_BETWEEN			= 'between';		//	greaterThanOrEqual 1 && lessThanOrEqual 2
	/* Rule Operators (Numeric Special) which are translated to standard numeric operators with calculated values */
//	const AUTOFILTER_COLUMN_RULE_TOPTEN				= 'topTen';			//	greaterThan calculated value
//	const AUTOFILTER_COLUMN_RULE_TOPTENPERCENT		= 'topTenPercent';	//	greaterThan calculated value
//	const AUTOFILTER_COLUMN_RULE_ABOVEAVERAGE		= 'aboveAverage';	//	Value is calculated as the average
//	const AUTOFILTER_COLUMN_RULE_BELOWAVERAGE		= 'belowAverage';	//	Value is calculated as the average
	/* Rule Operators (String) which are set as wild-carded values */
//	const AUTOFILTER_COLUMN_RULE_BEGINSWITH			= 'beginsWith';			// A*
//	const AUTOFILTER_COLUMN_RULE_ENDSWITH			= 'endsWith';			// *Z
//	const AUTOFILTER_COLUMN_RULE_CONTAINS			= 'contains';			// *B*
//	const AUTOFILTER_COLUMN_RULE_DOESNTCONTAIN		= 'notEqual';			//	notEqual *B*
	/* Rule Operators (Date Special) which are translated to standard numeric operators with calculated values */
//	const AUTOFILTER_COLUMN_RULE_BEFORE				= 'lessThan';
//	const AUTOFILTER_COLUMN_RULE_AFTER				= 'greaterThan';
//	const AUTOFILTER_COLUMN_RULE_YESTERDAY			= 'yesterday';
//	const AUTOFILTER_COLUMN_RULE_TODAY				= 'today';
//	const AUTOFILTER_COLUMN_RULE_TOMORROW			= 'tomorrow';
//	const AUTOFILTER_COLUMN_RULE_LASTWEEK			= 'lastWeek';
//	const AUTOFILTER_COLUMN_RULE_THISWEEK			= 'thisWeek';
//	const AUTOFILTER_COLUMN_RULE_NEXTWEEK			= 'nextWeek';
//	const AUTOFILTER_COLUMN_RULE_LASTMONTH			= 'lastMonth';
//	const AUTOFILTER_COLUMN_RULE_THISMONTH			= 'thisMonth';
//	const AUTOFILTER_COLUMN_RULE_NEXTMONTH			= 'nextMonth';
//	const AUTOFILTER_COLUMN_RULE_LASTQUARTER		= 'lastQuarter';
//	const AUTOFILTER_COLUMN_RULE_THISQUARTER		= 'thisQuarter';
//	const AUTOFILTER_COLUMN_RULE_NEXTQUARTER		= 'nextQuarter';
//	const AUTOFILTER_COLUMN_RULE_LASTYEAR			= 'lastYear';
//	const AUTOFILTER_COLUMN_RULE_THISYEAR			= 'thisYear';
//	const AUTOFILTER_COLUMN_RULE_NEXTYEAR			= 'nextYear';
//	const AUTOFILTER_COLUMN_RULE_YEARTODATE			= 'yearToDate';			//	<dynamicFilter val="40909" type="yearToDate" maxVal="41113"/>
//	const AUTOFILTER_COLUMN_RULE_ALLDATESINMONTH	= 'allDatesInMonth';	//	<dynamicFilter type="M2"/> for Month/February
//	const AUTOFILTER_COLUMN_RULE_ALLDATESINQUARTER	= 'allDatesInQuarter';	//	<dynamicFilter type="Q2"/> for Quarter 2

	/**
	 * Autofilter Column
	 *
	 * @var PHPExcel_Worksheet_AutoFilter_Column
	 */
	private $_parent = NULL;


	/**
	 * Autofilter Rule Type
	 *
	 * @var string
	 */
	private $_ruleType = self::AUTOFILTER_RULETYPE_FILTER;


	/**
	 * Autofilter Rule Value
	 *
	 * @var string
	 */
	private $_value = '';

	/**
	 * Autofilter Rule Operator
	 *
	 * @var string
	 */
	private $_operator = '';

	/**
	 * DateTimeGrouping Group Value
	 *
	 * @var string
	 */
	private $_grouping = '';


	/**
	 * Create a new PHPExcel_Worksheet_AutoFilter_Column_Rule
	 *
	 * @param PHPExcel_Worksheet_AutoFilter_Column $pParent
	 */
	public function __construct(PHPExcel_Worksheet_AutoFilter_Column $pParent = NULL)
	{
		$this->_parent = $pParent;
	}

	/**
	 * Get AutoFilter Rule Type
	 *
	 * @return string
	 */
	public function getRuleType() {
		return $this->_ruleType;
	}

	/**
	 *	Set AutoFilter Rule Type
	 *
	 *	@param	string		$pRuleType
	 *	@throws	PHPExcel_Exception
	 *	@return PHPExcel_Worksheet_AutoFilter_Column
	 */
	public function setRuleType($pRuleType = self::AUTOFILTER_RULETYPE_FILTER) {
		if (!in_array($pRuleType,self::$_ruleTypes)) {
			throw new PHPExcel_Exception('Invalid rule type for column AutoFilter Rule.');
		}

		$this->_ruleType = $pRuleType;

		return $this;
	}

	/**
	 * Get AutoFilter Rule Value
	 *
	 * @return string
	 */
	public function getValue() {
		return $this->_value;
	}

	/**
	 *	Set AutoFilter Rule Value
	 *
	 *	@param	string|string[]		$pValue
	 *	@throws	PHPExcel_Exception
	 *	@return PHPExcel_Worksheet_AutoFilter_Column_Rule
	 */
	public function setValue($pValue = '') {
		if (is_array($pValue)) {
			$grouping = -1;
			foreach($pValue as $key => $value) {
				//	Validate array entries
				if (!in_array($key,self::$_dateTimeGroups)) {
					//	Remove any invalid entries from the value array
					unset($pValue[$key]);
				} else {
					//	Work out what the dateTime grouping will be
					$grouping = max($grouping,array_search($key,self::$_dateTimeGroups));
				}
			}
			if (count($pValue) == 0) {
				throw new PHPExcel_Exception('Invalid rule value for column AutoFilter Rule.');
			}
			//	Set the dateTime grouping that we've anticipated
			$this->setGrouping(self::$_dateTimeGroups[$grouping]);
		}
		$this->_value = $pValue;

		return $this;
	}

	/**
	 * Get AutoFilter Rule Operator
	 *
	 * @return string
	 */
	public function getOperator() {
		return $this->_operator;
	}

	/**
	 *	Set AutoFilter Rule Operator
	 *
	 *	@param	string		$pOperator
	 *	@throws	PHPExcel_Exception
	 *	@return PHPExcel_Worksheet_AutoFilter_Column_Rule
	 */
	public function setOperator($pOperator = self::AUTOFILTER_COLUMN_RULE_EQUAL) {
		if (empty($pOperator))
			$pOperator = self::AUTOFILTER_COLUMN_RULE_EQUAL;
		if ((!in_array($pOperator,self::$_operators)) &&
			(!in_array($pOperator,self::$_topTenValue))) {
			throw new PHPExcel_Exception('Invalid operator for column AutoFilter Rule.');
		}
		$this->_operator = $pOperator;

		return $this;
	}

	/**
	 * Get AutoFilter Rule Grouping
	 *
	 * @return string
	 */
	public function getGrouping() {
		return $this->_grouping;
	}

	/**
	 *	Set AutoFilter Rule Grouping
	 *
	 *	@param	string		$pGrouping
	 *	@throws	PHPExcel_Exception
	 *	@return PHPExcel_Worksheet_AutoFilter_Column_Rule
	 */
	public function setGrouping($pGrouping = NULL) {
		if (($pGrouping !== NULL) &&
			(!in_array($pGrouping,self::$_dateTimeGroups)) &&
			(!in_array($pGrouping,self::$_dynamicTypes)) &&
			(!in_array($pGrouping,self::$_topTenType))) {
			throw new PHPExcel_Exception('Invalid rule type for column AutoFilter Rule.');
		}

		$this->_grouping = $pGrouping;

		return $this;
	}

	/**
	 *	Set AutoFilter Rule
	 *
	 *	@param	string				$pOperator
	 *	@param	string|string[]		$pValue
	 *	@param	string				$pGrouping
	 *	@throws	PHPExcel_Exception
	 *	@return PHPExcel_Worksheet_AutoFilter_Column_Rule
	 */
	public function setRule($pOperator = self::AUTOFILTER_COLUMN_RULE_EQUAL, $pValue = '', $pGrouping = NULL) {
		$this->setOperator($pOperator);
		$this->setValue($pValue);
		//	Only set grouping if it's been passed in as a user-supplied argument,
		//		otherwise we're calculating it when we setValue() and don't want to overwrite that
		//		If the user supplies an argumnet for grouping, then on their own head be it
		if ($pGrouping !== NULL)
			$this->setGrouping($pGrouping);

		return $this;
	}

	/**
	 * Get this Rule's AutoFilter Column Parent
	 *
	 * @return PHPExcel_Worksheet_AutoFilter_Column
	 */
	public function getParent() {
		return $this->_parent;
	}

	/**
	 * Set this Rule's AutoFilter Column Parent
	 *
	 * @param PHPExcel_Worksheet_AutoFilter_Column
	 * @return PHPExcel_Worksheet_AutoFilter_Column_Rule
	 */
	public function setParent(PHPExcel_Worksheet_AutoFilter_Column $pParent = NULL) {
		$this->_parent = $pParent;

		return $this;
	}

	/**
	 * Implement PHP __clone to create a deep clone, not just a shallow copy.
	 */
	public function __clone() {
		$vars = get_object_vars($this);
		foreach ($vars as $key => $value) {
			if (is_object($value)) {
				if ($key == '_parent') {
					//	Detach from autofilter column parent
					$this->$key = NULL;
				} else {
					$this->$key = clone $value;
				}
			} else {
				$this->$key = $value;
			}
		}
	}

}
