/*********************************************************************************************
 * Copyright 2021 - Volian Enterprises, Inc. All rights reserved.
 * Volian Enterprises - Proprietary Information - DO NOT COPY OR DISTRIBUTE
 * ------------------------------------------------------------------------------
 * $Workfile: VlnXml.cs $     $Revision: 23 $
 * $Author: Jsj $   $Date: 6/20/05 1:29p $
 *
 * $History: VlnXml.cs $
 * 
 * *****************  Version 23  *****************
 * User: Jsj          Date: 6/20/05    Time: 1:29p
 * Updated in $/LibSource/RODBInterface
 * added status message while reading ROs for Complete RO Report.
 * 
 * *****************  Version 22  *****************
 * User: Jsj          Date: 6/08/05    Time: 4:32p
 * Updated in $/LibSource/RODBInterface
 * Complete RO Report Bug fix  B2001-001
 * 
 * *****************  Version 21  *****************
 * User: Jsj          Date: 9/27/04    Time: 11:02a
 * Updated in $/LibSource/RODBInterface
 * upped release number
 * 
 * *****************  Version 20  *****************
 * User: Kathy        Date: 7/15/04    Time: 11:11a
 * Updated in $/LibSource/RODBInterface
 * Fix B2004-017
 * 
 * *****************  Version 19  *****************
 * User: Kathy        Date: 5/06/04    Time: 9:52a
 * Updated in $/LibSource/RODBInterface
 * B2004-012 fix: skip process of param display data for RO Cmp Rpt
 * 
 * *****************  Version 18  *****************
 * User: Jsj          Date: 4/08/04    Time: 9:43a
 * Updated in $/LibSource/RODBInterface
 * Added and commented out calls to VlnProfiler
 * 
 * *****************  Version 17  *****************
 * User: Jsj          Date: 1/21/04    Time: 12:10p
 * Updated in $/LibSource/RODBInterface
 * added function to return current selected field type of multi type
 * field
 * 
 * *****************  Version 16  *****************
 * User: Kathy        Date: 5/21/03    Time: 12:41p
 * Updated in $/LibSource/RODBInterface
 * B2003-035: process ro's with just one field
 * 
 * *****************  Version 15  *****************
 * User: Jsj          Date: 4/14/03    Time: 2:59p
 * Updated in $/LibSource/RODBInterface
 * changes resulting from speeding up RO FST creation
 * 
 * *****************  Version 14  *****************
 * User: Kathy        Date: 3/11/03    Time: 11:24a
 * Updated in $/LibSource/RODBInterface
 * allow extra text on accpageid template
 * 
 * *****************  Version 13  *****************
 * User: Kathy        Date: 12/17/02   Time: 12:53p
 * Updated in $/LibSource/RODBInterface
 * get image data by node for rofst creation
 * 
 * *****************  Version 12  *****************
 * User: Kathy        Date: 12/10/02   Time: 2:25p
 * Updated in $/LibSource/RODBInterface
 * fieldname special chars & various bugs
 * 
 * *****************  Version 11  *****************
 * User: Kathy        Date: 12/02/02   Time: 8:29a
 * Updated in $/LibSource/RODBInterface
 * fieldname replace chars
 * 
 * *****************  Version 10  *****************
 * User: Jsj          Date: 11/27/02   Time: 12:47p
 * Updated in $/LibSource/RODBInterface
 * modifications for RO.FST file creation
 * 
 * *****************  Version 9  *****************
 * User: Kathy        Date: 11/19/02   Time: 11:32a
 * Updated in $/LibSource/RODBInterface
 * fields within {} are not required
 * 
 * *****************  Version 8  *****************
 * User: Kathy        Date: 11/11/02   Time: 7:14a
 * Updated in $/LibSource/RODBInterface
 * Added complete report methods.
 *********************************************************************************************/
using System;
using System.Xml;
using System.Text;
using System.Collections;
using System.IO;
using System.Windows.Forms;
using ROFields;
using VlnStatus;
//using VlnProfiler; //don't forget to add VlnProfiler to the reference list
namespace RODBInterface
{
	/// 
	/// Summary description for Class1.
	/// 
 
	public class VlnXmlDocument:XmlDocument 
	{
		FileStream Rptfs;		// for complete report of this document
		BinaryWriter RptBW;
		
