/*********************************************************************************************
 * Copyright 2004 - Volian Enterprises, Inc. All rights reserved.
 * Volian Enterprises - Proprietary Information - DO NOT COPY OR DISTRIBUTE
 * ------------------------------------------------------------------------------
 * $Workfile: Proc.cs $     $Revision: 26 $
 * $Author: Jsj $   $Date: 9/25/06 2:08p $
 *
 * $History: Proc.cs $
 * 
 * *****************  Version 26  *****************
 * User: Jsj          Date: 9/25/06    Time: 2:08p
 * Updated in $/LibSource/VEObject
 * allow user to move a procedure in the approved list
 * 
 * *****************  Version 25  *****************
 * User: Jsj          Date: 8/30/06    Time: 10:04a
 * Updated in $/LibSource/VEObject
 * Added Multi Procedure Data Checker
 * 
 * *****************  Version 24  *****************
 * User: Kathy        Date: 5/01/06    Time: 11:17a
 * Updated in $/LibSource/VEObject
 * Fix B2006-018: single quote in proc number causes problem on data
 * request
 * 
 * *****************  Version 23  *****************
 * User: Kathy        Date: 2/23/06    Time: 10:52a
 * Updated in $/LibSource/VEObject
 * Fix B2006-006, use actual database field for column mode in set file
 * during approve selected. Also, don't crash on saving of column mode
 * from procedure properties if value was null
 * 
 * *****************  Version 22  *****************
 * User: Kathy        Date: 8/16/05    Time: 2:56p
 * Updated in $/LibSource/VEObject
 * B2005-030: error if missing ndx
 * 
 * *****************  Version 21  *****************
 * User: Kathy        Date: 7/28/05    Time: 2:08p
 * Updated in $/LibSource/VEObject
 * for mod proc number, copy data into/from correct file number for
 * approve ind
 * 
 * *****************  Version 20  *****************
 * User: Kathy        Date: 7/18/05    Time: 10:55a
 * Updated in $/LibSource/VEObject
 * Lib doc transition reference may be upper or lower case
 * 
 * *****************  Version 19  *****************
 * User: Kathy        Date: 6/21/05    Time: 7:25a
 * Updated in $/LibSource/VEObject
 * clear variable for edit from approve
 * 
 * *****************  Version 18  *****************
 * User: Kathy        Date: 5/25/05    Time: 10:32a
 * Updated in $/LibSource/VEObject
 * Allow edits for tmpchg
 * 
 * *****************  Version 17  *****************
 * User: Kathy        Date: 5/19/05    Time: 11:07a
 * Updated in $/LibSource/VEObject
 * speed up approve
 * 
 * *****************  Version 16  *****************
 * User: Kathy        Date: 5/11/05    Time: 9:29a
 * Updated in $/LibSource/VEObject
 * approve all selectinto
 * 
 * *****************  Version 15  *****************
 * User: Kathy        Date: 4/26/05    Time: 10:23a
 * Updated in $/LibSource/VEObject
 * Check for dbnull on dates
 * 
 * *****************  Version 14  *****************
 * User: Kathy        Date: 4/21/05    Time: 10:22a
 * Updated in $/LibSource/VEObject
 * remove upgrade2005 define
 * 
 * *****************  Version 13  *****************
 * User: Jsj          Date: 4/15/05    Time: 9:44a
 * Updated in $/LibSource/VEObject
 * added check to see if proc number exists in set file before adding to
 * dependency list
 * 
 * *****************  Version 12  *****************
 * User: Jsj          Date: 4/08/05    Time: 10:55a
 * Updated in $/LibSource/VEObject
 * comment about enabling slave proc number/title changes
 * 
 * *****************  Version 11  *****************
 * User: Jsj          Date: 4/07/05    Time: 11:17a
 * Updated in $/LibSource/VEObject
 * Unit Specific call
 * 
 * *****************  Version 10  *****************
 * User: Kathy        Date: 3/22/05    Time: 10:03a
 * Updated in $/LibSource/VEObject
 * Remove chgbar
 * 
 * *****************  Version 9  *****************
 * User: Kathy        Date: 3/08/05    Time: 1:50p
 * Updated in $/LibSource/VEObject
 * Approval
 * 
 * *****************  Version 8  *****************
 * User: Kathy        Date: 1/31/05    Time: 11:06a
 * Updated in $/LibSource/VEObject
 * Fix B2005-005 (connection & delete directory errors). also, fix icon
 * 
 * *****************  Version 7  *****************
 * User: Kathy        Date: 11/12/04   Time: 8:43a
 * Updated in $/LibSource/VEObject
 * B2004-056: no date update on set file record when procedure data change
 * 
 * *****************  Version 6  *****************
 * User: Jsj          Date: 8/20/04    Time: 9:02a
 * Updated in $/LibSource/VEObject
 * Disable the main form when we spawn off to  VFW.EXE so the user cannot
 * select a different tree node while we are bringing up the procedure
 * editor.
 * 
 * *****************  Version 5  *****************
 * User: Jsj          Date: 8/19/04    Time: 11:37a
 * Updated in $/LibSource/VEObject
 * fixed typo in transition usage message displayed when trying to delete
 * a procedure
 * 
 * *****************  Version 4  *****************
 * User: Jsj          Date: 8/16/04    Time: 4:23p
 * Updated in $/LibSource/VEObject
 * RECID not incremented inserting new procdure
 * 
 * *****************  Version 3  *****************
 * User: Kathy        Date: 8/10/04    Time: 3:42p
 * Updated in $/LibSource/VEObject
 * duplicate file names on new proc & proc has wrong rec ids on new
 * 
 * *****************  Version 2  *****************
 * User: Kathy        Date: 8/04/04    Time: 11:12a
 * Updated in $/LibSource/VEObject
 * stop two vfw sessions from spawning on quick 2 double clicks
 * 
 * *****************  Version 1  *****************
 * User: Kathy        Date: 7/27/04    Time: 8:53a
 * Created in $/LibSource/VEObject
 *********************************************************************************************/
