/// <summary>Associates an alias name with an actual name.</summary>
 /// <remarks>
 /// Associates an alias name with an actual name.
 /// <p>
 /// Define a alias mapping from one namespace/property to another. Both
 /// property names must be simple names. An alias can be a direct mapping,
 /// where the alias and actual have the same data type. It is also possible
 /// to map a simple alias to an item in an array. This can either be to the
 /// first item in the array, or to the 'x-default' item in an alt-text array.
 /// Multiple alias names may map to the same actual, as long as the forms
 /// match. It is a no-op to reregister an alias in an identical fashion.
 /// Note: This method is not locking because only called by registerStandardAliases
 /// which is only called by the constructor.
 /// Note2: The method is only package-private so that it can be tested with unittests
 /// </remarks>
 /// <param name="aliasNS">
 /// The namespace URI for the alias. Must not be null or the empty
 /// string.
 /// </param>
 /// <param name="aliasProp">
 /// The name of the alias. Must be a simple name, not null or the
 /// empty string and not a general path expression.
 /// </param>
 /// <param name="actualNS">
 /// The namespace URI for the actual. Must not be null or the
 /// empty string.
 /// </param>
 /// <param name="actualProp">
 /// The name of the actual. Must be a simple name, not null or the
 /// empty string and not a general path expression.
 /// </param>
 /// <param name="aliasForm">
 /// Provides options for aliases for simple aliases to array
 /// items. This is needed to know what kind of array to create if
 /// set for the first time via the simple alias. Pass
 /// <code>XMP_NoOptions</code>, the default value, for all
 /// direct aliases regardless of whether the actual data type is
 /// an array or not (see
 /// <see cref="Com.Adobe.Xmp.Options.AliasOptions"/>
 /// ).
 /// </param>
 /// <exception cref="Com.Adobe.Xmp.XMPException">for inconsistant aliases.</exception>
 internal void RegisterAlias(string aliasNS, string aliasProp, string actualNS, string actualProp, AliasOptions aliasForm)
 {
     lock (this)
     {
         ParameterAsserts.AssertSchemaNS(aliasNS);
         ParameterAsserts.AssertPropName(aliasProp);
         ParameterAsserts.AssertSchemaNS(actualNS);
         ParameterAsserts.AssertPropName(actualProp);
         // Fix the alias options
         AliasOptions aliasOpts = aliasForm != null ? new AliasOptions(XMPNodeUtils.VerifySetOptions(aliasForm.ToPropertyOptions(), null).GetOptions()) : new AliasOptions();
         if (p.Matcher(aliasProp).Find() || p.Matcher(actualProp).Find())
         {
             throw new XMPException("Alias and actual property names must be simple", XMPErrorConstants.Badxpath);
         }
         // check if both namespaces are registered
         string aliasPrefix  = GetNamespacePrefix(aliasNS);
         string actualPrefix = GetNamespacePrefix(actualNS);
         if (aliasPrefix == null)
         {
             throw new XMPException("Alias namespace is not registered", XMPErrorConstants.Badschema);
         }
         else
         {
             if (actualPrefix == null)
             {
                 throw new XMPException("Actual namespace is not registered", XMPErrorConstants.Badschema);
             }
         }
         string key = aliasPrefix + aliasProp;
         // check if alias is already existing
         if (aliasMap.ContainsKey(key))
         {
             throw new XMPException("Alias is already existing", XMPErrorConstants.Badparam);
         }
         else
         {
             if (aliasMap.ContainsKey(actualPrefix + actualProp))
             {
                 throw new XMPException("Actual property is already an alias, use the base property", XMPErrorConstants.Badparam);
             }
         }
         XMPAliasInfo aliasInfo = new _XMPAliasInfo_390(actualNS, actualPrefix, actualProp, aliasOpts);
         aliasMap.Put(key, aliasInfo);
     }
 }