/**
	 * Constructor.
	 *
	 * Tests to see whether $value is a valid parameter. If not, it throws a
	 *		exception if $wikiCitationValidateArguments is set.
	 * @global $wikiCitationValidateArguments
	 * @param string|WCParameterEnum $value = the text, which may or may not be a
	 *		valid parameter, or the WCParameterEnum object.
	 */
	public function __construct( $value = Null ) {

		if ( $value instanceOf WCSourceTypeEnum ) {
			$parameterType = $value;
		} else {
			global $wikiCitationValidateArguments;
			$parameterType = WCSourceTypeEnum::match( $value, WCSourceTypeEnum::$magicWordArray,
					WCSourceTypeEnum::$flipMagicWordKeys, 'WCTypeEnum' );
			if ( !$parameterType && $wikiCitationValidateArguments ) {
				throw new WCException( 'wc-type-parameter-unknown', $parameterType );
			}
		}
		$this->parameter = $parameterType;
	}
	public static function init() {
		parent::init( self::$magicWordKeys, self::$substitutes,
				self::$magicWordArray, self::$flipMagicWordKeys );
		self::$general                     = new self( self::general );
		self::$book                        = new self( self::book );
			self::$dictionary              = new self( self::dictionary );
			self::$encyclopedia            = new self( self::encyclopedia );
		self::$periodical                  = new self( self::periodical );
			self::$magazine                = new self( self::magazine );
			self::$newspaper               = new self( self::newspaper );
			self::$journal                 = new self( self::journal );
		self::$entry                       = new self( self::entry );
			self::$article                 = new self( self::article );
			self::$chapter                 = new self( self::chapter );
			self::$review                  = new self( self::review );
		self::$paper                       = new self( self::paper );
			self::$manuscript              = new self( self::manuscript );
			self::$musicalScore            = new self( self::musicalScore );
			self::$pamphlet                = new self( self::pamphlet );
			self::$conferencePaper         = new self( self::conferencePaper );
			self::$thesis                  = new self( self::thesis );
			self::$report                  = new self( self::report );
			self::$poem                    = new self( self::poem );
			self::$song                    = new self( self::song );
		self::$enactment                   = new self( self::enactment );
			self::$bill                    = new self( self::bill );
			self::$statute                 = new self( self::statute );
			self::$treaty                  = new self( self::treaty );
			self::$rule                    = new self( self::rule );
			self::$regulation              = new self( self::regulation );
		self::$legalDocument               = new self( self::legalDocument );
			self::$patent                  = new self( self::patent );
			self::$deed                    = new self( self::deed );
			self::$governmentGrant         = new self( self::governmentGrant );
			self::$filing                  = new self( self::filing );
				self::$patentApplication   = new self( self::patentApplication );
				self::$regulatoryFiling    = new self( self::regulatoryFiling );
		self::$litigation                  = new self( self::litigation );
			self::$legalOpinion            = new self( self::legalOpinion );
			self::$legalCase               = new self( self::legalCase );
		self::$graphic                     = new self( self::graphic );
			self::$photograph              = new self( self::photograph );
			self::$map                     = new self( self::map );
		self::$statement                   = new self( self::statement );
			self::$pressRelease            = new self( self::pressRelease );
			self::$interview               = new self( self::interview );
			self::$speech                  = new self( self::speech );
			self::$personalCommunication   = new self( self::personalCommunication );
		self::$internetResource            = new self( self::internetResource );
			self::$webpage                 = new self( self::webpage );
			self::$post                    = new self( self::post );
		self::$production                  = new self( self::production );
			self::$motionPicture           = new self( self::motionPicture );
			self::$recording               = new self( self::recording );
			self::$play                    = new self( self::play );
			self::$broadcast               = new self( self::broadcast );
				self::$televisionBroadcast = new self( self::televisionBroadcast );
				self::$radioBroadcast      = new self( self::radioBroadcast );
				self::$internetBroadcast   = new self( self::internetBroadcast );
		self::$object                      = new self( self::object );
			self::$star                    = new self( self::star );
			self::$gravestone              = new self( self::gravestone );
			self::$monument                = new self( self::monument );
			self::$realProperty            = new self( self::realProperty );
	}
	/**
	 * Read and parse arguments from a WCArgumentReader object.
	 * @param WCArgumentReader $wcArgumentReader = the argument reader
	 * @global $wikiCitationValidateArguments
	 */
	public function readArguments( WCArgumentReader $argumentReader ) {

		$this->citationType = $argumentReader->getCitationType();
		$this->citationLength = $argumentReader->getCitationLength();

		/**
		 * Recognize and process the parameters and names.
		 */
		foreach( $argumentReader->parameters as $var => $value ) {

			# See if scope name only is present, in which case the parameter is assumed to be the title.
			# This allows the user to enter "journal=Nature" or "work=Origin of Species", etc.
			$scope = WCScopeEnum::match( $var, WCScopeEnum::$magicWordArray,
					WCScopeEnum::$flipMagicWordKeys, 'WCScopeEnum' );
			if ( $scope ) {
				$property = WCPropertyEnum::$title;
				$this->reference->setProperty( $scope, $property, new WCTitle( $value ) );
				continue;
			}

			# Match the parameter scope.
			list( $scope, $parameterText ) = WCScopeEnum::matchPrefix( $var, WCScopeEnum::$magicWordArray,
					WCScopeEnum::$flipMagicWordKeys, 'WCScopeEnum' );
			if ( !$scope ) {
				$scope = WCScopeEnum::$work; # Set the default
			}

			# See if a type name is present, in which case the parameter is assumed to be the title.
			# This allows the wiki editor to enter "book=Origin of Species", "pamphlet=Common Sense," etc., or even "container-encyclopedia=Encyclopedia Brittanica."
			# If either the title or type have already been set, then neither will be set again.
			# Thus, it will be possible to use "book" as a locator.
			$type = WCSourceTypeEnum::match( $parameterText, WCSourceTypeEnum::$magicWordArray,
				WCSourceTypeEnum::$flipMagicWordKeys, 'WCTypeEnum' );
			if ( $type ) {
				$propertyEnumTitle = WCPropertyEnum::$title;
				$propertyEnumType = WCPropertyEnum::$type;
				$title = $this->reference->getProperty( $scope, $propertyEnumTitle );
				$type = $this->reference->getProperty( $scope, $propertyEnumType );
				if ( is_null( $this->reference->getProperty( $scope, $propertyEnumTitle ) ) && is_null( $this->getProperty( $scope, $propertyEnumType ) ) ) {
					$this->reference->setProperty( $scope, $propertyEnumTitle, new WCTitle( $value ) );
					$this->reference->setProperty( $scope, $propertyEnumType, new WCTypeData( $type ) );
				}
				continue;
			}

			global $wikiCitationValidateArguments;

			# Match properties.
			$property = WCPropertyEnum::match( $parameterText, WCPropertyEnum::$magicWordArray,
				WCPropertyEnum::$flipMagicWordKeys, 'WCPropertyEnum' );
			if ( $property ) {
				$attributeKey = $property->getAttribute()->key;
				$attributeClass = WCAttributeEnum::$attribute[ $attributeKey ];
				if ( $attributeKey == WCAttributeEnum::locator ) {
					# Locators disregard the scope.
					$locator = $this->getLocator( $property );
					if ( $wikiCitationValidateArguments && isset( $locator ) ) {
						throw new WCException( 'wc-parameter_defined_twice', $property );
					} else {
						$this->setLocator( $property, new WCLocator( $value ) );
					}
				} else {
					$prop = $this->reference->getProperty( $scope, $property );
					if ( $wikiCitationValidateArguments && isset( $prop ) ) {
						throw new WCException( 'wc-parameter_defined_twice', $property );
					} else {
						$this->reference->setProperty( $scope, $property, new $attributeClass( $value ) );
					}
				}
				# Set attribute
				continue;
			}

			# Match names.
			$match = False;
			list( $nameEnum, $namePartText ) = WCNameTypeEnum::matchPrefix( $parameterText,
				WCNameTypeEnum::$magicWordArray, WCNameTypeEnum::$flipMagicWordKeys, 'WCNameTypeEnum' );
			if ( $namePartText ) {
				list( $namePartEnum, $nameNum ) = WCNamePartEnum::matchPartAndNumber(
						$namePartText, WCNamePartEnum::$magicWordArray, WCNamePartEnum::$flipMagicWordKeys, 'WCNamePartEnum' );
				if ( $namePartEnum ) {
					if ( !$nameEnum ) {
						$nameEnum = new WCNameTypeEnum();
					}
					$match = True;
				} elseif ( $nameEnum ) {
					$namePartEnum = new WCNamePartEnum();
					$match = True;
				}
			} elseif ( $nameEnum ) {
				$namePartEnum = new WCNamePartEnum();
				$nameNum = 1;
				$match = True;
			}
			if ( $match ) {
				if ( is_null( $this->reference->getNames( $scope, $nameEnum ) ) ) {
					$this->reference->setNames( $scope, $nameEnum, new WCNames() );
				}
				$theNames = $this->reference->getNames( $scope, $nameEnum );
				$part = $theNames->getNamePart( $nameNum, $namePartEnum );
				if ( $wikiCitationValidateArguments && isset( $part ) ) {
					throw new WCException( 'wc-parameter_defined_twice', $nameEnum . $nameNum. '-' . $namePartEnum );
				} else {
					$theNames->setNamePart( $nameNum, $namePartEnum, $value );
				}
				continue;
			}

			# Argument has no matches.
			if ( $wikiCitationValidateArguments ) {
				throw new WCException( 'wc-parameter-unknown', $parameterText );
			}
		}

	}