public override void WriteEndAttribute ()
		{
			if (state != WriteState.Attribute)
				throw StateError ("End of attribute");

			if (writer.Wrapped == preserver) {
				writer = writer.PreviousWrapper ?? new TextWriterWrapper (source, this);
				string value = preserver.ToString ();
				if (is_preserved_xmlns) {
					if (preserved_name.Length > 0 &&
					    value.Length == 0)
						throw ArgumentError ("Non-empty prefix must be mapped to non-empty namespace URI.");
					string existing = nsmanager.LookupNamespace (preserved_name, false);
					explicit_nsdecls.Add (preserved_name);
					if (open_count > 0) {

						if (v2 &&
						    elements [open_count - 1].Prefix == preserved_name &&
						    elements [open_count - 1].NS != value)
							throw new XmlException (String.Format ("Cannot redefine the namespace for prefix '{0}' used at current element", preserved_name));

						if (elements [open_count - 1].NS != String.Empty ||
						    elements [open_count - 1].Prefix != preserved_name) {
							if (existing != value)
								nsmanager.AddNamespace (preserved_name, value);
						}
					}
				} else {
					switch (preserved_name) {
					case "lang":
						if (open_count > 0)
							elements [open_count - 1].XmlLang = value;
						break;
					case "space":
						switch (value) {
						case "default":
							if (open_count > 0)
								elements [open_count - 1].XmlSpace = XmlSpace.Default;
							break;
						case "preserve":
							if (open_count > 0)
								elements [open_count - 1].XmlSpace = XmlSpace.Preserve;
							break;
						default:
							throw ArgumentError ("Invalid value for xml:space.");
						}
						break;
					}
				}
				writer.Write (value);
			}

			writer.Write (formatSettings.QuoteChar);
			
			if (writer.InBlock) {
				writer.MarkBlockEnd ();
				if (writer.Column > TextPolicy.FileWidth) {
					WriteIndentAttribute ();
					writer.WriteBlock (true);
					writer.AttributesPerLine++;
				} else {
					writer.WriteBlock (false);
				}
			}
			
			state = WriteState.Element;
		}
		public TextWriterWrapper (TextWriter wrapped, XmlFormatterWriter formatter, TextWriterWrapper currentWriter)
			: this (wrapped, formatter)
		{
			PreviousWrapper = currentWriter;
		}
		// Attribute

		public override void WriteStartAttribute (
			string prefix, string localName, string namespaceUri)
		{
			// LAMESPEC: this violates the expected behavior of
			// this method, as it incorrectly allows unbalanced
			// output of attributes. Microfot changes description
			// on its behavior at their will, regardless of
			// ECMA description.
			if (state == WriteState.Attribute)
				WriteEndAttribute ();

			if (state != WriteState.Element && state != WriteState.Start)
				throw StateError ("Attribute");

			if ((object) prefix == null)
				prefix = String.Empty;

			// For xmlns URI, prefix is forced to be "xmlns"
			bool isNSDecl = false;
			if (namespaceUri == XmlnsNamespace) {
				isNSDecl = true;
				if (prefix.Length == 0 && localName != "xmlns")
					prefix = "xmlns";
			}
			else
				isNSDecl = (prefix == "xmlns" ||
					localName == "xmlns" && prefix.Length == 0);

			if (namespaces) {
				// MS implementation is pretty hacky here. 
				// Regardless of namespace URI it is regarded
				// as NS URI for "xml".
				if (prefix == "xml")
					namespaceUri = XmlNamespace;
				// infer namespace URI.
				else if ((object) namespaceUri == null) {
					if (isNSDecl)
						namespaceUri = XmlnsNamespace;
					else
						namespaceUri = String.Empty;
				}

				// It is silly design - null namespace with
				// "xmlns" are allowed (for namespace-less
				// output; while there is Namespaces property)
				// On the other hand, namespace "" is not 
				// allowed.
				if (isNSDecl && namespaceUri != XmlnsNamespace)
					throw ArgumentError (String.Format ("The 'xmlns' attribute is bound to the reserved namespace '{0}'", XmlnsNamespace));

				// If namespace URI is empty, then either prefix
				// must be empty as well, or there is an
				// existing namespace mapping for the prefix.
				if (prefix.Length > 0 && namespaceUri.Length == 0) {
					namespaceUri = nsmanager.LookupNamespace (prefix, false);
					if (namespaceUri == null || namespaceUri.Length == 0)
						throw ArgumentError ("Namespace URI must not be null when prefix is not an empty string.");
				}

				// Dive into extremely complex procedure.
				if (!isNSDecl && namespaceUri.Length > 0)
					prefix = DetermineAttributePrefix (
						prefix, localName, namespaceUri);
			}

			writer.AttributesPerLine++;
			if (formatSettings.WrapAttributes && writer.AttributesPerLine > 1)
				writer.MarkBlockStart ();
			
			if (formatSettings.AttributesInNewLine || writer.AttributesPerLine > formatSettings.MaxAttributesPerLine) {
				writer.MarkBlockEnd ();
				WriteIndentAttribute ();
				writer.AttributesPerLine = 1;
			}
			else if (state != WriteState.Start)
				writer.Write (' ');

			if (prefix.Length > 0) {
				writer.Write (prefix);
				writer.Write (':');
			}
			writer.Write (localName);
			WriteAssignment ();
			writer.Write (formatSettings.QuoteChar);

			if (isNSDecl || prefix == "xml") {
				if (preserver == null)
					preserver = new StringWriter ();
				else
					preserver.GetStringBuilder ().Length = 0;
				writer = new TextWriterWrapper (preserver, this, writer);

				if (!isNSDecl) {
					is_preserved_xmlns = false;
					preserved_name = localName;
				} else {
					is_preserved_xmlns = true;
					preserved_name = localName == "xmlns" ? 
						String.Empty : localName;
				}
			}

			state = WriteState.Attribute;
		}
		void Initialize (TextWriter writer)
		{
			if (writer == null)
				throw new ArgumentNullException ("writer");
			XmlNameTable name_table = new NameTable ();
			this.writer = new TextWriterWrapper (writer, this);
			if (writer is StreamWriter)
				base_stream = ((StreamWriter) writer).BaseStream;
			source = writer;
			nsmanager = new XmlNamespaceManager (name_table);
			newline = writer.NewLine;

			escaped_text_chars =
				newline_handling != NewLineHandling.None ?
				new char [] {'&', '<', '>', '\r', '\n'} :
				new char [] {'&', '<', '>'};
			escaped_attr_chars =
				new char [] {'"', '&', '<', '>', '\r', '\n'};
		}