/*********************************************************************************************
 * Copyright 2004 - Volian Enterprises, Inc. All rights reserved.
 * Volian Enterprises - Proprietary Information - DO NOT COPY OR DISTRIBUTE
 * ------------------------------------------------------------------------------
 * $Workfile: ProcSet.cs $     $Revision: 45 $
 * $Author: Jsj $   $Date: 11/09/06 11:33a $
 *
 * $History: ProcSet.cs $
 * 
 * *****************  Version 45  *****************
 * User: Jsj          Date: 11/09/06   Time: 11:33a
 * Updated in $/LibSource/VEObject
 * skip empty library document files
 * 
 * *****************  Version 44  *****************
 * User: Jsj          Date: 10/06/06   Time: 11:21a
 * Updated in $/LibSource/VEObject
 * fixed logic in creating a new Enhanced Document set and in updating an
 * Enhanced Document SET file.
 * 
 * *****************  Version 43  *****************
 * User: Jsj          Date: 8/30/06    Time: 10:04a
 * Updated in $/LibSource/VEObject
 * Added Multi Procedure Data Checker
 * 
 * *****************  Version 42  *****************
 * User: Jsj          Date: 7/21/06    Time: 2:58p
 * Updated in $/LibSource/VEObject
 * fixed Unhandled Exception error
 * 
 * *****************  Version 41  *****************
 * User: Jsj          Date: 7/06/06    Time: 2:08p
 * Updated in $/LibSource/VEObject
 * Fixed enhanced document set creation bug.  The link files where being
 * put in the wrong place.
 * 
 * *****************  Version 40  *****************
 * User: Kathy        Date: 6/15/06    Time: 8:59a
 * Updated in $/LibSource/VEObject
 * B2006-024 fix: check for exclusive connection before approval & lock
 * during approval
 * 
 * *****************  Version 39  *****************
 * User: Kathy        Date: 5/01/06    Time: 11:18a
 * Updated in $/LibSource/VEObject
 * Fix B2006-018: single quote in proc number causes problem on data
 * request
 * 
 * *****************  Version 38  *****************
 * User: Jsj          Date: 9/20/05    Time: 2:48p
 * Updated in $/LibSource/VEObject
 * ContAct.INI logic for approve and master/slave, also Proc.INI logic for
 * approve
 * 
 * *****************  Version 37  *****************
 * User: Kathy        Date: 9/20/05    Time: 1:17p
 * Updated in $/LibSource/VEObject
 * Copy lib docs - initialize a variable
 * 
 * *****************  Version 36  *****************
 * User: Jsj          Date: 9/16/05    Time: 9:55a
 * Updated in $/LibSource/VEObject
 * Additional approval checks for RO Usage, RO directory existance, and
 * date of RO.FST file
 * 
 * *****************  Version 35  *****************
 * User: Kathy        Date: 9/06/05    Time: 11:25a
 * Updated in $/LibSource/VEObject
 * B2005-032 (use largest numDatabases for app ind write ro.fst)
 * 
 * *****************  Version 34  *****************
 * User: Kathy        Date: 8/31/05    Time: 11:33a
 * Updated in $/LibSource/VEObject
 * B2005-032: new groups crashed when writing to ro.fst during approve
 * sel.
 * 
 * *****************  Version 33  *****************
 * User: Kathy        Date: 8/16/05    Time: 2:56p
 * Updated in $/LibSource/VEObject
 * B2005-030: error if missing ndx
 * 
 * *****************  Version 32  *****************
 * User: Kathy        Date: 7/26/05    Time: 2:07p
 * Updated in $/LibSource/VEObject
 * Improve error message on updatesetdti if bad largestnumber data
 * 
 * *****************  Version 31  *****************
 * User: Jsj          Date: 7/15/05    Time: 4:06p
 * Updated in $/LibSource/VEObject
 * added check for empty RO usage
 * 
 * *****************  Version 30  *****************
 * User: Kathy        Date: 7/11/05    Time: 8:02a
 * Updated in $/LibSource/VEObject
 * Fix status message
 * 
 * *****************  Version 29  *****************
 * User: Kathy        Date: 7/07/05    Time: 1:49p
 * Updated in $/LibSource/VEObject
 * Fix Approve All Remove Change Bars from WD caption
 * 
 * *****************  Version 28  *****************
 * User: Kathy        Date: 6/21/05    Time: 7:26a
 * Updated in $/LibSource/VEObject
 * update ro from procedures & minor fixes
 * 
 * *****************  Version 27  *****************
 * User: Jsj          Date: 6/16/05    Time: 2:46p
 * Updated in $/LibSource/VEObject
 * Check for valid RO path before doing an approval
 * 
 * *****************  Version 26  *****************
 * User: Kathy        Date: 6/06/05    Time: 12:35p
 * Updated in $/LibSource/VEObject
 * Allow lock to be set, even if plant or system lock exists
 * 
 * *****************  Version 25  *****************
 * User: Jsj          Date: 6/02/05    Time: 11:35a
 * Updated in $/LibSource/VEObject
 * fix for approving with conditional ROs
 * 
 * *****************  Version 24  *****************
 * User: Kathy        Date: 5/31/05    Time: 12:42p
 * Updated in $/LibSource/VEObject
 * ? in vfw for ro values if approve selected before vfw
 * 
 * *****************  Version 23  *****************
 * User: Kathy        Date: 5/25/05    Time: 10:32a
 * Updated in $/LibSource/VEObject
 * Allow edits for tmpchg
 * 
 * *****************  Version 22  *****************
 * User: Kathy        Date: 5/20/05    Time: 10:23a
 * Updated in $/LibSource/VEObject
 * explicit close of ro.fst
 * 
 * *****************  Version 21  *****************
 * User: Jsj          Date: 5/20/05    Time: 9:22a
 * Updated in $/LibSource/VEObject
 * get the non-processed ro return value for saving in the RO.FST file
 * 
 * *****************  Version 20  *****************
 * User: Kathy        Date: 5/19/05    Time: 11:07a
 * Updated in $/LibSource/VEObject
 * missed updating oldto transition field on approve all
 * 
 * *****************  Version 19  *****************
 * User: Jsj          Date: 5/17/05    Time: 11:58a
 * Updated in $/LibSource/VEObject
 * Approve Graphic fix, cleanup
 * 
 * *****************  Version 18  *****************
 * User: Jsj          Date: 5/12/05    Time: 11:52a
 * Updated in $/LibSource/VEObject
 * fixed logic dealing with PROC.INI parent (master) identification and
 * the EOP.LNK parent identification
 * 
 * *****************  Version 17  *****************
 * User: Kathy        Date: 5/11/05    Time: 9:29a
 * Updated in $/LibSource/VEObject
 * bug fixes/mods for approval testing
 * 
 * *****************  Version 16  *****************
 * User: Jsj          Date: 5/06/05    Time: 12:08p
 * Updated in $/LibSource/VEObject
 * bug fix setting creating new enhanced document set (setting up)
 * 
 * *****************  Version 15  *****************
 * User: Kathy        Date: 4/21/05    Time: 10:23a
 * Updated in $/LibSource/VEObject
 * remove upgrade2005 define & cleanup
 * 
 * *****************  Version 14  *****************
 * User: Jsj          Date: 4/15/05    Time: 9:46a
 * Updated in $/LibSource/VEObject
 * Bug fix B2005-021, parent and erg selections (backgrounds, deviations,
 * slaves) was not sticking when changed.
 * 
 * *****************  Version 13  *****************
 * User: Kathy        Date: 4/12/05    Time: 1:04p
 * Updated in $/LibSource/VEObject
 * B2005-008: C2005-001: B2005-020.
 * 
 * *****************  Version 12  *****************
 * User: Jsj          Date: 3/31/05    Time: 9:17a
 * Updated in $/LibSource/VEObject
 * 
 * *****************  Version 11  *****************
 * User: Jsj          Date: 3/28/05    Time: 12:17p
 * Updated in $/LibSource/VEObject
 * 
 * *****************  Version 10  *****************
 * User: Kathy        Date: 3/22/05    Time: 10:09a
 * Updated in $/LibSource/VEObject
 * approve: remove chg bar/log file
 * 
 * *****************  Version 9  *****************
 * User: Jsj          Date: 3/14/05    Time: 1:37p
 * Updated in $/LibSource/VEObject
 * 
 * *****************  Version 8  *****************
 * User: Jsj          Date: 3/10/05    Time: 4:01p
 * Updated in $/LibSource/VEObject
 * hooks to use the new rofst file namespace
 * 
 * *****************  Version 7  *****************
 * User: Kathy        Date: 3/08/05    Time: 1:51p
 * Updated in $/LibSource/VEObject
 * Approval
 * 
 * *****************  Version 6  *****************
 * User: Kathy        Date: 1/31/05    Time: 11:06a
 * Updated in $/LibSource/VEObject
 * Fix B2005-005 (connection & delete directory errors). also, fix icon
 * 
 * *****************  Version 5  *****************
 * User: Kathy        Date: 1/24/05    Time: 2:45p
 * Updated in $/LibSource/VEObject
 * B2005-004 fixes
 * 
 * *****************  Version 4  *****************
 * User: Kathy        Date: 1/10/05    Time: 1:07p
 * Updated in $/LibSource/VEObject
 * B2004-062: Allow new sets name of PROCS & PROCS2, and other fixes
 * 
 * *****************  Version 3  *****************
 * User: Jsj          Date: 11/12/04   Time: 10:35a
 * Updated in $/LibSource/VEObject
 * Change Default Settings fix
 * 
 * *****************  Version 2  *****************
 * User: Kathy        Date: 10/25/04   Time: 10:25a
 * Updated in $/LibSource/VEObject
 * Fix B2004-049 and don't load link info if only checking for child data
 * 
 * *****************  Version 1  *****************
 * User: Kathy        Date: 7/27/04    Time: 8:53a
 * Created in $/LibSource/VEObject
 *********************************************************************************************/
using System;
using System.Collections;
using System.Text;
using System.IO;
using System.Windows.Forms;
using System.Data;
using System.ComponentModel;
using System.Diagnostics;
using Utils;
using GUI_Utils;
using VlnStatus;
using VDB_Proc;
using VENetwork;
using VDB;
using VDB_Set;
using VDB_SetExt;
using VDB_TransUsage;
using VDB_ROUsage;
using IniFileIO;
namespace VEObject
{
	/// 
	/// VEO_ProcSet support procedure set functionality.
	/// 
	public class VEO_ProcSet : VEO_Base
	{
		public bool isArchived;
		public bool isApproved;			// flags that this is an approved set
		public bool isSetApproved;		// flags set that has an approved subdirectory
		public bool isTempChange;		// flags that this is a temporary change set,
										//   i.e. tmpchg subdirectory in an approved dir
		public bool hasLibDocs;
		public bool setExists;
		public bool hasExtensions;		// has setextension (proccomment) option
		public bool cfg_load;			// flags whether cfg settings have been loaded yet
		public ProcTypeOptions _ProcType;
		public string parentLink;
		public string guideLink;
		public string ROPath;
		public string _curDirectory;
		public string _formatTitle;
		private PSProperties propdlg;
		public string ErrorOnPSName;
		protected string tmpTitle;
		protected string tmpLocation;
		protected bool changeLocation; 
		protected bool changeTitle;
		private string[] LinkFiles={"\\BCK.LNK","\\DVT.LNK","\\ERG.LNK"};
		private string PrevDirectory;
		public string SuffixFlags;
		public string ExtraRevNumber;
		public string origExtraRevNumber;  // check against for saving
		public bool hasExtraRevNumber;
		public long accessFlags;
		public bool blnCopiedProcINI;
		public string DateTimeInit;
		public bool HasRevision;	// flags that serial number includes approval revising function
		public bool UseLongProcTitles;
		// flag whether to remove change bars during approval (set on procset properties &
		// value saved in proc.ini). Default is true.
		public bool RmChgBarOnApp;
		public bool tmpRmChgBarOnApp;
		// the following should contain one of the procs to approve for approve selected, in case
		// of edit conflicts at the set or 'Procedures' level.
		public VEO_Proc AppSelForEdit;
		public VEO_ProcSet(UserRunTime iusrRunTime, string ititle, string ipath, long acFlags)
		{
			isTempChange=false;
			isApproved=false;
			accessFlags=acFlags;
			ErrorOnPSName=null;
			ExtraRevNumber=null;
			origExtraRevNumber=null;
			usrRunTime = iusrRunTime;
			cfg_load = false;
			hasExtensions = usrRunTime.SerialNumber.GetSNOption((uint)Utils.SerialNo.SN_Flags.SN_PROCCOMMENT_ON)>0;
			hasExtraRevNumber=false;
			SuffixFlags=null;
			blnCopiedProcINI = false;
			AppSelForEdit = null;
			if (ititle==null) 
			{
				_curDirectory = ipath;
				isNew=true;
				_Title = "New Procedure Set";
				_Location = "";
			}
			else
			{
				int indx1, indx2;
				if (((indx1=ipath.IndexOf("\\approved"))>-1) || ((indx2=ipath.IndexOf("\\APPROVED"))>-1))
					isApproved=true;
				
				isSetApproved=false;
				if(!isApproved)	// see if this set has associated approved version				
				{   
					string apname = ipath + "\\approved\\set.dbf";
					isSetApproved = File.Exists(apname);
				}			
				changeLocation=false;
				changeTitle=false;
				isNew=false;
				string tmpstr = ipath.ToLower();
				int indxd;
				int indxb;
				int indxs;
				indxd = tmpstr.IndexOf(".dvt");
				indxb = tmpstr.IndexOf(".bck");
				indxs = tmpstr.IndexOf(".sl");
				if (indxd > -1)
					_ProcType=ProcTypeOptions.Deviation;
				else if (indxb > -1) 
					_ProcType=ProcTypeOptions.Background;
				else if (indxs > -1)
					_ProcType=ProcTypeOptions.Slave;
				else 
					_ProcType = ProcTypeOptions.Standard;
				string tmploc=ipath;
			
				int lstslash = tmploc.LastIndexOf("\\");
				if (lstslash < 0) lstslash = 0;
				_curDirectory = tmploc.Substring(0,lstslash==0?tmploc.Length:lstslash);
				_Location = tmploc.Substring(lstslash+1,tmploc.Length-lstslash-1);
				_Title = ititle;
				VEObjectType = (int)VEObjectTypesDefs.ProcedureSet;
				isTempChange = (_Location.ToUpper().IndexOf("TMPCHG",0,_Location.Length)>-1);
				if (isTempChange) isApproved=false;
			}
			UseLongProcTitles=false;
			RmChgBarOnApp=true;
			FileInfo fi = new FileInfo(_curDirectory+"\\"+_Location+"\\PROC.INI");
			if (fi.Exists)
			{
				PrivateProfile ppCfg;
				ppCfg = new PrivateProfile(_curDirectory+"\\"+_Location+"\\PROC.INI");
				string pptmp=ppCfg.Attr("Set Options","UseLongProcTitles");
				if (pptmp.ToUpper() == "TRUE") UseLongProcTitles=true;
				pptmp = ppCfg.Attr("Set Options","RemoveChangeBarOnApproval");
				if (pptmp.ToUpper() == "FALSE") RmChgBarOnApp=false;		
			}
			tmpRmChgBarOnApp=RmChgBarOnApp;
			LoadLockInfo();
			if (isTempChange)
				iconStates = new int[5] {23,23,25,23,24};
			else if (isApproved) 
				iconStates = new int[5] {18,18,20,18,19};
			else
				iconStates = new int[5] {12,21,14,22,13};
			icon = iconStates[(int)Lock.LockStatus];
		}
		// Return true/false if the "masterdir" setting in the PROC.INI file
		// matches the current directory name.  Also set "mpath" to the
		// "masterdir" value
		public bool InMaster(ref string mpath)
		{
			PrivateProfile procINI;
			string iniMasterDir;
			procINI = new PrivateProfile(_curDirectory+"\\"+_Location+"\\PROC.INI");
			iniMasterDir=procINI.Attr("Applicability","masterdir");
			if (mpath != null)
				mpath = iniMasterDir;
			return (iniMasterDir.ToUpper()).Equals(_Location.ToUpper());
		}
		public string GetMasterFromProcINI()
		{
			string rtnstr="";
			InMaster(ref rtnstr);
			return rtnstr;
		}
		public override void LoadLockInfo()
		{
			Lock = new VELock(_curDirectory+"\\"+_Location, usrRunTime.myUserData, usrRunTime.InMultiUserMode?VENetwork.LockTypes.ProcSet:VENetwork.LockTypes.None);
		}
		[Description("Location"),Category("Procedure Set"),ReadOnly(true)]public string Location
		{
			get{return _Location;}
			set{_Location=value;}
		}
		[Description("Current Directory"),Category("Procedure Set"),ReadOnly(true)]public string CurDirectory
		{
			get{return _curDirectory;}
			set{_curDirectory=value;}
		}
		[Description("Title"),Category("Procedure Set"),EditorAttribute(typeof(VESymbDlg), typeof(System.Drawing.Design.UITypeEditor))]public string Title
		{
			get
			{
				if (!changeTitle)
					return _Title;
				else
					return tmpTitle;
			}
			set
			{
				changeTitle=true;
				tmpTitle=value;
			}
		}
		[Description("Format Title"),Category("Procedure Set"),ReadOnly(true)]public string FormatTitle
		{
			get{return _formatTitle;}
			set{_formatTitle=value;}
		}
		public override void Restore()
		{
			changeLocation=false;
			changeTitle=false;
			tmpRmChgBarOnApp=RmChgBarOnApp;
			if(hasExtraRevNumber)ExtraRevNumber=origExtraRevNumber;
		}
		public override bool Open()
		{
			if(_Location!=null)
			{
				isOpen = true;
				if (Directory.GetCurrentDirectory() == _curDirectory+"\\"+_Location)
					PrevDirectory = _curDirectory;
				else
					PrevDirectory = Directory.GetCurrentDirectory();
				Directory.SetCurrentDirectory(_curDirectory+"\\"+_Location);
			}
			return true;
		}
		// The close method resets, if necessary from any multi-user settings and
		// positions back to the parent directory (which is a level above the 
		// current level)
		public override bool Close()
		{
			if (!isOpen)return false;
			isOpen = false;
			if (Connection !=null)Connection.Exit();
			Directory.SetCurrentDirectory("..");
			return true;
		}
		public string GetFormatTitle()
		{
			if (isNew)
			{
				_formatTitle = "No format selected";
				return _formatTitle;
			}
			// get curset pathname, i.e. whether single or multi user.
			// for now, hardcode.
			CurSet cs = new CurSet(this._curDirectory+"\\"+this._Location+"\\curset.dat");
			cs.Read();
			FmtFile ff = new FmtFile(cs.DefaultPlantFmt+".fmt");
			_formatTitle = ff.GetFormatTitle(usrRunTime);
			return _formatTitle;
		}
		
