private static Dictionary<object, LocalizabilityAttribute> DefinedAttributes; // stores pre-defined attribute for types

        #endregion Fields

        #region Constructors

        static DefaultAttributes()
        {
            // predefined localizability attributes
            DefinedAttributes = new Dictionary<object, LocalizabilityAttribute>(32);

            // nonlocalizable attribute
            LocalizabilityAttribute notReadable = new LocalizabilityAttribute(LocalizationCategory.None);
            notReadable.Readability = Readability.Unreadable;

            LocalizabilityAttribute notModifiable = new LocalizabilityAttribute(LocalizationCategory.None);
            notModifiable.Modifiability = Modifiability.Unmodifiable;

            // not localizable CLR types
            DefinedAttributes.Add(typeof(Boolean),   notReadable);
            DefinedAttributes.Add(typeof(Byte),      notReadable);
            DefinedAttributes.Add(typeof(SByte),     notReadable);
            DefinedAttributes.Add(typeof(Char),      notReadable);
            DefinedAttributes.Add(typeof(Decimal),   notReadable);
            DefinedAttributes.Add(typeof(Double),    notReadable);
            DefinedAttributes.Add(typeof(Single),    notReadable);
            DefinedAttributes.Add(typeof(Int32),     notReadable);
            DefinedAttributes.Add(typeof(UInt32),    notReadable);
            DefinedAttributes.Add(typeof(Int64),     notReadable);
            DefinedAttributes.Add(typeof(UInt64),    notReadable);
            DefinedAttributes.Add(typeof(Int16),     notReadable);
            DefinedAttributes.Add(typeof(UInt16),    notReadable);
            DefinedAttributes.Add(typeof(Uri),       notModifiable);
        }
        /// <summary>
        /// It combines the min values of two localizability attributes. 
        /// </summary>
        /// <param name="first">first </param>
        /// <param name="second">second</param>
        /// <returns>LocalizabilityAttribute</returns>
        private LocalizabilityAttribute CombineMinimumLocalizability(
            LocalizabilityAttribute first,
            LocalizabilityAttribute second
            )
        {
            if (first == null || second == null)
            {
                return (first == null) ? second : first; 
            }
            
            // min of two readability enum. The less the more restrictive.
            Readability readability = (Readability) Math.Min(
                (int) first.Readability, 
                (int) second.Readability
                );
            
            // min of two Modifiability enum. The less the more restrictive.
            Modifiability modifiability = (Modifiability) Math.Min(
                (int) first.Modifiability, 
                (int) second.Modifiability
                );

            // for category, NeverLocalize < Ignore < { all others } < None
            // If both categories belong to { all others }, first.Category wins
            LocalizationCategory category = LocalizationCategory.None;
            
            if ( first.Category  == LocalizationCategory.NeverLocalize 
              || second.Category == LocalizationCategory.NeverLocalize)
            {                
                category = LocalizationCategory.NeverLocalize;
            }
            else if ( first.Category  == LocalizationCategory.Ignore
                   || second.Category == LocalizationCategory.Ignore)
            {
                category = LocalizationCategory.Ignore;                
            }
            else 
            {
                category = ( first.Category != LocalizationCategory.None) ?
                    first.Category : 
                    second.Category;
            }

            LocalizabilityAttribute result = new LocalizabilityAttribute(category);
            result.Readability   = readability;
            result.Modifiability = modifiability;

            return result;
        }
        /// <summary>
        /// Create the inherited localizability attribute 
        /// </summary>
        /// <param name="source">localizability attribute defined in source</param>
        /// <param name="inheritable">localizability attribute inheritable from above</param>
        /// <returns>LocalizabilityAttribute</returns>
        private LocalizabilityAttribute CreateInheritedLocalizability(
            LocalizabilityAttribute source,
            LocalizabilityAttribute inheritable            
            )
        {        
            LocalizationCategory category = 
                (source.Category == LocalizationCategory.Inherit) ? 
                inheritable.Category :
                source.Category;

            Readability readability = 
                (source.Readability == Readability.Inherit) ?
                inheritable.Readability : 
                source.Readability;

            Modifiability modifiability = 
                (source.Modifiability == Modifiability.Inherit) ?
                inheritable.Modifiability :
                source.Modifiability;
                
            LocalizabilityAttribute attribute = new LocalizabilityAttribute(category);
            attribute.Readability   = readability;
            attribute.Modifiability = modifiability;
            return attribute;                
        }
        /// <summary>
        /// Combine inheritable attributes, and propegate it down the tree.        
        /// </summary>
        /// <param name="node">current node</param>
        /// <param name="localizabilityFromSource">localizability defined in source code</param>
        /// <returns>
        /// The LocalizabilityAttribute to used for this node. It is not the same as the 
        /// inheritable attributes of the node when the node is set to Ignore.    
        /// </returns>
        /// <remarks>We always walk the baml tree in depth-first order</remarks>
        private LocalizabilityAttribute CombineAndPropagateInheritanceValues(
            ILocalizabilityInheritable  node, 
            LocalizabilityAttribute     localizabilityFromSource
            )
        {
            if (node == null )
            {
                return localizabilityFromSource;
            }

            // If this node's inheritable localizability has been constructed, we can skip it
            // This can happen when recursively format the content
            if (node.InheritableAttribute != null)
            {
                return (!node.IsIgnored) ? node.InheritableAttribute : LocalizabilityIgnore;
            }
        
            // To test wether the current node needs to inherit values from parents. 
            // It inherits values if: 
            // o This node is set to Ignore, in which case it propagates parent values. 
            // o Some of its attributes set to Inherit.
            if ( localizabilityFromSource.Category      != LocalizationCategory.Ignore
              && localizabilityFromSource.Category      != LocalizationCategory.Inherit 
              && localizabilityFromSource.Readability   != Readability.Inherit
              && localizabilityFromSource.Modifiability != Modifiability.Inherit)
            {
                // just return the same one because no value is inherited
                node.InheritableAttribute = localizabilityFromSource;
                return node.InheritableAttribute;
            }          

            // find the ancestor to inherit values now.
            ILocalizabilityInheritable ancestor = node.LocalizabilityAncestor;            

            // find out the attribute that is inheritable from above
            LocalizabilityAttribute inheritableAttribute = ancestor.InheritableAttribute; 

            if (inheritableAttribute == null)
            {
                // if ancestor's inheritable value isn't resolved yet, we recursively 
                // resolve it here.
                BamlStartElementNode elementNode = ancestor as BamlStartElementNode;
                if (elementNode != null)
                {
                    string formattingTag;
                    GetLocalizabilityForElementNode(elementNode, out inheritableAttribute, out formattingTag);
                }
                else 
                {
                    BamlStartComplexPropertyNode propertyNode = ancestor as BamlStartComplexPropertyNode;
                    GetLocalizabilityForPropertyNode(propertyNode, out inheritableAttribute);
                }

                CombineAndPropagateInheritanceValues(ancestor, inheritableAttribute);
                
                inheritableAttribute = ancestor.InheritableAttribute;
                Debug.Assert(inheritableAttribute != null);
            }
                             
            // if this item is set to ignore
            if ( localizabilityFromSource.Category == LocalizationCategory.Ignore)
            {
                // It propagates ancestor's inheritable localizability, but it will use
                // its own value declared in source.
                // We also mark this node as being "Ignored" in the inheritance tree to signal that
                // this node is not using the inheritance value.
                node.InheritableAttribute = inheritableAttribute;
                node.IsIgnored = true; 
                return LocalizabilityIgnore;
            }
            
            // the item is not set to ignore, so we process the inheritable values
            BamlTreeNode treeNode = (BamlTreeNode) node;
            switch (treeNode.NodeType)
            {
                case BamlNodeType.StartElement :
                case BamlNodeType.LiteralContent :
                {
                    // if everything set to inherit, we just return the inheritable localizability
                    if (localizabilityFromSource.Category == LocalizationCategory.Inherit
                      && localizabilityFromSource.Readability == Readability.Inherit
                      && localizabilityFromSource.Modifiability == Modifiability.Inherit)
                    {
                        // just propagate the ancestor's localizability.
                        node.InheritableAttribute = inheritableAttribute;
                    }
                    else
                    {
                        // set new inherited values
                        node.InheritableAttribute = CreateInheritedLocalizability(
                            localizabilityFromSource,
                            inheritableAttribute
                            );
                    }
                    break;
                }                
                case BamlNodeType.Property :
                case BamlNodeType.StartComplexProperty :
                {
                    ILocalizabilityInheritable parent = (ILocalizabilityInheritable) treeNode.Parent;
                
                    // Find the mininum localizability of the containing class and 
                    // parent property. Parent property means the proeprty from parent node that 
                    // has the same name.
                    LocalizabilityAttribute inheritedAttribute = CombineMinimumLocalizability(
                        inheritableAttribute,
                        parent.InheritableAttribute
                        );

                    node.InheritableAttribute = CreateInheritedLocalizability(
                        localizabilityFromSource,
                        inheritedAttribute
                        );

                    if (parent.IsIgnored && localizabilityFromSource.Category == LocalizationCategory.Inherit)
                    {
                        // If the parent node is Ignore and this property is set to inherit, then 
                        // this property node is to be ignore as well. We set the the "Ignore" flag so that
                        // the node will always be ignored without looking at the source localizability again. 
                        node.IsIgnored = true;
                        return LocalizabilityIgnore;
                    }                        
                    break;
                }
                default: 
                {
                    Debug.Assert(false, "Can't process localizability attribute on nodes other than Element, Property and LiteralContent.");
                    break;
                }
            }            

            return node.InheritableAttribute;            
        }
        private void GetLocalizabilityForPropertyNode(
            BamlStartComplexPropertyNode node,
            out LocalizabilityAttribute  localizability
            )
        {
            localizability = null;           
            
            string assemblyName      = node.AssemblyName;
            string className         = node.OwnerTypeFullName; 
            string propertyLocalName = node.PropertyName;
          
            if (className == null || className.Length == 0)
            {
                // class name can be empty or null. For example, <Set PropertyPath="...">
                // We will use the parent node's value.  
                string formattingTag;                
                GetLocalizabilityForElementNode((BamlStartElementNode)node.Parent, out localizability, out formattingTag);
                return;
            }

            LocalizabilityGroup comment = _resolver.GetLocalizabilityComment(
                    (BamlStartElementNode) node.Parent, 
                    node.PropertyName
                    );            

            localizability = _resolver.GetPropertyLocalizability(
                    assemblyName, 
                    className, 
                    propertyLocalName
                    );

            if (comment != null)
            {
                localizability = comment.Override(localizability);
            }
        }
        private void GetLocalizabilityForElementNode(
            BamlStartElementNode        node,            
            out LocalizabilityAttribute localizability,
            out string                  formattingTag
            )        
        {     
            localizability = null;
            formattingTag  = null;
            
            // get the names we need
            string assemblyName = node.AssemblyName;
            string className    = node.TypeFullName;          
            
            // query the resolver
            ElementLocalizability result = _resolver.GetElementLocalizability(
                 assemblyName, 
                 className                        
                 );

            LocalizabilityGroup comment = null;
            comment = _resolver.GetLocalizabilityComment(node, BamlConst.ContentSuffix);
         
            if (comment != null)
            {
                localizability = comment.Override(result.Attribute);
            }
            else
            {
                localizability = result.Attribute;
            }
            
            formattingTag  = result.FormattingTag;
        }
        // Helper to override a localizability attribute. Not needed for compiler
        internal LocalizabilityAttribute Override(LocalizabilityAttribute attribute)
        {
            Modifiability modifiability   = attribute.Modifiability;
            Readability   readability     = attribute.Readability;
            LocalizationCategory category = attribute.Category;

            bool overridden = false;
            if (((int) Modifiability)!= InvalidValue)
            {
                modifiability = Modifiability;
                overridden = true;
            }

            if (((int) Readability) != InvalidValue)
            {
                readability = Readability;
                overridden = true;
            }

            if (((int) Category) != InvalidValue)
            {
                category = Category;
                overridden = true;
            }

            if (overridden)
            {
                attribute = new LocalizabilityAttribute(category);
                attribute.Modifiability = modifiability;
                attribute.Readability   = readability;
            }

            return attribute;
        }
        /// <summary>
        /// Get the localizability of a CLR property
        /// </summary>
        private void GetLocalizabilityForClrProperty(
            string                      propertyName,
            Type                        owner,
            out LocalizabilityAttribute localizability,
            out Type                    propertyType
            )
        {
            localizability = null;
            propertyType   = null;

            PropertyInfo info = owner.GetProperty(propertyName);
            if (info == null)
            {
                return; // couldn't find the Clr property
            }

            // we found the CLR property, set the type of the property
            propertyType = info.PropertyType;

            object[] locAttributes = info.GetCustomAttributes(
                TypeOfLocalizabilityAttribute, // type of the attribute
                true                    // search in base class
            );

            if (locAttributes.Length == 0)
            {
                return;
            }
            else
            {
                Debug.Assert(locAttributes.Length == 1, "Should have only 1 localizability attribute");

                // we found the attribute defined on the property
                localizability = (LocalizabilityAttribute) locAttributes[0];
            }
        }
        /// <summary>
        /// Get localizability for attached property
        /// </summary>
        /// <param name="propertyName">property name</param>
        /// <param name="owner">owner type</param>
        /// <param name="localizability">out: localizability attribute</param>
        /// <param name="propertyType">out: type of the property</param>
        private void GetLocalizabilityForAttachedProperty(
            string                      propertyName,
            Type                        owner,
            out LocalizabilityAttribute localizability,
            out Type                    propertyType
            )
        {
            localizability = null;
            propertyType   = null;

            // if it is an attached property, it should have a dependency property with the name
            // <attached proeprty's name> + "Property"
            DependencyProperty attachedDp = DependencyPropertyFromName(
                propertyName, // property name
                owner
                );       // owner type

            if (attachedDp == null)
                return;  // couldn't find the dp.

            // we found the Dp, set the type of the property
            propertyType = attachedDp.PropertyType;

            FieldInfo fieldInfo = attachedDp.OwnerType.GetField(
                attachedDp.Name + "Property",
                BindingFlags.Public | BindingFlags.NonPublic |
                BindingFlags.Static | BindingFlags.FlattenHierarchy);

            Debug.Assert(fieldInfo != null);

            object[] attributes = fieldInfo.GetCustomAttributes(
                TypeOfLocalizabilityAttribute, // type of localizability
                true
                );                // inherit

            if (attributes.Length == 0)
            {
                // didn't find it.
                return;
            }
            else
            {
                Debug.Assert(attributes.Length == 1, "Should have only 1 localizability attribute");
                localizability = (LocalizabilityAttribute) attributes[0];
            }
        }
        /// <summary>
        /// Get the localizability attribute for a type
        /// </summary>
        internal static LocalizabilityAttribute GetDefaultAttribute(object type)
        {
            if (DefinedAttributes.ContainsKey(type))
            {
                LocalizabilityAttribute predefinedAttribute = DefinedAttributes[type];

                // create a copy of the predefined attribute and return the copy
                LocalizabilityAttribute result = new LocalizabilityAttribute(predefinedAttribute.Category);
                result.Readability   = predefinedAttribute.Readability;
                result.Modifiability = predefinedAttribute.Modifiability;
                return result;
            }
            else
            {
                Type targetType = type as Type;
                if ( targetType != null && targetType.IsValueType)
                {
                    // It is looking for the default value of a value type (i.e. struct and enum)
                    // we use this default.
                    LocalizabilityAttribute attribute = new LocalizabilityAttribute(LocalizationCategory.Inherit);
                    attribute.Modifiability           = Modifiability.Unmodifiable;
                    return attribute;
                }
                else
                {
                    return DefaultAttribute;
                }
            }
        }