/*********************************************************************************************
 * Copyright 2004 - Volian Enterprises, Inc. All rights reserved.
 * Volian Enterprises - Proprietary Information - DO NOT COPY OR DISTRIBUTE
 * ------------------------------------------------------------------------------
 * $Workfile: RO.cs $     $Revision: 6 $
 * $Author: Kathy $   $Date: 5/02/06 9:46a $
 *
 * $History: RO.cs $
 * 
 * *****************  Version 6  *****************
 * User: Kathy        Date: 5/02/06    Time: 9:46a
 * Updated in $/LibSource/VEObject
 * B2006-018: ro usages for procnums with single quote
 * 
 * *****************  Version 5  *****************
 * User: Jsj          Date: 6/02/05    Time: 11:36a
 * Updated in $/LibSource/VEObject
 * fix for approving with conditional ROs and code cleanup
 * 
 * *****************  Version 4  *****************
 * User: Kathy        Date: 5/19/05    Time: 11:08a
 * Updated in $/LibSource/VEObject
 * speed up approve
 * 
 * *****************  Version 3  *****************
 * User: Jsj          Date: 5/17/05    Time: 12:00p
 * Updated in $/LibSource/VEObject
 * Approve graphic fix
 * 
 * *****************  Version 2  *****************
 * User: Jsj          Date: 3/10/05    Time: 4:02p
 * Updated in $/LibSource/VEObject
 * hooks to new namespace for RO FST file
 * 
 * *****************  Version 1  *****************
 * User: Kathy        Date: 3/08/05    Time: 1:51p
 * Created in $/LibSource/VEObject
 * Approval
 *********************************************************************************************/
