public static function init() {
		parent::init( self::$magicWordKeys, self::$substitutes,
				self::$magicWordArray, self::$flipMagicWordKeys );
		self::$nothing    = new self( self::nothing );
		self::$spring     = new self( self::spring );
		self::$summer     = new self( self::summer );
		self::$autumn     = new self( self::autumn );
		self::$winter     = new self( self::winter );
		self::$AD         = new self( self::AD );
		self::$BC         = new self( self::BC );
		self::$yearTerm   = new self( self::yearTerm );
		self::$monthTerm  = new self( self::monthTerm );
		self::$dayTerm    = new self( self::dayTerm );
		self::$circa      = new self( self::circa );
		self::$number     = new self( self::number );
		self::$namedMonth = new self( self::namedMonth );
	}
	/**
	 * Constructor.
	 * @param WCCitation $citation = the WCCitation object
	 * @param WCScopeEnum $scope = the scope (i.e., work, container, series, etc.)
	 * @param WCParameterEnum $type = the type of property.
	 * @param string date = the unprocessed date text.
	 */
	public function __construct( $date ) {

		# Separate into segments comprising numbers, letters, or special terms.
		$adTerms = MagicWord::get( WCDateTermsEnum::$magicWordKeys[ WCDateTermsEnum::AD ] )->getSynonyms();
		$bcTerms = MagicWord::get( WCDateTermsEnum::$magicWordKeys[ WCDateTermsEnum::BC ] )->getSynonyms();
		$circaTerms = MagicWord::get( WCDateTermsEnum::$magicWordKeys[ WCDateTermsEnum::circa ] )->getSynonyms();
		$options = implode( '|', array_merge( $adTerms, $bcTerms, $circaTerms ) );
		if ( !preg_match_all( '/'. $options . '|\p{N}+|\p{L}+|./uS', $date, $matches ) ) {
			$this->year           = 0;
			$this->era            = WCDateTermsEnum::AD;
			$this->month          = 0;
			$this->day            = 0;
			$this->isUncertain    = True;
			return;
		}

		$chunks = $matches[0];
		$numbers = $unknowns = array();
		$years = $months = $days = array();
		$eras = $seasons = $circas = $yearTerms = $monthTerms = $dayTerms = array();
		$counter = 0;

		foreach( $chunks as $chunk ) {
			# Match month names.
			$month = $this->matchMonths( $chunk ); # $month is integer >= 1 or False
			if ( $month && count( $months ) < 2 ) {
				$months[ $counter ] = $month;
				$numbers[ $counter++ ] = new WCDateNumber( $counter, $month, WCDateNumber::month );
				continue;
			}

			# Match date terms.
			$dateTermEnum = WCDateTermsEnum::match( $chunk, WCDateTermsEnum::$magicWordArray,
					WCDateTermsEnum::$flipMagicWordKeys, 'WCDateTermsEnum' );
			if ( $dateTermEnum ) {
				switch ( $dateTermEnum->key ) {
					case WCDateTermsEnum::AD:
						if ( count( $eras ) < 2 ) {
							$eras[ $counter++ ] = WCDateTermsEnum::AD;
						}
						continue 2;
					case WCDateTermsEnum::BC:
						if ( count( $eras ) < 2 ) {
							$eras[ $counter++ ] = WCDateTermsEnum::BC;
						}
						continue 2;
					case WCDateTermsEnum::spring:
						if ( count( $seasons ) < 2 ) {
							$seasons[ $counter++ ] = WCDateTermsEnum::spring;
						}
						continue 2;
					case WCDateTermsEnum::summer:
						if ( count( $seasons ) < 2 ) {
							$seasons[ $counter++ ] = WCDateTermsEnum::summer;
						}
						continue 2;
					case WCDateTermsEnum::autumn:
						if ( count( $seasons ) < 2 ) {
							$seasons[ $counter++ ] = WCDateTermsEnum::autumn;
						}
						continue 2;
					case WCDateTermsEnum::winter:
						if ( count( $seasons ) < 2 ) {
							$seasons[ $counter++ ] = WCDateTermsEnum::winter;
						}
						continue 2;
					case WCDateTermsEnum::year:
						if ( count( $yearTerms ) < 2 ) {
							$yearTerms[ $counter++ ] = WCDateTermsEnum::yearTerm;
						}
						continue 2;
					case WCDateTermsEnum::month:
						if ( count( $monthTerms ) < 2 ) {
							$monthTerms[ $counter++ ] = WCDateTermsEnum::monthTerm;
						}
						continue 2;
					case WCDateTermsEnum::day:
						if ( count( $dayTerms ) < 2 ) {
							$dayTerms[ $counter++ ] = WCDateTermsEnum::dayTerm;
						}
						continue 2;
					case WCDateTermsEnum::circa:
						if ( count( $circas ) < 2 ) {
							$circas[ $counter++ ] = WCDateTermsEnum::circa;
						}
						continue 2;
				}
			}

			# Check for roman numerals (month is often Roman in Hungary, Poland, Romania).
			$intTerm = $this->romanToInt( $chunk );
			# Convert to integer.
			if ( ! $intTerm ) {
				$intTerm = (integer) $chunk; # Note, this converts ordinals too.
				if ( ! $intTerm ) {
					# '00' cannot be month or day, so it must be the two-digit year 2000:
					if ( mb_substr( $chunk, 0, 2 ) == '00' ) {
						$numbers[ $counter ] = new WCDateNumber( $counter, 2000, WCDateNumber::year );
						$years[ $counter ] = 2000;
						++$counter;
						continue;
					} else {
						continue; # not a recognized number
					}
				}
			}
			$numbers[ $counter ] = $unknowns[ $counter ] = new WCDateNumber( $counter, $intTerm );
			++$counter;
		}

		# Look for and handle named Year/Month/Day labels
		foreach( $yearTerms as $yearTermKey => $yearTerm ) {
			if ( empty( $unknowns ) ) break;
			$unknown = $this->searchAdjacentTerm( $unknowns, $yearTermKey, $chunks );
			if ( $unknown && count( $years ) < 2 ) {
				$years[ $unknown->key ] = $unknown->num;
				$unknown->setYear( $unknowns, $years );
			}
		}
		foreach( $monthTerms as $monthTermKey => $monthTerm ) {
			if ( empty( $unknowns ) ) break;
			$unknown = $this->searchAdjacentTerm( $unknowns, $monthTermKey, $chunks );
			if ( $unknown && count( $months ) < 2 ) {
				$months[ $unknown->key ] = $unknown->num;
				$unknown->setMonth( $unknowns, $months );
			}
		}
		foreach( $dayTerms as $dayTermKey => $dayTerm ) {
			if ( empty( $unknowns ) ) break;
			$unknown = $this->searchAdjacentTerm( $unknowns, $dayTermKey, $chunks );
			if ( $unknown && count( $days ) < 2 ) {
				$days[ $unknown->key ] = $unknown->num;
				$unknown->setDay( $unknowns, $days );
			}
		}

		# If one or more seasons is specified, treat specially and return.
		if ( ! empty( $seasons ) ) {
			$this->season = reset( $seasons );
			$season2 = next( $seasons );
			# Only one season specified
			if ( $season2 === False || $season2 == $this->season ) {
				$isRange = False;
				# Determine year.
				if ( count( $years ) >= 1 ) {
					$year = reset( $years ); # Use first number as year
					$this->assignYearsAndEras( $eras, False, $year->num );
				}
				elseif ( count( $unknowns ) >= 1 ) {
					$year = reset( $unknowns ); # Use first number as year
					$this->assignYearsAndEras( $eras, False, $year->num );
				}
				else {
					$curDate = getdate();
					$this->year = $curDate['year'];
					$this->era = WCDateTermsEnum::AD;
				}
			}
			# Two seasons specified
			else {
				$isRange = True;
				$this->season2 = $season2;
				# Determine year
				if ( count( $years ) >= 2 ) {
					$year = reset( $years )->num;
					$year2 = next( $years )->num;
					if ( $year2 == $year ) {
						$this->assignYearsAndEras( $eras, False, $year );
					}
					else {
						$this->assignYearsAndEras( $eras, True, $year, $year2 );
					}
				}
				elseif ( count( $years ) == 1 ) {
					$yearA = reset( $years )->num;
					if ( empty( $unknowns ) ) {
						$this->assignYearsAndEras( $eras, False, $yearA );
					}
					else {
						$yearB = reset( $unknowns )->num;
						if ( $yearA == $yearB ) {
							$this->assignYearsAndEras( $eras, False, $yearA );
						}
						elseif ( $yearA < $yearB ) {
							$this->assignYearsAndEras( $eras, True, $yearA, $yearB );
						}
						else {
							$this->assignYearsAndEras( $eras, True, $yearB, $yearA );
						}
					}
				}
				elseif ( count( $unknowns ) >= 2 ) {
					# Use first two numbers as years.
					$year = reset( $unknowns )->num;
					$year2 = next( $unknowns )->num;
					if ( $year2 == $year ) {
						$this->assignYearsAndEras( $eras, False, $year );
					}
					else {
						$this->assignYearsAndEras( $eras, True, $year, $year2 );
					}
				}
				elseif ( count( $unknowns ) == 1 ) {
					$year = reset( $unknowns )->num;
					$this->assignYearsAndEras( $eras, False, $year );
				}
				else {
					$curDate = getdate();
					$this->year = $curDate['year'];
					$this->era = WCDateTermsEnum::AD;
				}
			}
			$this->assignUncertainty( $circas, $isRange, $numbers, $chunks );
			return;
		}

		# Handle numbers and/or named months.
		switch ( count( $numbers ) ) {

			case 0:                                       /****** CASE 0 ******/

				$this->finalizeDate( $days, $months, $years, $eras );
				$this->assignUncertainty( $circas, False, $numbers, $chunks );
				break;

			case 1:                                       /****** CASE 1 ******/
				/** Must be year
				 */
				if ( ! empty( $unknowns ) ) {
					reset( $unknowns ) -> setYear( $unknowns, $years );
				}
				$this->finalizeDate( $days, $months, $years, $eras );
				$this->assignUncertainty( $circas, False, $numbers, $chunks );
				break;

			case 2:                                       /****** CASE 2 ******/
				/** Can be any of the following:
				 * month-year
				 * year-year
				 * year-month
				 */
				$order1 = array( WCDateNumber::month, WCDateNumber::year );
				$order2 = array( WCDateNumber::year,  WCDateNumber::year );
				$order3 = array( WCDateNumber::year,  WCDateNumber::month );
				if ( ! (
					$this->monthUpTo12( $unknowns, $days, $years ) ||
					$this->cannotBeDay( $unknowns, $months, $years ) ||
					$this->yearAdjacentEra( $unknowns, $years, $eras, $chunks ) ||
					$this->yearsInOrder( $unknowns, $days, $months, $years, $eras ) ||
					$this->tryOrder( $unknowns, $days, $months, $years, $order1 ) ||
					$this->tryOrder( $unknowns, $days, $months, $years, $order2 ) ||
					$this->tryOrder( $unknowns, $days, $months, $years, $order3 )
				)  ) {
					foreach( $unknowns as $unknownKey => $unknown ) {
						if ( empty( $months ) ) {
							$months[ $unknownKey ] = $unknown->num;
						}
						elseif ( count( $years ) < 2 ) {
							$years[ $unknownKey ] = $unknown->num;
						}
					}
				}
				$isRange = $this->finalizeDate( $days, $months, $years, $eras );
				$this->assignUncertainty( $circas, $isRange, $numbers, $chunks );

				break;

			case 3:                                       /****** CASE 3 ******/
				/** Can be any of the following:
				 * day-month-year
				 * month-day-year
				 * year-month-day
				 * month-month-year
				 * year-month-month
				 */
				$order1 = array( WCDateNumber::day,   WCDateNumber::month, WCDateNumber::year );
				$order2 = array( WCDateNumber::month, WCDateNumber::day,   WCDateNumber::year );
				$order3 = array( WCDateNumber::year,  WCDateNumber::month, WCDateNumber::day );
				$order4 = array( WCDateNumber::month, WCDateNumber::month, WCDateNumber::year );
				$order5 = array( WCDateNumber::year,  WCDateNumber::month, WCDateNumber::month );
				if ( ! (
					$this->dayUpTo31( $unknowns, $months, $years ) ||
					$this->monthUpTo12( $unknowns, $days, $years ) ||
					$this->yearAdjacentEra( $unknowns, $years, $eras, $chunks ) ||
					$this->yearsInOrder( $unknowns, $days, $months, $years, $eras ) ||
					$this->tryOrder( $unknowns, $days, $months, $years, $order1 ) ||
					$this->tryOrder( $unknowns, $days, $months, $years, $order2 ) ||
					$this->tryOrder( $unknowns, $days, $months, $years, $order3 ) ||
					$this->tryOrder( $unknowns, $days, $months, $years, $order4 ) ||
					$this->tryOrder( $unknowns, $days, $months, $years, $order5 )
				) ) {
					foreach( $unknowns as $unknownKey => $unknown ) {
						if ( empty( $day ) ) {
							$days[ $unknownKey ] = $unknown->num;
						}
						elseif ( empty( $months ) ) {
							$months[ $unknownKey ] = $unknown->num;
						}
						elseif ( empty( $years ) ) {
							$years[ $unknownKey ] = $unknown->num;
						}
						else {
							$months[ $unknownKey ] = $unknown->num;
						}
					}
				}
				$isRange = $this->finalizeDate( $days, $months, $years, $eras );
				$this->assignUncertainty( $circas, $isRange, $numbers, $chunks );

				break;

			case 4:                                       /****** CASE 4 ******/

				/** Can be any of the following:
				 * day-day-month-year
				 * month-day-day-year
				 * year-month-day-day
				 * month-year-month-year
				 * year-month-year-month
				 */
				$order1 = array( WCDateNumber::day,   WCDateNumber::day,   WCDateNumber::month, WCDateNumber::year );
				$order2 = array( WCDateNumber::month, WCDateNumber::day,   WCDateNumber::day,   WCDateNumber::year );
				$order3 = array( WCDateNumber::year,  WCDateNumber::month, WCDateNumber::day,   WCDateNumber::day );
				$order4 = array( WCDateNumber::month, WCDateNumber::year,  WCDateNumber::month, WCDateNumber::year );
				$order5 = array( WCDateNumber::year,  WCDateNumber::month, WCDateNumber::year,  WCDateNumber::month );
				if ( ! (
					$this->dayUpTo31( $unknowns, $months, $years ) ||
					$this->monthUpTo12( $unknowns, $days, $years ) ||
					$this->yearAdjacentEra( $unknowns, $years, $eras, $chunks ) ||
					$this->yearsInOrder( $unknowns, $days, $months, $years, $eras ) ||
					$this->tryOrder( $unknowns, $days, $months, $years, $order1 ) ||
					$this->tryOrder( $unknowns, $days, $months, $years, $order2 ) ||
					$this->tryOrder( $unknowns, $days, $months, $years, $order3 ) ||
					$this->tryOrder( $unknowns, $days, $months, $years, $order4 ) ||
					$this->tryOrder( $unknowns, $days, $months, $years, $order5 )
				) ) {
					foreach( $unknowns as $unknownKey => $unknown ) {
						if ( count( $day ) < 2 ) {
							$days[ $unknownKey ] = $unknown->num;
						}
						elseif ( empty( $months ) ) {
							$months[ $unknownKey ] = $unknown->num;
						}
						elseif ( empty( $years ) ) {
							$years[ $unknownKey ] = $unknown->num;
						}
						elseif ( count( $months ) < 2 ) {
							$months[ $unknownKey ] = $unknown->num;
						}
						else {
							$years[ $unknownKey ] = $unknown->num;
						}
					}
				}
				$isRange = $this->finalizeDate( $days, $months, $years, $eras );
				$this->assignUncertainty( $circas, $isRange, $numbers, $chunks );

				break;

			case 5:                                       /****** CASE 5 ******/

				/** Can be any of the following:
				 * day-month-day-month-year
				 * month-day-month-day-year
				 * year-month-day-month-day
				 */
				$order1 = array( WCDateNumber::day,   WCDateNumber::month, WCDateNumber::day,   WCDateNumber::month, WCDateNumber::year );
				$order2 = array( WCDateNumber::month, WCDateNumber::day,   WCDateNumber::month, WCDateNumber::day,   WCDateNumber::year );
				$order3 = array( WCDateNumber::year,  WCDateNumber::month, WCDateNumber::day,   WCDateNumber::month, WCDateNumber::day );
				if ( ! (
					$this->dayUpTo31( $unknowns, $months, $years ) ||
					$this->monthUpTo12( $unknowns, $days, $years ) ||
					$this->yearAdjacentEra( $unknowns, $years, $eras, $chunks ) ||
					$this->yearsInOrder( $unknowns, $days, $months, $years, $eras ) ||
					$this->tryOrder( $unknowns, $days, $months, $years, $order1 ) ||
					$this->tryOrder( $unknowns, $days, $months, $years, $order2 ) ||
					$this->tryOrder( $unknowns, $days, $months, $years, $order3 )
				) ) {
					foreach( $unknowns as $unknownKey => $unknown ) {
						if ( count( $day ) < 2 ) {
							$days[ $unknownKey ] = $unknown->num;
						}
						elseif ( count( $months ) < 2 ) {
							$months[ $unknownKey ] = $unknown->num;
						}
						else {
							$years[ $unknownKey ] = $unknown->num;
						}
					}
				}
				$isRange = $this->finalizeDate( $days, $months, $years, $eras );
				$this->assignUncertainty( $circas, $isRange, $numbers, $chunks );

				break;

			default:                                     /****** CASE 6+ ******/

				/** Can be one of the following:
				 * day-month-year-day-month-year
				 * month-day-year-month-day-year
				 * year-month-day-year-month-day
				 */
				$order1 = array( WCDateNumber::day,   WCDateNumber::month, WCDateNumber::year,  WCDateNumber::day,   WCDateNumber::month, WCDateNumber::year );
				$order2 = array( WCDateNumber::month, WCDateNumber::day,   WCDateNumber::year,  WCDateNumber::month, WCDateNumber::day,   WCDateNumber::year );
				$order3 = array( WCDateNumber::year,  WCDateNumber::month, WCDateNumber::day,   WCDateNumber::year,  WCDateNumber::month, WCDateNumber::day );
				if ( ! (
					$this->dayUpTo31( $unknowns, $months, $years ) ||
					$this->monthUpTo12( $unknowns, $days, $years ) ||
					$this->yearAdjacentEra( $unknowns, $years, $eras, $chunks ) ||
					$this->yearsInOrder( $unknowns, $days, $months, $years, $eras ) ||
					$this->tryOrder( $unknowns, $days, $months, $years, $order1 ) ||
					$this->tryOrder( $unknowns, $days, $months, $years, $order2 ) ||
					$this->tryOrder( $unknowns, $days, $months, $years, $order3 )
				) ) {
					foreach( $unknowns as $unknownKey => $unknown ) {
						if ( count( $day ) < 2 ) {
							$days[ $unknownKey ] = $unknown->num;
						}
						elseif ( count( $months ) < 2 ) {
							$months[ $unknownKey ] = $unknown->num;
						}
						else {
							$years[ $unknownKey ] = $unknown->num;
						}
					}
				}
				$isRange = $this->finalizeDate( $days, $months, $years, $eras );
				$this->assignUncertainty( $circas, $isRange, $numbers, $chunks );
		}

	}