void Populate(object callbacks, object o, RootElement root)
		{
			MemberInfo last_radio_index = null;
			var members = o.GetType().GetMembers(BindingFlags.DeclaredOnly | BindingFlags.Public |
												 BindingFlags.NonPublic | BindingFlags.Instance);

			Section section = null;

			foreach (var mi in members)
			{
				Type mType = GetTypeForMember(mi);

				if (mType == null)
					continue;

				string caption = null;
				object[] attrs = mi.GetCustomAttributes(false);
				bool skip = false;
				foreach (var attr in attrs)
				{
					if (attr is SkipAttribute)
						skip = true;
					if (attr is CaptionAttribute)
						caption = ((CaptionAttribute)attr).Caption;
					else if (attr is SectionAttribute)
					{
						if (section != null)
							root.Add(section);
						var sa = attr as SectionAttribute;
						section = new Section(sa.Caption, sa.Footer);
					}
				}
				if (skip)
					continue;

				if (caption == null)
					caption = MakeCaption(mi.Name);

				if (section == null)
					section = new Section();

				Element element = null;
				
				if (mType == typeof(string)) {
					PasswordAttribute pa = null;
					AlignmentAttribute align = null;
					EntryAttribute ea = null;
					object html = null;
					EventHandler invoke = null;
					bool multi = false;

					foreach (object attr in attrs) {
						if (attr is PasswordAttribute)
							pa = attr as PasswordAttribute;
						else if (attr is EntryAttribute)
							ea = attr as EntryAttribute;
						else if (attr is MultilineAttribute)
							multi = true;
						else if (attr is HtmlAttribute)
							html = attr;
						else if (attr is AlignmentAttribute)
							align = attr as AlignmentAttribute;

						if (attr is OnTapAttribute) {
							string mname = ((OnTapAttribute)attr).Method;

							if (callbacks == null) {
								throw new Exception("Your class contains [OnTap] attributes, but you passed a null object for `context' in the constructor");
							}

							var method = callbacks.GetType().GetMethod(mname);
							if (method == null)
								throw new Exception("Did not find method " + mname);
							invoke = delegate {
								 method.Invoke(method.IsStatic ? null : callbacks, new object[0]);
							 };
						}
					}

					string value = (string)GetValue(mi, o);
					if (pa != null)
						element = new EntryElement(caption, value) { Hint = pa.Placeholder, Password = true };
					else if (ea != null)
						element = new EntryElement(caption, value) { Hint = ea.Placeholder };
					else if (multi)
						element = new MultilineElement(caption, value);
					else if (html != null)
						element = new HtmlElement(caption, value);
					else
					{
						var selement = new StringElement(caption, value);
						element = selement;

						if (align != null)
							selement.Alignment = align.Alignment;
					}

					if (invoke != null)
					{
						//                        ((StringElement)element).Click += invoke;
					}
				}
				else if (mType == typeof(float))
				{
					var floatElement = new FloatElement(null, null, (int)GetValue(mi, o));
					floatElement.Caption = caption;
					element = floatElement;

					foreach (object attr in attrs)
					{
						if (attr is RangeAttribute)
						{
							var ra = attr as RangeAttribute;
							floatElement.MinValue = ra.Low;
							floatElement.MaxValue = ra.High;
							floatElement.ShowCaption = ra.ShowCaption;
						}
					}
				}
				else if (mType == typeof(bool))
				{
					bool checkbox = false;
					foreach (object attr in attrs)
					{
						if (attr is CheckboxAttribute)
							checkbox = true;
					}

					if (checkbox)
						element = new CheckboxElement(caption, (bool)GetValue(mi, o));
					else
						element = new BooleanElement(caption, (bool)GetValue(mi, o));
				}
				else if (mType == typeof(DateTime))
				{
					var dateTime = (DateTime)GetValue(mi, o);
					bool asDate = false, asTime = false;

					foreach (object attr in attrs)
					{
						if (attr is DateAttribute)
							asDate = true;
						else if (attr is TimeAttribute)
							asTime = true;
					}

					if (asDate)
						element = new DateElement(caption, dateTime);
					else if (asTime)
						element = new TimeElement(caption, dateTime);
					else
						element = new DateTimeElement(caption, dateTime);
				}
				else if (mType.IsEnum)
				{
					var csection = new Section();
					ulong evalue = Convert.ToUInt64(GetValue(mi, o), null);
					int idx = 0;
					int selected = 0;

					foreach (var fi in mType.GetFields(BindingFlags.Public | BindingFlags.Static))
					{
						ulong v = Convert.ToUInt64(GetValue(fi, null));

						if (v == evalue)
							selected = idx;

						csection.Add(new RadioElement(MakeCaption(fi.Name)));
						idx++;
					}

					element = new RootElement(caption, new RadioGroup(null, selected)) { csection };
				}
				else if (mType == typeof(ImageView))
				{
					element = new ImageElement(null); // (ImageView)GetValue(mi, o));
				}
				else if (typeof(System.Collections.IEnumerable).IsAssignableFrom(mType))
				{
					var csection = new Section();
					int count = 0;

					if (last_radio_index == null)
						throw new Exception("IEnumerable found, but no previous int found");
					foreach (var e in (IEnumerable)GetValue(mi, o))
					{
						csection.Add(new RadioElement(e.ToString()));
						count++;
					}
					int selected = (int)GetValue(last_radio_index, o);
					if (selected >= count || selected < 0)
						selected = 0;
					element = new RootElement(caption, new MemberRadioGroup(null, selected, last_radio_index)) { csection };
					last_radio_index = null;
				}
				else if (typeof(int) == mType)
				{
					foreach (object attr in attrs)
					{
						if (attr is RadioSelectionAttribute)
						{
							last_radio_index = mi;
							break;
						}
					}
				}
				else
				{
					var nested = GetValue(mi, o);
					if (nested != null)
					{
						var newRoot = new RootElement(caption);
						Populate(callbacks, nested, newRoot);
						element = newRoot;
					}
				}

				if (element == null)
					continue;

				section.Add(element);
				mappings[element] = new MemberAndInstance(mi, o);
			}
			root.Add(section);
		}
		public static RootElement TestElements()
		{
			RootElement re1 = new RootElement("re1");
			Debug.WriteLine(re1.ToString());
			Section s1 = new Section();
			Debug.WriteLine(s1.ToString());
			//Section s2 = new Section(new Android.Views.View(a1));
			//Debug.WriteLine(s2.ToString());
			Section s3 = new Section("s3");
			Debug.WriteLine(s3.ToString());
			//Section s4 = new Section
			//					(
			//					  new Android.Views.View(a1)
			//					, new Android.Views.View(a1)
			//					);
			//Debug.WriteLine(s4.ToString());
			Section s5 = new Section("caption", "footer");
			Debug.WriteLine(s5.ToString());

			StringElement se1 = new StringElement("se1");
			Debug.WriteLine(se1.ToString());
			StringElement se2 = new StringElement("se2", delegate() { });
			Debug.WriteLine(se2.ToString());
			//StringElement se3 = new StringElement("se3", 4);
			StringElement se4 = new StringElement("se4", "v4");
			Debug.WriteLine(se4.ToString());
			//StringElement se5 = new StringElement("se5", "v5", delegate() { });
			
			// removed - protected (all with LayoutID)
			// StringElement se6 = new StringElement("se6", "v6", 4);
			// Debug.WriteLine(se6.ToString());

			// not cross platform! 
			// TODO: make it!?!?!?
			// AchievementElement
			
			BooleanElement be1 = new BooleanElement("be1", true);
			Debug.WriteLine(be1.ToString());
			BooleanElement be2 = new BooleanElement("be2", false, "key");
			Debug.WriteLine(be2.ToString());
			
			// Abstract
			// BoolElement be3 = new BoolElement("be3", true);

			CheckboxElement cb1 = new CheckboxElement("cb1");
			Debug.WriteLine(cb1.ToString());
			CheckboxElement cb2 = new CheckboxElement("cb2", true);
			Debug.WriteLine(cb2.ToString());
			CheckboxElement cb3 = new CheckboxElement("cb3", false, "group1");
			Debug.WriteLine(cb3.ToString());
			CheckboxElement cb4 = new CheckboxElement("cb4", false, "subcaption", "group2");
			Debug.WriteLine(cb4.ToString());

			DateElement de1 = new DateElement("dt1", DateTime.Now);
			Debug.WriteLine(de1.ToString());

			// TODO: see issues 
			// https://github.com/kevinmcmahon/MonoDroid.Dialog/issues?page=1&state=open
			EntryElement ee1 = new EntryElement("ee1", "ee1");
			Debug.WriteLine(ee1.ToString());
			EntryElement ee2 = new EntryElement("ee2", "ee2 placeholder", "ee2 value");
			Debug.WriteLine(ee2.ToString());
			EntryElement ee3 = new EntryElement("ee3", "ee3 placeholder", "ee3 value", true);
			Debug.WriteLine(ee3.ToString());

			FloatElement fe1 = new FloatElement("fe1");
			Debug.WriteLine(fe1.ToString());
			FloatElement fe2 = new FloatElement(-0.1f, 0.1f, 3.2f);
			Debug.WriteLine(fe2.ToString());
			FloatElement fe3 = new FloatElement
									(
									  null
									, null // no ctors new Android.Graphics.Bitmap()
									, 1.0f
									);
			Debug.WriteLine(fe3.ToString());

			HtmlElement he1 = new HtmlElement("he1", "http://holisiticware.net");
			Debug.WriteLine(he1.ToString());

			
			// TODO: image as filename - cross-platform
			ImageElement ie1 = new ImageElement(null);
			Debug.WriteLine(ie1.ToString());

			// TODO: not in Kevin's MA.D
			// ImageStringElement

			MultilineElement me1 = new MultilineElement("me1");
			Debug.WriteLine(me1.ToString());
			MultilineElement me2 = new MultilineElement("me2", delegate() { });
			Debug.WriteLine(me2.ToString());
			MultilineElement me3 = new MultilineElement("me3", "me3 value");
			Debug.WriteLine(me3.ToString());

			RadioElement rde1 = new RadioElement("rde1");
			Debug.WriteLine(rde1.ToString());
			RadioElement rde2 = new RadioElement("rde1", "group3");
			Debug.WriteLine(rde2.ToString());

			// TODO: not in Kevin's MA.D
			// StyledMultilineElement

			TimeElement te1 = new TimeElement("TimeElement", DateTime.Now);
			Debug.WriteLine(te1.ToString());



			re1.Add(s1);
			//re1.Add(s2);
			re1.Add(s3);
			//re1.Add(s4);
			re1.Add(s5);

			return re1;
		}