1257 lines
43 KiB
C#

// ========================================================================
// Copyright 2006 - Volian Enterprises, Inc. All rights reserved.
// Volian Enterprises - Proprietary Information - DO NOT COPY OR DISTRIBUTE
// ------------------------------------------------------------------------
// $Workfile: $ $Revision: $
// $Author: $ $Date: $
//
// $History: $
// ========================================================================
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Text;
using System.IO;
using System.Xml.Serialization;
using System.Xml;
using System.Xml.XPath;
using System.Text.RegularExpressions;
using System.Data;
using System.Data.SqlClient;
using Csla;
using Csla.Data;
using Volian.Base.Library;
using JR.Utils.GUI.Forms;
namespace VEPROMS.CSLA.Library
{
public partial class ROFst
{
public static ROFst GetJustROFst(int rOFstID)
{
if (!CanGetObject())
throw new System.Security.SecurityException("User not authorized to view a ROFst");
try
{
ROFst tmp = GetCachedByPrimaryKey(rOFstID);
if (tmp == null)
{
tmp = DataPortal.Fetch<ROFst>(new PKCriteriaJustROFst(rOFstID));
AddToCache(tmp);
}
if (tmp.ErrorMessage == "No Record Found")
{
tmp.Dispose(); // Clean-up ROFst
tmp = null;
}
return tmp;
}
catch (Exception ex)
{
throw new DbCslaException("Error on ROFst.Get", ex);
}
}
[Serializable()]
protected class PKCriteriaJustROFst
{
private int _ROFstID;
public int ROFstID
{ get { return _ROFstID; } }
public PKCriteriaJustROFst(int rOFstID)
{
_ROFstID = rOFstID;
}
}
private void DataPortal_Fetch(PKCriteriaJustROFst criteria)
{
if (_MyLog.IsDebugEnabled) _MyLog.DebugFormat("[{0}] ROFst.DataPortal_Fetch", GetHashCode());
try
{
using (SqlConnection cn = Database.VEPROMS_SqlConnection)
{
ApplicationContext.LocalContext["cn"] = cn;
using (SqlCommand cm = cn.CreateCommand())
{
cm.CommandType = CommandType.StoredProcedure;
cm.CommandText = "getJustROFst";
cm.Parameters.AddWithValue("@ROFstID", criteria.ROFstID);
cm.CommandTimeout = Database.DefaultTimeout;
using (SafeDataReader dr = new SafeDataReader(cm.ExecuteReader()))
{
if (!dr.Read())
{
_ErrorMessage = "No Record Found";
return;
}
ReadData(dr);
}
}
// removing of item only needed for local data portal
if (ApplicationContext.ExecutionLocation == ApplicationContext.ExecutionLocations.Client)
ApplicationContext.LocalContext.Remove("cn");
}
}
catch (Exception ex)
{
if (_MyLog.IsErrorEnabled) _MyLog.Error("ROFst.DataPortal_Fetch", ex);
_ErrorMessage = ex.Message;
throw new DbCslaException("ROFst.DataPortal_Fetch", ex);
}
}
}
public delegate List<string> ROFstInfoROTableUpdateEvent(object sender, ROFstInfoROTableUpdateEventArgs args);
public delegate void ROFstInfoProgressBarRefresh(int value, int max, string text);
public partial class ROFstInfo
{
#region Log4Net
private static readonly log4net.ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
#endregion
[Serializable()]
protected class PKCriteriaJustROFst
{
private int _ROFstID;
public int ROFstID
{ get { return _ROFstID; } }
public PKCriteriaJustROFst(int rOFstID)
{
_ROFstID = rOFstID;
}
}
#region Fields
// this is used by the frmBatchRefresh which is the Adim Tools so that one message is display for a group of procedure sets processed
public static StringBuilder MessageList = null;
private static List<int> DocVersionsNeedingROUpdate = new List<int>();
#endregion
#region Events
public event ROFstInfoROTableUpdateEvent ROTableUpdate;
#endregion
#region Public Methods
public ROFSTLookup GetROFSTLookup(DocVersionInfo dvi, string ovrrideChild = null, bool showLoadingStatus = true)
{
// B2022-107: Display Progress Bar Messages/Statuses when a new ROFST binary file is loaded into the database
return new ROFSTLookup(this.ROFstID, dvi, ovrrideChild, showLoadingStatus);
}
/// <summary>
/// Adds an ro.fst into a sql database.
/// </summary>
/// <param name="rdi" - the Rodb to use as the path for updating the ro.fst, i.e. import from there.
/// <param name="docver" - hook into this doc version></param>
/// <returns>ROFst: Returns the created rofst object</returns>
public static ROFst AddRoFst(RODbInfo rdi, DocVersion docver, ROFstInfoProgressBarRefresh myProgressBarRefresh)
{
string rofstfilepath = rdi.FolderPath + @"\ro.fst";
DirectoryInfo di = new DirectoryInfo(rdi.FolderPath);
if (!di.Exists) return null;
if (!File.Exists(rofstfilepath)) return null;
// check if this rofst has been loaded, i.e. dts on file versus dts in db... if so, just make association with docversion.
ROFst rofst = ROFst.GetByRODbID_DTS(rdi.RODbID, di.LastWriteTimeUtc);
if (rofst != null)
{
docver.DocVersionAssociations.Add(rofst);
docver.Save();
return rofst;
}
byte[] rofstBytes = null; // B2022-026 RO Memory Reduction code - more descriptive name
using (FileStream fsIn = new FileStream(rofstfilepath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
{
using (BinaryReader r = new BinaryReader(fsIn))
{
rofstBytes = r.ReadBytes((int)fsIn.Length);
fsIn.Close();
}
}
using (RODb rodb = RODb.GetJustRoDb(rdi.RODbID))
{
using (ROImageInfoList myROImages = ROImageInfoList.GetByRODbID(rdi.RODbID))
{
Dictionary<string, int> myExistingROImages = BuildROImagesList(myROImages);
List<int> myUnChangedROImages = new List<int>();
List<string> myAddedROImages = new List<string>();
List<string> MyChangedFigureROIDs = new List<string>();
rofst = ROFst.MakeROFst(rodb, rofstBytes, null, di.LastWriteTimeUtc, rdi.UserID);
// Hook this into the current docversion by replacing the rofstid field in the doc version association object:
docver.DocVersionAssociations.Add(rofst);
docver.Save();
// Now load any images in... type 8 - integrated graphics ro type
// B2022-026 RO Memory Reduction code now load the children with a separate call which will get only the Image ROs
ROFSTLookup myLookup = new ROFSTLookup(rofst.ROFstID, DocVersionInfo.Get(docver.VersionID));
ROFSTLookup.rochild[] children = myLookup.GetRoChildrenByType(E_ROValueType.Image);
if (children != null && children.Length > 0)
{
using (ROFstInfo rfi = ROFstInfo.Get(rofst.ROFstID))
{
int cnt = children.Length; // get the total number of RO figures
int curCnt = 0;
rfi.MigrateRoFstGraphics(rdi, children, rodb, rofst, myExistingROImages, myUnChangedROImages, myAddedROImages, MyChangedFigureROIDs, myProgressBarRefresh, cnt, ref curCnt);// TODO: Need to add MyImages
}
}
if (myUnChangedROImages.Count > 0)
using (FigureInfoList fil = FigureInfoList.AddByROFstIDImageIDs(rofst.ROFstID, buildImageIDString(myUnChangedROImages))) ;
return rofst;
}
}
}
// B2022-026 RO Memory Reduction code - pass in the ROFstInfo
public static int RefreshROFst(DocVersionInfo dvi, ROFstInfoProgressBarRefresh myProgressBarRefresh, System.Windows.Forms.TextBox tbStatus, ROFstInfo origROFst)
{
int fixedROs = 0;
if (dvi.DocVersionConfig.SelectedSlave <= 0)
{
myProgressBarRefresh(1, 100, "Update MS Word ROs");
Pdf.DeleteAllDocVersion(dvi.VersionID); // remove word section PDFs to force update of RO values when printed
int i = 0;
foreach (ProcedureInfo proc in dvi.Procedures)
{
DateTime start = DateTime.Now;
ProcedureInfo.ResetROCounters();
myProgressBarRefresh(++i, dvi.Procedures.Count, string.Format("{0} ({1}/{2} ROs {3})", proc.DisplayNumber, i, dvi.Procedures.Count, fixedROs));
ProcedureInfo.RefreshReferenceObjects(proc, origROFst);
fixedROs += ProcedureInfo.ROFixCount;
TimeSpan ts = DateTime.Now - start;
if (tbStatus != null)
tbStatus.AppendText(string.Format("Procedure: {1}{0}, Checked {2} Referenced Objects{0}, Fixed {3} Referenced Objects{0}, Elapsed Seconds:{4}{0}{0}", Environment.NewLine, proc.DisplayNumber, ProcedureInfo.ROCheckCount, ProcedureInfo.ROFixCount, ts.TotalSeconds));
}
}
return fixedROs;
}
//C2022-028 for Admin tool to check for bad RO links
//B2022-144 we now loop through checked procedures list from Admin Tools and call this method for each procedure we want to process
public static int CheckROLinksInThisProcedure(ProcedureInfo proc, System.Windows.Forms.TextBox tbStatus)
{
int FoundBadROLinks = 0;
DocVersionInfo dvi = DocVersionInfo.Get(proc.MyDocVersion.VersionID);
if (dvi.DocVersionConfig.SelectedSlave <= 0)
{
int i = 0;
DateTime start = DateTime.Now;
ProcedureInfo.ResetCheckROLinkCounters();
ProcedureInfo.CheckReferenceObjectsLinks(proc);
FoundBadROLinks += ProcedureInfo.BadROLinksCount;
TimeSpan ts = DateTime.Now - start;
if (tbStatus != null)
tbStatus.AppendText(string.Format("Procedure: {1}{0}, Checked {2} Referenced Objects Links{0}, Found {3} Bad RO Links{0} Elapsed Seconds:{5}{0}{0}", Environment.NewLine, proc.DisplayNumber, ProcedureInfo.CheckROLinksCount, ProcedureInfo.BadROLinksCount, ProcedureInfo.FixedROLinksCount, ts.TotalSeconds));
/*** keep for now - incase we decide to fix RO links later on, this will show the number of RO Links that we fixed
//tbStatus.AppendText(string.Format("Procedure: {1}{0}, Checked {2} Referenced Objects Links{0}, Found {3} Bad RO Links{0}, Fixed {4} Bad RO Links{0} Elapsed Seconds:{5}{0}{0}", Environment.NewLine, proc.DisplayNumber, ProcedureInfo.CheckROLinksCount, ProcedureInfo.BadROLinksCount, ProcedureInfo.FixedROLinksCount, ts.TotalSeconds));
***/
}
return FoundBadROLinks; // return the total number of bad RO links (in step text only) for the entire procedure set
}
// returns the path and file name with Proc Set Name and the completed date/time (used for all update RO calls except for Amin Tool from the V button)
public static string ROUpdateResultsPath(DocVersionInfo dvi)
{
// B2019-032 - call ValidFileName.FixFileName() to clean up the file name.
return Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments) + @"\VEPROMS\ROUpdateReport_" + ValidFileName.FixFileName(dvi.MyFolder.Name.Replace(" ", "_") + "_" + DateTime.Now.ToString("MM-dd-yyyy_HH-mm-ss") + ".txt");
}
// B2022-026 RO Memory Reduction code - moved the call to UpdateROFst() to before we call RefreshROFst
// so that we used the correct ROFstInfo which as the needed event methods set when updated RO Table types
public static ROFst RefreshROFst(DocVersion docver, ROFstInfo origROFst, ROFstInfoProgressBarRefresh myProgressBarRefresh, System.Windows.Forms.TextBox tbStatus)
{
ROFst rofst = null;
rofst = docver.DocVersionAssociations[0].MyROFst;
DocVersionInfo dvi = DocVersionInfo.Get(docver.VersionID);
SetAssociationLastCompleted(docver, string.Empty);
int fixedROs = RefreshROFst(dvi, myProgressBarRefresh, tbStatus, origROFst);
SetAssociationLastCompleted(docver, DateTime.Now.ToString()); // RO Update completed successfully and un-interrupted, save the date/time to the Doc Version Association config
myProgressBarRefresh(100, 100, "RO Update Complete"); // update the progress bar
System.Windows.Forms.Application.DoEvents();
// pop up a message window telling the user the RO Update has completed and how many ROs were updated
// If we are updating RO from the Admin Tools (from the V button) and we are updating more than on procedure set, then just append the "RO Update Complete" text
// To the MessageList. Once completed will all procedure sets, Admin Tools will display one message box with all the results in it.
if (MessageList == null)
FlexibleMessageBox.Show(fixedROs == 0 ? "No ROs Required Updating" : string.Format("{0} ROs Updated for {1}", fixedROs, dvi.MyFolder.Name), "RO Update Complete");
else
MessageList.AppendLine((fixedROs == 0 ? "No ROs Required Updating for " : string.Format("{0} ROs Updated for ", fixedROs)) + dvi.MyFolder.Name);
return rofst;
}
/// <summary>
/// Updates an ro.fst into a sql database.
/// </summary>
/// <param name="rdi" - the Rodb to use as the path for updating the ro.fst, i.e.
/// import from there.
/// <param name="dva" - the association record to modify, i.e. make new rofst
/// the current one.
/// <param name="docver" - hook into this doc version></param>
/// <returns>ROFst: Returns the created rofst object</returns>
// B2022-026 RO Memory Reduction code - removed checks and calls to update the RO values in the text.
// all of the calls aways set the flags to not update the RO values
public static ROFst UpdateRoFst(RODbInfo rdi, DocVersion docver, ROFstInfo origROFst, ROFstInfoProgressBarRefresh myProgressBarRefresh)
{
if (myProgressBarRefresh != null) myProgressBarRefresh(0, 100, "Starting Update");
DirectoryInfo di = new DirectoryInfo(rdi.FolderPath);
string rofstfilepath = rdi.FolderPath + @"\ro.fst";
FileStream fsIn = new FileStream(rofstfilepath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
FileInfo rofstFI = new FileInfo(rofstfilepath);
// check if this rofst has been loaded, i.e. dts on file versus dts in db...
// if so, just make association to existing with docversion.
ROFst rofst = ROFst.GetByRODbID_DTS(rdi.RODbID, rofstFI.LastWriteTimeUtc);
if (rofst != null)
{
// Get a list of figures which have changed content (DTS)
List<string> MyChangedFigureROIDs = null;
if (docver.ROfstLoadingFigures) // B2017-125 see if loading figures was completed
{
ROFSTLookup myLookup = new ROFSTLookup(rofst.ROFstID, DocVersionInfo.Get(docver.VersionID));
MyChangedFigureROIDs = UpdateROFigures(rdi, myProgressBarRefresh, rofst, RODb.GetJustRoDb(rdi.RODbID), myLookup, docver);
}
else
{
MyChangedFigureROIDs = GetChangedFigureROIDs(origROFst, ROFstInfo.GetJustROFst(rofst.ROFstID), DocVersionInfo.Get(docver.VersionID), myProgressBarRefresh);
}
docver.DocVersionAssociations[0].MyROFst = rofst;
SetAssociationLastCompleted(docver, string.Empty);
return rofst;
}
// Read in the rofst & make the rofst record.
// Create an instance of StreamReader that can read characters from the FileStream.
BinaryReader r = new BinaryReader(fsIn);
byte[] ab = r.ReadBytes((int)fsIn.Length);
fsIn.Close();
using (RODb rodb = RODb.GetJustRoDb(rdi.RODbID))
{
rofst = ROFst.MakeROFst(rodb, ab, null, rofstFI.LastWriteTimeUtc, rdi.UserID);
// Hook this into the current docversion by replacing the rofstid field in the doc version association object:
docver.DocVersionAssociations[0].MyROFst = rofst;
SetAssociationROFiguresLoading(docver, "Started"); // B2017-125 flag was we are loading the RO figures
ROFSTLookup myLookup = new ROFSTLookup(rofst.ROFstID, DocVersionInfo.Get(docver.VersionID));
// Keep a list of ROIDs for Images that have changed.
List<string> MyChangedFigureROIDs = UpdateROFigures(rdi, myProgressBarRefresh, rofst, rodb, myLookup, docver);
return rofst;
}
}
public bool IsSetpointDB(int id, DocVersionInfo dvi)
{
ROFSTLookup.rodbi[] dbs = GetROFSTLookup(dvi).GetRODatabaseList(false);
foreach (ROFSTLookup.rodbi rodbi in dbs)
{
if (id == rodbi.dbiID)
return (rodbi.dbiAP.StartsWith("SP"));
}
return false;
}
public ROFst GetJustROFst()
{
return ROFst.GetJustROFst(ROFstID);
}
public List<string> OnROTableUpdate(object sender, ROFstInfoROTableUpdateEventArgs args)
{
if (ROTableUpdate != null) return ROTableUpdate(sender, args);
return null;
}
public static ROFstInfo GetJustROFst(int rOFstID)
{
try
{
ROFstInfo tmp = GetCachedByPrimaryKey(rOFstID);
if (tmp == null)
{
tmp = DataPortal.Fetch<ROFstInfo>(new PKCriteriaJustROFst(rOFstID));
AddToCache(tmp);
}
if (tmp.ErrorMessage == "No Record Found")
{
tmp.Dispose(); // Clean-up ROFstInfo
tmp = null;
}
if (tmp != null)
{
tmp.ClearROLookupBytes();
}
return tmp;
}
catch (Exception ex)
{
throw new DbCslaException("Error on ROFstInfo.Get", ex);
}
}
public ROImageInfo GetROImageByFilename(string filename, ItemInfo myItemInfo)
{
ROImageInfoList images = ROImageInfoList.GetByRODbIDFilename(RODbID, filename);
if (images == null || images.Count == 0)
{
ROWarning(myItemInfo, "Referenced Object Image {0} Missing", filename);
return null;
}
ROImageInfo retval = null;
foreach (ROImageInfo image in images)
{
if (image.DTS > DTS && retval != null) break;
retval = image;
}
if (retval.DTS > DTS)
ROWarning(myItemInfo, "Referenced Object Image {0} newer {1} than RO.FST {2}", filename, retval.DTS.ToShortDateString(), DTS.ToShortDateString());
else
ROWarning(myItemInfo, "Referenced Object Image {0} older {1} then RO.FST {2}", filename, retval.DTS.ToShortDateString(), DTS.ToShortDateString());
return retval;
}
#endregion
#region Private Methods
// Place the date/time of the completed RO Update in the DocVersion association config
// this will tell us if the RO Update was completed, interrupted, or just needs done and whether to make the Update ROs button available
private static void SetAssociationLastCompleted(DocVersion docver, string value)
{
string cfg = docver.DocVersionAssociations[0].Config;
AssociationConfig ac = new AssociationConfig((cfg == null || cfg.Length == 0) ? "<Config />" : cfg);
ac.ROUpdate_LastCompleted = value;
docver.DocVersionAssociations[0].Config = ac.ToString();
docver.Save();
}
// Place the status of loading the RO Figures when updating RO Values
private static void SetAssociationROFiguresLoading(DocVersion docver, string value)
{
string cfg = docver.DocVersionAssociations[0].Config;
AssociationConfig ac = new AssociationConfig((cfg == null || cfg.Length == 0) ? "<Config />" : cfg);
ac.ROUpdate_LoadingFigures = value;
docver.DocVersionAssociations[0].Config = ac.ToString();
docver.Save();
}
private static List<string> UpdateROFigures(RODbInfo rdi, ROFstInfoProgressBarRefresh myProgressBarRefresh, ROFst rofst, RODb rodb, ROFSTLookup myLookup, DocVersion docVer)
{
List<string> MyChangedFigureROIDs = new List<string>();
// Now load any images in... type 8 - integrated graphics ro type
using (ROImageInfoList myROImages = ROImageInfoList.GetByRODbIDNoData(rdi.RODbID))
{
Dictionary<string, int> myExistingROImages = BuildROImagesList(myROImages);
List<int> myUnChangedROImages = new List<int>();
List<string> myAddedROImages = new List<string>();
// B2022-026 RO Memory Reduction code - get only the Image ROs
ROFSTLookup.rochild[] children = myLookup.GetRoChildrenByType(E_ROValueType.Image);
if (children != null && children.Length > 0)
{
using (ROFstInfo rfi = ROFstInfo.Get(rofst.ROFstID))
{
int cnt = children.Length; // get the total number of RO figures
int curCnt = 0;
rfi.MigrateRoFstGraphics(rdi, children, rodb, rofst, myExistingROImages, myUnChangedROImages, myAddedROImages, MyChangedFigureROIDs, myProgressBarRefresh, cnt, ref curCnt);// TODO: Need to add MyImages
}
}
// Add references for existing RO Images to the Figure table (Figure table relates ro.fst with its images)
if (myUnChangedROImages.Count > 0)
using (FigureInfoList fil = FigureInfoList.AddByROFstIDImageIDs(rofst.ROFstID, buildImageIDString(myUnChangedROImages))) ;
}
SetAssociationROFiguresLoading(docVer, string.Empty); // B2017-125 loading RO Figures is completed
return MyChangedFigureROIDs;
}
/// <summary>
/// Get a list of ROIDs for figures that have changed content. This is only used when the contents of a figure
/// is changed without changing the filename.
/// </summary>
/// <param name="origROFst">Original ROFST Object</param>
/// <param name="rofst">Current ROFST Object</param>
/// <param name="docver">DocVersion (Working Draft)</param>
/// <returns>List of ROIDs which can be used to refresh MSWord PDFs</returns>
private static List<string> GetChangedFigureROIDs(ROFstInfo origROFst, ROFstInfo rofst, DocVersionInfo docver, ROFstInfoProgressBarRefresh myProgressBarRefresh)
{
// Need to create a list of ROIDs for figures which have changed
List<string> ChangedFiles = GetChangedFigures(origROFst, rofst, myProgressBarRefresh);
// Get ROID associated with FileNames
List<string> ROIDs = GetROIDsFromLookup(rofst, ChangedFiles, docver);
return ROIDs;
}
/// <summary>
/// Find all of the ROIDs associated with files that have changed
/// </summary>
/// <param name="rofst">Current ROFST Object</param>
/// <param name="ChangedFiles">List of Changed Files</param>
/// <param name="docver">DocVersion (Working Draft)</param>
/// <returns>List of FIleNames with changed content</returns>
private static List<string> GetROIDsFromLookup(ROFstInfo rofst, List<string> ChangedFiles, DocVersionInfo docver)
{
List<string> roids = new List<string>();
// B2022-088: [JPR] Find Doc Ro button not working in Word Sections
// B2022-098: [JPR] ROs not being resolved in Word Sections
if(rofst != null && ChangedFiles != null && ChangedFiles.Count > 0)
{
ROFSTLookup myLookup = new ROFSTLookup(rofst.ROFstID, docver);
// B2022-026 RO Memory Reduction code - get only the Image type of ROs
ROFSTLookup.rochild[] children = myLookup.GetRoChildrenByType(E_ROValueType.Image);
if (children != null && children.Length > 0)
{
for (int i = 0; i < children.Length; i++)
{
string filename = children[i].value;
filename = filename.Substring(0, filename.IndexOf('\n'));
if (ChangedFiles.Contains(filename))
{
roids.Add(children[i].roid);
}
}
}
}
return roids;
}
/// <summary>
/// Get a List of figures which have changed
/// </summary>
/// <param name="origROFst">Original ROFST Object</param>
/// <param name="rofst">Current ROFST Object</param>
/// <returns>List of Files which have changed (DTS)</returns>
private static List<string> GetChangedFigures(ROFstInfo origROFst, ROFstInfo rofst, ROFstInfoProgressBarRefresh myProgressBarRefresh)
{
if (origROFst.ROFstFigures == null) return null;
Dictionary<string, int> orig = new Dictionary<string, int>();
int i = 0;
foreach (FigureInfo fi in origROFst.ROFstFigures)
{
string key = fi.ROImage_FileName ?? fi.MyROImage.FileName;
myProgressBarRefresh(++i, origROFst.ROFstFigures.Count, "Original " + key);
if (!orig.ContainsKey(key)) orig.Add(key, fi.ImageID);
}
// B2018-032 Don't crash if there are no figures
if (rofst.ROFstFigures == null)
return null;
i = 0;
foreach (FigureInfo fi in rofst.ROFstFigures)
{
string key = fi.ROImage_FileName ?? fi.MyROImage.FileName;
myProgressBarRefresh(++i, rofst.ROFstFigures.Count, "Current " + key);
if (orig.ContainsKey(key) && orig[key] == fi.ImageID) orig.Remove(key);
}
List<string> changedFigures = new List<string>();
i = 0;
foreach (string key in orig.Keys)
{
myProgressBarRefresh(++i, orig.Count, "Compare " + key);
changedFigures.Add(key);
}
return changedFigures;
}
private static Dictionary<string, int> BuildROImagesList(ROImageInfoList myROImages)
{
Dictionary<string, int> myRoImagesList = new Dictionary<string, int>();
if (myROImages != null)
{
foreach (ROImageInfo myROImage in myROImages)
{
myRoImagesList.Add(ROImageKey(myROImage.FileName, myROImage.DTS), myROImage.ImageID);
}
}
return myRoImagesList;
}
private static string ROImageKey(string fileName, DateTime dts)
{
return string.Format("{0}:{1}", fileName, dts);
}
private static string buildImageIDString(List<int> myROImageIDs)
{
StringBuilder sb = new StringBuilder();
// B2022-088: [JPR] Find Doc Ro button not working in Word Sections
// B2022-098: [JPR] ROs not being resolved in Word Sections
if (myROImageIDs != null)
{
string sep = string.Empty;
foreach (int imageID in myROImageIDs)
{
sb.Append(sep + imageID.ToString());
sep = ",";
}
}
return sb.ToString();
}
private static void UpdateROValuesText(ROFstInfo origROFstInfo, ROFst newROFst, DocVersionInfo dvi, ROFstInfoProgressBarRefresh myProgressBarRefresh, List<string> MyChangedFigureROIDs)
{
if (myProgressBarRefresh != null) myProgressBarRefresh(0, 100, "Update Ro Values");
string versionList = dvi.VersionID.ToString();
ROFSTLookup origLookup = new ROFSTLookup(origROFstInfo.ROFstID, dvi);
ROFSTLookup newLookup = new ROFSTLookup(newROFst.ROFstID, dvi);
List<string> delList = new List<string>();
List<string> chgList = newLookup.GetValueDifferences(origROFstInfo.ROFstID, ref delList);
// Any figures which have been changed will be included in the list of values that have changed.
if (MyChangedFigureROIDs != null)
{
foreach (string roid in MyChangedFigureROIDs)
{
if (!chgList.Contains(roid)) chgList.Add(roid);
}
}
string RoidList = GetRoidList(newROFst.RODbID, chgList);
if (myProgressBarRefresh != null) myProgressBarRefresh(0, chgList.Count, "Getting List of ROs Used");
List<string> activeRoids = BuildActiveROIDsForRoUsages12(RoidList, versionList);
if (myProgressBarRefresh != null) myProgressBarRefresh(0, chgList.Count, "Updating RO Values");
int iCount = 0;
if (activeRoids.Count > 0)
{
foreach (string chg in chgList)
{
if (myProgressBarRefresh != null) myProgressBarRefresh(++iCount, chgList.Count, "Updating RO Values");
if (activeRoids.Contains(chg.Substring(0, 12)))
{
ROFSTLookup.rochild roch = newLookup.GetRoChild(chg);
string desc = string.Format("Change in RO Values: Old value = {0}, New value = {1}", origLookup.GetRoChild(chg).value, roch.value);
// roid's are stored in database as 16 characters long in the RoUsages table. They may be stored as 12 characters in the ro.fst.
// string padroid = chg.Length <= 12 ? chg + "0000" : chg;
// B2022-088: Find Doc Ro button not working in Word Sections
string padroid = ROFSTLookup.FormatRoidKey(chg, true);
using (RoUsageInfoList affected = RoUsageInfoList.GetAffected(origROFstInfo.MyRODb.RODbID, padroid, desc, "Changed", versionList))
{
foreach (RoUsageInfo roUsg in affected)
{
using (Content content = Content.Get(roUsg.MyContent.ContentID))
{
foreach (ItemInfo ii in roUsg.MyContent.ContentItems)
{
string val = newLookup.GetTranslatedRoValue(padroid, ii.ActiveFormat.PlantFormat.FormatData.SectData.ConvertCaretToDelta, ii.ActiveFormat.PlantFormat.FormatData.SectData.UseTildaPoundCharsForSuperSubScriptInROValues, false, ii);
content.FixContentText(roUsg, val, roch.type, origROFstInfo, true);
if (content.IsDirty)
{
// Update UserID and DTS when RO Value is updated.
content.UserID = Volian.Base.Library.VlnSettings.UserID;
content.DTS = DateTime.Now;
content.Save();
if (content.MyGrid != null)
{
GridInfo.Refresh(content.MyGrid);
}
}
}
}
}
}
}
}
}
if (myProgressBarRefresh != null) myProgressBarRefresh(0, chgList.Count, "Getting List of ROs Used");
List<string> activeDRoids = BuildActiveROIDsForDRoUsages12(RoidList, versionList);
iCount = 0;
if (activeDRoids.Count > 0)
{
foreach (string chg in chgList)
{
// B2022-088: Find Doc Ro button not working in Word Sections
// string padroid = chg.Length <= 12 ? chg + "0000" : chg;
string padroid = ROFSTLookup.FormatRoidKey(chg, true);
if (myProgressBarRefresh != null) myProgressBarRefresh(++iCount, chgList.Count, "Updating RO Values");
if (activeDRoids.Contains(chg.Substring(0, 12)))
{
ROFSTLookup.rochild roch = newLookup.GetRoChild(chg);
string desc = string.Format("Change in RO Values: Old value = {0}, New value = {1}", origLookup.GetRoChild(chg).value, roch.value);
// roid's are stored in database as 16 characters long in the rousages table. They may be stored as 12 characters in the ro.fst.
using (DROUsageInfoList affected = DROUsageInfoList.GetAffected(origROFstInfo.MyRODb.RODbID, padroid, desc, "Changed", versionList))
{
foreach (DROUsageInfo droUsg in affected)
{
Pdf.DeleteAll(droUsg.DocID);
}
}
}
}
}
iCount = 0;
string RoidDelList = GetRoidList(newROFst.RODbID, delList);
if (myProgressBarRefresh != null) myProgressBarRefresh(0, chgList.Count, "Getting List of ROs Used");
activeRoids = BuildActiveROIDsForRoUsages12(RoidDelList, versionList);
if (activeRoids.Count > 0)
{
foreach (string del in delList)
{
// B2022-088: Find Doc Ro button not working in Word Sections
//string padroiddel = del.Length <= 12 ? del + "0000" : del;
string padroiddel = ROFSTLookup.FormatRoidKey(del, true);
if (myProgressBarRefresh != null) myProgressBarRefresh(++iCount, chgList.Count, "Removing Old RO Values");
string desc = string.Format("Deleted RO: Value = {0}", origLookup.GetRoChild(del).value);
if (activeRoids.Contains(del.Substring(0, 12).ToUpper()))
{
using (RoUsageInfoList affected = RoUsageInfoList.GetAffected(origROFstInfo.MyRODb.RODbID, padroiddel, desc, "Deleted", versionList))
{
foreach (RoUsageInfo roUsg in affected)
{
using (Content content = Content.Get(roUsg.MyContent.ContentID))
{
content.FixContentText(roUsg, "?", 0, origROFstInfo);
if (content.IsDirty)
{
// Update UserID and DTS when RO Value is updated.
content.UserID = Volian.Base.Library.VlnSettings.UserID;
content.DTS = DateTime.Now;
content.Save();
}
}
}
}
}
}
}
if (myProgressBarRefresh != null) myProgressBarRefresh(0, chgList.Count, "Getting List of ROs Used");
activeDRoids = BuildActiveROIDsForDRoUsages12(RoidDelList, versionList);
iCount = 0;
if (activeDRoids.Count > 0)
{
foreach (string del in delList)
{
// B2022-088: Find Doc Ro button not working in Word Sections
string padroiddel = ROFSTLookup.FormatRoidKey(del, true);
if (myProgressBarRefresh != null) myProgressBarRefresh(++iCount, chgList.Count, "Removing Old RO Values");
string desc = string.Format("Deleted RO: Value = {0}", origLookup.GetRoChild(del).value);
// If there's an issue then maybe try getting the RoChild with the Padded roid instead
//string desc = string.Format("Deleted RO: Value = {0}", origLookup.GetRoChild(padroiddel).value);
if (activeDRoids.Contains(del.Substring(0, 12).ToUpper()))
{
using (DROUsageInfoList Daffected = DROUsageInfoList.GetAffected(origROFstInfo.MyRODb.RODbID, padroiddel, desc, "Deleted", versionList))
{
foreach (DROUsageInfo droUsg in Daffected)
{
if (myProgressBarRefresh != null) myProgressBarRefresh(++iCount, chgList.Count, "Removing Old RO Values");
Pdf.DeleteAll(droUsg.DocID);
}
}
}
}
}
if (myProgressBarRefresh != null) myProgressBarRefresh(100, 100, "RO Values Updated");
}
private static DateTime ShowDuration(DateTime dtLast, string message)
{
DateTime dtNext = DateTime.Now;
Console.WriteLine("{0,10:#####0.00},'{1}'", TimeSpan.FromTicks(dtNext.Ticks - dtLast.Ticks).TotalSeconds, message);
return dtNext;
}
private static List<string> BuildActiveROIDsForRoUsages12(string RoidList, string versions)
{
List<string> activeRoids = new List<string>();
using (RoUsageInfoList activeList = RoUsageInfoList.GetROUSagesByROIDsAndVersions(RoidList, versions))
{
foreach (RoUsageInfo roui in activeList)
{
string roid = roui.ROID.ToUpper().Substring(0, 12);
if (!activeRoids.Contains(roid))
activeRoids.Add(roid);
}
}
return activeRoids;
}
private static List<string> BuildActiveROIDsForDRoUsages12(string RoidList, string versions)
{
List<string> activeRoids = new List<string>();
using (DROUsageInfoList activeList = DROUsageInfoList.GetDROUsagesByROIDsAndVersions(RoidList, versions))
{
foreach (DROUsageInfo roui in activeList)
{
string roid = roui.ROID.Substring(0, 12);
if (!activeRoids.Contains(roid))
activeRoids.Add(roid);
}
}
return activeRoids;
}
private static string GetRoidList(int dbid, List<string> chgList)
{
StringBuilder sb = new StringBuilder(string.Format("{0}", dbid));
string sep = ":";
foreach (string roid in chgList)
{
sb.Append(sep + roid);
sep = ",";
}
return sb.ToString();
}
// B2022-026 RO Memory Reduction code - all rochild types passed in are of type image (graphics)
private void MigrateRoFstGraphics(RODbInfo rdi, ROFSTLookup.rochild[] rochild, RODb rodb, ROFst rofst, Dictionary<string, int> myExistingROImages, List<int> myUnChangedROImages, List<string> myAddedROImages, List<string> MyChangedFigureROIDs, ROFstInfoProgressBarRefresh myProgressBarRefresh, int cnt, ref int curCnt)
{
if (rochild != null)
{
for (int i = 0; i < rochild.Length; i++)
{
this.AddGraphic(rdi, rochild[i], rodb, rofst, myExistingROImages, myUnChangedROImages, myAddedROImages, MyChangedFigureROIDs, myProgressBarRefresh, cnt, curCnt);
curCnt++;
}
}
}
private void AddGraphic(RODbInfo rdi, ROFSTLookup.rochild myRO, RODb rodb, ROFst rofst, Dictionary<string, int> myExistingROImages, List<int> myUnChangedROImages, List<string> myAddedROImages, List<string> MyChangedFigureROIDs, ROFstInfoProgressBarRefresh myProgressBarRefresh, int cnt, int curCnt)
{
if (string.IsNullOrEmpty(myRO.value)) return;
string p = myRO.value;
string imgname = p.Substring(0, p.IndexOf('\n'));
int thedot = imgname.LastIndexOf('.');
string fname = imgname;
if (thedot == -1 || (thedot != (imgname.Length - 4)))
{
RODbConfig roDbCfg = new RODbConfig(rdi.Config);
fname += string.Format(".{0}", roDbCfg.GetDefaultGraphicExtension());
}
string imgfile = rdi.FolderPath + @"\" + fname;
ROImage roImg = null;
if (File.Exists(imgfile))
{
FileInfo fi = new FileInfo(imgfile);
// if the roimage record exists, don't create a new one...
string key = ROImageKey(imgname, fi.LastWriteTimeUtc);
if (myExistingROImages.ContainsKey(key))
{
int imageID = myExistingROImages[key];
if (!myUnChangedROImages.Contains(imageID))
myUnChangedROImages.Add(imageID);
}
else
{
if (!myAddedROImages.Contains(key))
{
myProgressBarRefresh(curCnt, cnt, "Loading " + imgname); // show progress of loading images
FileStream fsIn = new FileStream(imgfile, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
BinaryReader r = new BinaryReader(fsIn);
byte[] ab = r.ReadBytes((int)fsIn.Length);
r.Close();
fsIn.Close();
byte[] cmp = ROImageInfo.Compress(ab);
int existingImageID = FindExisting(myExistingROImages, imgname, imgfile, cmp, ab);
if (existingImageID != 0)
{
if (!myUnChangedROImages.Contains(existingImageID))
{
myUnChangedROImages.Add(existingImageID);
}
return;
}
ROImageConfig rc = new ROImageConfig();
rc.Image_Size = ab.Length.ToString();
using (roImg = ROImage.MakeROImage(rodb, imgname, ROImageInfo.Compress(ab), rc.ToString(), fi.LastWriteTimeUtc, "Migration"))
{
using (Figure figure = Figure.GetByROFstID_ImageID(this.ROFstID, roImg.ImageID))
{
if (figure != null) return;
Figure.MakeFigure(rofst, roImg, null).Dispose();
myAddedROImages.Add(key);
MyChangedFigureROIDs.Add(myRO.roid); // Save the roid so that the related documents will be refeshed. (PDF will be deleted)
}
}
}
}
}
}
private int FindExisting(Dictionary<string, int> myExistingROImages, string imgname, string imgfile, byte[] cmpFileContents, byte[] fileContents)
{
// the reason the following check is necessary is that the DTS can be off by hours
// because of the way windows handles Daylight savings time for file DTS.
FileInfo fi = new FileInfo(imgfile);
DateTime dts = fi.LastWriteTimeUtc;
// loop through myExistingROImages looking for matching name.
foreach (string key in myExistingROImages.Keys)
{
// if found, compare the date/time stamp
string part1 = Regex.Replace(key, ":.*$", "");
string part2 = Regex.Replace(key, "^.*?:", "");
if (part1.ToUpper() == imgname.ToUpper())
{
// if date/time stamps matches date, minutes & seconds, compare contents
string cmp1 = Regex.Replace(dts.ToString(), " [0-9]*:", " x:");
cmp1 = Regex.Replace(cmp1, " [AP]", " x");
string cmp2 = Regex.Replace(part2, " [0-9]*:", " x:");
cmp2 = Regex.Replace(cmp2, " [AP]", " x");
if (cmp1 == cmp2)
{
// compare contents
int imgId = myExistingROImages[key];
using (ROImageInfo roii = ROImageInfo.Get(imgId))
{
ROImageConfig roicfg = new ROImageConfig(roii);
int size = Convert.ToInt32(roicfg.Image_Size);
byte[] tmpb = ROImageInfo.Decompress(roii.Content, size);
if (ByteArrayCompare.DoCompare(roii.Content, cmpFileContents))
return imgId;
if (ByteArrayCompare.DoCompare(tmpb, fileContents))
return imgId;
}
}
}
}
return 0;
}
private static void ROWarning(ItemInfo myItemInfo, string format, params object[] args)
{
int key = 0;
if (myItemInfo != null && myItemInfo.MyDocVersion != null) key = myItemInfo.MyDocVersion.VersionID;
if (!DocVersionsNeedingROUpdate.Contains(key))
{
if (myItemInfo == null)
{
string prefix = string.Format("\r\nNeed to Update RO Values\r\n");
_MyLog.WarnFormat(prefix + format, args);
DocVersionsNeedingROUpdate.Add(key);
}
else
{
string prefix = string.Format("\r\nNeed to Update RO Values for {0}\r\nProcedure {1}\r\n", myItemInfo.SearchDVPath, myItemInfo.MyProcedure.DisplayNumber);
_MyLog.WarnFormat(prefix + format, args);
DocVersionsNeedingROUpdate.Add(key);
}
}
}
private void DataPortal_Fetch(PKCriteriaJustROFst criteria)
{
if (_MyLog.IsDebugEnabled) _MyLog.DebugFormat("[{0}] ROFstInfo.DataPortal_Fetch", GetHashCode());
try
{
using (SqlConnection cn = Database.VEPROMS_SqlConnection)
{
ApplicationContext.LocalContext["cn"] = cn;
using (SqlCommand cm = cn.CreateCommand())
{
cm.CommandType = CommandType.StoredProcedure;
cm.CommandText = "getJustROFst";
cm.Parameters.AddWithValue("@ROFstID", criteria.ROFstID);
cm.CommandTimeout = Database.DefaultTimeout;
using (SafeDataReader dr = new SafeDataReader(cm.ExecuteReader()))
{
if (!dr.Read())
{
_ErrorMessage = "No Record Found";
return;
}
ReadData(dr);
}
}
// removing of item only needed for local data portal
if (ApplicationContext.ExecutionLocation == ApplicationContext.ExecutionLocations.Client)
ApplicationContext.LocalContext.Remove("cn");
}
}
catch (Exception ex)
{
if (_MyLog.IsErrorEnabled) _MyLog.Error("ROFstInfo.DataPortal_Fetch", ex);
_ErrorMessage = ex.Message;
throw new DbCslaException("ROFstInfo.DataPortal_Fetch", ex);
}
}
#endregion
}
public class ROFstInfoROTableUpdateEventArgs
{
private string _ROText;
public string ROText
{
get { return _ROText; }
set { _ROText = value; }
}
private string _OldGridXml;
public string OldGridXml
{
get { return _OldGridXml; }
set { _OldGridXml = value; }
}
public ROFstInfoROTableUpdateEventArgs(string rotext, string oldgridxml)
{
_ROText = rotext;
_OldGridXml = oldgridxml;
}
}
public partial class ROFstInfoList
{
[Serializable()]
private class RoFstSizeCriteria
{
public RoFstSizeCriteria(int roDbID, int len)
{
_RODbID = roDbID;
_Len = len;
}
private int _RODbID;
public int RODbID
{
get { return _RODbID; }
set { _RODbID = value; }
}
private int _Len;
public int Len
{
get { return _Len; }
set { _Len = value; }
}
}
public static ROFstInfoList GetBySize(int roDbID, int len)
{
try
{
ROFstInfoList tmp = DataPortal.Fetch<ROFstInfoList>(new RoFstSizeCriteria(roDbID, len));
ROFstInfo.AddList(tmp);
tmp.AddEvents();
return tmp;
}
catch (Exception ex)
{
throw new DbCslaException("Error on RoFstInfoList.GetBySize", ex);
}
}
public static bool ROFstDiffBySize(string rofstPath, int roDbID, int len)
{
try
{
bool isDifferent = false;
using (ROFstInfoList tmp = GetBySize(roDbID, len))
{
if (tmp.Count > 0)
{
// B2017-078 WCN users with Read only access to the RO FST file where not able to open the file for reading when
// another user was accessing the file. Changed FileShare from Read to ReadWrite
FileStream fsIn = new FileStream(rofstPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
// Create an instance of StreamReader that can read characters from the FileStream.
BinaryReader r = new BinaryReader(fsIn);
byte[] ab = r.ReadBytes((int)fsIn.Length);
r.Close();
fsIn.Close();
Dictionary<int, byte[]> rofstBytes = new Dictionary<int, byte[]>();
foreach (ROFstInfo irofst in tmp)
{
if (!rofstBytes.ContainsKey(irofst.ROFstID))
{
rofstBytes.Add(irofst.ROFstID, ROFSTLookup.GetRofstLookupBytes(irofst.ROFstID));
}
var bytes = rofstBytes[irofst.ROFstID];
irofst.Dispose();
// compare contents by comparing each byte.
for (int i = 20; i < len; i++) // this skips past RO.FST header which has the FST creation date/time
{
if (ab[i] != bytes[i])
{
isDifferent = true;
break;
}
}
if (isDifferent)
break;
}
}
}
//GC.Collect();
return isDifferent;
}
catch (Exception ex)
{
throw new DbCslaException("Error on RoFstInfoList.ROFstDiffBySize", ex);
}
}
private void DataPortal_Fetch(RoFstSizeCriteria criteria)
{
this.RaiseListChangedEvents = false;
if (_MyLog.IsDebugEnabled) _MyLog.DebugFormat("[{0}] ROFstInfoList.DataPortal_FetchBySize", GetHashCode());
try
{
using (SqlConnection cn = Database.VEPROMS_SqlConnection)
{
using (SqlCommand cm = cn.CreateCommand())
{
cm.CommandType = CommandType.StoredProcedure;
cm.CommandText = "getRoFstBySize";
cm.Parameters.AddWithValue("@RODbID", criteria.RODbID);
cm.Parameters.AddWithValue("@Len", criteria.Len);
cm.CommandTimeout = Database.DefaultTimeout;
using (SafeDataReader dr = new SafeDataReader(cm.ExecuteReader()))
{
IsReadOnly = false;
while (dr.Read())
this.Add(new ROFstInfo(dr));
IsReadOnly = true;
}
}
}
}
catch (Exception ex)
{
if (_MyLog.IsErrorEnabled) _MyLog.Error("ROFstInfoList.DataPortal_FetchBySize", ex);
throw new DbCslaException("ROFstInfoList.DataPortal_FetchBySize", ex);
}
this.RaiseListChangedEvents = true;
}
}
}