		public string GetParentLink()
		{
			if((_ProcType==ProcTypeOptions.Deviation || _ProcType==ProcTypeOptions.Background)
				&& parentLink==null)
			{
				string tmpPath = _curDirectory + "\\" + _Location + "\\eop.lnk";
				string line;
				try 
				{
					StreamReader sr = new StreamReader(tmpPath);
					line = sr.ReadLine();
					sr.Close();
					parentLink=line;
				}
				catch (Exception) 
				{
					parentLink=null;
				}
			}
			else if (_ProcType==ProcTypeOptions.Slave)
			{
				parentLink = GetMasterFromProcINI();
				if (parentLink.Equals(""))
					parentLink = null;
			}
			if (parentLink != null)
			{
				if (parentLink[1] != ':')
				{
					// build full path
					string CurDirSave = Directory.GetCurrentDirectory();
					if (parentLink.StartsWith(".") ||
						parentLink.StartsWith("\\"))
						Directory.SetCurrentDirectory(_curDirectory + "\\" + _Location);
					else
						Directory.SetCurrentDirectory(_curDirectory);
					Directory.SetCurrentDirectory(parentLink);
					parentLink = Directory.GetCurrentDirectory();
					Directory.SetCurrentDirectory(CurDirSave);
				}
			}
			return parentLink;
		}
		public string GetGuideLink()
		{
			if(_ProcType==ProcTypeOptions.Deviation && guideLink==null)
			{
				string tmpPath = _curDirectory + "\\" + _Location + "\\erg.lnk";
				string line;
				try 
				{
					StreamReader sr = new StreamReader(tmpPath);
					line = sr.ReadLine();
					sr.Close();
					guideLink=line;
				}
				catch (Exception e) 
				{
					MessageBox.Show(e.Message,"Error Finding ERG Path");
					guideLink=null;
				}
			}
			return guideLink;
		}
		public bool CheckParentLink(string EOPSet, ProcTypeOptions linktype)
		{
			// Setup path to the linked EOP directory, if it's already set, don't allow change
			string tmpPath = EOPSet + LinkFiles[(linktype==ProcTypeOptions.Background?0:1)];
			FileInfo fi = new FileInfo(tmpPath);
			if (fi.Exists == true && !isNew) return (false);
			return (true);
		}
		public bool SetParentLink(string EOPSet, ProcTypeOptions linktype)
		{
			return SetParentLink(EOPSet,linktype,false);
		}
		public bool SetParentLink(string EOPSet, ProcTypeOptions linktype, bool SelectionChange)
		{
			string enhSet=_curDirectory + "\\" + _Location;
			// If Slave procedure set, then update the PROC.INI with the 
			// path to the master procedure set
			if (linktype == ProcTypeOptions.Slave)
			{
				INIFile prcini = new INIFile();
				prcini.WriteINIKeyValueStr("Applicability","masterdir",EOPSet,"proc.ini");
			}
			else
			{
				// Setup path to the linked EOP directory, if it's already set, don't allow change
				string tmpPath = EOPSet + LinkFiles[(linktype==ProcTypeOptions.Background?0:1)];
				FileInfo fi = new FileInfo(tmpPath);
				if (fi.Exists == true && !SelectionChange) return (false);
			
				tmpPath = enhSet + "\\EOP.LNK";
				DirectoryInfo di = new DirectoryInfo(enhSet);
				if (di.Exists == false) return false;
				// tmpPath = _Location + "\\eop.lnk";
				// currently in the directory
//				fi = new FileInfo("eop.lnk");
				fi = new FileInfo(tmpPath);
				if (fi.Exists)
					fi.Delete();
				try 
				{
//					StreamWriter sw = new StreamWriter("eop.lnk");
					StreamWriter sw = new StreamWriter(tmpPath);
					sw.WriteLine(EOPSet);
					sw.Close();
				}
				catch (Exception e) 
				{
					MessageBox.Show(e.Message,"Error Creating EOP.LNK");
					return false;
				}
				// Establish link file in EOP directory for use by "LinkTo"
//				string enhSet=_curDirectory + "\\" + _Location;
				tmpPath = EOPSet + LinkFiles[(linktype==ProcTypeOptions.Background?0:1)];
				try 
				{
					StreamWriter sw = new StreamWriter(tmpPath);
					sw.WriteLine(enhSet);
					sw.Close();
				}
				catch (Exception e) 
				{
					MessageBox.Show(e.Message,"Error Creating Background or Deviation LinkTO File");
					return false;
				}
			}
			return (true);   
		}
		public bool SetGuideLink(string ERGSet)   //,bool full)
		{
			string enhSet=_curDirectory + "\\" + _Location;
			if (ERGSet == null || ERGSet=="") return false;
			//string tmpPath = _Location + "\\erg.lnk";
			// Delete existing link file and write a new one.
//			FileInfo fi = new FileInfo("erg.lnk");
			string tmpPath = enhSet + "\\erg.lnk";
//			FileInfo fi = new FileInfo("erg.lnk");
			DirectoryInfo di = new DirectoryInfo(enhSet);
			if (di.Exists == false) return false;
			FileInfo fi = new FileInfo(tmpPath);
			if (fi.Exists)
				fi.Delete();
			try 
			{
//				StreamWriter sw = new StreamWriter("erg.lnk");
				StreamWriter sw = new StreamWriter(tmpPath);
				sw.WriteLine(ERGSet);
				sw.Close();
			}
			catch (Exception e) 
			{
				MessageBox.Show(e.Message,"Error Creating ERG.LNK File");
				return false;
			}
			return true;
		}
    