using System;
using System.Windows.Forms;
using System.ComponentModel;
using System.Diagnostics;
using System.Text;
using System.Data;
using System.IO;
using System.Messaging;
using System.Runtime.InteropServices;
using System.Collections;
using Utils;
using VDB;
using VDB_Proc;
using VDB_Set;
using VDB_TransUsage;
using VDB_ROUsage;
using VEMessageNS;
using ROFST_FILE;
namespace VEObject
{
	/// 
	/// VEO_Proc support procedure functionality
	/// 
	public class VEO_Proc: VEO_Base
	{
		public VEO_ProcExt procExt;
		public string origDate;
		public string origTime;
		public string _Prcnum;
		public string recid;
		public ProcColumnOptions _ProcColumn;
		public string _ProcCode;
		public string origProcCode;
		public DataRow pdatarow;			// row from set file.
		private string[] DBExtensions={"DBF","DBT","NDX","SCR","FIX","APL","PGN","TCX","LLF","RTF","INF"};
		private bool[] AppExtensions={false,false,false,false,true,false,true,false,false,false,true};
		public string _ModInfo;
		protected string tmpTitle;
		protected string tmpProcNum;
		protected ProcColumnOptions tmpProcCol;
		protected bool changeProcNum;
		protected bool changeTitle;
		protected bool changeProcCol;
		private string PrevDirectory;
		private Process myProcess;
		private Form mainForm;
		private bool activeEdit;    // flag that vfw is currently being brought up - don't do twice, if delay
		public VEO_Proc(string ilocaltitle, string ipath, string iprcnum, string irecid, VEO_Base.ProcColumnOptions format, string iprccode, DataRow dr, VEO_DummySet dset, bool inew)
		{
			activeEdit=false;
			iconStates = new int[5] {26,26,26,26,26};
			procExt=null;
			_Title = ilocaltitle;
			_Location = ipath;
			_Prcnum = iprcnum;
			_ProcCode = iprccode;
			origProcCode = _ProcCode;
			_ProcColumn=(VEO_Base.ProcColumnOptions)format;
			recid = irecid;
			pdatarow = dr;
			parentObj = dset;
			
			usrRunTime = dset.usrRunTime;
			if(!inew)
			{
				if (dr["DATE"] is System.DBNull)
				{
					origDate = null;
					origTime = null;
				}
				else
				{
					origDate = dr["DATE"].ToString().PadRight(8,' ');
					origTime = dr["TIME"].ToString().PadRight(5,' ');
				}
				SetModString(dr["INITIALS"].ToString(),origDate,origTime);
				DTI.SetDateTimeInit=origDate+origTime+dr["INITIALS"].ToString().PadRight(5,' ');
			}	
			isNew = inew;
			changeProcNum=false;
			changeTitle=false;
			changeProcCol=false;
			VEObjectType = (int)VEObjectTypesDefs.Procedure;
			LoadLockInfo();
			icon = iconStates[(int) Lock.LockStatus];
		}
		[Description("FileName"),Category("Procedure"),ReadOnly(true)]public string File_Name
		{
			get{return _Location;}
			set{_Location=value;}
		}
		[Description("Modification Information"),Category("Procedure"),ReadOnly(true)]public string Modification_Information
		{
			get{return _ModInfo;}
			set{_ModInfo=value;}
		}
		[Description("Procedure Number"),Category("Procedure"),EditorAttribute(typeof(VESymbDlg), typeof(System.Drawing.Design.UITypeEditor))]public string Procedure_Number
		{
			get
			{
				if(!changeProcNum)
					return _Prcnum;
				else
					return tmpProcNum;
			}
			set
			{
				changeProcNum=true;
				tmpProcNum=value;
			}
		}
		[Description("Procedure Title"),Category("Procedure"),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"),Category("Procedure")]public ProcColumnOptions Procedure_Column
		{
			get
			{
				if(!changeProcCol)
					return _ProcColumn;
				else
					return tmpProcCol;
			}
			set
			{
				changeProcCol=true;
				tmpProcCol=value;
			}
		}
		private void SetModString(string person, string sdt, string tm)
		{
			string outtm=null;
			string outdt=null;
			DateTime dt;
			if (tm!=null && tm!="")outtm=tm.Substring(0,2)+":"+tm.Substring(2,2);
			if (sdt !=null && sdt != "")
			{
				dt = System.Convert.ToDateTime(sdt);
				outdt = dt.ToShortDateString();
			}
			_ModInfo = person + "   " + outdt + "   " + outtm;
		}
		private bool IsInSet(string fname)
		{
			VEO_DummySet ds = (VEO_DummySet) parentObj;
			VEO_Proc prc = null;
			foreach (Object chld in ds.Children)
			{
				prc = (VEO_Proc)chld;
				if (prc._Location == fname)return true;
			}
			return false;
		}
		private void SetUpNewFileName()
		{
			int i=0;
			StringBuilder newname = new StringBuilder();
			if(!isOpen) Open();
			while(i==0 || (File.Exists(newname.ToString())||IsInSet(newname.ToString())))
			{
				newname.Remove(0,newname.Length);
				newname.Append("PROC");
				string tmp = i.ToString();
				newname.Append(i.ToString("d3"));
				newname.Append(".dbf");
				i++;
			}
			this._Location = newname.ToString().Substring(0,7);
		}
		public override bool PropertiesDlg(Object parent)
		{
			bool retval = false;
			PrcProperties propdlg;
			if (isNew) SetUpNewFileName();
			propdlg = new PrcProperties(parent, this, procExt);
			if (propdlg.ShowDialog() == DialogResult.OK)
			{
				SetModString(pdatarow["INITIALS"].ToString(),pdatarow["DATE"].ToString(),pdatarow["TIME"].ToString());
				retval=true;
			}
			else this.Restore();
			propdlg = null;
			return retval;
		}
		
		public override void Restore()
		{
			changeProcNum=false;
			changeTitle=false;
			changeProcCol=false;
		}
		public override string GetTreeNodeText()
		{
			VEO_DummySet dset = (VEO_DummySet) this.parentObj;
			string UnitSpecPrcNum = ROFST_FILE.ROProcessTools.UnitSpecific(Procedure_Number,0,0,dset.LargestNumber); 
//			return Procedure_Number + "  " + Title;
			return UnitSpecPrcNum + "  " + Title;
		}
		public override bool Open()
		{
			isOpen = true;
			PrevDirectory = Directory.GetCurrentDirectory();
			VEO_DummySet ps = (VEO_DummySet) this.parentObj;
			Directory.SetCurrentDirectory(ps._Location);
			return true;
		}
		// The close method resets, if necessary from any multi-user settings and
		// positions back to the datapath directory (which is a level above the 
		// current level)
		public override bool Close()
		{
			isOpen = false;
			Directory.SetCurrentDirectory(PrevDirectory);
			return true;
		}
		
#if Upgrade2005_Print
		public override bool Read(bool ChkForChldOnly)
		{
			VEO_DummySet ds = (VEO_DummySet) parentObj;
			VEO_ProcSet ps = (VEO_ProcSet) ds.parentObj;
			string pth = ps._curDirectory + "\\" + ps._Location + "\\" + this._Location + ".dbf";
			if (ChkForChldOnly)
			{
				try
				{
//					vdb_Proc dbprc = new vdb_Proc(pth);
//					int cnt = dbprc.GetCount("WHERE [SEQUENCE] like ' %'");
//					if (cnt>0)
//					{
						VEO_Section sct = new VEO_Section("XX", "XXXX", "TEMP", "XX", "0XXXXXXX"); //, this, true);
						this.Children.Add(sct);
//					}
				}
				catch (Exception e)
				{
					MessageBox.Show("Could not get count of sections " + e.Message);
					return false;
				}
			}
			else
			{
				try
				{
					vdb_Proc dbprc = new vdb_Proc(pth);
					DataSet sectset = dbprc.GetSortedByStepSeqType("WHERE [SEQUENCE] like ' %'");
					/* see if in order, assuming they are because of get sorted query.. */
					foreach (DataRow row in sectset.Tables[0].Rows)
					{
						// get properties of section & then create a section.
						string Step = row["STEP"].ToString();
						string Sequence = row["SEQUENCE"].ToString();
						string Txt = row["TEXT"].ToString();
						string Type = row["TYPE"].ToString();
						string RecID = row["RECID"].ToString();
						VEO_Section sct = new VEO_Section(Step, Sequence, Txt, Type, RecID, this, false);
						Children.Add(sct);
					}
				}
				catch (Exception e)
				{
					MessageBox.Show("Error reading sections for " + this._Prcnum + ", " + e.Message);
					return false;
				}
			}
#else
		public override bool Read(bool dummy)
		{
			//load procs from set.dbf
#endif
			return true;
		}
		public override bool EditNode()
		{
			if(!isOpen) Open();
			if (!activeEdit)
			{
				ExecVfw(null);
				activeEdit=true;
			}
			return true;
		}
		public void ExecVfw(string appendarg)
		{
			StringBuilder sb = new StringBuilder();
			sb.Append("/c start /separate /w ");
			sb.Append(this.usrRunTime.ExeAdjust("@vfw.exe"));
			sb.Append(" /u-");
			sb.Append(this.usrRunTime.UserID); //user login/initials
			sb.Append(" -o");
			sb.Append(this.usrRunTime.sec.userid.ToString());
			sb.Append(" -i");   // do initials
			sb.Append(this.usrRunTime.sec.initials);
			sb.Append(" -s\"");
			sb.Append(this.usrRunTime.syspath);
			sb.Append("\\vesam.opt\" -w");
			sb.Append(System.Convert.ToString(VEMessage.Handle_16bit,16));
			if (appendarg !=null && appendarg=="t") 
				sb.Append(" -t");
			else if (appendarg !=null && appendarg=="a")
				sb.Append(" -a");
			sb.Append(" -new");
			
			// execute vfw using cmd because process was not creating the vfw process in
			// its own memory space, i.e. only one copy of vfw came up even if two browsers
			// tried to spawn it. 
			myProcess = new Process();
			myProcess.StartInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
			myProcess.StartInfo.FileName = "cmd";
			myProcess.StartInfo.Arguments = sb.ToString();
			myProcess.StartInfo.UseShellExecute = true;
			myProcess.EnableRaisingEvents = true;
			myProcess.Exited += new System.EventHandler(MyExitFunc);
			// When vfw exits, 'MyExitFunc' method gets called from the above eventhandler 
			// where form is made visible again & locking/connecting is checked.
			
			try
			{
				IntPtr handle = 
					System.Diagnostics.Process.GetCurrentProcess().MainWindowHandle;
				mainForm = (Form)Form.FromHandle(handle);
				mainForm.Enabled = false;
				
				myProcess.Start();
			}
			catch (Win32Exception e)
			{
				MessageBox.Show(e.Message + ". Error on load of vfw.");
			}		
		}
		private void MyExitFunc(object sender, System.EventArgs e)
		{
			mainForm.Visible = true;
			mainForm.Enabled = true;
			TreeView tv = null;
			foreach (Control ctl in mainForm.Controls)
			{
				if (ctl is TreeView) tv = (TreeView)ctl;
			}
			if (tv != null) tv.Focus();
			VEO_DummySet ds = (VEO_DummySet) parentObj;
			VEO_ProcSet ps = (VEO_ProcSet) ds.parentObj;
			// enter the connection (reenter). This will check for changes in locking, etc.
			ps.Connection.Enter(false);
			if (ps.Lock.LockStatus==VENetwork.Status.LockPending) ps.Lock.LockStatus=VENetwork.Status.Locked;
			ps.icon = ps.iconStates[(int)ps.Lock.LockStatus];
			ps.treeNode.ImageIndex = ps.icon;
			ps.treeNode.SelectedImageIndex = ps.icon;
			mainForm = null;
			activeEdit=false;
			ps.AppSelForEdit=null;
		}
		// see if the procedure can be deleted...
		private bool canDelete()
		{
			// check for transitions to this procedure. If they exist, make
			// up a search result list & use vfw to resolve.
			VEO_DummySet pds = (VEO_DummySet) this.parentObj;
			VEO_ProcSet ps = (VEO_ProcSet) pds.parentObj;
			string pth = ps._curDirectory+"\\"+ps.Location+"\\tran.dbf";
			vdb_TransUsage transusg = new vdb_TransUsage(pth);
			DataSet ds = transusg.GetSortedByToTrans("[TONUMBER] = \'"+this._Prcnum.Replace("'","''")+"\'");
			if (ds.Tables[0].Rows.Count !=0) 
			{
				bool is_ext=false;
				foreach(DataRow dr in ds.Tables[0].Rows)
				{
					if (dr["FROMNUMBER"].ToString() != this._Prcnum)
					{
						is_ext=true;
						break;
					}
				}
				if (is_ext)
				{
					MessageBox.Show("Delete Operation failed!\n\nYou need to remove transition references to this procedure.\n\nThe procedure editor will now display with a list of the transition locations.");
					ExecVfw("t");
					return false;
				}
			}
			return true;
		}
		public override bool Delete()
		{
			if (!isOpen) Open();
			// first see if the procedure can be deleted (if the procedure has 
			// transitions to it, it cannot be deleted). If so, do it.
			if (canDelete()==false) return false;
			
			VEO_DummySet pds = (VEO_DummySet) this.parentObj;
			VEO_ProcSet ps = (VEO_ProcSet) pds.parentObj;
			//Remove the transitions 'from' in the usage file.
			string pth = ps._curDirectory+"\\"+ps.Location+"\\tran.dbf";
			vdb_TransUsage transusg = new vdb_TransUsage(pth);
			DataSet ds = transusg.GetSortedByFromTrans("[FROMNUMBER] = \'"+this._Prcnum.Replace("'","''")+"\'");
			int ndr = ds.Tables[0].Rows.Count;
			foreach (DataRow dr in ds.Tables[0].Rows) dr.Delete();
			// if deleted any, need to save data & pack database
			if (ndr>0) 
			{
				transusg.DB_Data = ds.Tables[0].DataSet;
				transusg.Pack();
			}
			// now, do the same for RO references
			pth = ps._curDirectory+"\\"+ps.Location+"\\usagero.dbf";
			vdb_ROUsage rousg = new vdb_ROUsage(pth);
			ds = rousg.GetSortedByProc("[NUMBER] = \'"+this._Prcnum.Replace("'","''")+"\'");
			ndr = ds.Tables[0].Rows.Count;
			foreach (DataRow dr in ds.Tables[0].Rows)dr.Delete();
			if (ndr>0) 
			{
				rousg.DB_Data = ds.Tables[0].DataSet;
				rousg.Pack();
			}
	
			// remove procedure files & related rtffiles
			foreach(string str in DBExtensions)
			{
				// status update function - count);
				string filename = pds._Location + "\\" + this._Location + "." + str;
				if (File.Exists(filename)) File.Delete(filename);
			}
			RemoveAccessoryFiles(this._Location,"wpfiles");
			RemoveAccessoryFiles(this._Location,"rtffiles");
			// delete the record if the above goes ok.
			pdatarow.Delete();
			VEO_DummySet dset = (VEO_DummySet) this.parentObj;
			dset.vdbSet.DB_Data = pdatarow.Table.DataSet;
			// if there was a set extension record. Delete it too.
			if(ps.hasExtensions)
			{
				procExt.drow.Delete();
				dset.vdbSetExt.DB_Data = procExt.drow.Table.DataSet;
				procExt=null;
			}
			// if parent dummy set only has this child, set its icon to empty
			if (dset.Children.Count<=1) IsEmpty = true;
			// Note that the database is not getting packed - so pack it, and
			// then re-read in the data for the procs (from the parent node).
			int whichone=0;
			for (int i=0;iptlength?ptlength:tmpTitle.Length);
				pdatarow["TITLE"] = tmpTitle;
				_Title = tmpTitle;
				changeTitle=false;
				dchange=true;
				if (tmpTitle.Length+1 > dset.LargestTitleForMenu)
				{
					dset.LargestTitleForMenu = tmpTitle.Length+1;
					dchnglarge=true;
				}
			}
			if (changeProcNum && (string)pdatarow["NUMBER"]!=tmpProcNum)
			{
				if(tmpProcNum.Length>20) tmpProcNum= tmpProcNum.Substring(0,20);
				oldnumber=_Prcnum;
				newnumber=tmpProcNum;
				pdatarow["NUMBER"] = tmpProcNum;
				_Prcnum = tmpProcNum;
				dchange=true;
				if (tmpProcNum.Length+1 > dset.LargestNumber)
				{
					dset.LargestNumber = tmpProcNum.Length+1;
					dchnglarge=true;
				}
				if ((tmpProcNum.Substring(0,1)!=" ") && tmpProcNum.Length+1>dset.LargestNumberForMenu)
				{
					dset.LargestNumberForMenu = tmpProcNum.Length+1;
					dchnglarge= true;
				}
			}
			
			int itmpcol = (int)Procedure_Column+1;
			string stmpcol=itmpcol.ToString();
			// check that the internal temporary column wasn't set to a default value of 2, 
			// this is set when the FORMAT field = null or 0. The Browser (and original DMAS)
			// did not look at the format file value PMODE, as it should, to determine
			// the default. This cannot be fixed at this time because during the format files
			// are not read/parsed to get the value of PMODE.
			bool deflt = (pdatarow["FORMAT"] is System.DBNull || (string)pdatarow["FORMAT"]=="0")&&stmpcol=="2";
			bool datadiff=false;
			if (pdatarow["FORMAT"] is System.DBNull)
			{
				if (stmpcol!="2") datadiff=true;
			}
			else
				datadiff = (string)pdatarow["FORMAT"]!=stmpcol;
			if (changeProcCol && datadiff && !deflt)
			{
				pdatarow["FORMAT"] = stmpcol;
				_ProcColumn=Procedure_Column;
				changeProcCol=false;
				dchange=true;
			}
			if(origProcCode != _ProcCode)
			{
				pdatarow["PROCCODE"] = _ProcCode;
				dchange=true;
			}
			if(dchange)
			{
				try
				{
					// modify the first record if the largest string length changed.
					if (dchnglarge)
					{
						DataRow recidrow = pdatarow.Table.Rows[0];
						string padstr1 = dset.LargestNumber.ToString("d2").PadLeft(2,'0');
						string padstr2 = dset.LargestNumberForMenu.ToString("d2").PadLeft(2,'0');
						string padstr3 = dset.LargestTitleForMenu.ToString("d2").PadLeft(2,'0');
						recidrow["NUMBER"] = padstr1 + " " + padstr2 + " " + padstr3; 
					}
					dset.vdbSet.DB_Data = pdatarow.Table.DataSet;
				}
				catch (Exception e)
				{
					MessageBox.Show(e.Message);
					return false;
				}
			}
			// see if this has a setext to save....
			
			if (pset.hasExtensions)
			{
				bool ret = this.procExt.Write(dset);
				if (!ret) return false;
			}
			// if the procedure number was changed, then need to update usage files
			// with the new procnumber
			if (changeProcNum && (newnumber != oldnumber))
			{
				//Remove the transitions 'from' in the usage file.
				string pth = pset._curDirectory+"\\"+pset.Location+"\\tran.dbf";
				vdb_TransUsage transusg = new vdb_TransUsage(pth);
				transusg.UpdateProcNumber(oldnumber,newnumber);
				transusg=null;
				pth = pset._curDirectory+"\\"+pset.Location+"\\usagero.dbf";
				vdb_ROUsage rousage = new vdb_ROUsage(pth);
				rousage.UpdateProcNumber(oldnumber,newnumber);
				rousage=null;
				changeProcNum=false;
			}
			return true;
		}
		// Make an initial dummy step.
		static void CreateInitStep(vdb_Proc prc)
			{
			// update the recid
			DataTable tbl = prc.DB_Data.Tables[0];
			DataRow recidrow = tbl.Rows[0];
			string tmprecid = recidrow["RECID"].ToString();
			int irecid = System.Convert.ToInt32(tmprecid.Substring(2,6));
			irecid++;
			tmprecid = tmprecid.Substring(0,2)+irecid.ToString("d6");
			recidrow["RECID"]=tmprecid;
			// add the new row for the first section
			DataRow pdatarow = tbl.NewRow();
			pdatarow["RECID"] = "00000002";
			pdatarow["STEP"] = "A1";
			pdatarow["SEQUENCE"] = "S";
			pdatarow["TEXT"] = "Dummy Step";
			pdatarow["TYPE"] = "01";
			DateTime tm = System.DateTime.Now;
			pdatarow["DATE"] = tm.ToString("MM/dd/yyyy");
			pdatarow["TIME"] = tm.ToString("HHmm") + ":";
			tbl.Rows.Add(pdatarow);
			prc.DB_Data = pdatarow.Table.DataSet;
		}
		// Make an initial procedure step section.
		static void CreateInitSection(vdb_Proc prc)
		{
			// update the recid
			DataTable tbl = prc.DB_Data.Tables[0];
			DataRow recidrow = tbl.Rows[0];
			string tmprecid = recidrow["RECID"].ToString();
			int irecid = System.Convert.ToInt32(tmprecid.Substring(2,6));
			irecid++;
			tmprecid = tmprecid.Substring(0,2)+irecid.ToString("d6");
			recidrow["RECID"]=tmprecid;
			// add the new row for the first section
			DataRow pdatarow = tbl.NewRow();
			pdatarow["RECID"] = "00000001";
			pdatarow["STEP"] = "A0";
			pdatarow["SEQUENCE"] = " 1X";
			pdatarow["TEXT"] = "Procedure Steps";
			pdatarow["TYPE"] = "01";
			DateTime tm = System.DateTime.Now;			
			pdatarow["DATE"] = tm.ToString("MM/dd/yyyy");
			pdatarow["TIME"] = tm.ToString("HHmm") + ":";
			tbl.Rows.Add(pdatarow);
			prc.DB_Data = pdatarow.Table.DataSet; //save the changed dataset info
		}
		// Create a new procedure.
		public override bool SaveNew(string dummy)
		{
			try 
			{
				VEO_DummySet ds = (VEO_DummySet) this.parentObj;
				VEO_ProcSet ps = (VEO_ProcSet) ds.parentObj;
				// check for a valid name.
				// create the new procedure file, create the initial section & initial step.
				vdb_Proc newprc = new vdb_Proc("");
				newprc.CreateTable(this._Location);
				CreateInitSection(newprc);		// Make procedure section
				CreateInitStep(newprc);			// Add a dummy step
				// Add the record to the set file.
				DataTable pdatatable = ds.vdbSet.DB_Data.Tables[0];
				DataRow recidrow = pdatatable.Rows[0];
				string currecid = recidrow["RECID"].ToString();
				string tmprecid = currecid;
				int irecid = System.Convert.ToInt32(tmprecid.Substring(2,6));
				irecid++;
				tmprecid = tmprecid.Substring(0,2)+irecid.ToString("d6");
				recidrow["RECID"]=tmprecid;
				pdatarow = pdatatable.NewRow();
			
				// check whether to trim the number & title.
				if (Procedure_Number.Length>20)Procedure_Number=Procedure_Number.Substring(0,20);
				if (Title.Length>78)Title=Title.Substring(0,78);
				pdatarow["RECID"] = currecid;
				pdatarow["TITLE"] = Title;
				pdatarow["NUMBER"] = Procedure_Number;
				int itmpcol = (int)Procedure_Column+1;
				pdatarow["FORMAT"] = itmpcol.ToString();
				pdatarow["ENTRY"] = _Location;
				DateTime tm = System.DateTime.Now;
				pdatarow["DATE"] = tm.ToString("MM/dd/yyyy");
				pdatarow["TIME"] = tm.ToString("HHmm") + ":";
				pdatarow["PROCCODE"] = _ProcCode;
				pdatatable.Rows.Add(pdatarow);
				// See if this proc's data changes the largest numbers stored
				// in the first record.
				bool chg = false;
				if (Procedure_Number.Length+1 > ds.LargestNumber) 
				{
					chg=true;
					ds.LargestNumber = Procedure_Number.Length+1;
				}
				if ((Procedure_Number.Substring(0,1)!=" ") && (Procedure_Number.Length+1>ds.LargestNumberForMenu)) 
				{
					chg=true;
					ds.LargestNumberForMenu = Procedure_Number.Length+1;
				}
				if (Title.Length+1 > ds.LargestTitleForMenu)
				{
					chg=true;
					ds.LargestTitleForMenu = Title.Length+1;
				}
				if (chg)
				{
					string padstr1 = ds.LargestNumber.ToString("d2").PadLeft(2,'0');
					string padstr2 = ds.LargestNumberForMenu.ToString("d2").PadLeft(2,'0');
					string padstr3 = ds.LargestTitleForMenu.ToString("d2").PadLeft(2,'0');
					recidrow["NUMBER"] = padstr1 + " " + padstr2 + " " + padstr3;
				}
				ds.vdbSet.DB_Data = pdatarow.Table.DataSet;
				_Title=Title;
				_Prcnum=Procedure_Number;
				_ProcColumn=Procedure_Column;
				changeTitle=false;
				changeProcCol=false;
				changeProcNum=false;
				if (ps.hasExtensions) this.procExt.SaveNew(this, tmprecid);
				isNew=false;
				ds.icon = ds.iconStates[0];  // in case it was empty
			}
			catch (Exception e)
			{
				MessageBox.Show(e.Message,"Could not perform database functions required to add procedure.");
				return false;
			}
			return true;
		}
		public override bool updateROValues()
		{
			// update the ro values for this procset, so get parent's (dummy set), parent
			VEO_DummySet ds = (VEO_DummySet) this.parentObj;
			VEO_ProcSet ps = (VEO_ProcSet) ds.parentObj;
			return ps.updateROValues();
		}
		public override void CleanTransitionsAndROsUsages(int clntype,string ProcName) 
		{
			// clean, send this procname to procedure set to spawn the clean
			VEO_DummySet ds = (VEO_DummySet) this.parentObj;
			VEO_ProcSet ps = (VEO_ProcSet) ds.parentObj;
			ps.CleanTransitionsAndROsUsages(clntype,this._Prcnum);
		}
		public override void ApproveProcedures(int aptype, ArrayList procs)
		{
			VEO_DummySet ds = (VEO_DummySet) this.parentObj;
			VEO_ProcSet ps = (VEO_ProcSet) ds.parentObj;
			if (aptype == 0)
				ps.ApproveProcedures(aptype,null);
			else if (procs.Count>0)
				ps.ApproveProcedures(aptype,procs);
			else
			{
				ArrayList prcs = new ArrayList();
				prcs.Add(this);
				ps.ApproveProcedures(aptype,prcs);
			}
		}
		public override void DataIntegrityCheck(string ProcName) 
		{
			// send this procname to procedure set to spawn the DataCheck
			VEO_DummySet ds = (VEO_DummySet) this.parentObj;
			VEO_ProcSet ps = (VEO_ProcSet) ds.parentObj;
			ps.DataIntegrityCheck(this._Prcnum);
		}
		private void MoveFixFile(string apname, string appath, VEO_ProcSet ps)
		{
			string[] FxExt = {".FIX",".FX1",".FX2",".FX3",".FX4",".FX5",".FX6",".FX7",".FX8"};
			string apvname = (apname==null || apname == "")?_Location:apname;
			foreach (string str in FxExt)
				ps.CopyAnyFileToApproved(_Location+str,apvname+str,appath);
		}
		private void FixProcDateAndTime(string apname, VEO_ProcSet ps)
		{
			string[] extensions = {".dbf",".dbt",".ndx"};
			string appath = null;
			string wd = null;
			string apvname = (apname==null||apname=="")?_Location:apname;
			foreach (string str in extensions)
			{
				appath = ps.GetApprovedDirectory("\\") + apvname + str;
				wd = _Location + str;
				FileInfo fi_app = new FileInfo(appath);
				FileInfo fi_wd = new FileInfo(wd);
				fi_app.LastWriteTime = fi_wd.LastWriteTime;
				File.Copy(appath, wd, true);
				fi_app = new FileInfo(appath);
				fi_wd = new FileInfo(wd);
				fi_app.LastWriteTime = fi_wd.LastWriteTime;
				fi_wd.LastWriteTime = fi_app.LastWriteTime;
			}	
		}
		public void Copy(string srcdir, string destdir, string prcnum, string prcfile)
		{
			VEO_DummySet ds = (VEO_DummySet) parentObj;		
			VEO_ProcSet ps = (VEO_ProcSet) ds.parentObj;
			// if there is a new procedure to add for a modified proc number, 
			// prcfile will not == the _Location. Use it instead.
			string loc=null;
			if (prcfile != _Location)
				loc = prcfile;
			else
				loc = _Location;
			string destfile = destdir + "\\" + loc;
			string srcfile = (srcdir==null)? _Location: srcdir + "\\" + _Location;
			if (!File.Exists(srcfile+".dbf")) return;
			if (File.Exists(destfile+".dbf")) File.Delete(destfile+".dbf");
			if (File.Exists(destfile+".ndx")) File.Delete(destfile+".ndx");
			if (File.Exists(destfile+".dbt")) File.Delete(destfile+".dbt");
			
			vdb_Proc dbprc = null;
			try
			{		
				dbprc = new vdb_Proc(srcfile+".dbf");
				// Use SelectIntoNewTable to create the table & copy it over using
				// sql select * into ... Then just make an instance of the table, this
				// will set up indexes and inf files as necessary.
				dbprc.SelectIntoNewTable(srcdir+"\\"+destfile);
				string cwd = Directory.GetCurrentDirectory();
				Directory.SetCurrentDirectory(destdir);
				vdb_Proc apprc = new vdb_Proc(loc+".dbf");
				Directory.SetCurrentDirectory(cwd);
				apprc=null;
			}
			catch (Exception e)
			{
				MessageBox.Show("Could not copy " + _Location + " to approved." + e.Message);
				return;
			}
			// now copy over rtf files by finding the procedure records that are attachments.
			DataSet accset=null;
			try
			{
				accset = dbprc.GetSortedByStepSeqType("WHERE [SEQUENCE] like ' %'");
			}
			catch (Exception e)
			{
				MessageBox.Show("Could not copy over accessory page files " + this._Prcnum + ", " + e.Message);
				return;
			}
			string rtfsrcdir = srcdir + "\\rtffiles\\" + this._Location + ".A";
			string rtfdestdir = destdir + "\\rtffiles\\" + prcfile + ".A";
			foreach (DataRow dr in accset.Tables[0].Rows)
			{
				bool accpage = (char.IsLetter(dr["STEP"].ToString()[1]))?true:false;
				if (accpage)
				{
					string stpno = (string) dr["STEP"].ToString();
					char accsect = stpno[0];
					string tmpext = (accsect-'@').ToString("D2");
					if (File.Exists(rtfsrcdir+tmpext))
						File.Copy(rtfsrcdir+tmpext,rtfdestdir+tmpext,true);
				}
			}
			for (int i=0;iptlength?ptlength:_Title.Length);
			foundRow["NUMBER"] = _Prcnum;
			foundRow["ENTRY"]= _Location==ApProcFile?_Location:ApProcFile;
			foundRow["FORMAT"] = pdatarow["FORMAT"];  // if modified, pdatarow has current
			foundRow["PROCCODE"] = _ProcCode;
			// if removing change bars, update the working draft date/time stamp
			// for this procedure.
			if (ps.RmChgBarOnApp) 
			{
				ps.UpdateSetDTI(false,pdatarow);
				ds.vdbSet.DB_Data = pdatarow.Table.DataSet;
			}
			
			vdbSet.DB_Data = foundRow.Table.DataSet;  // write it out
			// now make sure we update the largestnumber data in the set header
			
			recidrow = pdatarow.Table.Rows[0];
			string tmplarge = recidrow["NUMBER"].ToString();
			if (tmplarge == null || tmplarge == "") tmplarge = "00000000";
			bool update=false;
			if (ds.LargestNumber != System.Convert.ToInt32(tmplarge.Substring(0,2)))
			{
				update=true;
				tmplarge = ds.LargestNumber.ToString("d2").PadLeft(2,'0') + tmplarge.Substring(2,tmplarge.Length-2);
			}
			if (ds.LargestNumberForMenu != System.Convert.ToInt32(tmplarge.Substring(3,2)))
			{
				update = true;
				tmplarge = tmplarge.Substring(0,3) + ds.LargestNumberForMenu.ToString("d2").PadLeft(2,'0') + tmplarge.Substring(5,tmplarge.Length-5);
			}
			if (ds.LargestTitleForMenu != System.Convert.ToInt32(tmplarge.Substring(6,2)))
			{
				update = true;
				tmplarge = tmplarge.Substring(0,6) + ds.LargestTitleForMenu.ToString("d2").PadLeft(2,'0');
			}
			if (update)
			{
				recidrow["NUMBER"] = tmplarge;
				vdbSet.DB_Data = recidrow.Table.DataSet;  // write it out
			}
		}
		// pass in approved path & approved procedure number, i.e. original procedure
		// number - if the proc number is modified, this stores original otherwise
		// it is the current proc number. (if this is a new procedure then ApProcNum=null.
		public void FixTransitionReferences(string ApprovedPath, string ApProcNum)
		{
			string appath=ApprovedPath+"\\tran.dbf";
			VEO_DummySet ds = (VEO_DummySet) parentObj;
			VEO_ProcSet ps = (VEO_ProcSet) ds.parentObj;
			try
			{
				vdb_TransUsage atransusg = new vdb_TransUsage(appath);
				// if this procedure existed before this approval, then remove transitions-from
				// approved version (they'll be added back later). 
				if (ApProcNum != null)
				{				
					DataSet adset = atransusg.GetSortedByFromTrans("[FROMNUMBER] = \'"+ApProcNum.Replace("'","''")+"\'");
					int ndr = adset.Tables[0].Rows.Count;
					if (ndr > 0)
					{
						int errs = atransusg.DeleteSelected("[FROMNUMBER] = \'"+ApProcNum.Replace("'","''")+"\'");
						if (errs>0)
						{
							MessageBox.Show("Error resolving transition records");
							return;
						}
						atransusg.Pack();
					}
					// if there was a change in procedure number, then update the transitions-to in
					// the approved version.
					if (ApProcNum!=_Prcnum)
					{
						adset.Clear();
						adset = atransusg.GetSortedByToTrans("[TONUMBER] = \'"+ApProcNum.Replace("'","''")+"\'");
						ndr = adset.Tables[0].Rows.Count;
						foreach (DataRow dr in adset.Tables[0].Rows) dr["TONUMBER"]=_Prcnum;
						if (ndr>0) atransusg.DB_Data = adset.Tables[0].DataSet;
					}
					adset.Clear();
					adset=null;
				}
				// now update the approved transitions from data based on data in the working
				// draft.
				vdb_TransUsage transusg = new vdb_TransUsage(ps._curDirectory+"\\"+ps.Location+"\\tran.dbf");
				DataSet wdset = transusg.GetSortedByFromTrans("[FROMNUMBER] = \'"+_Prcnum.Replace("'","''")+"\'");
				if (wdset.Tables[0].Rows.Count>0)
				{
					int errs = transusg.InsertInto(ps._curDirectory+"\\"+ps.Location+"\\"+appath,"[FROMNUMBER] = \'"+_Prcnum.Replace("'","''")+"\'");
					if (errs>0)
					{
						MessageBox.Show("Error resolving transition records");
						return;
					}	
					// Now update the working draft 'OLDTO' field to contain the current
					// working draft 'TONUMBER'+'TOSEQUENCE' fields.
					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.FROMNUMBER=\'");
					qry.Append(_Prcnum.Replace("'","''"));
					qry.Append("\' AND tran.TOSEQUENCE IS NOT NULL)");
					// This one handles the libdocs (their TOSEQUENCE is null).
					bool success  = transusg.UpdateUsing(qry.ToString());
					if (!success) MessageBox.Show("Error When Updating Transition history");
					qry.Length=0;
					qry.Append("UPDATE TRAN SET TRAN.OLDTO = [TONUMBER] & Space(20-Len([TONUMBER])+12) ");
					qry.Append("WHERE (tran.FROMNUMBER=\'");
					qry.Append(_Prcnum.Replace("'","''"));
					qry.Append("\' AND tran.TOSEQUENCE IS NULL)");
					success  = transusg.UpdateUsing(qry.ToString());
					if (!success) MessageBox.Show("Error When Updating Transition history");
				}
				wdset.Dispose();
				transusg=null;
				atransusg=null;
			}
			catch (Exception e)
			{
				MessageBox.Show("Could not approve transition usages for " + _Prcnum + ", "+e.Message);
			}
		}
		
#if Upgrade2005_Print
#else
		public override void AddToTree(TreeNode parentnd)
		{
		}
		public override bool Expand(TreeNode parentnd)
		{	
			return true;
		}
#endif
		public override bool mnuAllowUpdRO()
		{
			VEO_DummySet ds = (VEO_DummySet) this.parentObj;
			VEO_ProcSet ps = (VEO_ProcSet) ds.parentObj;
			if (ps.isApproved||ps.IsEmpty||ps.isTempChange) return false;
			return (amILockedByMe());
		}
		
		public override bool mnuAllowClean()
		{
			VEO_DummySet ds = (VEO_DummySet) this.parentObj;
			VEO_ProcSet ps = (VEO_ProcSet) ds.parentObj;
			if (ps.isApproved||ps.IsEmpty) return false;
			if (amILockedByMe()==false) return false;
			if ((ps.accessFlags&Security.CLEAN)==Security.CLEAN) return true;
			return false;
		}
		public override bool mnuAllowDataCheck()
		{
			VEO_DummySet ds = (VEO_DummySet) this.parentObj;
			VEO_ProcSet ps = (VEO_ProcSet) ds.parentObj;
			if (ps.isApproved||ps.IsEmpty) return false;
			if (amILockedByMe()==false) return false;
			if ((ps.accessFlags&Security.CLEAN)==Security.CLEAN) return true;
			return false;
		}
		public override bool mnuAllowChgDef()
		{
			VEO_DummySet ds = (VEO_DummySet) this.parentObj;
			VEO_ProcSet ps = (VEO_ProcSet) ds.parentObj;
			if (ps.IsEmpty) return false;
			return(amILockedByMe());
		}
		public override bool mnuAllowNew()
		{
			return false;
		}
		public override bool mnuAllowApprove()
		{
			VEO_DummySet ds = (VEO_DummySet) this.parentObj;
			VEO_ProcSet ps = (VEO_ProcSet) ds.parentObj;
			if (amILockedByMe()==false) return false;
			if ((ps.isApproved == false) && (ps.isTempChange==false)) return true;
			return false;
		}
		public override bool mnuAllowApproveSel()
		{
			VEO_DummySet ds = (VEO_DummySet) this.parentObj;
			VEO_ProcSet ps = (VEO_ProcSet) ds.parentObj;
			if (ps.isApproved || ps.IsEmpty || ps.isTempChange) return false;
			if (amILockedByMe()==false) return false;
			if (ps.isSetApproved && ((ps.accessFlags&Security.APPROVESINGLE)==Security.APPROVESINGLE)) return true;
			return false;
		}
		public override bool mnuAllowApproveAll()
		{
			bool allowit=false;
			bool allowonlyonce=false;
			VEO_DummySet ds = (VEO_DummySet) this.parentObj;
			VEO_ProcSet ps = (VEO_ProcSet) ds.parentObj;
			if (ps.isApproved || ps.IsEmpty || ps.isTempChange) return false;  // cannot approve an approved set
			if (amILockedByMe()==false) return false;
			if ((ps.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 && ps.isSetApproved) return false;
			if (allowit) return true;
			return false;
		}
		// the following method is used by various other methods to determine whether modifications
		// can be made to the procedure.
		private bool AllowMods()
		{
			VEO_DummySet ds = (VEO_DummySet) this.parentObj;
			VEO_ProcSet ps = (VEO_ProcSet) ds.parentObj;
			if (ps.isApproved == true) return false;
			if (amILockedByMe()==false) return false;
// Right now we are allowing the slave's procedure number and title be changed
// - but it will be wiped out when/if the master's set file changes.
// - If we want to NOT allow changes to the slave's procedure number and title
//   then uncomment the following line. - jsj 04/08/05
//			if (ps._ProcType == ProcTypeOptions.Slave) return false;
			if ((ps.accessFlags&Security.ADDMODDEL)==Security.ADDMODDEL) return true;
			return false;
		}
		public override bool mnuAllowDelete()
		{
			return AllowMods();
		}
		public override bool canEdit()
		{
			return AllowMods();
		}
		// determine whether drag/drop can occur.
		public override bool canDoDragDrop()
		{
			// allow user to change order in approved set list
			//			return AllowMods();    
			VEO_DummySet ds = (VEO_DummySet) this.parentObj;
			VEO_ProcSet ps = (VEO_ProcSet) ds.parentObj;
			if (amILockedByMe()==false) return false;
			if (ps._ProcType == ProcTypeOptions.Slave) return false;
			if ((ps.accessFlags&Security.ADDMODDEL)==Security.ADDMODDEL) return true;
			return false;
		}
	}
}