		public VlnXmlDocument():base() 
		{
		}
		public override XmlElement CreateElement( string prefix, string localname, string nsURI) 
		{
			VlnXmlElement elem = new VlnXmlElement(prefix, localname, nsURI, this);
			return elem;
		}
		public bool OpenTemp()
		{
			try
			{
				//Rptfs = new FileStream("print.tmp", FileMode.Create);
				Rptfs = new FileStream("print.tmp", FileMode.Append);
				// Create the writer for data.
				RptBW = new BinaryWriter(Rptfs);
			}
			catch (Exception ex) 
			{
				Console.WriteLine("Open Print.Tmp: {0}", ex.Message);
				return false;
			}
			return true;
		}
		public void CloseTemp()
		{
			RptBW.Close();
			Rptfs.Close();
		}
		public void writeInt(short val)
		{
			RptBW.Write(val);
		}
		public void writeText(string str)
		{
			short n = (short) str.Length;
			writeInt(n);
			// write out char by char. (Using rite
			// of entire stirng caused special characters to be
			// written as two bytes - which temp file reading code
			int i;
			for(i =0; i < str.Length; i++)
			{
				byte WrByte;
				WrByte = (byte)str[i];
				RptBW.Write(WrByte);
			}
		}
		public void writeTextValue(string str)
		{
			writeInt(100);
			writeText(str);
		}
		public void writePlot(string str)
		{
			writeInt(101);
			writeText(str);
		}
		public void writeImage(string str)
		{
			writeInt(102);
			writeText(str);
		}
		public void pushHeader(string str)
		{
			writeInt(2);
			writeText(str);
		}
		public void popHeader()
		{
			writeInt(3);
		}
		public void doHeader(ArrayList headers)
		{
			int spaces = -1;
			short cnt = (short) headers.Count;
			writeInt(255);
			writeInt(1);
			writeInt(cnt);
			for (int i=0; i < cnt ;i++)
			{
				writeInt(0);
				if (spaces>0)
				{
					string spc = new String(' ',2*(spaces-1));
					writeText(spc+headers[i].ToString());
				}
				else
				writeText(headers[i].ToString());
				spaces++;
			}
		}
		public void writeRROBegin()
		{
			writeInt(4);
		}
		public void writeRROEnd()
		{
			writeInt(5);
		}
	
