public override void WriteChecks(CsCodeWriter code)
 {
     using (code.WriteBlock("if (!value.IsValid())"))
     {
         code.WriteLine("if (onError == null)");
         code.WriteLineIndent("return false;");
         code.WriteLine(
             "{0}System.Collections.Generic.List<{0}NClassify.Library.ValidationError> errors = " +
             "new {0}System.Collections.Generic.List<{0}NClassify.Library.ValidationError>();",
             CsCodeWriter.Global
             );
         code.WriteLine("value.GetBrokenRules(errors.Add);");
         code.WriteLine("onError(new {0}NClassify.Library.ValidationError(TypeFields.{1}, errors));",
             CsCodeWriter.Global, _field.PropertyName);
         code.WriteLine("return false;");
     }
 }
        public override void ReadXmlMessage(CsCodeWriter code)
        {
            if (_type.ImplementationName != _type.QualifiedName)
                code.WriteLine("{0}{1} value = ({2} as {0}{1}) ?? new {0}{1}({2});",
                    CsCodeWriter.Global, _type.ImplementationName, FieldBackingName);
            else
                code.WriteLine("{0}{1} value = {2};", 
                    CsCodeWriter.Global, _type.ImplementationName, FieldBackingName);

            code.WriteLine("if (value.IsReadOnly())");
            code.WriteLineIndent("value = object.ReferenceEquals(value, {0}{1}.DefaultInstance) ? new {0}{1}() : new {0}{1}({2});",
                CsCodeWriter.Global, _type.ImplementationName, FieldBackingName);

            code.WriteLine("value.ReadXml(reader.LocalName, reader);");
            code.WriteLine("{0} = value;", FieldBackingName);
            if (HasBackingName != null)
                code.WriteLine(HasBackingName + " = true;");
        }
 public override void WriteCopy(CsCodeWriter code, string other)
 {
     if(_generator.IsMessage)
     {
         code.WriteLine("foreach ({0} item in {1}.{2})", _generator.GetPublicType(code), other, PropertyName);
         code.WriteLineIndent("{0}.Add(({1})item.Clone());", FieldBackingName, _generator.GetStorageType(code));
     }
     else
         code.WriteLine("{0}.AddRange({1}.{2});", FieldBackingName, other, PropertyName);
 }
        public override void DeclareTypes(CsCodeWriter code)
        {
            string collection = GetStorageType(code);
            string itemType = _generator.GetPublicType(code);
            
            using (code.CodeRegion(collection))
            using (code.DeclareClass(
                new CodeItem(collection) { Access = FieldAccess.Private },
                new[]
                    {
                        CsCodeWriter.Global + "System.Collections.Generic.IList<" + _generator.GetPublicType(code) + ">",
                        CsCodeWriter.Global + "System.ICloneable",
                    }))
            {
                using(code.WriteBlock("private static T AssertNotNull<T>(T value) where T : class"))
                {
                    code.WriteLine("if (null == value) throw new {0}System.ArgumentNullException({1});",
                        CsCodeWriter.Global, code.MakeString(PropertyName)); 
                    code.WriteLine("return value;");
                }

                string value = _generator.IsNullable ? "AssertNotNull(value)" : "value";
                code.WriteLine("private bool _readOnly;");
                code.WriteLine("private readonly {0}System.Collections.Generic.List<{1}> _contents;", CsCodeWriter.Global, itemType);

                using(code.WriteBlock("public {0}()", collection))
                {
                    code.WriteLine("_readOnly = false;");
                    code.WriteLine("_contents = new {0}System.Collections.Generic.List<{1}>();", CsCodeWriter.Global, itemType);
                }
                using (code.WriteBlock("public {0}({1}System.Collections.Generic.IList<{2}> contents, bool clone)", collection, CsCodeWriter.Global, itemType))
                {
                    code.WriteLine("_readOnly = false;");
                    if (!_generator.IsNullable)
                    {
                        code.WriteLine("_contents = new {0}System.Collections.Generic.List<{1}>(AssertNotNull(contents));",
                            CsCodeWriter.Global, itemType);
                    }
                    else
                    {
                        code.WriteLine("_contents = new {0}System.Collections.Generic.List<{1}>(AssertNotNull(contents).Count);",
                            CsCodeWriter.Global, itemType);
                        using (code.WriteBlock("foreach ({0} item in contents)", _generator.GetPublicType(code)))
                        {
                            if (_generator.IsMessage)
                            {
                                code.WriteLine("if (clone)");
                                code.WriteLineIndent("_contents.Add(({0})AssertNotNull(item).Clone());", itemType);
                                code.WriteLine("else");
                            }
                            code.WriteLine("_contents.Add(AssertNotNull(item));");
                        }
                    }
                }
                _generator.Constraints.ForAll(x => x.WriteMember(code));
                using (code.WriteBlock("public void MakeReadOnly()"))
                {
                    code.WriteLine("if (_readOnly) return;");
                    code.WriteLine("_readOnly = true;");
                    if (_generator.IsMessage)
                        using (code.WriteBlock("for (int i=0; i < _contents.Count; i++)"))
                        {
                            _generator.MakeReadOnly(code, "_contents[i]");
                        }
                }
                using (code.WriteBlock("private {0}System.Collections.Generic.List<{1}> Modify", CsCodeWriter.Global, itemType))
                    code.WriteLine("get {{ if (!IsReadOnly) return _contents; throw new {0}System.InvalidOperationException(); }}", CsCodeWriter.Global);
                using (code.WriteBlock("public {0} this[int index]", itemType))
                {
                    code.WriteLine("get { return _contents[index]; }");
                    code.WriteLine("set {{ Modify[index] = {0}; }}", value);
                }
                code.WriteLine("public int Count { get { return _contents.Count; } }");
                code.WriteLine("public bool IsReadOnly { get { return _readOnly; } }");
                code.WriteLine("public void Add({0} value) {{ Modify.Add({1}); }}", itemType, value);
                using (code.WriteBlock("public void AddRange({1}System.Collections.Generic.ICollection<{0}> value)", itemType, CsCodeWriter.Global))
                {
                    if (_generator.IsNullable)
                        code.WriteLine("foreach ({0} item in AssertNotNull(value)) AssertNotNull(item);", _generator.GetPublicType(code));
                    code.WriteLine("Modify.AddRange(AssertNotNull(value));");
                }
                code.WriteLine("public void Insert(int index, {0} value) {{ Modify.Insert(index, {1}); }}", itemType, value);
                code.WriteLine("public bool Remove({0} item) {{ return Modify.Remove(item); }}", itemType);
                code.WriteLine("public void RemoveAt(int index) { Modify.RemoveAt(index); }");
                code.WriteLine("public void Clear() { Modify.Clear(); }");
                code.WriteLine("public bool Contains({0} item) {{ return _contents.Contains(item); }}", itemType);
                code.WriteLine("public int IndexOf({0} item) {{ return _contents.IndexOf(item); }}", itemType);
                code.WriteLine("public void CopyTo({0}[] array, int arrayIndex) {{ _contents.CopyTo(array, arrayIndex); }}", itemType);
                code.WriteLine("object {0}System.ICloneable.Clone() {{ return Clone(); }}", CsCodeWriter.Global);
                using (code.WriteBlock("public {0} Clone()", collection))
                {
                    code.WriteLine("return _readOnly ? this : new {0}(this, true);", collection);
                }
                code.WriteLine("public {0}System.Collections.Generic.IEnumerator<{1}> GetEnumerator()", CsCodeWriter.Global, itemType);
                code.WriteLine("{ return _contents.GetEnumerator(); }");
                code.WriteLine("{0}System.Collections.IEnumerator {0}System.Collections.IEnumerable.GetEnumerator()", CsCodeWriter.Global);
                code.WriteLine("{{ return (({0}System.Collections.IEnumerable)_contents).GetEnumerator(); }}", CsCodeWriter.Global);
            }
        }
        public void WriteXmlReadMembers(CsCodeWriter code, IEnumerable<BaseFieldGenerator> rawfields)
        {
            List<BaseFieldGenerator> fields = new List<BaseFieldGenerator>(rawfields);
            fields.Sort((a, b) => StringComparer.Ordinal.Compare(a.XmlOptions.XmlName, b.XmlOptions.XmlName));
            bool hasMessage = fields.Exists(f => f.IsMessage);

            code.WriteLine("private static readonly string[] _fieldNamesToIx = new string[] {{ \"{0}\" }};",
                           String.Join("\", \"", fields.Select(f => f.XmlOptions.XmlName).ToArray()));
            if (hasMessage)
                code.WriteLine("private static readonly bool[] _isMessageFldIx = new bool[] {{ {0} }};",
                               String.Join(", ", fields.Select(f => f.IsMessage ? "true" : "false").ToArray()));

            string xmlns = CsCodeWriter.Global + "System.Xml";
            if (!_subclass)
            {
                using (code.WriteBlock("public void ReadXml({0}.XmlReader reader)", xmlns))
                    code.WriteLine("ReadXml(\"{0}\", reader);", _xmlName);

                using (code.WriteBlock("public void ReadXml(string localName, {0}.XmlReader reader)", xmlns))
                {
                    code.WriteLine("reader.MoveToContent();");
                    code.WriteLine("if (!reader.IsStartElement(localName))");
                    code.WriteLineIndent("throw new global::System.FormatException();");

                    code.WriteLine("if (reader.MoveToFirstAttribute())");
                    code.WriteLineIndent("MergeFrom(reader);");

                    code.WriteLine("bool empty = reader.IsEmptyElement;");
                    code.WriteLine("reader.ReadStartElement(localName);");
                    using (code.WriteBlock("if (!empty)"))
                    {
                        code.WriteLine("MergeFrom(reader);");
                        code.WriteLine("reader.ReadEndElement();");
                    }
                }
                using (code.WriteBlock("public void MergeFrom({0}.XmlReader reader)", xmlns))
                {
                    code.WriteLine("int depth = reader.Depth;");
                    using (code.WriteBlock("while (!reader.EOF && reader.Depth >= depth)"))
                    {
                        code.WriteLine("if (reader.NodeType == global::System.Xml.XmlNodeType.EndElement) break;");
                        using (code.WriteBlock("if (reader.NodeType != global::System.Xml.XmlNodeType.Element && reader.NodeType != global::System.Xml.XmlNodeType.Attribute)"))
                        {
                            code.WriteLine("reader.Read();");
                            code.WriteLine("continue;");
                        }
                        code.WriteLine("else MergeField(reader);");
                    }
                }
            }
            using (code.WriteBlock("protected {1} void MergeField({0}.XmlReader reader)", xmlns, _subclass ? "override" : "virtual"))
            {
                code.WriteLine("int field = global::System.Array.BinarySearch(_fieldNamesToIx, reader.LocalName, {0}System.StringComparer.Ordinal);", CsCodeWriter.Global);
                code.WriteLine("bool isElement = reader.NodeType == global::System.Xml.XmlNodeType.Element;");
                code.WriteLine("bool isAttribute = isElement ? false : reader.NodeType == global::System.Xml.XmlNodeType.Attribute;");
                code.WriteLine("if (!isElement && !isAttribute) throw new global::System.FormatException();");

                using (code.WriteBlock("if (field < 0)"))
                {
                    if (_subclass)
                        code.WriteLine("base.MergeField(reader);");
                    else
                    {
                        code.WriteLine("if (isElement)");
                        code.WriteLineIndent("reader.ReadInnerXml();");
                        code.WriteLine("else if (!reader.MoveToNextAttribute())");
                        code.WriteLineIndent("reader.MoveToElement();");
                    }
                }
                if (hasMessage)
                {
                    using (code.WriteBlock("else if (_isMessageFldIx[field])"))
                    {
                        code.WriteLine("if (!isElement)");
                        code.WriteLineIndent("throw new global::System.FormatException();");

                        using (code.WriteBlock("switch(field)"))
                        {
                            for (int i = 0; i < fields.Count; i++)
                            {
                                if (!fields[i].IsMessage)
                                    continue;

                                using (code.WriteBlock("case {0}:", i))
                                {
                                    fields[i].ReadXmlMessage(code);
                                    code.WriteLine("break;");
                                }
                            }
                        }
                    }
                }
                using (code.WriteBlock("else"))
                {
                    code.WriteLine("global::System.Text.StringBuilder sbuilder = new global::System.Text.StringBuilder();");
                    using (code.WriteBlock("if (isAttribute)"))
                    {
                        code.WriteLine("sbuilder.Append(reader.Value);");
                        code.WriteLine("if (!reader.MoveToNextAttribute())");
                        code.WriteLineIndent("reader.MoveToElement();");
                    }
                    code.WriteLine("else if (reader.IsEmptyElement)");
                    code.WriteLineIndent("reader.ReadStartElement();");
                    using (code.WriteBlock("else"))
                    {
                        code.WriteLine("int stop = reader.Depth;");
                        using (code.WriteBlock("while (reader.Read() && reader.Depth > stop)"))
                        {
                            code.WriteLine("while (reader.IsStartElement()) reader.Skip();");
                            code.WriteLine("if (((1 << (int)reader.NodeType) & 0x6018) != 0)");
                            code.WriteLineIndent("sbuilder.Append(reader.Value);");
                        }
                        code.WriteLine("reader.ReadEndElement();");
                    }
                    using (code.WriteBlock("switch(field)"))
                    {
                        for (int i = 0; i < fields.Count; i++)
                        {
                            if (fields[i].IsMessage)
                                continue;

                            using (code.WriteBlock("case {0}:", i))
                            {
                                using (fields[i].XmlOptions.IgnoreEmpty ? code.WriteBlock("if (sbuilder.Length > 0)") : null)
                                    fields[i].ReadXmlValue(code, "sbuilder.ToString()");
                                code.WriteLine("break;");
                            }
                        }
                        using (code.WriteBlock("default:"))
                        {
                            code.WriteLine("break;");
                        }
                    }
                }
            }
        }