using System;
using System.IO;
using System.Data;
using System.Windows.Forms;
using System.Collections;
using Utils;
using ROFST_FILE;
using VDB_ROUsage;
using VlnStatus;
namespace VEObject
{
	/// 
	/// Summary description for ROFST. Provides support/interface to/from RO.fst file.
	/// 
	public class ROFST : ROFST_File
	{
		// constructor loads ro.fst databases
		public ROFST(string path):base(path)
		{
		}
		~ ROFST()
		{
		}
		public void CopyImagesToApproved(string appdir, VlnStatusMessage StatMsgWindow)
		{
			for(int i=0;i0) return true;
			return false;
		}
		private void CopyROFile(string fname, string ApprovedDir)
		{
			PrivateProfile ropathINI = new PrivateProfile("PROC.INI");
			string ropath = ropathINI.Attr("RO Defaults","ROPATH");
			if (ropath == null || ropath == "") ropath = "..\\RO";
			string src = ropath + "\\" + fname;
			string dst = ApprovedDir + "\\" + fname;
			if (File.Exists(src)) 
			{
				File.Copy(src,dst,true);
				FileInfo fi_src = new FileInfo(src);
				FileInfo fi_dst = new FileInfo(dst);
				fi_dst.LastWriteTime = fi_src.LastWriteTime;
			}
			else
				MessageBox.Show("Could not copy " + src);
		}
		private long CalculatePromsDate(DateTime imgdate)
		{
			/* 
			 * do some conversion so that comparison can be made on date/time 
			 * stored on image data from ro.fst to a datetime from .net.
			 * Proms had it in seconds since 00:00:00 1/1/1970.
			 * .NET has it in ticks since 00:00:00 1/1/1
			 */ 
			DateTime promsdt = new DateTime(1970,1,1,0,0,0); // Jan 1, 1970
			// Convert the promsdt to UTC (GMT)
			DateTime promsdtU = promsdt.ToUniversalTime();
			long promsdtU_num = promsdtU.Ticks / 10000000;
			// Convert the image file datetime to UTC
			DateTime imgdateU = imgdate.ToUniversalTime();
			long imgdateu_num = imgdateU.Ticks / 10000000;
			/**
			 * Get the time adjustment for the current Time Zone with respect
			 * to the coordinated universal time (UTC) - a.k.a. Greenwich mean time (GMT).
			 * The time gotten for the Jan 1, 1970 is in UTC time, the imgdate time is
			 * in EST.
			 * 
			 * Get the offset time between this time zone and UTC (GMT) time.
			 * Convert the offset to seconds.
			 * Subtract the offset from the UTC time gotten for Jan 1, 1970
			 */
			ThisTimeZone TZ = new ThisTimeZone();
			TimeSpan TimeZoneSpan = TZ.GetUtcOffset(promsdt); // Time Zone offset from UTC
			long TimeZoneAdj = Math.Abs(TimeZoneSpan.Ticks / 10000000); // convert to seconds
			/*
			 * The file date/time and the Jan 1, 1970 adjustment date are in UTC.
			 * Subtract the "Jan 1, 1970" date/time from the file date/time
			 * the add the Time Zone offset to place the date/time value into
			 * local time.
			 */
			long lsec = (imgdateu_num - promsdtU_num) + TimeZoneAdj;
			return lsec;
		}
		public void ApproveGraphicsFile(string fstRec, string appdir, VlnStatusMessage StatMsgWindow)
		{
			long dt;
			// position to Graphics file name
			int nlindx = fstRec.IndexOf("\n"); 
			// Graphics file name
			string fbuf = fstRec.Substring(0,nlindx);
			// Grpahics file date/time (stored in RO.FST)
			dt = System.Convert.ToInt32(fstRec.Substring(nlindx+1,8),16);
			// Add the graphics file extension if needed
			int indx = fbuf.IndexOf(".");
			if (indx<0 || (fbuf.Length>indx+1 && fbuf[indx+1]=='\\'))
			{
				if (DefaultGraphicFileExt[0] != '.') fbuf = fbuf + ".";
				fbuf = fbuf + DefaultGraphicFileExt;
			}
			// if file doesn't exist in approved 
			// or if it is more recent than approved,
			// copy it to approved.
			string appfbuf = appdir + "\\" + fbuf;
			FileInfo app_fi = new FileInfo(fbuf);
			if (!File.Exists(appfbuf) || (CalculatePromsDate(app_fi.LastWriteTime)!=dt))
			{
				if (StatMsgWindow !=null) StatMsgWindow.StatusMessage = "Updating graphic " + fbuf;
				CopyROFile(fbuf,appdir);
			}
		}
		private void ProcessGroupsForImages(string appdir, string tmp,uint x1,string ttl,BinaryReader br,
			uint start, short level, ushort tblid, VlnStatusMessage StatMsgWindow)
		{
			uint id, parid;
			short howmany;
			long wasAt = br.BaseStream.Position;
			br.BaseStream.Seek((long) start, SeekOrigin.Begin);
			id = br.ReadUInt32();
			parid = br.ReadUInt32();
			howmany = br.ReadInt16();
			if (howmany <= 0 && (ttl!=null && ttl!="") && wasused(tblid,id))
			{
				byte bt = br.ReadByte();		// skip type
				bt = br.ReadByte();
				// Read the Graphics File ROFST record
				string dtl = ROFST.GetAsciiString(br);
				// Approve the Graphics file
				ApproveGraphicsFile(dtl, appdir, StatMsgWindow);
			}
			
			// if count in howmany is greater than zero, this must be a group
			// recursively call this to find ros.
			if (howmany>0)
			{
				if (level>=0)
				{
					string [] title = new string [howmany];
					UInt32 [] offset = new UInt32 [howmany];
					UInt16 [] type = new UInt16 [howmany];
					for (int i=0; i0)
							ProcessGroupsForImages(appdir,null,type[i],title[i],br,offset[i],System.Convert.ToInt16(level+1),tblid,StatMsgWindow);
					}
				}
			}
			br.BaseStream.Seek(wasAt,SeekOrigin.Begin);
		}
	}
	public class Usages
	{
		static Usages()
		{
			
		}
		public static int CheckRoReferences(VEO_ProcSet ps, string path, ArrayList al, ArrayList ModROs, string keystr)
		{
			// get usage records for the input string 'keystr' and then check to 
			// see if the RO is in the input Modified list. 
			// If keystr is a lib-doc (i.e. starts with "DOC") then just return the
			// whether there is modified ro in here. 
			// If keystr is a procedure num, check to see if other procedures use this 
			// modified RO and add them to the list of items to approve (al).
			// -1 flags failure on return. Otherwise, return count of those found.
			int retval=0;
			vdb_ROUsage rousg=null;
			DataSet dataset=null;
			string us_path = path + "\\usagero.dbf";
			try
			{
				rousg = new vdb_ROUsage(us_path);
				dataset = rousg.GetSortedByProc("[NUMBER] = \'"+keystr.Replace("'","''")+"\'");
			}
			catch (Exception e)
			{
				MessageBox.Show("Could not get RO usages for this item " + keystr + ", " + e.Message);
				return -1;
			}
			foreach (DataRow dr in dataset.Tables[0].Rows)
			{
				// if we find an RO that's in the ModROs list, then here's where
				// we see if it's used by other procedures too.
				string roid = dr["ROID"].ToString();
				if (roid.Length == 12)
					roid = roid + "0000";
				else if (!roid.EndsWith("0000"))
					roid = roid.Substring(0,12) + "0000";
				ModRO wasModRO = null;
				foreach (ModRO mro in ModROs)
				{
					string tmpROID = mro.roid;
					if (tmpROID.Length == 12)
						tmpROID = tmpROID + "0000";
					if (tmpROID.Equals(roid))
					{
						mro.roid = tmpROID;
						wasModRO = mro;
						mro.IsUsed = true;
						break;
					}
				}
				// if just checking if the library document has any modified ROs, then
				// just return (return with a number greater than 0 to flag that it had
				// modified ROs. Doc is only passed in as the keystr when checking for
				// modified library documents.
				if (keystr.Substring(0,3).ToUpper()=="DOC")
				{
					if (wasModRO != null) return 1;
					return 0;
				}
				// if this was a procedure, then we'll see if other procedures use this.
				if (wasModRO != null)
				{
					us_path = path + "\\approved\\usagero.dbf";
					rousg = null;
					rousg = new vdb_ROUsage(us_path);
					DataSet dataset_prc = null;
					string keyroid = roid.Substring(0,12)+"%";
					try
					{
						dataset_prc = rousg.GetSortedByROID("[ROID] LIKE \'"+keyroid+"\'");
						//dataset_prc = rousg.GetSortedByROID("[ROID] = \'"+roid+"\'");
					}
					catch (Exception e)
					{
						MessageBox.Show("Could not get procedures using modified RO " + roid + ", " + e.Message);
						return -1;
					}
					foreach (DataRow drroid in dataset_prc.Tables[0].Rows)
					{
						// first see if this prpc is already in list of procedures to approve
						// if so, don't add it, but check to be sure this ro is in the conflict
						// list.
						bool inlist = false;
						AppIndItem cur=null;
						foreach (object obal in al)
						{
							AppIndItem aiiobj = (AppIndItem) obal;
							if (aiiobj.Proc._Prcnum == (string)drroid["NUMBER"])
							{
								cur=aiiobj;
								inlist=true;
								break;
							}
						}
						if (!inlist)
						{
							VEO_DummySet ds = (VEO_DummySet) ps.Children[1];
							// find the procedure object to add it the the approve list	
							foreach (object ob in ds.Children)
							{
								VEO_Proc pr = (VEO_Proc) ob;
								if (pr._Prcnum == (string) drroid["NUMBER"])
								{
									cur = new AppIndItem(pr);
									al.Add(cur);
									retval++;
									break;
								}
							}
							if (cur==null)
							{
								retval++;
								cur = new AppIndItem(null);
							}
						}
						// is this ROID already in the conflict list.
						inlist = false;
						foreach (AppConflict aco in cur.ConflictList)
						{
							if (aco.CType == AppConflictTypes.RO)
							{
								AppROConflict raco = (AppROConflict) aco;
								if (raco.ROID == roid) 
								{
									inlist=true;
									break;
								}
							}
						}
						if (!inlist)
						{
							string val1 = (drroid["NUMBER"]==System.DBNull.Value)?null:(string)drroid["NUMBER"];
							string val2 = (drroid["SEQUENCE"]==System.DBNull.Value)?null:(string)drroid["SEQUENCE"];
							AppROConflict roc = new AppROConflict((VEO_DummySet)ps.Children[1],roid, val1, val2,wasModRO.IsImage,wasModRO.Val1,wasModRO.Val2);
							cur.AddConflict(roc);
						}
					}
				}
			}
			return retval;
		}
		// For approve individual, update the approved version with the ro usages for the
		// procedure or library defined by input 'WdNum'. 'ApNum' is the procedure number if
		// this is a procedure - if libdoc this will be same as 'WdNum', in case of change
		// in procedure number.
		public static void FixROUsages(string WdPath, string ApprovedPath, string ApNum, string WdNum)
		{
			string appath=ApprovedPath+"\\usagero.dbf";
			try
			{
				vdb_ROUsage arousg = new vdb_ROUsage(appath);
				// remove ro usages from the approved ro usage file. ApNum will be null
				// if this is a new procedure - in this case we don't need to remove anything
				// from the approved usages file.
				if (ApNum != null)
				{
					DataSet adset = arousg.GetSortedByProc("[NUMBER]=\'"+ApNum.Replace("'","''")+"\'");
					int ndr = adset.Tables[0].Rows.Count;
					if (ndr>0)
					{
						int errs = arousg.DeleteSelected("[NUMBER]=\'"+ApNum.Replace("'","''")+"\'");
						if (errs>0)
						{
							MessageBox.Show("Error resolving transition records");
							return;
						}
						arousg.Pack();
					}
					adset=null;
				}
				// now update the approved ro usages from data based on data in the working
				// draft.
				vdb_ROUsage rousg = new vdb_ROUsage(WdPath+"\\usagero.dbf");
				DataSet wdset = rousg.GetSortedByProc("[NUMBER] = \'"+WdNum.Replace("'","''")+"\'");
				if (wdset.Tables[0].Rows.Count>0)
				{
					int errs = rousg.InsertInto(WdPath+"\\"+ApprovedPath+"\\usagero.dbf","[NUMBER] = \'"+WdNum.Replace("'","''")+"\'");
					if (errs>0)
					{
						MessageBox.Show("Error resolving RO usage records.");
						return;
					}
				}
				wdset.Dispose();
				rousg=null;
				arousg=null;
			}
			catch (Exception e)
			{
				MessageBox.Show("Could not approve ro usages for " + WdNum + ", "+e.Message);
				return;
			}
		}
	}
}