public virtual NuGenHL7Exception[] testComponent(Genetibase.NuGenHL7.model.Type type, Component profile, System.String profileID)
		{
			System.Collections.ArrayList exList = new System.Collections.ArrayList(20);
			
			addToList(testType(type, profile, null, profileID), exList);
			
			//test children
			if (profile.SubComponents > 0 && !profile.Usage.Equals("X") && hasContent(type))
			{
				if (typeof(Composite).IsAssignableFrom(type.GetType()))
				{
					Composite comp = (Composite) type;
					for (int i = 1; i <= profile.SubComponents; i++)
					{
						SubComponent childProfile = profile.getSubComponent(i);
						try
						{
							Genetibase.NuGenHL7.model.Type child = comp.getComponent(i - 1);
							addToList(testType(child, childProfile, null, profileID), exList);
						}
						catch (DataTypeException de)
						{
							exList.Add(new NuGenProfileNotHL7CompliantException("More subcomponents in profile than allowed in message: " + de.Message));
						}
					}
					addToList(checkExtraComponents(comp, profile.SubComponents), exList);
				}
				else
				{
					exList.Add(new NuGenProfileNotFollowedException("A component has primitive type " + type.GetType().FullName + " but the profile defines subcomponents"));
				}
			}
			
			return toArray(exList);
		}
		/// <summary> Copies data from a group object into the corresponding group element, creating any 
		/// necessary child nodes.  
		/// </summary>
		private void  encode(Genetibase.NuGenHL7.model.Group groupObject, System.Xml.XmlElement groupElement)
		{
			System.String[] childNames = groupObject.Names;
			System.String messageName = groupObject.Message.getName();
			
			try
			{
				for (int i = 0; i < childNames.Length; i++)
				{
					Structure[] reps = groupObject.getAll(childNames[i]);
					for (int j = 0; j < reps.Length; j++)
					{
						System.Xml.XmlElement childElement = groupElement.OwnerDocument.CreateElement(makeGroupElementName(messageName, childNames[i]));
						groupElement.AppendChild(childElement);
						if (reps[j] is Group)
						{
							encode((Group) reps[j], childElement);
						}
						else if (reps[j] is Segment)
						{
							encode((Segment) reps[j], childElement);
						}
					}
				}
			}
			catch (System.Exception e)
			{
				throw new NuGenHL7Exception("Can't encode group " + groupObject.GetType().FullName, NuGenHL7Exception.APPLICATION_INTERNAL_ERROR, e);
			}
		}
		/// <summary> Tests a Type against the corresponding section of a profile.</summary>
		/// <param name="encoded">optional encoded form of type (if you want to specify this -- if null,  
		/// default pipe-encoded form is used to check length and constant val)
		/// </param>
        public virtual NuGenHL7Exception[] testType(Genetibase.NuGenHL7.model.Type type, AbstractComponent profile, System.String encoded, System.String profileID)
		{
			System.Collections.ArrayList exList = new System.Collections.ArrayList();
			if (encoded == null)
				encoded = NuGenPipeParser.encode(type, this.enc);
			
			NuGenHL7Exception ue = testUsage(encoded, profile.Usage, profile.Name);
			if (ue != null)
				exList.Add(ue);
			
			if (!profile.Usage.Equals("X"))
			{
				//check datatype
				System.String typeClass = type.GetType().FullName;
				if (typeClass.IndexOf("." + profile.Datatype) < 0)
				{
					typeClass = typeClass.Substring(typeClass.LastIndexOf('.') + 1);
					exList.Add(new NuGenProfileNotHL7CompliantException("HL7 datatype " + typeClass + " doesn't match profile datatype " + profile.Datatype));
				}
				
				//check length
				if (encoded.Length > profile.Length)
					exList.Add(new NuGenProfileNotFollowedException("The type " + profile.Name + " has length " + encoded.Length + " which exceeds max of " + profile.Length));
				
				//check constant value
				if (profile.ConstantValue != null && profile.ConstantValue.Length > 0)
				{
					if (!encoded.Equals(profile.ConstantValue))
						exList.Add(new NuGenProfileNotFollowedException("'" + encoded + "' doesn't equal constant value of '" + profile.ConstantValue + "'"));
				}
				
				NuGenHL7Exception[] te = testTypeAgainstTable(type, profile, profileID);
				for (int i = 0; i < te.Length; i++)
				{
					exList.Add(te[i]);
				}
			}
			
			return this.toArray(exList);
		}
        public virtual NuGenHL7Exception[] testField(Genetibase.NuGenHL7.model.Type type, Field profile, bool escape, System.String profileID)
		{
			System.Collections.ArrayList exList = new System.Collections.ArrayList(20);
			
			//account for MSH 1 & 2 which aren't escaped
			System.String encoded = null;
			if (!escape && typeof(Primitive).IsAssignableFrom(type.GetType()))
				encoded = ((Primitive) type).Value;
			
			addToList(testType(type, profile, encoded, profileID), exList);
			
			//test children
			if (profile.Components > 0 && !profile.Usage.Equals("X"))
			{
				if (typeof(Composite).IsAssignableFrom(type.GetType()))
				{
					Composite comp = (Composite) type;
					for (int i = 1; i <= profile.Components; i++)
					{
						Component childProfile = profile.getComponent(i);
						try
						{
							Genetibase.NuGenHL7.model.Type child = comp.getComponent(i - 1);
							addToList(testComponent(child, childProfile, profileID), exList);
						}
						catch (DataTypeException de)
						{
							exList.Add(new NuGenProfileNotHL7CompliantException("More components in profile than allowed in message: " + de.Message));
						}
					}
					addToList(checkExtraComponents(comp, profile.Components), exList);
				}
				else
				{
					exList.Add(new NuGenProfileNotHL7CompliantException("A field has type primitive " + type.GetType().FullName + " but the profile defines components"));
				}
			}
			
			return toArray(exList);
		}
		private static int numStandardComponents(Genetibase.NuGenHL7.model.Type t)
		{
			int n = 0;
			if (typeof(Varies).IsAssignableFrom(t.GetType()))
			{
				n = numStandardComponents(((Varies) t).Data);
			}
			else if (typeof(Composite).IsAssignableFrom(t.GetType()))
			{
				n = ((Composite) t).Components.Length;
			}
			else
			{
				n = 1;
			}
			return n;
		}
		/// <summary> Returns the number of components in the given type, i.e. the
		/// number of standard components (e.g. 6 for CE) plus any extra components that
		/// have been added at runtime.  
		/// </summary>
		public static int numComponents(Genetibase.NuGenHL7.model.Type type)
		{
			if (typeof(Varies).IsAssignableFrom(type.GetType()))
			{
				return numComponents(((Varies) type).Data);
			}
			else
			{
				return numStandardComponents(type) + type.ExtraComponents.numComponents();
			}
		}
		/// <summary> Returns the number of components in the given field, i.e. the
		/// number of standard components (e.g. 6 for CE) plus any extra components that
		/// have been added at runtime.  This may vary by repetition, as different reps
		/// may have different extra components.
		/// </summary>
		/*public static int numComponents(Type field) throws HL7Exception {
		return numComponents(seg.getField(field, rep));
		}*/
		
		/// <summary> Returns the number of sub-components in the specified component, i.e. 
		/// the number of standard sub-components (e.g. 6 for CE) plus any extra components that
		/// that have been added at runtime.
		/// </summary>
		/// <param name="component">numbered from 1 
		/// </param>
		public static int numSubComponents(Genetibase.NuGenHL7.model.Type type, int component)
		{
			int n = - 1;
			if (component == 1 && typeof(Primitive).IsAssignableFrom(type.GetType()))
			{
				//note that getComponent(primitive, 1) below returns the primitive 
				//itself -- if we do numComponents on it, we'll end up with the 
				//number of components in the field, not the number of subcomponents
				n = 1;
			}
			else
			{
				Genetibase.NuGenHL7.model.Type comp = getComponent(type, component);
				n = numComponents(comp);
			}
			return n;
			/*
			//Type t = seg.getField(field, rep);
			if (Varies.class.isAssignableFrom(type.getClass())) {
			return numSubComponents(((Varies) type).getData(), component);
			} else if (Primitive.class.isAssignableFrom(type.getClass()) && component == 1) {
			n = 1;  
			} else if (Composite.class.isAssignableFrom(type.getClass()) && component <= numStandardComponents(t)) {
			n = numComponents(((Composite) type).getComponent(component - 1));
			} else { //we're being asked about subcomponents of an extra component
			n = numComponents(t.getExtraComponents().getComponent(component - numStandardComponents(t) - 1));
			}
			return n;
			*/
		}
		/// <summary> Returns the component (or sub-component, as the case may be) at the given
		/// index.  If it does not exist, it is added as an "extra component".  
		/// If comp > 1 is requested from a Varies with GenericPrimitive data, the 
		/// data is set to GenericComposite (this avoids the creation of a chain of 
		/// ExtraComponents on GenericPrimitives).  
		/// Components are numbered from 1.  
		/// </summary>
        private static Genetibase.NuGenHL7.model.Type getComponent(Genetibase.NuGenHL7.model.Type type, int comp)
		{
			Genetibase.NuGenHL7.model.Type ret = null;
			if (typeof(Varies).IsAssignableFrom(type.GetType()))
			{
				Varies v = (Varies) type;
				
				try
				{
					if (comp > 1 && typeof(GenericPrimitive).IsAssignableFrom(v.Data.GetType()))
						v.Data = new GenericComposite(v.Message);
				}
				catch (DataTypeException de)
				{
					System.String message = "Unexpected exception copying data to generic composite: " + de.Message;
					throw new System.ApplicationException(message);
				}
				
				ret = getComponent(v.Data, comp);
			}
			else
			{
				if (typeof(Primitive).IsAssignableFrom(type.GetType()) && comp == 1)
				{
					ret = type;
				}
				else if (typeof(GenericComposite).IsAssignableFrom(type.GetType()) || (typeof(Composite).IsAssignableFrom(type.GetType()) && comp <= numStandardComponents(type)))
				{
					//note that GenericComposite can return components > number of standard components
					
					try
					{
						ret = ((Composite) type).getComponent(comp - 1);
					}
					catch (System.Exception e)
					{
						throw new Exception("Internal error: HL7Exception thrown on getComponent(x) where x < # standard components.", e);
					}
				}
				else
				{
					ret = type.ExtraComponents.getComponent(comp - numStandardComponents(type) - 1);
				}
			}
			return ret;
		}
		/// <summary> Attempts to extract a Primitive from the given type. If it's a composite, 
		/// drills down through first components until a primitive is reached. 
		/// </summary>
        private static Primitive getPrimitive(Genetibase.NuGenHL7.model.Type type)
		{
			Primitive p = null;
			if (typeof(Varies).IsAssignableFrom(type.GetType()))
			{
				p = getPrimitive(((Varies) type).Data);
			}
			else if (typeof(Composite).IsAssignableFrom(type.GetType()))
			{
				try
				{
					p = getPrimitive(((Composite) type).getComponent(0));
				}
				catch (NuGenHL7Exception)
				{
					throw new System.ApplicationException("Internal error: HL7Exception thrown on Composite.getComponent(0).");
				}
			}
			else if (type is Primitive)
			{
				p = (Primitive) type;
			}
			return p;
		}