		public bool Exists(string dname)
		{
			if(dname==null||dname=="") return false;
			string pname=null;
			// see if this is a pathname, it needs to be for the Exists check.
			if (dname.IndexOf("\\") < 0)   // it's not a path, prepend the path
				pname = _curDirectory + "\\" + dname;
			else
				pname = dname;
			// loop through all subdirectories to see if this one exists.
			VEO_Plant plnt = (VEO_Plant) parentObj;
			int numsets = plnt.Children.Count;
			for (int i=0;i" argument
			if (!amILockedByMe())
			{
				string UserTempDir = usrRunTime.TempDirPath;
				if (UserTempDir != null)
					myProcess.StartInfo.Arguments = " -dir" + Directory.GetCurrentDirectory() + "\\" + UserTempDir;
			}
			
			myProcess.Start();
			myProcess.WaitForExit();
			// reset the format title.
			GetFormatTitle();
			return true;
		}
		public bool IsValid()
		{
			// name validity is checked in dialog.
			// check for none-empty data.
			if (_Location == null || _Location == "" || _Title == null || _Title == "")
			{
				MessageBox.Show("Need to fill in all data.", "General Error");
				return false;
			}
			// check for correct linkage if this is a background or deviation.
			if (this._ProcType == VEObject.ProcTypeOptions.Background ||
				this._ProcType == VEObject.ProcTypeOptions.Deviation)
			{
				// is the parent link already linked to a different document, if so.
				// can't do another.
				bool lnk = CheckParentLink(this.parentLink,this._ProcType);
				if (!lnk)
				{
					MessageBox.Show("This document has a link already","General Error");
					return false;
				}
			}
			return true;
		}
		public bool CheckForValidPSName(string newdname)
		{
			bool rtnval = true;
			ErrorOnPSName = null;
			// get the new name for the procset & check that it ends with
			// the correct extension & does not already exist.
			// be sure the name doesn't exist.
			string newpath = _curDirectory + "\\" + newdname;
			if (Directory.Exists(newpath) == true)
			{
				ErrorOnPSName = "Location name for this set already exists.";
				rtnval = false;
			}
			// if standard type & procs - it's a valid name
			if (rtnval && (this._ProcType==VEObject.ProcTypeOptions.Standard&&newdname.ToUpper() == "PROCS"))return true;
			if (rtnval && (this._ProcType==VEObject.ProcTypeOptions.Standard&&newdname.ToUpper() == "PROCS2")) return true;
	
			if (rtnval && newdname.IndexOf(".") <0)
			{
				ErrorOnPSName = "Location (directory) name must have an extension.";
				rtnval = false;
			}
			if (rtnval)
			{
				int idx = newdname.LastIndexOf('.');
				string ext = "";
				if (idx > 0)
				{
					ext = newdname.Substring(idx+1);
					ext = ext.ToUpper();
				}
				if (this._ProcType == VEObject.ProcTypeOptions.Standard)
				{
					if (!ext.Equals("PRC"))
					{
						ErrorOnPSName = "Standard procedure set location (directory) must end in .PRC";
						rtnval = false;
					}
				}
				else if (this._ProcType == VEObject.ProcTypeOptions.Background)
				{
					if (!ext.Equals("BCK"))
					{
						ErrorOnPSName = "Background procedure set location (directory) must end in .BCK";
						rtnval = false;
					}
				}
				else if (this._ProcType == VEObject.ProcTypeOptions.Deviation)
				{
					if (!ext.Equals("DVT"))
					{
						ErrorOnPSName = "Deviation procedure set location (directory) must end in .DVT";
						rtnval = false;
					}
				}
				else if (this._ProcType == VEObject.ProcTypeOptions.Slave)
				{
					if (ext.Length != 3 || !((ext.Substring(0,2)).Equals("SL")) || !System.Char.IsDigit(ext[2]))
					{
						ErrorOnPSName = "Slave procedure set location (directory) must end in .SL#\n\n Where # is a number from 1 to 9.";
						rtnval = false;
					}
				}
			}
			if (!rtnval)
			{
				MessageBox.Show(ErrorOnPSName,"Check Directory Name...");
			}
			return rtnval;
		}
		// write out the TITLE file.
		private void WriteTextLineToFile(string fname, string title)
		{
			StreamWriter myWriter = new StreamWriter(fname,false);  //overwrite if exist
			myWriter.Write(title);
			myWriter.Close();
		}
		private void WriteExtraRevNumber()
		{
			vdb_Set vdbSet=new vdb_Set(_curDirectory+"\\"+_Location+"\\set.dbf");
			DataRow rw = vdbSet.DB_Data.Tables[0].Rows[0];
			rw["TITLE"] = ExtraRevNumber;
			vdbSet.DB_Data = rw.Table.DataSet;
			vdbSet=null;
		}
		public override bool Write()
		{
			// only write out title.
			if (changeTitle) _Title=tmpTitle;
			changeTitle=false;
			if (RmChgBarOnApp!=tmpRmChgBarOnApp) // flags change.
			{
				RmChgBarOnApp = tmpRmChgBarOnApp;
				INIFile inifile =  new INIFile();
				if (RmChgBarOnApp)
					inifile.WriteINIKeyValueStr("Set Options","RemoveChangeBarOnApproval","TRUE",_curDirectory+"\\"+_Location+"\\PROC.INI");
				else
					inifile.WriteINIKeyValueStr("Set Options","RemoveChangeBarOnApproval","FALSE",_curDirectory+"\\"+_Location+"\\PROC.INI");
				inifile = null;
			}
			string pathTitle = _curDirectory + "\\" + _Location + "\\TITLE";
			WriteTextLineToFile(pathTitle,_Title);
			// check if hasExtraRevNumber, and if changed, write it to set file.
			if (this.hasExtraRevNumber&&(origExtraRevNumber!=ExtraRevNumber))
				WriteExtraRevNumber();
			return true;
		}
		static bool AddApplicabilityToMaster(string masterpath)
		{
			bool bUpdateSlavePROCINI = false;
			INIFile ProcINIfile = new INIFile();
			string MasterName, MasterProcFile;
			string rtnbuf = "";
			MasterName = masterpath.Substring(masterpath.LastIndexOf('\\')+1);
			MasterProcFile = masterpath + "\\PROC.INI";
			rtnbuf = ProcINIfile.GetINIKeyValueStr("Applicability","masterdir","",15,MasterProcFile);
			// If Applicability section not yet there, add it
			if (rtnbuf.Equals(""))
			{
				ProcINIfile.WriteINIKeyValueStr("Applicability","masterdir",MasterName,MasterProcFile);
			}
			rtnbuf = ProcINIfile.GetINIKeyValueStr("Unit","Number","",15,MasterProcFile);
			// If Unit section not yet there, add it
			if (rtnbuf.Equals(""))
			{
				ProcINIfile.WriteINIKeyValueStr("Unit","Number","1,2",MasterProcFile);
				ProcINIfile.WriteINIKeyValueStr("Unit","Name","Unit 1,Unit 2",MasterProcFile);
				ProcINIfile.WriteINIKeyValueStr("Unit","Other Number","2,1",MasterProcFile);
				ProcINIfile.WriteINIKeyValueStr("Unit","Other Name","Unit 2,Unit 1",MasterProcFile);
				bUpdateSlavePROCINI = true;
			}
			return bUpdateSlavePROCINI;
		}
		static void AddApplicabilityToSlave(string slavepath)
		{
			INIFile ProcINIfile = new INIFile();
			string SlaveProcFile;
			SlaveProcFile = slavepath + "\\PROC.INI";
			// Preset to Slave one
			ProcINIfile.WriteINIKeyValueStr("Unit","Number","1",SlaveProcFile);
			ProcINIfile.WriteINIKeyValueStr("Unit","Name","Unit 1",SlaveProcFile);
			ProcINIfile.WriteINIKeyValueStr("Unit","Other Number","2",SlaveProcFile);
			ProcINIfile.WriteINIKeyValueStr("Unit","Other Name","Unit 2",SlaveProcFile);
		}
		// Create a new procedure set.
		public override bool SaveNew(string dummy)
		{
			// Determine the type of set. Validity of links has already been
			// checked.
			VEObject.ProcTypeOptions type = this._ProcType;
				
			// make the directory
			string dname = _curDirectory + "\\" + Location;
			DirectoryInfo di = new DirectoryInfo(dname);
			if (di.Exists)
			{
				MessageBox.Show("Directory already exists, cannot create this set.","General Error");
				return false;
			}
			Cursor.Current = Cursors.WaitCursor;
			di.Create();
			string prevdir = Directory.GetCurrentDirectory();
			Directory.SetCurrentDirectory(dname);
			// do database files now
			vdb_Set newset = new vdb_Set(dname);
			// if a slave set, copy files from master set
			if (type == VEObject.ProcTypeOptions.Slave)
			{
				CopyFileFrom(parentLink,"set.dbf");
				// Add Applicability section to Master's PROC.INI file if that
				// information does not yet exist
				bool UpdateSlaveUnits = AddApplicabilityToMaster(parentLink);
				// Copy needed files from the master set
				// Note that if user manually entered data in the Advanced tab
				// (for PROC.INI information, that info will be used instead
				// of what is  being copied from the master procedure set
				CopyFileFrom(parentLink,"proc.ini");
				// If the master uses Automatic Continuous Action Summary sections
				// copy the CONTACT.INI file
				CopyFileFrom(parentLink,"ContAct.ini");
				blnCopiedProcINI = true;
				if (UpdateSlaveUnits)
					AddApplicabilityToSlave(this.CurDirectory + "\\" + this.Location);
				CopyFileFrom(parentLink,"curset.dat");
				CopyFileFrom(parentLink,"Tran.dbf");
				CopyFileFrom(parentLink,"Tranfrom.ndx");
				CopyFileFrom(parentLink,"Tranto.ndx");
				CopyFileFrom(parentLink,"Usagero.dbf");
				CopyFileFrom(parentLink,"Usagero.ndx");
				CopyFileFrom(parentLink,"Usagroid.ndx");
			}
				// Bug fix:  B2006-042
				// copy the SET.DBF file from the parent EOP set into the Enhanced
				// Document folder
			else if (type == VEObject.ProcTypeOptions.Deviation || type == VEObject.ProcTypeOptions.Background)
			{
				CopyFileFrom(parentLink,"set.dbf");
			}
			else
			{
				newset.CreateTable("set");
			}
			// do the SET Ext stuff
			if(hasExtensions)
			{
				vdb_SetExt newsetext = new vdb_SetExt(dname);
				newsetext.CreateTable("setext");
			}
	
			// title file
			WriteTextLineToFile("TITLE",Title);
			if (type != VEObject.ProcTypeOptions.Slave)
			{
				// trans & Ro usage files
				vdb_TransUsage newtranusage = new vdb_TransUsage(dname);
				newtranusage.CreateTable("TRAN");
				vdb_ROUsage newrousage = new vdb_ROUsage(dname);
				newrousage.CreateTable("USAGERO");
			}
	
			// if this set has an extra rev number, write it out in first record, TITLE field.
			if (this.hasExtraRevNumber&&(ExtraRevNumber!=null&&ExtraRevNumber!=""))WriteExtraRevNumber();
			if (type != VEObject.ProcTypeOptions.Slave)
			{
				// create the PROC.INI file.
				FileInfo fi = new FileInfo("PROC.INI");
				FileStream fs = fi.Create();
				fs.Close();
				// create the current settings file (which sets the format)
				CurSet curset = new CurSet("");    // create will set name.
				bool success=curset.Create(usrRunTime);
				if (success==false)
					MessageBox.Show("Could not create a current settings file.","General Error");
				else
					curset.Read();
				if (type == VEObject.ProcTypeOptions.Background) curset.DefaultPlantFmt = "EBCK";
				else if (type == VEObject.ProcTypeOptions.Deviation)curset.DefaultPlantFmt = "ESFDEV";
			
				success = ChgDefSettings();
			
				// Set up the links if this is a deviation or background.
				if (type != VEObject.ProcTypeOptions.Standard) success = SetParentLink(parentLink,type);
				success = SetGuideLink(guideLink);
			} // end not slave set
			// set up the RO directory path. If it's an enhanced document directory,
			// copy the RO.FST file from the parent (EOP.LNK), otherwise, get user 
			// profile info.
			if (type == VEObject.ProcTypeOptions.Standard)
			{
				if(getROPath()!=null)
				{
					updateROValues();
					setROPath(ROPath,dname);
				}
			}
			else	// slave or enhanced doc, copy RO.FST from parent.
				CopyFileFrom(parentLink,"ro.fst");
			// if the not Removing change bars (as set on the properties page) then
			// save this to the proc.ini file. Default is TRUE, so don't bother unless
			// it was set to FALSE.
			if (!RmChgBarOnApp)
			{
				INIFile inifile =  new INIFile();
				inifile.WriteINIKeyValueStr("Set Options","RemoveChangeBarOnApproval","FALSE",_curDirectory+"\\"+_Location+"\\PROC.INI");
				inifile=null;
			}
			tmpRmChgBarOnApp=RmChgBarOnApp;  // used for mods on propery page.
			// add the dummy nodes for zip files, procedures & lib docs.
			VEO_DummyZip zp = new VEO_DummyZip(usrRunTime, "Zip Files", dname);
			zp.parentObj=this;
			Children.Add(zp);
			zp.IsEmpty = true;
			zp.icon = zp.iconStates[(int)VEO_IconStates.Empty];
			VEO_DummySet prc = new VEO_DummySet(usrRunTime, "Procedures",dname);
			prc.parentObj=this;
			prc.vdbSet = newset;
			Children.Add(prc);
			prc.icon = prc.iconStates[(int)VEO_IconStates.Empty];
			prc.IsEmpty = true;
			VEO_DummyLibDoc ld = new VEO_DummyLibDoc(usrRunTime, "Library Documents",dname);
			ld.parentObj=this;
			Children.Add(ld);
			ld.icon = ld.iconStates[(int)VEO_IconStates.Empty];
			ld.IsEmpty = true;
			_Title=Title;
			_Location=Location;
			changeTitle=false;
			changeLocation=false;
			Cursor.Current = Cursors.Default;
			icon = iconStates[(int)VEO_IconStates.Normal];
			// set a security flag for this. Cases could be that there is no security in vesam,
			// that it has security in vesam, though it didn't exist for this user until now, 
			// or the user could be super user.
			accessFlags=0L;
			int plntsecindx = usrRunTime.sec.GetPlantSecurityIndex(_curDirectory);
			bool hasSec = usrRunTime.sec.ProcSetHasSecurity(plntsecindx, dname);
			if (hasSec) accessFlags = usrRunTime.sec.GetProcSecurity(dname);
			// reset directory after adding the new procedure set directory.
			if (prevdir != Directory.GetCurrentDirectory()) Directory.SetCurrentDirectory(prevdir);
			MessageBox.Show("The VE-PROMS Security Access Module (VESAM) may need to be used to set permissions to access the new procedure set.","VE-PROMS Security Note");
			return true;
		}
		private string getROPath()
		{
			return getROPath(true);
		}
		private string getROPath(bool domessage)
		{
			PrivateProfile ppCfg;
			string ropath;
			if (this.ROPath!=null) return ROPath;
			ppCfg = new PrivateProfile("PROC.INI");
			ropath=ppCfg.Attr("RO Defaults","ROPATH");
			if (ropath == null || ropath == "") ropath = "..\\RO";
			if (Directory.Exists(ropath))
			{
				ROPath = ropath;
				return ROPath;
			}
			// did not find a valid RO Path. Start with the current directory,
			// back up a level at a time to see if an RO Directory could be found.
			StringBuilder testPath = new StringBuilder();
			testPath.Append(_curDirectory);
			int slash = testPath.ToString().LastIndexOf("\\");
			while (slash > -1)
			{
				testPath.Remove(slash,testPath.Length-slash);
				testPath.Append("\\RO");
				if (Directory.Exists(testPath.ToString()))
				{
					ROPath=testPath.ToString();
					break;
				}
				testPath.Remove(slash,3);  // remove appended \RO
				slash = testPath.ToString().LastIndexOf("\\");
			}
			// if an RO directory not found, display an information message
			if(ROPath==null && domessage)MessageBox.Show("No Referenced Object Database could be found.","Referenced Objects Path Error");
			return ROPath;
		}
		private bool setROPath(string pth, string dstpth)
		{
			INIFile inifile = new INIFile();
			if (dstpth != null) // add destination path to PROC.INI file.
			{
				StringBuilder DestPath = new StringBuilder(132);
				DestPath.Append(dstpth);
				DestPath.Append("\\PROC.INI");
				inifile.WriteINIKeyValueStr("RO Defaults","ROPATH",pth,DestPath.ToString());
			}
			else
				inifile.WriteINIKeyValueStr("RO Defaults","ROPATH",pth,"PROC.INI");
			ROPath = pth;
			return true;
		}
		private void CopyFileFrom(string from, string filename)
		{
			string frmfile;
			if (from == null) return;
			// create path to ro.fst in from directory. 
			// current working directory is the enhanced doc directory
			frmfile = from + "\\" + filename;
			
			if (File.Exists(frmfile) == true)
				File.Copy(frmfile,filename,true);
		}
		public override bool updateROValues()
		{
			bool status = false;
			if (ROPath != null) // clear it to find correct path.
				ROPath = null;
			
			// check PROC.INI for ROPath.
			if (getROPath() != null)
			{
				string ROFstFile = ROPath + "\\Ro.fst";
				string ROFstFileLocal = "Ro.fst";
				if (File.Exists(ROFstFile) != true)
				{
					MessageBox.Show("Ro.fst does not exist. Create from the ROEditor.","RO.FST File Error");
					status = false;
				}
				else
				{
					// check to see if the fst file should be updated, i.e. the one
					// in the RO directory is more recent.
					FileInfo fstfile = new FileInfo(ROFstFile);
					FileInfo fstfilelocal = new FileInfo(ROFstFileLocal);
					bool cpy = true;
					if (fstfilelocal.Exists == false)
						cpy = true;
					else if (fstfilelocal.LastWriteTime >fstfile.LastWriteTime)
					{
						System.Windows.Forms.DialogResult rslt;
						rslt = MessageBox.Show("The Ro.fst in this procedure set is newer compared to the RO directory.\n\nCopy from the RO directory?","VE-PROMS",MessageBoxButtons.YesNo);
						if (rslt == DialogResult.No) cpy = false;
					}
					else if (fstfilelocal.LastWriteTime == fstfile.LastWriteTime)
					{
						MessageBox.Show("Referenced Object values are current.","VE-PROMS");
						cpy = false;
					}
					if (cpy == true)
					{
						File.Copy(ROFstFile,ROFstFileLocal,true);
						MessageBox.Show("Referenced Object values have been updated.","VE-PROMS");
					}
					if (File.Exists("ro.fst") == false)
					{
						MessageBox.Show("Referenced Object Values were not successfully updated.","VE-PROMS Error");
						status = false;
					}
					else
						status = true;
				}
			}
			return status;
		}
		/*
		** This function will from all of the backup files created from the
		** Clean Referenced Objects And Transition Usages function (VECLEAN)
		*/
		public void RestoreUsageAndProcFilesFromBadVECLEAN()
		{
			string[] FromStr = {"*.DBO","*.NDO","*.DTO"};
			string[] ToStr = {".DBF",".NDX",".DBT"};
			for (int i=0; i< 3; i++)
			{
				string[] dbfiles = Directory.GetFiles(FromStr[i]);
				foreach (string dbfile in dbfiles) 
				{
					string oldname = dbfile;
					int indx = dbfile.IndexOf(".");
					if (indx>-1)
					{
						string nname = dbfile.Substring(0,indx);
						string newname = nname + ToStr[i];
						File.Delete(newname);
						File.Move(oldname,newname);
					}
				}
			}
		}
		public void CheckForFailedCleanFunction()
		{
			// check for failed clean by looking for DBO and NDO files
			if( File.Exists("*.dbo") || File.Exists("*.ndo") || File.Exists("*.dto"))
			{
				MessageBox.Show("An error has occurred running the clean function.\nThe database files will be restored from the backup.",
					"VE-PROMS",MessageBoxButtons.OK);
				RestoreUsageAndProcFilesFromBadVECLEAN(); // retores from the DBO and NDO backup files
			}
		}
		public override void CleanTransitionsAndROsUsages(int clntype,string ProcName) 
		{
			bool wasOpen = isOpen;
			//change directory before doing the Clean function
			if(!isOpen)Open();
			StringBuilder buf = new StringBuilder();
			buf.Append("CLEAN -NOPASS");
			// if clntype is 2, then we are doing the Clean Selected (single) function
			if (clntype == 2)
			{
				buf.Append(" SELECT");
				// if a procedure number was passed in, append to clean command
				if (ProcName != null || ProcName != "")buf.Append(" \""+ProcName+"\"");
			}
			// create a process & wait until it exits.
			Process myProcess = new Process();
			myProcess.StartInfo.FileName = this.usrRunTime.ExeAdjust("@Wapprv.exe");
			myProcess.StartInfo.Arguments = buf.ToString();
			myProcess.Start();
			myProcess.WaitForExit();
			// check for failed clean by looking for DBO and NDO files
			CheckForFailedCleanFunction();
	  
			if(!wasOpen)Close();
		}
		public override void DataIntegrityCheck(string ProcName) 
		{
			bool wasOpen = isOpen;
			//change directory before doing the DataCheck function
			if(!isOpen)Open();
			StringBuilder buf = new StringBuilder();
			buf.Append("DATACHK -NOPASS");
			buf.Append(" SELECT");
			// if a procedure number was passed in, append to DataCheck command
			if (ProcName != null || ProcName != "")buf.Append(" \""+ProcName+"\"");
			// create a process & wait until it exits.
			Process myProcess = new Process();
			myProcess.StartInfo.FileName = this.usrRunTime.ExeAdjust("@Wapprv.exe");
			myProcess.StartInfo.Arguments = buf.ToString();
			myProcess.Start();
			myProcess.WaitForExit();
			if(!wasOpen)Close();
		}
		private bool SetupDateTimeStamp()
		{
			string newdate=null;
			string tempinit = DTI.Initials;
			if (tempinit == "super") DTI.Initials="     ";
			DTI.UpdateDateTimeInit(0);
			DTI.Initials=tempinit;
			bool goodfmt = false;
			while (!goodfmt)
			{
				frmReadWord rwdlg = new frmReadWord(DTI.MakeDate(DTI.DateTimeInit,false,false),"Enter Revision Date:");
				rwdlg.ShowDialog();
				if (rwdlg.DialogResult == DialogResult.OK) 
				{
					newdate = rwdlg.ReadWordText;
					goodfmt=
						Char.IsDigit(newdate[0]) &&
						Char.IsDigit(newdate[1]) &&
						((newdate[2]=='/') || (newdate[2]=='-')) &&
						Char.IsDigit(newdate[3]) &&
						Char.IsDigit(newdate[4]) &&
						((newdate[5]=='/') || (newdate[5]=='-')) &&
						Char.IsDigit(newdate[6]) &&
						Char.IsDigit(newdate[7]) &&
						Char.IsDigit(newdate[8]) &&
						Char.IsDigit(newdate[9]);
				}
				else
					return false;
			}
			// note that from above validity check, the year must be 4 chars...
			// reset datetimeinit to have the input date
			if (newdate!=null)
			{
				// use temp variable, can't write to index of DateTimeInit
				StringBuilder tmpdt = new StringBuilder(DTI.DateTimeInit);
				for (int i=0;i<4;i++) tmpdt[i]=newdate[i+6];
				for (int i=3;i<5;i++) tmpdt[i+3]=newdate[i];
				for (int i=0;i<2;i++) tmpdt[i+4]=newdate[i];
				DTI.DateTimeInit = tmpdt.ToString();
			}
			return true;
		}
		public void CopyAnyFileToApproved(string name, string ApproveName, string ApprovedPath)
		{
			if (!File.Exists(name)) return;
			
			string ApprovedFileName=null;
			int lindx = name.LastIndexOf("//");
			if(lindx<0)lindx=0;
			string justname = name.Substring(lindx<0?0:lindx,name.Length-lindx);
			string apname = (ApproveName==null)?justname:ApproveName;
			if (ApprovedPath==null)
				ApprovedFileName = GetApprovedDirectory("\\") + apname;
			else
				ApprovedFileName = ApprovedPath+"\\"+apname;
			File.Copy(name,ApprovedFileName,true);
		}
		public string GetApprovedDirectory(string ExtraData)
		{
			int indx;
			string curdir = System.Environment.CurrentDirectory;
			if ((indx = curdir.LastIndexOf("\\")) >= 0)
			{
				string tmp = curdir.Substring(indx,curdir.Length-indx);
				if (tmp.ToUpper().Equals("TMPCHG"))return (".."+ExtraData);
			}
			return("APPROVED"+ExtraData);
		}
		
		public void UpdateSetDTI(bool doAll, DataRow dr)  // do single - figure out what to pass in
		{
			if(doAll)
			{
				// Loop thru the procset and update the date/time/init info
				VEO_DummySet ds = (VEO_DummySet) Children[1];
				DataTable tbl = ds.vdbSet.DB_Data.Tables[0];
				bool isfirst = true;
				string dtstr = DTI.MakeDate(DTI.DateTimeInit,false,true).Substring(0,8);
				string tmstr = DTI.DateTimeInit.Substring(8,5);
				foreach (DataRow row in tbl.Rows)
				{
					if (isfirst)
						isfirst = false;
					else
					{
						row["DATE"]=dtstr;
						row["TIME"]=tmstr;
						row["INITIALS"]="     ";  // approve all clears the init field
					}
				}
				ds.vdbSet.DB_Data = tbl.DataSet;
			} 
			else
			{
				// only set it, it gets written by caller.
				dr["DATE"]=DTI.MakeDate(DTI.DateTimeInit,false,true).Substring(0,8);
				dr["TIME"]=DTI.DateTimeInit.Substring(8,5);
				dr["INITIALS"]=DTI.DateTimeInit.Substring(13,5);
			}
		}
		private void MakeApprovedProcs(VlnStatusMessage StatMsgWindow)
		{
			string aprdir = GetApprovedDirectory("");
			if (aprdir.Equals("APPROVED")&&(!Directory.Exists(aprdir))) Directory.CreateDirectory(aprdir);
			
			CopyAnyFileToApproved("set.dbf",null,null);
			if (usrRunTime.SerialNumber.GetSNOption((uint)Utils.SerialNo.SN_Flags.SN_PROCCOMMENT_ON)>0 && File.Exists("setext.dbf")) 
			{
				/*if (ApprovedPath==null || ApprovedPath =="")
				apprfilepath=GetApprovedDirectory("\\"),dbname,".DBF",NULL);
					else
				strcmb(apprfilepath,BuildPath(ApprovedPath,"\\"),dbname,".DBF",NULL);
				 * 
				 * for(j=0;j0)
			{
				rtfdir = GetApprovedDirectory("\\RTFFILES");
				if (!Directory.Exists(rtfdir)) Directory.CreateDirectory(rtfdir);
			}
			// for all procedures, copy all of the files over....
			VEO_DummySet ds = (VEO_DummySet) this.Children[1];
			if (ds.Children.Count==0) ds.Read(false);
			foreach (object oproc in ds.Children)
			{
				VEO_Proc proc = (VEO_Proc) oproc;
				if (File.Exists(_curDirectory+"\\"+_Location+"\\"+proc._Location+".dbf"))
				{
					StatMsgWindow.StatusMessage = "Approving " + proc._Prcnum;
					proc.Copy(_curDirectory+"\\"+_Location,aprdir,proc._Prcnum,proc._Location);
				}
			}
			DTI.SetDateTimeInit=DTI.DateTimeInit;
			StatMsgWindow.StatusMessage = "Copying support files";
// we don't use Password.Dat anymore - VESAM handles the password stuff.
//			CopyAnyFileToApproved("password.dat",null,null);
			if (File.Exists("datapage.fm1")) CopyAnyFileToApproved("datapage.fm1",null,null);
			if (File.Exists("curset.dat") && !File.Exists(GetApprovedDirectory("\\curset.dat")))
				CopyAnyFileToApproved("curset.dat",null,null);
			CopyAnyFileToApproved("proc.ini",null,null);
			CopyAnyFileToApproved("set.ini",null,null);
			VEO_DummyLibDoc lds = (VEO_DummyLibDoc) Children[2];
			if (lds.Children.Count>0)
			{
				StatMsgWindow.StatusMessage = "Copying library documents";
				lds.Approve(_curDirectory+"\\"+_Location,aprdir);
			}
			// If they are using Automatic Continuous Action Summary Sections
			// copy the the ini file over to the approved as well.
			if (File.Exists("ContAct.INI"))
				CopyAnyFileToApproved("ContAct.INI",null,null);
		}
		private void MoveOutsideTransitions(VlnStatusMessage StatMsgWindow)
		{
			StatMsgWindow.StatusMessage = "Saving Approved Outside Transition Data";
			// old code did a pack, but these files don't have database support, just copy
			// them over.
			CopyAnyFileToApproved("xtsetid.dbf",null,null);
			CopyAnyFileToApproved("xtsetid.ndx",null,null);
			CopyAnyFileToApproved("xtprocid.dbf",null,null);
			CopyAnyFileToApproved("xtpidset.ndx",null,null);
			CopyAnyFileToApproved("xtpidsnp.ndx",null,null);
		}
		private void MoveTransitions(VlnStatusMessage StatMsgWindow)
		{
			StatMsgWindow.StatusMessage = "Approving transition usage files";
			vdb_TransUsage transusg = new vdb_TransUsage(_curDirectory+"\\"+_Location+"\\tran.dbf");
			transusg.Pack();
			transusg = null;		// close the transusage connection
			CopyAnyFileToApproved("tran.dbf",null,null);
			CopyAnyFileToApproved("tranfrom.ndx",null,null);
			CopyAnyFileToApproved("tranto.ndx",null,null);
			// Now cleanup the 'OLDTO' fields, i.e. make them = TranTo field, i.e.
			// working draft 'TONUMBER'+'TOSEQUENCE' fields. The first query if for non-libdocs.
			// The second does libdocs.
			transusg = new vdb_TransUsage(_curDirectory+"\\"+_Location+"\\tran.dbf");
			StringBuilder qry = new StringBuilder();
			qry.Append("UPDATE TRAN SET TRAN.OLDTO = [TONUMBER] & Space(20-Len([TONUMBER])) & [TOSEQUENCE] & Space(12-Len([TOSEQUENCE])) ");
			qry.Append("WHERE tran.TOSEQUENCE IS NOT NULL");
			bool success  = transusg.UpdateUsing(qry.ToString());
			if (!success) MessageBox.Show("Error When Updating Old Transition To fields","Approve All");
			qry.Length=0;
			qry.Append("UPDATE TRAN SET TRAN.OLDTO = [TONUMBER] & Space(20-Len([TONUMBER])) ");
			qry.Append("WHERE tran.TOSEQUENCE IS NULL");
			success  = transusg.UpdateUsing(qry.ToString());
			if (!success) MessageBox.Show("Error When Updating Old Transition To fields for library documents","Approve All");
			transusg=null;
		}
		private void MoveROs(VlnStatusMessage StatMsgWindow)
		{
			StatMsgWindow.StatusMessage = "Approving referenced object usage files";
			vdb_ROUsage rousg = new vdb_ROUsage(_curDirectory+"\\"+_Location+"\\usagero.dbf");
			rousg.Pack();
			rousg = null;
			this.CopyAnyFileToApproved("usagero.dbf",null,null);
			this.CopyAnyFileToApproved("usagero.ndx",null,null);
			this.CopyAnyFileToApproved("usagroid.ndx",null,null);
			this.CopyAnyFileToApproved("ro.fst",null,null);
		}
		public void MoveUserFormats(VlnStatusMessage StatMsgWindow)
		{	
			CurSet cs = new CurSet(_curDirectory+"\\"+_Location+"\\curset.dat");
			cs.Read();
			FmtFile ff = new FmtFile(cs.DefaultPlantFmt+".fmt");
			string [] sfis = Directory.GetFiles(".\\",cs.DefaultPlantFmt+".*");
			if (sfis.Length>0)StatMsgWindow.StatusMessage = "Approving user format files";
			foreach (string sfi in sfis)
			{
				FileInfo fi = new FileInfo(sfi);
				fi.CopyTo(this.GetApprovedDirectory("\\"+fi.Name),true);
			}
		}
		private void UpdateGraphicFiles(VlnStatusMessage StatMsgWindow)
		{
			StatMsgWindow.StatusMessage = "Approving graphic files from RO directory";
//			ROFST ro = new ROFST(Directory.GetCurrentDirectory() + "\\ro.fst", usrRunTime);
			ROFST ro = new ROFST(Directory.GetCurrentDirectory() + "\\ro.fst");
			ro.CopyImagesToApproved(this.GetApprovedDirectory(null),StatMsgWindow);
			ro.Close();
		}
		private void CopyTempChgFiles(string from, string to, string fpattern)
		{
			DirectoryInfo difrom = new DirectoryInfo(from);
			DirectoryInfo dito = new DirectoryInfo(to);
			if (!dito.Exists) dito.Create();
			FileInfo[] fis = difrom.GetFiles(fpattern);
			foreach (FileInfo fi in fis)
			{
				if (fi.Extension.ToUpper()!="PIX"&&fi.Name.ToUpper()!="B4APRVAL.ZIP")
				{
					fi.CopyTo(to+"\\"+fi.Name,true);
					// if this is title file, then the version text should state
					// 'Temporary Change Version' (either append or change the
					// 'Current Approved Version').
					if (fi.Name.ToUpper()=="TITLE")
					{
						StreamReader myReader = new StreamReader(to+"\\"+fi.Name);
						string chgtitle = myReader.ReadLine();
						myReader.Close();
						int indx = chgtitle.IndexOf(" - Current Approved Version");
						if (indx>-1)
							WriteTextLineToFile(to+"\\"+fi.Name,chgtitle.Substring(0,indx) + " - Temporary Change Version");
						else
							WriteTextLineToFile(to+"\\"+fi.Name,chgtitle + " - Temporary Change Version");	
					}
					FileInfo fi_tmpchg = new FileInfo(to+"\\"+fi.Name);
					fi_tmpchg.LastWriteTime = fi.LastWriteTime;
				}
			}
		}
		private void CopyTempChg(VlnStatusMessage StatMsgWindow)
		{
			if (usrRunTime.SerialNumber.GetSNOption((uint)Utils.SerialNo.SN_Flags.SN_TEMPCHANGE_ON)>0)
			{
				StatMsgWindow.StatusMessage = "Updating the Temporary change directory ...";
				
				CopyTempChgFiles("approved","approved\\tmpchg","*.*");
				if (Directory.Exists("rtffiles"))
					CopyTempChgFiles("approved\\rtffiles","approved\\tmpchg\\rtffiles","*.*");
			}
		}
		private void UpdateProcedureSetTitleFile(string ApprvPath)
		{
			if (File.Exists("Title"))
			{
				string appath = null;
				if (ApprvPath == null || ApprvPath=="")
					appath = GetApprovedDirectory("\\Title");
				else
					appath = ApprvPath+"\\Title";
				File.Copy("Title",appath,true);
				// Tack on Current Approved Version to the title in the approved directory
				StreamReader myReader = new StreamReader(appath);
				string chgtitle = myReader.ReadLine();
				myReader.Close();
				WriteTextLineToFile(appath,chgtitle + " - Current Approved Version");	
			}
		}
		private void ZipThis(string path, string ZipName)
		{
			CDZipNET dz = new CDZipNET();
			dz.ZIPFile = path + "\\" + ZipName + ".zip";
			StringBuilder sb = new StringBuilder();
			// Zip up the RTFFILES directory if it exists
			string RTFFilesPath = path + "\\RTFFILES";
			if (Directory.Exists(RTFFilesPath))
			{
				sb.Append(path);
				sb.Append("\\*.* ");
				sb.Append(path);
				sb.Append("\\RTFFILES\\*.*");
			}
			else 
			{
				sb.Append(path);
				sb.Append("\\*.*");
			}
			dz.RecurseFlag = false;
			dz.ItemList = sb.ToString();
			dz.CompressionFactor = 9; // maxium compression
			dz.ExcludeFollowingFlag = true;
			dz.ExcludeFollowing = "*.lck process.dat";
			dz.ActionDZ = CDZipNET.DZACTION.ZIP_ADD;	
		}
		// this can be used to archiving of clean or approval. Approval zips approval
		// and tmpchg directories if they exist.
		private void Archive(string ZipName, bool approving)
		{
			// get the path to the working draft directory
			string cwd = Directory.GetCurrentDirectory();
			
			VlnStatusMessage StatMsgWindow = new VlnStatusMessage("File Archival");
			
			// zip the working draft directory
			StatMsgWindow.StatusMessage = "Zipping " + cwd;
			ZipThis(cwd, ZipName); 
			if (approving && Directory.Exists("Approved"))
			{
				string CurApPath = cwd + "\\APPROVED";
				// Zip the Approved directory
				StatMsgWindow.StatusMessage = "Zipping " + CurApPath;
				ZipThis(CurApPath, ZipName);
				
				// Zip the Temporary Change directory
				if (Directory.Exists("Approved\\TMPCHG"))
				{
					string TchgPath = CurApPath+"\\TMPCHG";
					StatMsgWindow.StatusMessage = "Zipping " + TchgPath;					
					ZipThis(TchgPath, ZipName);
				}
			}
			StatMsgWindow.Dispose();
		}
		private bool NewOrModifiedGraphicFile(string Afname,string Wfname, string defExt)
		{
			bool rtnval = false;
			StringBuilder Agr_pathname = new StringBuilder(Afname.Length+5);
			StringBuilder Wgr_pathname = new StringBuilder(Wfname.Length+5);
			Agr_pathname.Append(Afname);
			Wgr_pathname.Append(Wfname);
			// if the file has an extension, just use it, otherwise use
			// the passed in default extension.  Note that the default
			// extension is automatically set up when the RO.FST file
			// is read into the ROFST class
			if ((Afname.Length<4) || Afname[Afname.Length-4] != '.')
			{
				if (defExt[0] != '.') Agr_pathname.Append(".");
				Agr_pathname.Append(defExt);
			}
			if ((Wfname.Length<4) || Wfname[Wfname.Length-4] != '.')
			{
				if (defExt[0] != '.') Wgr_pathname.Append(".");
				Wgr_pathname.Append(defExt);
			}
			string AgrName = Agr_pathname.ToString();
			string WgrName = Wgr_pathname.ToString();
			rtnval = (!File.Exists(AgrName));
			if (!rtnval)
			{
				// The graphic file exists in Approved directory.
				// See if the RO directory has a newer graphics file.
				rtnval = (File.GetLastWriteTime(WgrName) > File.GetLastWriteTime(AgrName));
			}
			return rtnval;
		}
//		private bool GraphicsFileNotInApproved(string fname, string defExt)
//		{
//			StringBuilder gr_pathname = new StringBuilder(fname.Length + 5);
//			gr_pathname.Append(fname);
////			// if the file has an extension, just use it, otherwise get default
////			// extension. This is in veproms.ini or default to .tif.
////			int indx = fname.LastIndexOf(".");
////			if (indx<0)
//
//			// if the file has an extension, just use it, otherwise use
//			// the passed in default extension.  Note that the default
//			// extension is automatically set up when the RO.FST file
//			// is read into the ROFST class
//			if ((fname.Length<4) || fname[fname.Length-4] != '.')
//			{
////				PrivateProfile pINI;
////				string fExt;
////				pINI = new PrivateProfile(usrRunTime.ExeAdjust("~veproms.ini"));
////				fExt=pINI.Attr("Graphics","defaultext");
////				if (fExt == null||fExt=="") fExt=".TIF";
////				pINI=null;
////				if (fExt.Substring(0,1)!=".") gr_pathname.Append(".");
////				gr_pathname.Append(fExt);
//				if (defExt[0] != '.') gr_pathname.Append(".");
//				gr_pathname.Append(defExt);
//			}
//			return (!File.Exists(gr_pathname.ToString()));
//		}
//
		// Verify we have a valid RO directory path
		private bool CheckROPathForApprove()
		{
			bool rtnval = true;
			StringBuilder sbWarning = new StringBuilder();
			// If Referenced Objects are being used, 
			// then see if the RO directory exists B2005-038
			vdb_ROUsage rousg=null;
			DataSet ROUsageDataSet=null;
			// Open the RO Usage file in the working draft and see if there
			// are any records in it.
			try 
			{
				rousg = new vdb_ROUsage(_curDirectory+"\\"+_Location+"\\usagero.dbf");
				ROUsageDataSet = rousg.GetSortedByROID("");	
			}
			catch (Exception e)
			{
				MessageBox.Show("Could not read RO Usages, cannot approve. " + e.Message,"Approval Error");
				rousg=null;
				ROUsageDataSet=null;
				return false; // don't allow approval
			}
			DataTable roTbl = ROUsageDataSet.Tables[0];
			rtnval = (roTbl.Rows.Count > 0);
			rousg=null;
			ROUsageDataSet=null;
			if (!rtnval)
				return true; // ROs are not used, no need to check for RO directory
			// At this point we know that we use RO's so now check to see if
			// the RO directory exists
			return CheckROpathAndFST();
		}
		// This function is called after we verify that Referenced Objects are being
		// used in the working draft (there are records in the ROUSAGE.DBF file)
		private bool CheckROpathAndFST()
		{
			bool rtnval = true;
			bool wdROfstExists;
			bool doWarning;
			StringBuilder sbMsg = new StringBuilder();
			string rpath = this.getROPath(false);
			if (rpath == null || rpath == "")
			{
				// Cannot find an RO Directory
				sbMsg.Append("Cannot find the Referenced Objects folder:  ");
				sbMsg.Append(rpath);
				sbMsg.Append("\n\nReferenced Object usages cannot be validated without access to the RO database folder.");
				sbMsg.Append("\n\n * Verify the RO Path in the PROC.INI file.");
				sbMsg.Append("\n\n * Verify the RO folder does exist.");
				MessageBox.Show(sbMsg.ToString(),"Check Referenced Objects Settings");
				return false; // cancel approval
			}
			// Check to see if RO.FST file exists in working draft
			wdROfstExists = File.Exists(_curDirectory+"\\"+_Location+"\\ro.fst");
			// Check to see if the RO.FST file in the working draft is older or newer 
			// than the one in the RO directory
			if (wdROfstExists)
			{
				DateTime WdDateTime =  File.GetLastWriteTime(_curDirectory+"\\"+_Location+"\\ro.fst");
				DateTime RoDateTime = File.GetLastWriteTime(rpath + "\\ro.fst");
				switch (DateTime.Compare(WdDateTime,RoDateTime))
				{
					case 1:
						doWarning = true;
						sbMsg.Append("The Working Draft RO.FST file is Newer than the one last generated");
						sbMsg.Append("\nfrom the RO database.");
						break;
					case -1:
						doWarning = true;
						sbMsg.Append("The Working Draft RO.FST file is Older than the one last generated");
						sbMsg.Append("\nfrom the RO database.");
						break;
					default:
						doWarning = false;
						break;
				}
				if (doWarning)
				{
					sbMsg.Append("\n\nPlease verify that \"");
					sbMsg.Append(rpath);
					sbMsg.Append("\" is the correct RO database folder and");
					sbMsg.Append("\ncheck to see if the RO.FST needs updated in the Working Draft.");
					sbMsg.Append("\n\n\n\nDo You Want To Continue With The Approval Anyway?");
					DialogResult yn = MessageBox.Show(sbMsg.ToString(),"Check Referenced Objects Settings",MessageBoxButtons.YesNo);
					rtnval = yn.Equals(DialogResult.Yes);
					return rtnval;
				}
			}
			if (!wdROfstExists)
			{
				//if the working draft does not have a RO.FST file, don't allow approve
				sbMsg.Append("The working draft does not have an RO.FST file.");
				sbMsg.Append("\n\nReferenced Object usages cannot be validated.");
				sbMsg.Append("\n\n * Verify the RO Path in the PROC.INI file.");
				sbMsg.Append("\n\n * Run the Update Referenced Objects tool");
				MessageBox.Show(sbMsg.ToString(),"Check Referenced Objects Settings");
				return false; // cancel approval
			}
			return true; // fell through the checks, assume it's O.K. to continue
		}
		// FindModifiedROs determines which ROs, if any, are different between the working
		// draft & the approved version of the ro.fst files. It only looks at those ROs
		// that are used in the working draft version of the document, i.e. it compares
		// the ro.fst data for those ROs listed in the usage file.
		private bool FindModifiedROs(ArrayList ModROs, VlnStatusMessage StatMsgWindow)
		{			
			vdb_ROUsage rousg=null;
			DataSet ROUsageDataSet=null;
			//Loop through all of the usages. 
			try 
			{
				rousg = new vdb_ROUsage(_curDirectory+"\\"+_Location+"\\usagero.dbf");
				ROUsageDataSet = rousg.GetSortedByROID("");	
			}
			catch (Exception e)
			{
				MessageBox.Show("Could not read RO Usages, cannot approve. " + e.Message,"Approval Error");
				rousg=null;
				ROUsageDataSet=null;
				return false;
			}
			DataTable roTbl = ROUsageDataSet.Tables[0];
			if (roTbl.Rows.Count == 0)
				return true; // no data
//			if (roTbl.Rows.Count>0) StatMsgWindow.StatusMessage = "Finding Modified Referenced Objects";
			
			// See if the RO.FST file exists in the working draft.  At this point
			// we have established that ROs are being used and there should be a
			// RO.FST file in the working draft.  Also see if the RO folder exists.
			// It's needed to check changes to graphic files.
			// B2005-038
			if (!CheckROpathAndFST()) return false;
			// Open the RO.FST files so that we can compare ro values
			
			ROFST WD_ROfst = new ROFST(_curDirectory+"\\"+_Location+"\\ro.fst");
			ROFST App_ROfst = new ROFST(_curDirectory+"\\"+_Location+"\\approved\\ro.fst");
			string lastROID = null;
			VlnStatusBar FndModROsStatWindow =  new VlnStatusBar("Processing ROs");
			FndModROsStatWindow.BarMax = roTbl.Rows.Count;
			FndModROsStatWindow.BarStepValue = 1;
			FndModROsStatWindow.BarValue = 0;
			FndModROsStatWindow.StatMsg = "Finding Modified Referenced Objects";
			foreach (DataRow row in roTbl.Rows)
			{
				FndModROsStatWindow.PerformStep();
				string thisROID = row["ROID"].ToString();
				// we want to always have "0000" at the end of the ROID
				// so that we get all possible return options for
				// conditional RO's
				thisROID = thisROID.Substring(0,12)+"0000";
				//				byte ff = 0xff;
				//				string instance = row["INSTANCE"].ToString();
				//				if(System.Char.IsWhiteSpace(instance[0]))
				if(thisROID==null || thisROID=="" || System.Char.IsWhiteSpace(thisROID[0]))
				{
					continue;
				}
				if (thisROID != lastROID)
				{
					lastROID = thisROID;
					string usagePnum = row["NUMBER"].ToString();
					string wd_val = WD_ROfst.GetRO(thisROID,usagePnum);
					string a_val = App_ROfst.GetRO(thisROID,usagePnum);
					ROFST.ROTypes rotype = WD_ROfst.GetROType(thisROID);
					if (rotype == ROFST.ROTypes.Figure)  // image
					{
						int nline = wd_val.IndexOf("\n");
						if (nline>0)
						{
							string gr_fname = this._curDirectory + "\\" + this._Location + "\\" + GetApprovedDirectory("\\") + wd_val.Substring(0,nline);
							string wd_fname = this.getROPath() + "\\" + wd_val.Substring(0,nline);
							if (wd_val!=a_val || NewOrModifiedGraphicFile(gr_fname,wd_fname,WD_ROfst.DefaultGraphicFileExt))
								//							if (wd_val!=a_val  || GraphicsFileNotInApproved(gr_fname,WD_ROfst.DefaultGraphicFileExt))
							{
								ModRO mro = new ModRO(thisROID,true,gr_fname,null);
								ModROs.Add(mro);
							}
						}
					}
					else
					{
						if (wd_val != a_val)
						{
							ModRO mro = null;
							if (rotype == ROFST.ROTypes.Table)
								mro = new ModRO(thisROID, false, "TABLE", "TABLE");
							else
								mro = new ModRO(thisROID, false, wd_val, a_val);
							ModROs.Add(mro);
						}
					}
				}
			}
			FndModROsStatWindow.Dispose();
			rousg=null;
			ROUsageDataSet=null;
			WD_ROfst.Close();
			App_ROfst.Close();
			return true;		
		}
		// determine if the input library document has any Modified Ro references
		private bool RoRef(string libname, ArrayList ModROs, ArrayList al)
		{
			int roref=0;
			int i = libname.IndexOf(".");
			string fname;
			if (i>0)
				fname = libname.Substring(0,i);
			else
				fname = libname;
			
			if ((roref=Usages.CheckRoReferences(this, _curDirectory+"\\"+_Location, al, ModROs, fname))<=0)
			{
				return false;
			}
			return true;
		}
		// Determine, based on date/time stamp, whether the Library Document
		// file was modified between the working draft & approved.
		private void LookForModifiedLibraryDoc(ArrayList ModLibDocs, ArrayList ModROs, ArrayList al, string libname)
		{
			// Use status codes for later file copying of library documents.
			// Stat 0 - No Change
			// Stat 1 - Copy working draft file to approved
			// Stat 2 - Copy RTFFILES file to approved
			// Stat 3 - Copy working draft file to approved and  RTF
			int stat=0;
			DateTime wd=DateTime.Now;   // default to now, but reset if file exists.
			DateTime wd_rtfdir=DateTime.Now;
			DateTime ap=DateTime.Now;
			DateTime ap_rtfdir=DateTime.Now;
			if (File.Exists(libname))wd = File.GetLastWriteTime(libname);
			if (File.Exists("RTFFILES\\"+libname))wd_rtfdir = File.GetLastWriteTime("RTFFILES\\"+libname);
			string apdir = GetApprovedDirectory("");
			if (File.Exists(apdir+"\\"+libname))ap = File.GetLastWriteTime(apdir+"\\"+libname);
			if (File.Exists(apdir+"\\RTFFILES\\"+libname))ap_rtfdir = File.GetLastWriteTime(apdir+"\\RTFFILES\\"+libname);
			// now see if there are any referenced objects in this library document
			// that have a modified RO - if so, copy those too.
			bool roStat = RoRef(libname, ModROs, al);
			// if approved directory has RTFFILES subdirectory with this libdoc...
			if (File.Exists(apdir+"\\RTFFILES\\"+libname))
			{
				// if working draft has RTFFiles subdirectory with this libdoc
				if (File.Exists("RTFFILES\\"+libname))
				{
					// if working draft is newer or contains a modified RO
					if (roStat || (wd_rtfdir>ap_rtfdir)) 
						stat=2;			
				}
				else // if working draft does NOT have libdoc file
					stat = 3;	
			} 
				// the approved directory does not have RTFFILES directory, but has the
				// library document in the APPROVED directory.
			else if (File.Exists(apdir+"\\"+libname))
			{
				// if the working draft has the library document in the RTFFILES directory
				if (File.Exists("RTFFILES\\"+libname))
				{
					// if working draft library document is newer or contains modified ro
					if (roStat || (wd_rtfdir > ap))
						stat=2;
					// if the working draft version is newer or contains a modified RO
				}
				else 
				{
					if (roStat || (File.Exists(libname) && wd>ap)) stat = 1;
				}
			} 
				// else there is no library document in approved at all, add it.
			else
			{
				if (File.Exists("RTFFILES\\"+libname))
					stat=2;
				else
					stat=1;
			}
			if (stat!=0)
			{
				// see if filename is in the list. If not add it, otherwise it's a duplicate.
				for (int i=0;i 0)
			{
				App_ROfst.processAppUpdFile(AppUpdtmp,WD_ROfst.numDatabases>App_ROfst.numDatabases?WD_ROfst.numDatabases:App_ROfst.numDatabases);
				App_ROfst.CreateMergedFSTFile(NewFST);
				if (File.Exists(NewFST))
				{
					string ROFST = this.GetApprovedDirectory("\\RO.FST");
					string ROFSTbck = this.GetApprovedDirectory("\\RO.BAK");
					File.Copy(ROFST,ROFSTbck,true);
					File.Copy(NewFST,ROFST,true);
					File.Delete(NewFST);
				}
			}
			if (File.Exists(AppUpdtmp))File.Delete(AppUpdtmp);
			WD_ROfst.Close();
			App_ROfst.Close();
		}
		private bool SetupProcessInd(ArrayList ModROs, ArrayList ModLibDocs, ArrayList al, VlnStatusMessage StatMsgWindow)
		{
			bool success;
			success = FindModifiedROs(ModROs, StatMsgWindow);
			if (!success)return false;
			success = FindModifiedLibDocs(ModLibDocs, ModROs, al, StatMsgWindow);
			if (!success) return false;
			return true;
		}
		public bool ProcessInd(ArrayList al, int indx, ArrayList ModROs, ArrayList ModLibDocs)
		{
			bool success=true;
			// process the procedure in the list at 'indx'. First mark it as checked. Then
			// see if it has any RO References that have changed & if so, add any other
			// procedures to the list that use the changed ROs. Then do the same for 
			// library documents & transitions (to/from).
			AppIndItem appitm = (AppIndItem) al[indx];
			if ( ModROs.Count>0) 
			{
				int roref = Usages.CheckRoReferences(this, _curDirectory+"\\"+_Location, al, ModROs,appitm.Proc._Prcnum);
				success=roref>-1;
			}
			if (!success) return false;
			
			if (ModLibDocs.Count>0)success = appitm.Proc.CheckLibraryDocReferences(al, indx, ModLibDocs, ModROs);
			if (!success)return false;
			success=appitm.Proc.CheckTransitionReferences(al);			 
			return success;
		}
		private bool ApproveInd(ArrayList Procs)
		{
			string tempinit = DTI.Initials;
			if (tempinit == "super") DTI.Initials="     ";
			DTI.UpdateDateTimeInit(0);
			DTI.Initials=tempinit;
			// Don't allow approval unless we have a valid path to the RO directory
/**
			 BUG FIX B2005-038
			if (!CheckROPathForApprove()) - done in FindModifiedROs() new
				return false;
**/
			VlnStatusMessage StatMsgWindow = new VlnStatusMessage("Approving Selected Procedures");
			StatMsgWindow.StatusMessage = "Preparing for Approval";	
			// if children are not loaded, load them here...
			VEO_DummySet ds = (VEO_DummySet) this.Children[1];
			if (ds.Children.Count==0) ds.Read(false);
			// find dependencies for those initially selected.
			ArrayList ModROs = new ArrayList();
			ArrayList ModLibDocs = new ArrayList();
			ArrayList AppProcess = new ArrayList();
			if (!SetupProcessInd(ModROs,ModLibDocs,AppProcess,StatMsgWindow))
			{
				StatMsgWindow.Dispose();
				return false;
			}
			// The selected procedures in the passed in list should be put in the
			// processing list of AppIndItems. Then for each item in this list,
			// check to see if conflicts require other procedures to be approved.
			// If a conflict is found, it is added the list of conflicts for the item
			// and the procedure found with the conflict is added to the AppIndItems
			// list, so that it getes checked too. After all items in the AppIndItems
			// list are processed, bring up the dialog with the list of procedures that
			// must be approved. Allow the user to add other procedures, to resolve/edit 
			// conflicts, etc.
			
			StatMsgWindow.StatusMessage = "Looking for Dependencies...";
			foreach (Object obj in Procs)
			{
				AppIndItem aii= new AppIndItem((VEO_Proc)obj);
				AppProcess.Add(aii);
			}
			
			// while there are items in the list to check, keep looking
			// for conflicts. Assume that there is at least one item in the
			// list that hasn't been checked or it wouldn't have gotten to here.
			int indx=0;
			if (AppProcess.Count<1) indx=-1;
			while (indx>=0)
			{
				AppIndItem CurItem = (AppIndItem) AppProcess[indx];
				StatMsgWindow.StatusMessage = "Checking " + CurItem.Proc._Prcnum;
				ProcessInd(AppProcess, indx, ModROs, ModLibDocs);
				CurItem.Checked=true;
				indx = -1;
				for (int i=0;i0)
				{
					string rtfdir = ApprovedPath + "\\RTFFILES";
					if (!Directory.Exists(rtfdir)) Directory.CreateDirectory(rtfdir);
				}
				fis=null;
			}
			string appath=null;
			if (ApprovedPath==null||ApprovedPath=="")
				appath = GetApprovedDirectory("");
			else
				appath = ApprovedPath + "";
			// If the PROC.INI file in the working draft is newer or older than the
			// approved, ask the user if this file should be copied to the approved.
			INIfileApproveCheck("PROC.INI",appath,"Proc.ini");
			// If the Continuous Action Summary ini (CONTACT.INI) file in the working
			// draft is newer or older than the approved, ask the user if this file 
			// should be copied to the approved.
			INIfileApproveCheck("CONTACT.INI",appath,"Continuous Action Summary ini");
			// See if this set has long procedure titles. This was a format flag, but
			// format flags are temporarily being stored in the proc.ini file. This is
			// used in the UpdateSetFile method, but just read it once & reuse.
			using (StreamWriter sw = new StreamWriter("Approval.log", true)) 
			{
				sw.Write("APPROVE SELECTED: Approving selected procedures on ");
				sw.Write(DateTime.Now);
				sw.WriteLine(" performed by " + DTI.Initials);
				sw.WriteLine(" ");
				foreach (AppIndItem ai in AppProcess)
				{
					StatMsgWindow.StatusMessage = "Approving Procedure to " + appath + "\\" +ai.Proc._Prcnum;
					// For the procedure number, see if it exists in the approved set. If
					// not, there is either a new procedure or a modified procedure number.
					// Both cases require a new procedure database fileset to be created.
					string ApProcFile = null;
					string ApProcNum = null;
					ai.Proc.GetApProcNumAndFile(appath, ref ApProcFile, ref ApProcNum);
					sw.WriteLine(" Approved " + ApProcNum);
					ai.Proc.Copy(Directory.GetCurrentDirectory(), appath, ApProcNum, ApProcFile);
					ai.Proc.UpdateSetFile(appath, ApProcNum, ApProcFile);	
					StatMsgWindow.StatusMessage = "Fixing Transition References for "+ai.Proc._Prcnum;
					ai.Proc.FixTransitionReferences(appath, ApProcNum);
					StatMsgWindow.StatusMessage = "Fixing RO Usages for "+ai.Proc._Prcnum;
					Usages.FixROUsages(Directory.GetCurrentDirectory(), appath, ApProcNum, ai.Proc._Prcnum);
				}
				sw.WriteLine(" ");
			}
			UpdateProcedureSetTitleFile(ApprovedPath);
		}
		private void CopyLibDocToApproved(string fname, string ApprovedPath, int stat)
		{
			string buff=fname;
			if (stat==2)
			{
				// Create approved rtf directory.
				if (!Directory.Exists(ApprovedPath+"\\RTFFILES"))Directory.CreateDirectory(ApprovedPath+"\\RTFFILES");
				// create rtf files name
				buff = "RTFFILES\\" + fname;
			} 
			else if (stat==3)
			{
				//  approved rtf version.
				if (Exists(ApprovedPath+"\\RTFFILES\\"+fname))File.Delete(ApprovedPath+"\\RTFFILES\\"+fname);
				buff=fname;
			}
			CopyAnyFileToApproved(buff, null, ApprovedPath);
		}
		private void MoveChangedDocuments(string ApprovedPath, ArrayList ModLibDocs, VlnStatusMessage StatMsgWindow)
		{
			int cnt = ModLibDocs.Count;
			for (int i = ModLibDocs.Count;i>0;i--)
			{
				ModLibDoc ld = (ModLibDoc) ModLibDocs[i-1];
				if (ld.DocPages!=0)
				{
					StatMsgWindow.StatusMessage = "Moving Library Document "+ld.LibFile;
					CopyLibDocToApproved(ld.LibFile,ApprovedPath,ld.status);
					string lbname = ld.LibFile.Substring(0,8);  // don't need extension, i.e. .LIB
					Usages.FixROUsages(Directory.GetCurrentDirectory(), ApprovedPath, lbname, lbname);
				}
			}
		}
		public void DoTheApproval(ArrayList AppProcess, ArrayList ModROs, ArrayList ModLibDocs)
		{
			bool hasTempChange = (Directory.Exists("APPROVED\\TMPCHG") && 
				(usrRunTime.SerialNumber.GetSNOption((uint)Utils.SerialNo.SN_Flags.SN_TEMPCHANGE_ON)>0)
				&& (GetApprovedDirectory("")=="APPROVED"));
			string ApprovedPath = GetApprovedDirectory("");
			VlnStatusMessage StatMsgWindow = new VlnStatusMessage("Do The Approval");
			MoveApprovedProcedures(AppProcess, ApprovedPath, StatMsgWindow);
			if (hasTempChange) MoveApprovedProcedures(AppProcess, "APPROVED\\TMPCHG", StatMsgWindow);
			SaveModifiedROs(ApprovedPath, ModROs, StatMsgWindow);
			if (hasTempChange) SaveModifiedROs("APPROVED\\TMPCHG", ModROs, StatMsgWindow);
			MoveChangedDocuments(ApprovedPath, ModLibDocs, StatMsgWindow);
			if (hasTempChange) MoveChangedDocuments("APPROVED\\TMPCHG", ModLibDocs, StatMsgWindow);
			// If the temporary change directory does not exist and not in the
			// temporary change directory, create the temporary change directory
			// and copy the files to it from the approved directory
			if (ApprovedPath == "APPROVED" && hasTempChange && !Directory.Exists("APPROVED\\TMPCHG")) CopyTempChg(StatMsgWindow);
			StatMsgWindow.Dispose();
			MessageBox.Show("Procedure(s) has been approved.","Approval Complete");
		}
		private void ApproveAll()
		{
			bool approveflag = false;
			
			string tempinit = DTI.Initials;
			if (tempinit == "super") DTI.Initials="     ";
			DTI.UpdateDateTimeInit(0);
			DTI.Initials=tempinit;
			// Don't allow approval unless we have a valid path to the RO directory
			if (!CheckROPathForApprove())
				return;
			DialogResult rslt = MessageBox.Show("About to Approve All of the Procedures in This Set. Continue With The Approval?","Approve All Procedures",MessageBoxButtons.YesNo);
			if (rslt == DialogResult.No) return;
			rslt = MessageBox.Show("Do you want to save the current data to an archive file before proceeding with the Approval?","Archive Data",MessageBoxButtons.YesNo);
			if (rslt == DialogResult.Yes)
			{
				string tmp = "B4APRVAL" + DateTime.Now.ToString("s").Replace(":","-");
				Archive(tmp,true);
			}
			if (RmChgBarOnApp)
			{
				rslt = MessageBox.Show("Remove Change Bars from Working Draft?","Approve All Procedures",MessageBoxButtons.YesNo);
				if (rslt==DialogResult.No) RmChgBarOnApp=tmpRmChgBarOnApp=false;
			}
			else
			{
				rslt = MessageBox.Show("Keep Change Bars in Working Draft?","Approve All Procedures",MessageBoxButtons.YesNo);
				if (rslt==DialogResult.No) RmChgBarOnApp=tmpRmChgBarOnApp=true;
			}
			if (!RmChgBarOnApp || SetupDateTimeStamp())
			{
				long spfree = DirSpace.Free();
				if( File.Exists(GetApprovedDirectory("\\set.dbf")) && (spfree > 200000L) )
					approveflag = true; 
		
				long tmp = DirSpace.Get(Environment.CurrentDirectory);
				if( !approveflag && !(spfree > DirSpace.Get(Environment.CurrentDirectory)) )
				{
					MessageBox.Show("Insufficient Disk Space for Approval!","General Approval Error");
					return;
				}
				VlnStatusMessage StatMsgWindow = new VlnStatusMessage("Approving All Procedures");
				StatMsgWindow.StatusMessage = "Preparing for Approval";	
			
				using (StreamWriter sw = new StreamWriter("Approval.log", true)) 
				{
					sw.Write("APPROVE ALL: on ");
					sw.Write(DateTime.Now);
					sw.WriteLine(" performed by " + DTI.Initials);
					sw.WriteLine(" ");
				}
				MakeApprovedProcs(StatMsgWindow);
				if(File.Exists("xtsetid.dbf"))MoveOutsideTransitions(StatMsgWindow);
				MoveTransitions(StatMsgWindow);
				MoveROs(StatMsgWindow);
				UpdateGraphicFiles(StatMsgWindow);
				MoveUserFormats(StatMsgWindow);
				UpdateProcedureSetTitleFile(null);
				CopyTempChg(StatMsgWindow);
				StatMsgWindow.Dispose();
				MessageBox.Show("Procedure Set has been approved.","Approval Complete");
			}
		}
		public override void ApproveProcedures(int ApproveType, ArrayList procs)
		{
			// before doing anything - verify that no one is 'connected' to the 
			// approved directory. do this by getting approved directory & 
			// using its object, see if there is an open connection. Make a lock
			// in the approved set. If this cannot be done - then can't approve.
			bool needtoUnlock = false;
			bool needtoDisConnect = false;
			VEO_ProcSet lckapp=null;
			if (isSetApproved && usrRunTime.InMultiUserMode)
			{
				bool proceed = true;
				VEO_ProcSet ps = null;
				VEO_Plant pl = (VEO_Plant) this.parentObj;
				for (int i=0; i< pl.Children.Count; i++)
				{
					VEO_ProcSet aps = (VEO_ProcSet) pl.Children[i];
					string dir = aps._curDirectory.ToUpper()+"\\"+aps._Location.ToUpper();
					if (dir==_curDirectory.ToUpper()+"\\"+_Location.ToUpper()+"\\APPROVED")
					{	
						ps = aps;
						break;
					}
				}
				if (ps!=null)
				{
					// if there are active users in the approved directory approval
					// cannot continue, put up message and return. Otherwise lock
					// the approved directory.
					if (ps.Connection == null) 
					{
						needtoDisConnect=true;
						ps.LoadLockInfo();
						ps.Connection = new VEConnection(ps.Lock, ps.usrRunTime);
						if (ps.Lock.LockStatus==VENetwork.Status.LockedByOther)proceed=false;
					}
					if (proceed)ps.Connection.Enter(false);
					if (proceed && ps.Connection.HasActiveUsers())proceed=false;
					if (proceed && !ps.amILockedByMe())
					{
						bool success = ps.Lock.CreateLock(ps.Connection, false);
						if (!success)
							proceed=false;
						else 
						{
							needtoUnlock=true;
							lckapp = ps;
						}
					}
				}
				if (ps==null||!proceed)
				{
					MessageBox.Show("Could not connect/lock the associated approval directory.\n Either another user is viewing the data or has a lock on the data.","VE-PROMS");
					if (ps != null) ps.Connection.MonitorUsers((int)ps.Lock.LockType-1);
					ps.Connection.Exit();
					if (needtoDisConnect)ps.Connection=null;
					return;
				}
			}
			bool wasOpen = isOpen;
			// change directory before doing functions
			if (!isOpen)Open();
			switch (ApproveType)
			{
				case 0:				// approve the entire set
					ApproveAll();
					break;
				case 1:
					ApproveInd(procs);
					break;
			}
			if(!wasOpen)Close();
			if (needtoUnlock)lckapp.Lock.UnLock(false);
//			if (needtoDisConnect)
// Bug Fix:  B2006-033
// Had a lock at VEplant level, thus lckapp was never set
			if (needtoDisConnect && lckapp != null)
			{
				lckapp.Connection.Exit();
				lckapp.Connection=null;
			}
		}
		public override bool Delete()
		{
			try
			{
				bool tst=false;
				if ((tst=Open())!=true) return false;
				// if this is an enhanced document, remove the bck.lnk or dvt.lnk
				// and erg.lnk for dev, files in the parentLink directory.
				if (_ProcType == VEObject.ProcTypeOptions.Background ||
					_ProcType == VEObject.ProcTypeOptions.Deviation)
				{
					if (parentLink==null) // load in the link.
						GetParentLink();
					string lnk = parentLink;
					if (lnk != null || lnk != "")
					{
						string dellnk;
						if(this._ProcType != VEObject.ProcTypeOptions.Background)
							dellnk = lnk+"\\DVT.LNK";
						else
							dellnk = lnk+"\\BCK.LNK";
						File.Delete(dellnk);
					}
					string tmppath = CurDirectory+"\\"+_Location+"\\eop.lnk";
					if (File.Exists(tmppath)) File.Delete(tmppath);
					if (_ProcType == VEObject.ProcTypeOptions.Deviation)
					{
						if (guideLink==null) GetGuideLink();
						tmppath = this.CurDirectory+"\\"+_Location+"\\ERG.LNK";
						File.Delete(tmppath);
						
					}
				}
				// Now delete the document directory. Close first, which closes
				// any open multi-user connections.
				Close();
				this.Children.Clear();
				string cwd = Directory.GetCurrentDirectory();
				Directory.Delete(CurDirectory+"\\"+_Location,true);
			}
			catch (Exception e)
			{
//				string cwd = Directory.GetCurrentDirectory();
				MessageBox.Show(e.Message,"Error Deleting");
				DirectoryInfo di = new DirectoryInfo(CurDirectory+"\\"+_Location);
				di.Delete(true);
				return false;
			}
			if (Directory.Exists(CurDirectory+"\\"+_Location)) return false;
			VEO_Plant plnt = (VEO_Plant) parentObj;
			if (plnt.Children.Count <=1) 
			{
				plnt.icon = plnt.iconStates[(int)VEO_IconStates.Empty];
				plnt.IsEmpty=true;
			}
			return true;
		}
		public override bool Read(bool ChkForChldOnly)
		{
			if (Lock.LockStatus == VENetwork.Status.LockedByOther) return false;
			string path = _curDirectory + "\\" + _Location;
			// for each procset, get its contents, i.e. zip files, whether there's
			// a set.dbf (shows that there ar]e procedure files), 
			StringBuilder fname = new StringBuilder();
			fname.Append(path);
			fname.Append("\\SOURCE.ZIP");
			FileInfo source = new FileInfo(fname.ToString());
			if (source.Exists) isArchived=true;
			VEO_DummyZip zp = new VEO_DummyZip(usrRunTime,"Zip Files", _curDirectory+"\\"+_Location);
			zp.parentObj=this;
			Children.Add(zp);
			// if !isArchived, check for any other zip files, or make the icon empty	
			DirectoryInfo di = new DirectoryInfo(path);
			FileInfo [] fi = di.GetFiles("*.ZIP");
			if (fi.Length<=0) 
			{
				zp.IsEmpty = true;
				zp.icon=zp.iconStates[(int)VEO_IconStates.Empty];
			}
			di = null;
			fi = null;
			// now check for procedures in the set
			fname.Remove(fname.Length-11,11);
			fname.Append("\\SET.DBF");
			source = new FileInfo(fname.ToString());
			if (source.Exists) 
			{
				IsEmpty=false;
				setExists = true;
				if (this.hasExtraRevNumber)
				{
					vdb_Set vdbSet=new vdb_Set(_curDirectory+"\\"+_Location+"\\set.dbf");
					DataRow rw = vdbSet.DB_Data.Tables[0].Rows[0];
					ExtraRevNumber = rw["TITLE"].ToString();
					origExtraRevNumber=ExtraRevNumber;
					vdbSet=null;
				}
			}
			else
				IsEmpty=true;
			VEO_DummySet prc = new VEO_DummySet(usrRunTime,"Procedures",_curDirectory+"\\"+_Location);
			if (IsEmpty) prc.icon = prc.iconStates[(int)VEO_IconStates.Empty];
			prc.parentObj=this;
			// Update Enhanced and Slave Set files
			if (!ChkForChldOnly) prc.SyncSetFile();
			// Update the Slave's Continue Actions Summary ini (ContAct.INI) file
			if (!ChkForChldOnly) prc.UpdateContActINI();
			Children.Add(prc);
			// check both rtffiles & procs directory for library documents
			di = new DirectoryInfo(path+"\\RTFFILES");
			if (di.Exists)
			{
				FileInfo[] fiArr = di.GetFiles("DOC_*.LIB");
				if (fiArr.Length>0) hasLibDocs = true;
				
			}
			if (!hasLibDocs)
			{
				di = new DirectoryInfo(path);
				FileInfo[] fiArr = di.GetFiles("DOC_*.LIB");
				if (fiArr.Length>0) hasLibDocs = true;
			}
			VEO_DummyLibDoc ld = new VEO_DummyLibDoc(usrRunTime,"Library Documents",_curDirectory+"\\"+_Location);
			ld.parentObj=this;
			if (!hasLibDocs) 
			{
				ld.icon = ld.iconStates[(int)VEO_IconStates.Empty];
				ld.IsEmpty=true;
			}
			Children.Add(ld);
			
			return true;
		}
		public override bool CollapseSibling()
		{
			if (!usrRunTime.InMultiUserMode) return false;
			return true;
		}
		public override bool mnuAllowLckDB()
		{
			if (!usrRunTime.InMultiUserMode) return false;
			//if (amILockedByMe()) return false;   // if I'm already locked, don't allow it
			if ((accessFlags&Security.LOCKPROC)==Security.LOCKPROC && Lock.LockStatus==VENetwork.Status.NoLock) return true;
			return false;
		}
		public override bool mnuAllowUnlckDB()
		{
			if (!usrRunTime.InMultiUserMode) return false;
			if ((accessFlags&Security.LOCKPROC)==Security.LOCKPROC&&(Lock.LockStatus==VENetwork.Status.Locked||
				Lock.LockStatus==VENetwork.Status.LockPending)) return true;
			return false;
		}
		public override bool mnuAllowUpdRO()
		{
			if (isApproved||IsEmpty||isTempChange) return false;
			if (amILockedByMe()==false) return false;
			return true;
		}
		
		public override bool mnuAllowClean()
		{
			if (isApproved||IsEmpty) return false;
			if (Lock.LockStatus!=VENetwork.Status.Locked)return false;
			if (amILockedByMe()==false) return false;
			if ((accessFlags&Security.CLEAN)==Security.CLEAN) return true;
			return false;
		}
		public override bool mnuAllowDataCheck()
		{
			if (isApproved||IsEmpty) return false;
			if (Lock.LockStatus!=VENetwork.Status.Locked)return false;
			if (amILockedByMe()==false) return false;
			if ((accessFlags&Security.CLEAN)==Security.CLEAN) return true;
			return false;
		}
		public override bool mnuAllowChgDef()
		{
			if(IsEmpty) return false;
			if (amILockedByMe()==false) return false;
			return true;
		}
		public override bool mnuAllowApprove()
		{
			if (isApproved || IsEmpty || isTempChange) return false;
			if (amILockedByMe()==false) return false;
			return true;
		}
		public override bool mnuAllowApproveAll()
		{
			bool allowit=false;
			bool allowonlyonce=false;
			if (isApproved || IsEmpty || isTempChange) return false;
			if (amILockedByMe()==false) return false;
			if ((accessFlags&Security.APPROVE)==Security.APPROVE) allowit = true;
			// also check if there is a serial number option which allows only one
			// approve-all, i.e. if an approved version exists, cannot approve all.
			if (usrRunTime.SerialNumber.GetSNOption((uint)Utils.SerialNo.SN_Flags.SN_ONLYAPPROVEONCE_ON)>0)
				allowonlyonce=true;
			if (allowonlyonce && this.isSetApproved) return false;
			if (allowit) return true;
			return false;
		}
		public override bool mnuAllowApproveSel()
		{
			if (isApproved || IsEmpty || isTempChange) return false;
			if (amILockedByMe()==false) return false;
			if (isSetApproved && ((accessFlags&Security.APPROVESINGLE)==Security.APPROVESINGLE)) return true;
			return false;
		}
		public override bool mnuAllowNew()
		{
			return false;
		}
		public override bool mnuAllowDelete()
		{
			if (amILockedByMe()==false) return false;
			if(usrRunTime.sec.PermissionToManageFlag) return true;
			return false;
		}
		public override bool canEdit()
		{
			if (amILockedByMe()==false) return false;
			if(usrRunTime.sec.PermissionToManageFlag) return true;
			return false;
		}
		public override void DoListView(ListView veoListView)
		{
			ListViewItem item=null;
			veoListView.Columns.Add("Type", 120, HorizontalAlignment.Left);
			
			for (int i=0; i= 10)) break;
					// get the largest values from the first record's number field
					if (isfirst)
					{
						isfirst = false;
						string nm = row["NUMBER"].ToString();
						if (nm != null && nm !="")
						{
							try
							{
								LargestNumber = System.Convert.ToInt32(nm.Substring(0,2));
								LargestNumberForMenu=System.Convert.ToInt32(nm.Substring(3,2));
								LargestTitleForMenu=System.Convert.ToInt32(nm.Substring(6,2));
							}
							catch (Exception)
							{
								MessageBox.Show("Invalid data in procedure set.dbf file. Contact Volian!", "set.dbf Error");
								return false;
							}
						}
					}
					else
					{
						string mytitle = row["TITLE"].ToString();
						string mynum = row["NUMBER"].ToString();
						string mypth = row["ENTRY"].ToString();
						string recid = row["RECID"].ToString();
						string tmpcol = row["FORMAT"].ToString();
						string proccode = row["PROCCODE"].ToString();
						int itmpcol;
						if (tmpcol==null||tmpcol=="") 
							itmpcol=1;
						else
						{
							try
							{
								itmpcol = System.Convert.ToInt32(tmpcol)-1;
							}
							catch
							{
								itmpcol = 1;
							}
						}
						if (itmpcol < 0) itmpcol = 1;  // if 0 in database, default to 2 col
						VEO_Base.ProcColumnOptions format = (VEO_Base.ProcColumnOptions) itmpcol;
				
						VEO_Proc prc = new VEO_Proc(mytitle,mypth,mynum,recid,format,proccode,row,this,false);
						Children.Add(prc);
					}
				}
				if (ps.hasExtensions)
				{
					// if not new and we have extensions, check for a setext file. if it doesn't
					// exist, notify user & set the flag to false. Just return, if we got to
					// this point, no errors were caught.
					string setextname = ps._curDirectory+"\\"+ps._Location+"\\setext.dbf";
					if (!isNew)
					{
						FileInfo fi = new FileInfo(setextname);
						if (fi.Exists == false)
						{
							MessageBox.Show("Procedure comment file (setext.dbf) does not exist.\nThis data will not be available.","Set Extension Error");
							ps.hasExtensions=false;
							return true;
						}
					}
					// the numeric data of the set extension file was not read correctly (an underlying
					// driver problem. So, change the data type from numeric (N) to character (C)
					// in the file at the 171th byte in the file, if it hasn't been changed.
					try
					{
						FileStream fs = new FileStream(setextname,FileMode.Open,FileAccess.ReadWrite,FileShare.ReadWrite);
						fs.Seek(171,SeekOrigin.Begin);
						int by = fs.ReadByte();
						if ((byte)by != (byte)'C')  // rewrite it.
						{
							fs.Seek(171,SeekOrigin.Begin);
							fs.WriteByte((byte)'C');
						}
						fs.Close();
					}
					catch (Exception e)
					{
						MessageBox.Show(e.Message,"Set Extension Error");
					}
					
					int chldindx=0;
					isfirst=true;
					vdbSetExt=new vdb_SetExt(_Location+"\\setext.dbf");
					// Loop thru the procset (process like a dataset)
					tbl = vdbSetExt.DB_Data.Tables[0];
					foreach (DataRow row in tbl.Rows)
					{
						// if in demo mode, only allow 10 procedures in set
						if (usrRunTime.sec.isDemoMode && (chldindx >= 10)) break;
						// skip the first one
						if (isfirst)
							isfirst = false;
						else
						{
							VEO_Proc prc = (VEO_Proc) Children[chldindx];
						
							string comment = row["COMMENT"].ToString();
							string rev = row["REV"].ToString();
							string pc = row["PC"].ToString();
							string recid = row["RECID"].ToString();
							string std = row["APPROVEDDATE"].ToString();
							prc.procExt = new VEO_ProcExt(comment, rev, pc, recid, std, row);
							chldindx++;
						}
					}
				}
			}
			catch (Exception e)
			{
				MessageBox.Show(e.Message,"Error reading procedure set");
				return false;
			}
			return true;
		}
		~ VEO_DummySet()
		{
			if (vdbtmpSet!=null)vdbtmpSet.Clear();
			vdbtmpSet=null;
			vdbSet=null;
			vdbSetExt= null;
		}
		// This method clears the vdbset, and vdbsetext if used, and reloads from
		// database. It then sync's up the datarows to the dummyset's children.
		// It is used for moving procedures within the set & on the pack operation.
		// Both of these required rewriting of a new database file.
		private bool ReLoadRows(int skip)
		{
			VEO_ProcSet ps = (VEO_ProcSet) parentObj;
			try
			{
				// now reopen a vdbset & vdbsetext & reassign the datarows.
				this.vdbSet = null;
				this.vdbSetExt = null;
				vdbSet=new vdb_Set(_Location+"\\set.dbf");
				// Loop thru the procset (process like a dataset)
				DataTable tbl = vdbSet.DB_Data.Tables[0];
				int rec = 1;
				for (int i=0;i=11, first
					// record is not a procedure)
					if (usrRunTime.sec.isDemoMode && (rec >= 11)) break;
					
					// if not skipping this child (on a delete), sync the database
					// row eith the internal proc row
					if (skip<0||i!=skip)
					{
						VEO_Proc prc = (VEO_Proc) Children[i];
						prc.pdatarow = tbl.Rows[rec];		// first table row is blank
						rec++;
					}
				}
				if (ps.hasExtensions)
				{
					this.vdbSetExt=null;
					vdbSetExt=new vdb_SetExt(_Location+"\\setext.dbf");
					// Loop thru the procset extensions file
					DataTable xtbl = vdbSetExt.DB_Data.Tables[0];
					rec=1;
					for (int i=0;i= 11)) break;
						if (skip<0||i!=skip)
						{
							VEO_Proc prc = (VEO_Proc) Children[i];
							VEO_ProcExt pe = prc.procExt;
							pe.drow = xtbl.Rows[rec];
							rec++;
						}
					}
				}
				return true;
			}
			catch (Exception e)
			{
				MessageBox.Show(e.Message, "Problem saving procedure data");
				return false;
			}
		}
		// When a procedure has been moved within the set, save the new order.
		public bool SaveOrder()
		{
			int rowcount;
			VEO_ProcSet ps = (VEO_ProcSet) this.parentObj;
			if(!ps.isOpen)ps.Open();
			string tempName = ps._curDirectory + "\\" + ps.Location + "\\NEWSET.DBF";
			if (File.Exists(tempName))File.Delete(tempName);
			string name = ps._curDirectory + "\\" + ps.Location + "\\SET.DBF";
			string tempNameEx = null;
			string nameEx = null;
			if(ps.hasExtensions)
			{
				tempNameEx = ps._curDirectory + "\\" + ps.Location + "\\NEWEXT.DBF";
				if (File.Exists(tempNameEx))File.Delete(tempNameEx);
				nameEx = ps._curDirectory + "\\" + ps.Location + "\\SETEXT.DBF";
			}
			// do set database files now
			try
			{
				vdb_Set newset = new vdb_Set(ps._curDirectory + "\\" + ps.Location);
				newset.CreateTable("newset");
				DataTable pdatatable = newset.DB_Data.Tables[0];
				DataTable origtable = vdbSet.DB_Data.Tables[0];
				DataRow recidrow = pdatatable.Rows[0];
				DataRow firstrow = origtable.Rows[0];
				recidrow.ItemArray=firstrow.ItemArray;
				rowcount = 1;
				foreach (VEO_Proc prc in Children)
				{	
					DataRow pdatarow = pdatatable.NewRow();
					DataRow curold = prc.pdatarow;
					pdatarow.ItemArray=curold.ItemArray;
					rowcount++;
					pdatatable.Rows.Add(pdatarow);
					prc.pdatarow = pdatarow;
				}
				newset.DB_Data = recidrow.Table.DataSet;
			}
			catch (Exception e)
			{
				MessageBox.Show(e.Message,"Error Saving Procedure Set Order");
				if (File.Exists(tempName))File.Delete(tempName);
				if (File.Exists(tempNameEx))File.Delete(tempNameEx);
				return false;
			}
			// if has setextensions, do the setext file now.
			if (ps.hasExtensions)
			{
				try
				{
					vdb_SetExt newext = new vdb_SetExt(ps._curDirectory + "\\" + ps.Location);
					newext.CreateTable("newext");
					DataTable exttbl = newext.DB_Data.Tables[0];
					DataRow firstdelrow = exttbl.Rows[0];
					// first row was made with a recid of 0001. We want to use the
					// first row from the original setext file.
					firstdelrow.Delete();
					DataRow firstrow = exttbl.NewRow();
					DataRow orig = vdbSetExt.DB_Data.Tables[0].Rows[0];
					firstrow.ItemArray = orig.ItemArray;
					exttbl.Rows.Add(firstrow);
					rowcount=1;
					foreach (VEO_Proc prc in Children)
					{	
						DataRow pdatarow = exttbl.NewRow();
						DataRow origr = prc.procExt.drow;
						pdatarow.ItemArray=origr.ItemArray;
						exttbl.Rows.Add(pdatarow);
						rowcount++;
						prc.procExt.drow = pdatarow;
					}
					newext.DB_Data = firstrow.Table.DataSet;
				}
				catch (Exception e)
				{
					MessageBox.Show(e.Message,"Error Saving Procedure Set Order");
					if (File.Exists(tempName))File.Delete(tempName);
					if (File.Exists(tempNameEx))File.Delete(tempNameEx);
					return false;
				}
			}
			// rename files & then reload the data (to sync up with internal tree)
			File.Delete(name);
			File.Move(tempName,name);			
			if (ps.hasExtensions)
			{
				File.Delete(nameEx);
				File.Move(tempNameEx,nameEx);
			}
			return (ReLoadRows(-1));
		}
		// back this database, pass in an integer to show the i'th child which was removed
		// so that this one is sync'd back up in the reload code.
		public bool PackDB(int i)
		{
			//call the database method for this dataset to pack. It will close the dataset
			//and will require a reopen of dataset.
			this.vdbSet.Pack();
			VEO_ProcSet ps = (VEO_ProcSet) this.parentObj;
			if (ps.hasExtensions) this.vdbSetExt.Pack();
			return (ReLoadRows(i));
		}
		// create a new document object (procedure child for this set)
		public override Object MakeNewChild()
		{
			// if in demo mode, only allow 10 procedures in set
			if (usrRunTime.sec.isDemoMode && (Children.Count >= 10)) 
			{
				MessageBox.Show("No more than 10 procedures while in Demo Mode.", "VE-PROMS Demo");
				return null;
			}
			// for this 'dummy' procedure list node, loop through its
			// children to get a unique procnumber.
			int i=0;
			bool newdc = false;
			string newdoc=null;
			while(!newdc)
			{
				if (i==0)
					newdoc = "NewDoc";
				else
					newdoc = "NewDoc"+(i-1).ToString();
				bool inlist = false;
				foreach (VEO_Proc chld in this.Children)
				{
					if (chld.Procedure_Number == newdoc) 
					{
						inlist=true;
						break;
					}
				}
				if(inlist)i++;
				else newdc=true;
			}
			
			// now get a unique file name
			VEO_Proc prc = new VEO_Proc("New Document",this._Location,newdoc,null,VEO_Base.ProcColumnOptions.TwoColumn, null, null, this, true);
			VEO_ProcSet ps = (VEO_ProcSet) parentObj;
			if (ps.hasExtensions) 
			{
				prc.procExt = new VEO_ProcExt(null, null, null, null, null, null);
			}
			return prc;		
		}
		public override bool SaveChild(Object obj)
		{
			VEO_Proc proc = (VEO_Proc)obj;
			bool succeed = proc.SaveNew(null);
			if (succeed == true) proc.parentObj = this;
			return succeed;
		}
		
		public override void DoListView(ListView veoListView)
		{
			ListViewItem item=null;
			veoListView.Columns.Add("ProcNumber", 120, HorizontalAlignment.Left);
			veoListView.Columns.Add("Title", 200, HorizontalAlignment.Left);
			veoListView.Columns.Add("ProcColumn", 100, HorizontalAlignment.Left);
			veoListView.Columns.Add("ModInfo", 150, HorizontalAlignment.Left);
			veoListView.Columns.Add("Location", 100, HorizontalAlignment.Left);	
			
			for (int i=0; i0))
			{
				// Enhanced Background Documents
				if (File.Exists(_Location+"\\SET.DBF"))
					UpdateEnhancedSetFile();
				else
				{
					// no set file, copy from EOPs
//					VEO_ProcSet ps = (VEO_ProcSet) this.parentObj;
					File.Copy(ps.GetParentLink()+"\\SET.DBF",_Location+"\\SET.DBF");
				}
			}