		public void writeMultiBegin()
		{
			writeInt(103);
		}
		public void writeMultiEnd()
		{
			writeInt(104);
		}
	}
	public class VlnXmlElement:XmlElement 
	{
		public VlnXmlElement( string prefix, string localname, string nsURI, XmlDocument doc ):base( prefix,localname,nsURI, doc )
		{
		}
		private string _MyROID;
		public string MyROID
		{
			get { return _MyROID; }
			set { _MyROID = value; }
		}
		private string CvtUserFldToFld(string fldname)
		{
			if (fldname.Length < 2)
				return fldname;
			// a digit cannot start an xml fieldname, prepend a "__" to it.
			string tmp0;
			if (char.IsDigit(fldname,0))
				tmp0 = "__" + fldname;
			else
				tmp0 = fldname;
			// an xml fieldname cannot have a space, change it to a "__"
			string tmpstr = tmp0.Replace(" ","__");
			int len = tmpstr.Length;
			int cnt = 0;
			// this is also our sequence that tells us the follow 3 digits is the ascii number (base 10)
			// of the character we replaced.
			string OKpunch = "-._"; 
			string outstr = "";
			int decval;
			while (cnt < len)
			{
				char tmpchr = tmpstr[cnt];
				if(!char.IsLetterOrDigit(tmpchr)&& (OKpunch.IndexOf(tmpchr) == -1) )
				{
					decval = tmpchr;
					outstr += OKpunch + decval.ToString("D3");
				}
				else
				{
					outstr += tmpchr.ToString();
				}
				cnt++;
			}
			return outstr;
		}
		private string CvtFldToUserFld(string fldname)
		{
			string tmpstr0;
			if (fldname.Length < 2) return fldname;
			// an xml element name cannot begin with a digit. we had prepended a "__"
			if (fldname.Substring(0,2) == "__" && char.IsDigit(fldname,2))
				tmpstr0 = fldname.Substring(2,fldname.Length-2);
			else
				tmpstr0 = fldname;
			// an xml element name cannot have a space, we converted to a "__"
			string tmpstr = tmpstr0.Replace("__"," ");
			int len = tmpstr.Length;
			int cur = 0;
			// this is also our sequence that tells us the follow 3 digits is the ascii number (base 10)
			// of the character we replaced.
			string OKpunch = "-._"; 
			string outstr = "";
			int decval, indx;
			if (tmpstr.Length <6)
				indx = -1;
			else
				indx=tmpstr.IndexOf(OKpunch,cur);
			string asc_spchar;
			while (indx>=0)
			{
				outstr += tmpstr.Substring(cur,indx-cur);
				asc_spchar = tmpstr.Substring(indx+3,3);
				decval = System.Convert.ToInt16(asc_spchar,10);
				outstr += System.Convert.ToChar(decval).ToString();
				cur = indx+6;
				if (cur+6 > len)
					indx = -1;
				else
					indx = tmpstr.IndexOf(OKpunch,cur);
			}
			if (cur");
			if (left >= 0 && right > 0) 
				fld = newtmpl.Substring(left+1,right-left-1);
			else
				return null;
			string usefld = CvtUserFldToFld(fld);
			
			XmlNode elmnode = (XmlNode) elm;
			XmlNode nd = elmnode.SelectSingleNode(usefld);
			// if not found it may be a combination, try this.
			if (nd == null)
			{
				string tmp = usefld + "a";
				nd = elmnode.SelectSingleNode(tmp);
			}
			if (nd == null)
			{
				string tmp = usefld + "b";
				nd = elmnode.SelectSingleNode(tmp);
			}
			if (nd == null)
			{
				string tmp = usefld + "c";
				nd = elmnode.SelectSingleNode(tmp);
			}
			if (nd == null)
			{
				string tmp = usefld + "d";
				nd = elmnode.SelectSingleNode(tmp);
			}
			if(nd != null)
			{
				StringBuilder strbld = new StringBuilder();
				if (left > 0) strbld.Append(newtmpl.Substring(0,left));
				strbld.Append(nd.InnerText.ToString());
				if (right+1 0) strbld.Append(menuitm.Substring(0,left));
	
			while (left != -1)
			{
				// get right bracket and then check for valid field & if commas with
				// this, check for integer values.
				right = menuitm.IndexOf(">",stindx);
				string tmpd = menuitm.Substring(left+1,right-left-1);
				// do comma parts now.
				string inusename;
				int comma1 = tmpd.IndexOf(",");
				int frmt1=0, frmt2=0;
				if (comma1 != -1)
				{
					// get any numbers for formatting & check for ints.
					int comma2 = tmpd.IndexOf(",",comma1+1);
					if (comma2 != -1) // two ints.
					{
						if (comma2-comma1 > 1) // first format field - not empty 
						{
							string int1 = tmpd.Substring(comma1+1,comma2-comma1-1);
							frmt1 = System.Convert.ToInt32(int1);
						}
						if (comma20)
								strbld.Append(text.PadRight(frmt2,' '));
							else
								strbld.Append(text);
						}
						else if (frmt1 != frmt2)
						{
							int cnt = 0;
//							while (cnt < tmp.Length && tmp[cnt] <= '9' && tmp[cnt] >= '0') cnt++; // new RO logic
//							int padcnt = (cnt>frmt1)?0:frmt1-cnt;
							int padcnt = OldROFSTMenuLogic(text,frmt1,frmt2); // testing!!!!!
							StringBuilder strtmp = new StringBuilder();
							cnt = 0;
							while(cnt frmt2) // longer than the field length?
								strtmp.Append(text.Substring(0,frmt2-cnt));
							else
								strtmp.Append(text);
							string tmpstr = strtmp.ToString();
							strbld.Append(tmpstr.PadRight(frmt2,' '));
						}
						else
							strbld.Append(text.PadLeft(frmt2,' '));
					}
				}
				stindx = right+1;
				left = menuitm.IndexOf("<",left+1);
				if (left != -1 && left > right+1)  // append any plain text.
					strbld.Append(menuitm.Substring(right+1,left-right-1));
			}
			if (right+1='0') || str[idx] =='-' || str[idx]=='+'))
			{
				siznum++;
				idx++;
			}
			if (siznum == 0)
			{
				newoff= siznum+(wid-slen)/2;
			} 
			else if (((doff-siznum)+slen)> wid)
			{
				newoff = wid-siznum-slen;
			}
			tmpwid = wid;
			while (tmpwid > 0 && siznum < newoff)
			{
				sps++;
				siznum++;
				tmpwid--;
			}
			return sps;
		}
		// for this (VlnXmlElement), get it's menu value template. This template is
		// used to generate the menu titles. Pass in a string 'GroupMenuItem' or
		// 'MenuItem' so that the group level or RRO level menu template is found.
		// This walkds up the tree to find the attribute ('GroupMenuItem' or 'MenuItem')
		// and returns it.
		public string GetMenuValueTemplate(string menuitm)
		{
			VlnXmlElement parent;
			string strmenuitm;
			VlnXmlElement tmp;
			if (menuitm == "GroupMenuItem")
			{		
				// if at top of tree, use this top GroupMenuItem. but if not,
				// the parent node defines the GroupMenuItem for the subgroups.
				if (this.ParentNode.Name == "RO_Root")
				{
					tmp = (VlnXmlElement) this.ParentNode;
					strmenuitm=tmp.GetAttribute(menuitm);
					return(strmenuitm);
				}
				else
					parent = (VlnXmlElement) this.ParentNode;
				while (parent != null) 
				{
					if (parent.HasAttribute(menuitm) == true) break;
					if (parent.Name != "RO_Root")
						parent = (VlnXmlElement) parent.ParentNode;
					else
						parent = null;
				}
				if (parent == null) return null;
				strmenuitm = parent.GetAttribute(menuitm);
				return strmenuitm;
			}
			// Now just do 'MenuItem', which is for ROs
			parent = (VlnXmlElement) this;
			strmenuitm = parent.GetAttribute(menuitm);
			while (parent != null && strmenuitm == "")
			{
				// walk up tree to get parent.
				strmenuitm = parent.GetAttribute(menuitm);
				parent = (VlnXmlElement) parent.ParentNode;
			}
			return strmenuitm;
		}
		// for this (VlnXmlElement), get the Return Value template.
		public string GetReturnValueTemplate()
		{
			VlnXmlElement parent;
			VlnXmlElement tmp=null;
			
			// get to top node of the ROs & groups to get the return for this tree.
			parent = (VlnXmlElement) this;
			tmp = parent;
			while((tmp.HasAttribute("RetVal") == false) && parent.Name != "RO_Root")
			{
				tmp = parent;
				parent = (VlnXmlElement) parent.ParentNode;
			}
			if (tmp.HasAttribute("RetVal") == false) return null;
			else return tmp.GetAttribute("RetVal");
		}
		/*
		 * return true if the field is a pre defined PROC.INI field name
		 */
		private bool IsProcIniDef(string fld)
		{
			bool rtnval = false;
			string tmpstr = fld.ToUpper();
			rtnval = (tmpstr.Equals("U") || 
						tmpstr.Equals("U-") ||
						tmpstr.Equals("P") || 
						tmpstr.Equals("P-") ||
						tmpstr.Equals("S") ||
						tmpstr.Equals("S-"));
			return rtnval;
		}
		/*
		 * This function checks the given field name with the list of fields
		 * that are "in use" for the current group.
		 * If the field name is of one of the pre-defined PROC.INI RO fields
		 * treat that field name as plain text (i.e. NOT in use)
		 */
		private bool IsAInUseField(ArrayList InUseList, string fld)
		{
			bool rtnval = false;
			int i;
			if (IsProcIniDef(fld)) // is this a pre-defined PROC.INI field?
				return rtnval; //return false!
			string tmpstr = fld.Substring(0,1);
			if (tmpstr.Equals("_"))
				tmpstr = fld.Substring(1,fld.Length-1);
			else
				tmpstr = fld;
			tmpstr = CvtFldToUserFld(fld);
			for(i=0; rtnval == false && i";
			}
			return applicValues;
		}
		public string GetReturnValue(RODB theDb, string TableName, string RtnValTemplate, ArrayList InUseList, ref ushort ValueType, string[] pcChildern)
		{
			string RtnValStr = "";
			VlnXmlElement elm = this;
			StringBuilder strbld = new StringBuilder();
			bool PCApplicability = (pcChildern != null && pcChildern.Length > 0);
			// Parse the template for the fields and generate a return string
			int left = RtnValTemplate.IndexOf("<"); // look for begining of field
			int right = -1;
			int stindx = 0;
			ushort FldType = 0;
			if (left > 0) strbld.Append(RtnValTemplate.Substring(0,left));
			while (left != -1)
			{
				// get right bracket and then check for valid field & if commas with
				// this, check for integer values.
				right = RtnValTemplate.IndexOf(">",stindx);
				string inusename;
				string substr = RtnValTemplate.Substring(left+1,right-left-1);
				inusename = CvtUserFldToFld(substr);
				// get contents of field & append it onto the string builder.
				XmlNode elmnode = (XmlNode) elm;
				XmlNode nd = elmnode.SelectSingleNode(inusename);
				// Check to see if the found field is a "Field In Use"
				if (IsAInUseField(InUseList,inusename))
				{
					string text="";
					if (nd == null)
					{
						text = GetComboFieldValueAndType(elmnode,inusename,ref FldType,false);
						if (text.Equals(""))
							text = " ";
					}
					else
					{
//						Profiler.Start("Grv7");
						FldType = theDb.RODB_GetFieldType((VlnXmlElement)nd,TableName,inusename);
//						Profiler.End("Grv7");
//						Profiler.Start("Grv8");
						// for an image, get the filename, height, width, otherwise just use
						// data in the node.
						if (FldType == 8) // for the '8' see RODBInterface - GetFSTreturntype
						{
							// get filename, length, width in that order, separated by newlines
							XmlNode tmp = nd.SelectSingleNode("Image_Filename");
							if (tmp != null && tmp.InnerText != null)
								text = tmp.InnerText + "\r\n";
							else
								text = " \r\n";
							tmp = nd.SelectSingleNode("Image_Height");
							if (tmp != null && tmp.InnerText != null)
								text = text + tmp.InnerText + "\r\n";
							else
								text = text + " \r\n";
							tmp = nd.SelectSingleNode("Image_Width");
							if (tmp != null && tmp.InnerText != null)
								text = text + tmp.InnerText + "\r\n";
							else
								text = text + " \r\n";
						}
						else
						{
							text = nd.InnerText;
						}
//						Profiler.End("Grv8");
					}
					ValueType |= FldType;
					if (PCApplicability)
						text = GetPCReturnValues(theDb, pcChildern, elm, PCApplicability, inusename, text); // C2021-026 Get P/C Children return values
					strbld.Append(text);
				}
				else
				{
					strbld.Append(RtnValTemplate.Substring(left,right-left+1));			
				}
				stindx = right+1;
				left = RtnValTemplate.IndexOf("<",left+1);
				if (left != -1 && left > right+1)  // append any plain text.
					strbld.Append(RtnValTemplate.Substring(right+1,left-right-1));			
			}
			right++; // move past the right bracket ('>')
			if (right < RtnValTemplate.Length)
				strbld.Append(RtnValTemplate.Substring(right,RtnValTemplate.Length-right));
// Bug fix: B2004-044
// If the ValueType is zero, then it will not appear on the list of ROs in the
// procedure editor.
			if (ValueType == 0)
				ValueType = 1;
			RtnValStr = strbld.ToString();
			return RtnValStr;
		}
		public string GetComboFieldValueAndType(XmlNode CurNode, string Fld, ref ushort FldTyp, bool ForMenu)
		{
			string RtnVal = "";
			XmlNode ChildNode = CurNode.FirstChild;
			FldTyp = 0;
			while (ChildNode != null && FldTyp == 0)
			{
				if (ChildNode is VlnXmlElement)
				{
					string ChildName = ChildNode.Name.ToString();
					if (ChildName.StartsWith(Fld))
					{
						char CmboChar = Convert.ToChar(ChildName.Substring(ChildName.Length-1,1));
						switch (CmboChar)
						{
							case 'a': // Fixed Text
							case 'b': // Multi Line Text
								FldTyp = 1;
								RtnVal = ChildNode.InnerText;
								break;
							case 'c': // Table
								FldTyp = 2;
								if (ForMenu)
									RtnVal = "(Table)";
								else
									RtnVal = ChildNode.InnerText;
								break;
							case 'd': // X/Y Plot
								FldTyp = 4;
								if (ForMenu)
									RtnVal = "(Graph)";
								else
									RtnVal = ChildNode.InnerText;
								break;
						}
					}
				}
					ChildNode = ChildNode.NextSibling;
			}
			return RtnVal;
		}
		// For this (VlnXmlElement), get the list of used fields. Need to find the
		// fields from the accessory page id template, the return value template 
		// and the menu title template or group title template (depends on if a
		// group edit or a RRO edit.
		public ArrayList GetRequiredFields()
		{
			ArrayList fldlist = new ArrayList();
			string accpagetmpl = GetAccPageIDTemplate();
			string retvaltmpl = null;
			string menutmpl = null;
			if (this.Name == "vlnGroup")
			{
				menutmpl = GetMenuValueTemplate("GroupMenuItem");
			}
			else
			{
				menutmpl = GetMenuValueTemplate("MenuItem");
				retvaltmpl = GetReturnValueTemplate();
			}
			// for each string, add its field names to the list.
			// accessory page id's only have a field and only used for ROs.
			if (this.Name != "vlnGroup" && accpagetmpl != null)
			{
				string fld = accpagetmpl.Substring(1,accpagetmpl.Length-2);
				fldlist.Add(fld+"\tAccessory Page Value");
			}
			// menutmpl's may have multiple fields. loop through them.
			int left, right, stindx, comma, rdelim;
			if (menutmpl != null)
			{
				left = menutmpl.IndexOf("<");
				right = 0;
				stindx = 0;
				comma = 0;
				while (left != -1)
				{
					// get right bracket and then check for valid field & if commas with
					// this, check for integer values.
					right = menutmpl.IndexOf(">",stindx);
					comma = menutmpl.IndexOf(",",stindx);
					rdelim = (comma>-1 && comma>left && comma',stindx);
					// first see if it is within it's own {}
					if (stindxbrace -1) 
					{
						rightbrace = retvaltmpl.IndexOf('}',stindxbrace);
						if ((left>leftbrace&&leftleftbrace&&right -1)
										xmldoc.writeImage(ind.InnerText.Substring(indx+1,ind.InnerText.Length-indx-1));
									else
										xmldoc.writeImage(ind.InnerText);
									// now do height & width??
									ind = this.SelectSingleNode("*/Image_Height");
									if (ind != null)
									{
										short iht = (short) System.Convert.ToInt16(ind.InnerText);
										xmldoc.writeInt(iht);
									}
									else
										xmldoc.writeInt(0);
									ind = this.SelectSingleNode("*/Image_Width");
									if (ind != null)
									{
										short iht = (short) System.Convert.ToInt16(ind.InnerText);
										xmldoc.writeInt(iht);
									}
									else
										xmldoc.writeInt(0);
								}
							}
							else
							{
								if (doingplot)
									xmldoc.writePlot(end.InnerText);
								else
								{
									xmldoc.writeTextValue(end.InnerText);
									defPCROval = end.InnerText;
								}
							}
						}
						// C2021_026 put out PC children values
						if (ContainedInArrayList(rof,InUseApplcList))
						{
							XmlNode pcn;
							int pcChildIdx = 0;
							foreach (string s in PCChildren)
							{
								pcChildIdx++;
								string pcName = nd.Name + string.Format("_PCCHILD{0}", pcChildIdx); // create child field name
								string pcField = rof.MakeFieldName(pcName);
								xmldoc.pushHeader("     "+s); // put out the PC Child name (indented 5 spaces) for complete RO Report
								// see if it has data in the ro.
								pcn = this.SelectSingleNode(pcField);
								if (pcn != null)
									xmldoc.writeTextValue(pcn.InnerText); // use  PC Child value
								else
									xmldoc.writeTextValue(defPCROval); // use default value
							}
						}
						xmldoc.popHeader();
					}
				}
				xmldoc.writeRROEnd();
			}
			return true;
		}
		// ShowGroup processes the input group node for the complete report by
		// using ShowGroupDetail to output data for the group and ShowRRO to
		// output data for the RO
		DateTime last = DateTime.Now;		// use these to control status message output
		private bool ShowGroup(RODB myrodb, ArrayList headers, VlnStatusMessage showStat)
		{
			XmlNode chldnode;
			
			if (this.ParentNode.Name != "RO_Root")
			{	
				/* Bug fix:  B2001-001
				 * Compete RO Report for All ROs was printing an extra
				 * page showing just a prameter field.  This information
				 * was not always related to the RO Group being printed at
				 * this time.  Turns out that we don't need to call the
				 * ShowGroupDetail() at this point, only need to save
				 * header informat.  -jsj 6/8/2005
				 *
				ShowGroupDetail(myrodb);
				*/
				headers.Add(this.GetAttribute("MenuTitle"));
			}
			else
			{
				int bracket = this.InnerXml.IndexOf("<",0);
				if (bracket>-1) 
					headers.Add(this.InnerXml.Substring(0,bracket));
				else
					headers.Add(this.InnerXml);
			}
			string haskids, kidsloaded;
			haskids = this.GetAttribute("HasChild");
			kidsloaded = this.GetAttribute("ChildLoaded");
			if (haskids == "True" && kidsloaded == "False" )
			{
				myrodb.RODB_GetChildData(this,true);
				this.SetAttribute("ChildLoaded", "True");
			}
			// go through all of the children for this node and put them out.
			chldnode = (XmlNode) this.FirstChild;
			
			while (chldnode != null)
			{
				if (chldnode is VlnXmlElement)
				{
					VlnXmlElement elem = (VlnXmlElement) chldnode;
					if (showStat != null)
						showStat.StatusMessage = elem.InnerText;
					// if it's a group, recurse through it.
					if (chldnode.Name == "vlnGroup")
						elem.ShowGroup(myrodb, headers, showStat);
						// do RO's too.
					else
					{
						int levelcnt = chldnode.ChildNodes.Count;
						bool isParDisData = chldnode.Name == "Parameter__Display__Data";
						string TheMenuTitle = elem.GetAttribute("MenuTitle");
						if (showStat != null)
						{
							if (TimeSpan.FromTicks(DateTime.Now.Ticks - last.Ticks).Seconds > 1)
							{
								showStat.StatusMessage = TheMenuTitle;
								last = DateTime.Now;
							}
						}
						if (!isParDisData && ((levelcnt > 1) || (levelcnt==1 && !TheMenuTitle.Equals(""))))
							elem.ShowRRO(myrodb, headers);
					}
				}
				chldnode = chldnode.NextSibling;
			}
			// remove this group from the headers.
			headers.RemoveAt(headers.Count-1);
			return true;
		}
		private static string[] PCChildren = null; //C2021-026 holds list of P/C children names
		public bool HasApplicabilityEnabled
		{
			get
			{
				return (PCChildren != null && PCChildren.Length > 0);
			}
		}
		// put this element, and if a group all it's subelements out to the 'print.tmp'
		// file for complete reports.
		public bool Show(RODB myrodb, ArrayList headers, VlnStatusMessage showStat, string [] pcChildren)
		{
			bool success;
			PCChildren = pcChildren;  // C2021-026 list of P/C children
			VlnXmlDocument xmldoc = (VlnXmlDocument) this.OwnerDocument;
			success = xmldoc.OpenTemp();
			if (success==false) return false;
			// if this is the top node, i.e. with name "RO_Root", it is a complete report 
			// for all Ros, work from the root.
			if (this.Name == "RO_Root")
			{
				// show each 'table' group under the top.
				VlnXmlElement group = (VlnXmlElement) this.FirstChild;
				VlnXmlElement tmpgroup;
				while (group != null)
				{	
					// Now get subgroups for each group.
					myrodb.RODB_GetChildData(group,true);
					group.ShowGroup(myrodb, headers, showStat);
					tmpgroup = group;
					group.RemoveAll();
					group = (VlnXmlElement) tmpgroup.NextSibling;
				}
							
			}
			// this is a particular RO or group of ROs.
			else
			{
				if (this.Name == "vlnGroup")
					ShowGroup(myrodb, headers, showStat);
				else
					ShowRRO(myrodb, headers);
			}
			xmldoc.CloseTemp();
			return true;
		}
	}
}