//			else if (LOC.EndsWith(".DVT") &&
			else if (!ps.isApproved && !ps.isTempChange && ps._ProcType.Equals(VEObject.ProcTypeOptions.Deviation) &&
				(usrRunTime.SerialNumber.GetSNOption((uint)Utils.SerialNo.SN_Flags.SN_DEVIATION_ON)>0))
			{
				// Enhanced Deviation Documents
				if (File.Exists(_Location+"\\SET.DBF"))
					UpdateEnhancedSetFile();
				else
				{
					// no set file, copy from EOPs
//					VEO_ProcSet ps = (VEO_ProcSet) this.parentObj;
					File.Copy(ps.GetParentLink()+"\\SET.DBF",_Location+"\\SET.DBF");
				}
			}
//			else if (LOC.IndexOf(".SL") > 0)
			else if (!ps.isApproved && !ps.isTempChange && ps._ProcType.Equals(VEObject.ProcTypeOptions.Slave))
			{
				// Slave Procedure Set
				UpdateSlaveSetFile();
			}
			else
				return; // not a enhanced or slave set
		}
		private void UpdateEnhancedSetFile()
		{
			VEO_ProcSet ps = (VEO_ProcSet) parentObj;
			int EnhIdx=1,PrcIdx=1,TmpIdx;
//			int EnhExtIdx=0;
			int EnhCnt=0, PrcCnt=0, NewCnt=0;
//			int EnhExtCnt=0, NewEnhExtCnt=0;
			int LargestRecID = 0;
			bool NeedToIncLargestRecID = false;
			string strEnhRecID, strPrcRecID, strLargestRecID,strNewRecID;
//			string NewEnhExtRecID;
			int EnhRecID, PrcRecID, NewRecID;
			DataRow EnhRow, PrcRow, NewRow;
//			DataRow EnhExtRow;
			string ParentPath = ps.GetParentLink();
			if (!Directory.Exists(ParentPath))
			{
				string cwd = Directory.GetCurrentDirectory();
				MessageBox.Show("Cannot update enhanced set " + ParentPath + ". It does not exist. Check your lnk file setting.", "Enhanced Document Error");
				return;
			}
			// compare the date/times of the two set files
			DateTime bcksetdt = File.GetLastWriteTimeUtc(_Location+"\\set.dbf");
			DateTime eopsetdt = File.GetLastWriteTimeUtc(ParentPath+"\\set.dbf");
//			if	( bcksetdt.ToUniversalTime() >= eopsetdt.ToUniversalTime()) 
			if (bcksetdt >= eopsetdt)
				return; // Enhanced Set file is up to date
			ArrayList EnhSetList = new ArrayList();
			ArrayList PrcSetList = new ArrayList();
			ArrayList NewEnhSetList = new ArrayList();
			// Array Lists for Set Extension databases
//			ArrayList EnhSetExtList = new ArrayList();
//			ArrayList NewEnhSetExtList = new ArrayList();
			// populate the array lists
			EnhCnt = PopulateSetArrayList(_Location,EnhSetList);
			PrcCnt = PopulateSetArrayList(ParentPath,PrcSetList);
//			if (ps.hasExtensions)
//				EnhExtCnt = PopulateSetExtArrayList(_Location,EnhSetExtList);
			// copy the first record from the Enhanced Set file
			// - we might modify this later
			EnhRow = (DataRow)EnhSetList[0];
			strEnhRecID = EnhRow["RECID"].ToString();
			EnhRecID = Convert.ToInt32(strEnhRecID.Substring(2));
			NewCnt = AddToArrayList(NewEnhSetList,EnhRow,NewCnt,strEnhRecID);
			strLargestRecID = strEnhRecID;
			LargestRecID = EnhRecID;
//			if (ps.hasExtensions)
//			{
//				// copy the first record from the setext
//				EnhExtRow = (DataRow)EnhSetExtList[0];
//				NewEnhExtRecID = EnhExtRow["RECID"].ToString();
//				NewEnhExtCnt = AddToArrayList(NewEnhSetExtList,EnhExtRow,NewEnhExtCnt,NewEnhExtRecID);
//			}
			
			while (EnhIdx < EnhCnt && PrcIdx < PrcCnt)
			{
				EnhRow = (DataRow)EnhSetList[EnhIdx];
				PrcRow = (DataRow)PrcSetList[PrcIdx];
				strEnhRecID = EnhRow["RECID"].ToString();
				strPrcRecID = PrcRow["RECID"].ToString();
				EnhRecID = Convert.ToInt32(strEnhRecID.Substring(2));
				PrcRecID = Convert.ToInt32(strPrcRecID.Substring(2));
				if (!(EnhRecID == PrcRecID))
				{
					if ((InThisArrayList(strEnhRecID,PrcSetList,PrcIdx,PrcCnt)) == -1)
					{
						// The EOP probable was deleted. Keep the Background
						// procedure around in case user needs to copy info
						// from it.
						if (EnhRecID > LargestRecID)
						{
							strLargestRecID = strEnhRecID;
							LargestRecID = EnhRecID;
							NeedToIncLargestRecID = true;
						}
						NewCnt = AddToArrayList(NewEnhSetList,EnhRow,NewCnt,strEnhRecID);
					}
				}
				// Copy the Date, Time, and Initials from the old Enhanced Set file
				TmpIdx = InThisArrayList(strPrcRecID,EnhSetList,1,EnhCnt);
				if (TmpIdx > -1)
				{
					DataRow TmpRow = (DataRow)EnhSetList[TmpIdx];
					PrcRow["DATE"] = TmpRow["DATE"];
					PrcRow["TIME"] = TmpRow["TIME"];
					PrcRow["INITIALS"] = TmpRow["INITIALS"];
				}
				if (PrcRecID > LargestRecID)
				{
					strLargestRecID = strPrcRecID;
					LargestRecID = PrcRecID;
					NeedToIncLargestRecID = true;
				}
				NewCnt = AddToArrayList(NewEnhSetList,PrcRow,NewCnt,strPrcRecID);
//				if (ps.hasExtensions)
//				{
//					// Add Set Extension info.
//					EnhExtIdx = InThisArrayList(strEnhRecID,EnhSetExtList,1,EnhExtCnt);
//					if (EnhExtIdx > -1)
//					{
//						EnhExtRow = (DataRow)EnhSetExtList[EnhExtIdx];
//						NewEnhExtRecID = EnhExtRow["RECID"].ToString();
//						NewEnhExtCnt = AddToArrayList(NewEnhSetExtList,EnhExtRow,NewEnhExtCnt,NewEnhExtRecID);
//					}
//				}
				EnhIdx++;
				PrcIdx++;
			}
			// add any BCK Records that are remaining
			while (EnhIdx < EnhCnt)
			{
				EnhRow = (DataRow)EnhSetList[EnhIdx];
				strEnhRecID = EnhRow["RECID"].ToString();
				EnhRecID = Convert.ToInt32(strEnhRecID.Substring(2));
				if (EnhRecID > LargestRecID)
				{
					strLargestRecID = strEnhRecID;
					LargestRecID = EnhRecID;
					NeedToIncLargestRecID = true;
				}
				NewCnt = AddToArrayList(NewEnhSetList,EnhRow,NewCnt,strEnhRecID);
				EnhIdx++;
//				if (ps.hasExtensions)
//				{
//					// Add Set Extension info.
//					EnhExtIdx = InThisArrayList(strEnhRecID,EnhSetExtList,1,EnhExtCnt);
//					if (EnhExtIdx > -1)
//					{
//						EnhExtRow = (DataRow)EnhSetExtList[EnhExtIdx];
//						NewEnhExtRecID = EnhExtRow["RECID"].ToString();
//						NewEnhExtCnt = AddToArrayList(NewEnhSetExtList,EnhExtRow,NewEnhExtCnt,NewEnhExtRecID);
//					}
//				}
			}
			// add any PRC Records that are remaining
			while (PrcIdx < PrcCnt)
			{
				PrcRow = (DataRow)PrcSetList[PrcIdx];
				strPrcRecID = PrcRow["RECID"].ToString();
				PrcRecID = Convert.ToInt32(strPrcRecID.Substring(2));
				if (PrcRecID > LargestRecID)
				{
					strLargestRecID = strPrcRecID;
					LargestRecID = PrcRecID;
					NeedToIncLargestRecID = true;
				}
				// Copy the Date, Time, and Initials from the old Enhanced Set file
				TmpIdx = InThisArrayList(strPrcRecID,EnhSetList,1,EnhCnt);
				if (TmpIdx > -1)
				{
					DataRow TmpRow = (DataRow)EnhSetList[TmpIdx];
					PrcRow["DATE"] = TmpRow["DATE"];
					PrcRow["TIME"] = TmpRow["TIME"];
					PrcRow["INITIALS"] = TmpRow["INITIALS"];
				}
				NewCnt = AddToArrayList(NewEnhSetList,PrcRow,NewCnt,strPrcRecID);
				PrcIdx++;
//				if (ps.hasExtensions)
//				{
//					// Add Set Extension info.
//					EnhExtIdx = InThisArrayList(strPrcRecID,EnhSetExtList,1,EnhExtCnt);
//					if (EnhExtIdx > -1)
//					{
//						EnhExtRow = (DataRow)EnhSetExtList[EnhExtIdx];
//						NewEnhExtRecID = EnhExtRow["RECID"].ToString();
//						NewEnhExtCnt = AddToArrayList(NewEnhSetExtList,EnhExtRow,NewEnhExtCnt,NewEnhExtRecID);
//					}
//				}
			}
			// Update Record zero's RECID if needed
			NewRow = (DataRow)NewEnhSetList[0];
			strNewRecID = NewRow["RECID"].ToString();
			NewRecID = Convert.ToInt32(strNewRecID.Substring(2));
			if (LargestRecID > NewRecID)
			{
				if (NeedToIncLargestRecID) LargestRecID++;
				strLargestRecID = strLargestRecID.Substring(0,2)+LargestRecID.ToString("d6");
				NewRow["RECID"] = strLargestRecID;
				NewEnhSetList[0] = NewRow;
//				if (ps.hasExtensions)
//				{
//					EnhExtRow = (DataRow)EnhSetExtList[0];
//					EnhExtRow["RECID"] = strLargestRecID;
//					EnhSetExtList[0] = EnhExtRow;
//				}
			}
			// Write out new SET.DBF file
//			WriteUpdatedSetFile(_Location,NewEnhSetList,EnhSetExtList,ps.hasExtensions);
			WriteUpdatedSetFile(_Location,NewEnhSetList,null,false);
		}
		static int PopulateSetArrayList(string Loc,ArrayList AryLst)
		{	
			int cnt =0;
			string SetFilePath = Loc+"\\set.dbf";
			if (File.Exists(SetFilePath))
			{
				try
				{
					vdb_Set TheSetFile = new vdb_Set(SetFilePath);
					// Loop thru the procset (process like a dataset)
					DataTable tbl = TheSetFile.DB_Data.Tables[0];
					foreach (DataRow row in tbl.Rows)
					{
						AryLst.Add(row);
						cnt++;
					}
				}
				catch (Exception e)
				{
					MessageBox.Show(e.Message,"Error populating Set Array Lists");
					return 0;
				}
			}
			return cnt;
		}
		static int PopulateSetExtArrayList(string Loc,ArrayList AryLst)
		{	
			int cnt =0;
			string SetExtPath = Loc+"\\setext.dbf";
			if (File.Exists(SetExtPath))
			{
				try
				{
					vdb_SetExt TheSetExtFile = new vdb_SetExt(SetExtPath);
					// Loop thru the procset (process like a dataset)
					DataTable tbl = TheSetExtFile.DB_Data.Tables[0];
					foreach (DataRow row in tbl.Rows)
					{
						AryLst.Add(row);
						cnt++;
					}
				}
				catch (Exception e)
				{
					MessageBox.Show(e.Message,"Error populating SetExt Array Lists");
					return 0;
				}
			}
			return cnt;
		}
		static int AddToArrayList(ArrayList AryLst,DataRow RowToAdd, int cnt, string AddRecID)
		{
			bool found=false;
			// Bug fix: B2006-043
			// skip the first record (record zero)
			int i=1; //0;
			while (!found && (i= 0)
						{
							extTbl.Rows.Add((DataRow)ExtAryLst[ExtAryLstIdx]);
						}
						else
						{
							// Create empty set extension record
							DataRow newdatarow = extTbl.NewRow();
							newdatarow["RECID"] = AryLstRecID;
							newdatarow["COMMENT"] = System.DBNull.Value; // (Comment!=null)&&(Comment!="")?Comment:System.DBNull.Value;
							newdatarow["REV"] = System.DBNull.Value;
							newdatarow["PC"] = System.DBNull.Value;
							newdatarow["TDSTAMP"] = System.DBNull.Value;
							extTbl.Rows.Add(newdatarow);
						}
					}
				}
				TheSetFile.DB_Data = tbl.DataSet;
				if (hasextensions)
				{
					TheSetExtFile.DB_Data = extTbl.DataSet;
				}
			}
			catch (Exception e)
			{
				MessageBox.Show(e.Message,"Error writing Enhanced Procedures' Set File");
				return;
			}
			return;
		}
		void UpdateSlaveSetFile()
		{
			VEO_ProcSet ps = (VEO_ProcSet) parentObj;
			bool updateDTS = true;
			string MasterDir = "";
			string PathToMaster = "";
			string PathToSlave = ps._curDirectory + "\\" + ps._Location;
			// InMaster() will return the MasterSetPath
//			if (InApproved() || InMaster(MasterDir)) return;
			if (ps.isApproved || ps.InMaster(ref MasterDir)) return;
			
			// For Updating the SET.DBF file in Slave procedure sets...
			// If the user had approved the slave procedure set:
			//   - don't copy the Date/Time field from the master
			// Else
			//   - copy the Date/Time field from the master
			if (File.Exists(PathToSlave + "\\APPROVED\\SET.DBF"))
				updateDTS = false;
			PathToMaster = ps.CurDirectory + "\\" + MasterDir;
			if (SlaveSetFileUpToDate(PathToMaster,PathToSlave)) 
				return; // Set file is up to date
			ArrayList SlaveSetList = new ArrayList();
			ArrayList MasterSetList = new ArrayList();
			ArrayList NewSlaveSetList = new ArrayList();
			int SlaveIdx = 0, MasterIdx = 0; //, NewSlaveIdx=0;
			int SlaveCnt, MasterCnt; //, NewCnt;
			DataRow SlaveRow, MasterRow; //, NewRow;
			string strMasterRecID; //,strSlaveRecID,strNewRecID;
			SlaveCnt = PopulateSetArrayList(PathToSlave,SlaveSetList);
			MasterCnt = PopulateSetArrayList(PathToMaster,MasterSetList);
//			if (ps.hasExtensions)
//				SlvExtCnt = PopulateSetExtArrayList(PathToSlave,SlvSetExtList);
			// Update the first record
			MasterRow = (DataRow)MasterSetList[0];
			strMasterRecID = MasterRow["RECID"].ToString();
			if ((InThisArrayList(strMasterRecID,SlaveSetList,0,SlaveCnt)) == 0)
			{
				//Update the first record
				SlaveRow = (DataRow)SlaveSetList[0];
				string MasterNumberField = MasterRow["NUMBER"].ToString();
				string SlaveNumberField = SlaveRow["NUMBER"].ToString();
				SlaveRow["NUMBER"] = MasterNumberField;
				NewSlaveSetList.Add(SlaveRow);
			}
			else
			{
				//Copy first record from master
				NewSlaveSetList.Add(MasterRow);
			}
			for(MasterIdx = 1; MasterIdx < MasterCnt; MasterIdx++)
			{
				MasterRow = (DataRow)MasterSetList[MasterIdx];
				strMasterRecID = MasterRow["RECID"].ToString();
				SlaveIdx = InThisArrayList(strMasterRecID,SlaveSetList,1,SlaveCnt);
				if (SlaveIdx > -1)
				{
					// Update Slave set record
					SlaveRow = (DataRow)SlaveSetList[SlaveIdx];
					SlaveRow["TITLE"] = MasterRow["TITLE"];
					SlaveRow["NUMBER"] = MasterRow["NUMBER"];
					SlaveRow["FORMAT"] = MasterRow["FORMAT"];
					if (updateDTS)
					{
						SlaveRow["DATE"] = MasterRow["DATE"];
						SlaveRow["TIME"] = MasterRow["TIME"];
					}
					NewSlaveSetList.Add(SlaveRow);
					// remove this item from the Slave list
					SlaveSetList.RemoveAt(SlaveIdx);
					SlaveCnt--;
				}
				else
				{
					// save new entry
					NewSlaveSetList.Add(MasterRow);
				}
			}
			// remove the deleted slave procedures
			for (SlaveIdx=1; SlaveIdx < SlaveCnt; SlaveIdx++)
			{
				SlaveRow = (DataRow)SlaveSetList[SlaveIdx];
				string filename = SlaveRow["ENTRY"].ToString();
				// Remove the data files for this procedure
				RemoveProcedureFiles(PathToSlave,filename);
				// Remove the transitions references
				vdb_TransUsage Tusage = new vdb_TransUsage(PathToSlave);
				string procnum = SlaveRow["NUMBER"].ToString();
				string WhereStr = "WHERE [FROMNUMBER] = \'" +	procnum.Replace("'","''") + "\' OR [TONUMBER] = \'"+ procnum.Replace("'","''") + "\'";
//				string WhereStr = "WHERE [FROMNUMBER] = \'" +	procnum + "\'";
				DataSet TransDataSet = Tusage.GetNotSorted(WhereStr);
				DataTable tbl = TransDataSet.Tables[0];
				int numrows = tbl.Rows.Count;
				foreach (DataRow row in tbl.Rows)
				{
					row.Delete();
				}
				// remove the deleted Trans Usage records
				if (tbl.Rows.Count > 0)
					Tusage.DB_Data = tbl.DataSet;
				// Remove the RO references
				vdb_ROUsage ROusage = new vdb_ROUsage(PathToSlave);
				WhereStr = "WHERE NUMBER = '" + procnum.Replace("'","''") + "'";
				DataSet RODataSet = ROusage.GetNotSorted(WhereStr);
				DataTable roTbl = RODataSet.Tables[0];
				foreach (DataRow row in roTbl.Rows)
				{
					row.Delete();
				}
				// remove the deleted RO usage records
				if (roTbl.Rows.Count >0)
					ROusage.DB_Data = roTbl.DataSet;
			}
			// Write the new SET.DBF file
			WriteUpdatedSetFile(PathToSlave,NewSlaveSetList,null,false);
		}
		static bool SlaveSetFileUpToDate(string MasterPath, string SlavePath)
		{
			bool rtnval = true;
			string MasterSetFile = MasterPath+"\\set.dbf";
			string SlaveSetFile = SlavePath+"\\set.dbf";
			if (File.Exists(MasterSetFile))
			{
				if (File.Exists(SlaveSetFile))
				{
					rtnval = (File.GetLastWriteTimeUtc(MasterSetFile) <=
						File.GetLastWriteTimeUtc(SlaveSetFile));
				}
				else 
					rtnval = false;
			}
			return rtnval;
		}
		static void RemoveProcedureFiles(string SlavePath, string FileName)
		{
			FileInfo[] fiArr;
			DirectoryInfo cur = new DirectoryInfo(SlavePath);
			// check for RTFFILES directory, skip this part if it doesn't exist.
			DirectoryInfo tstrtf = new DirectoryInfo(SlavePath+"\\RTFFILES");
			if (tstrtf.Exists)
			{
				fiArr = tstrtf.GetFiles(FileName+".*");
		
				// print out the names of the directories
				foreach (FileInfo fi in fiArr)
				{
					fi.Delete();
				}
			}
			fiArr = cur.GetFiles(FileName+".*");
			foreach (FileInfo fi in fiArr)
			{
				fi.Delete();
			}
		}
		public VEO_Proc GetProcFromNum(string procnum)
		{
			foreach (Object obj in Children)
			{
				VEO_Proc prc = (VEO_Proc) obj;
				if (prc._Prcnum.ToUpper() == procnum.ToUpper())
					return prc;
			}
			return null;  //not found
		}
		public string GetSectionNumAndTitle(string procnum, string stp)
		{
			// get to the list of procedures and find the procedure for the input
			// procedure number.
			string retstr = null;
			VEO_Proc prc = GetProcFromNum(procnum);
			vdb_Proc dbprc=null;
			// using the database name, do a select to get the section number & title.
			try 
			{
				dbprc = new vdb_Proc(prc._Location+".dbf");
				string wherestr = "STEP LIKE '" + stp.Substring(0,1) + "%' AND SEQUENCE LIKE ' %'";
				DataSet accSet = dbprc.GetNotSorted(wherestr);
				DataTable tbl = accSet.Tables[0];
				if (tbl.Rows.Count<1) return null;
				DataRow dr = tbl.Rows[0];
				string txt = dr["TEXT"].ToString();
				string title = txt.Substring(0,(txt.LengthSECTITLEBUFSZ+15)
				{
					int len = (txt.Length-85 0)
				{
					// create the lib doc to get it's title, then loop through those
					// that already are in the list to see if this title is already
					// there.
					VEO_LibDoc tmp = new VEO_LibDoc(fi.FullName, this, false);
					bool inlist = false;
					foreach (Object obj in Children)
					{
						VEO_LibDoc ld = (VEO_LibDoc) obj;
						//create the lib doc to get it's title, but only add it to the
						// children list if it's unique.
						if (ld._Title == tmp._Title) 
						{
							inlist = true;
							break;
						}
					}
					if (inlist == false) Children.Add(tmp);
				}
			}
			if (Children.Count==0)IsEmpty=true;
			return true;
		}
		
		public override Object MakeNewChild()
		{
			string comment = null;
			VEO_LibDoc ld = null;
			int MAXLIBDOCS=10000;
			VEO_ProcSet ps = (VEO_ProcSet) parentObj;
			ps.Open();
			// now get a unique file name
			OpenFileDialog openFileDialog1 = new OpenFileDialog();
			openFileDialog1.InitialDirectory = Directory.GetCurrentDirectory();
			openFileDialog1.Filter = "rtf files (*.rtf)|*.rtf|All files (*.*)|*.*" ;
			openFileDialog1.FilterIndex = 0 ;
			openFileDialog1.RestoreDirectory = true ;
			string rtffile=null;
			if(openFileDialog1.ShowDialog() == DialogResult.OK)
			{
				rtffile = openFileDialog1.FileName;
				//currentpath = rtffile.Substring(0,rtffile.LastIndexOf("\\"));
				// first open & read to verify that it is an rtf file.
				StreamReader myReader = new StreamReader(rtffile);// Open file
				int nbytes;
				char [] tbuf = new char[17];
				if((nbytes = myReader.Read(tbuf,0,16))<11)	// read some
				{
					myReader.Close();
					MessageBox.Show("File must be an RTF file","Library Document Error");
				}
				else
				{
					myReader.Close();
					string str = new string(tbuf);
					if (str.IndexOf("{\\rtf1\\ansi",0)<0)
					{
						MessageBox.Show("File must be an RTF file","Library Document Error");
						return null;
					}
				}
				// Make a unique title name
				int i=0;
				bool used=true;
				string newlibtitle = null;
				while(used)
				{
					newlibtitle = "NewLibDoc" + i.ToString();
					bool found=false;
					foreach (Object obj in Children)
					{
						VEO_LibDoc lld = (VEO_LibDoc) obj;
						if (lld._Title == newlibtitle) 
						{
							found=true;
							break;	
						}
					}
					if(!found)
						used=false;
					else
						i++;
				}
				comment = "New Library Document";
				// if the 'RTFFILES directory doesn't exist, create it here.
				if (Directory.Exists("RTFFILES")!=true) Directory.CreateDirectory("RTFFILES");
				// now find a unique file name.
				i=0;
				string buf1 = "DOC_" + i.ToString("D4") + ".lib";
				string buf2 = "RTFFILES\\DOC_" + i.ToString("D4") + ".lib";
				bool fexists=true;
				while(fexists)
				{
					if ((File.Exists(buf1) || File.Exists(buf2)) && i0)
				{
					xbuf = new char[comment.Length];
					xbuf = comment.ToCharArray();
					bw.Write(xbuf);
					bw.Write((byte)0);
				}
				//now append the selected file to the new lib file
				FileStream fsorig = new FileStream(rtffile,FileMode.Open,FileAccess.Read);
				using (BinaryReader br = new BinaryReader(fsorig,Encoding.ASCII))
				{
					byte ac;
					bool done = false;
					while(done==false)
					{
						if (br.PeekChar() >0)
						{
							ac = br.ReadByte();
							bw.Write(ac);
						}
						else
							done=true;
					}
				}
				bw.Close();
				fsorig.Close();
				fsnew.Close();
				if (!File.Exists(pthname))
				{
					MessageBox.Show("Could not create rtf file","Library Document Error");
					return null;
				}
				
				ld = new VEO_LibDoc(Directory.GetCurrentDirectory() + "\\"+pthname,this,true);
			}
			return ld;		
		}
		public void Approve(string src, string dst)
		{
			string[] fis = Directory.GetFiles(src,"DOC_*.LIB");
			foreach (string sfi in fis)
			{
				FileInfo fi = new FileInfo(sfi);
				if (!File.Exists(dst+"\\"+fi.Name)) fi.CopyTo(dst+"\\"+fi.Name,true);
			}
			string rtfsrc = src + "\\rtffiles\\";
			string rtfdst = dst + "\\rtffiles\\";
			fis = Directory.GetFiles(rtfsrc,"DOC_*.LIB");
			foreach (string sfi in fis) 
			{
				FileInfo fi = new FileInfo(sfi);
				fi.CopyTo(rtfdst+"\\"+fi.Name,true);
			}
		}
		public override bool SaveChild(Object obj)
		{
			VEO_LibDoc ld = (VEO_LibDoc)obj;
			bool succeed = ld.SaveNew(null);
			if (succeed == true) ld.parentObj = this;
			return succeed;
		}
		public override void DoListView(ListView veoListView)
		{
			ListViewItem item=null;
			veoListView.Columns.Add("Location", 120, HorizontalAlignment.Left);
			veoListView.Columns.Add("Title", 300, HorizontalAlignment.Left);
			
			for (int i=0; i