context: /*=============================================================================================================
  Open Dental GPL license Copyright (C) 2003  Jordan Sparks, DMD.  http://www.open-dent.com,  www.docsparks.com
  See header in FormOpenDental.cs for complete text.  Redistributions must retain this text.
  ===============================================================================================================*/
  //#define ISXP
  using System;
  using System.Collections;
  using System.Collections.Generic;
  using System.ComponentModel;
  using System.Data;
  using System.Diagnostics;
  using System.Drawing;
  using System.Drawing.Imaging;
  using System.Drawing.Design;
  using System.Drawing.Text;
  using System.Drawing.Drawing2D;
  using System.Drawing.Printing;
  using System.IO;
  using System.Net;
  using System.Resources;
  using System.Runtime.InteropServices;
  using System.Security.Cryptography;
  using System.Text;
  using System.Threading;
  using System.Windows.Forms;
  using AxAcroPDFLib;
  using OpenDental.UI;
  using OpenDentBusiness;
  using Tao.OpenGl;
  using CodeBase;
  using xImageDeviceManager;
  using System.Text.RegularExpressions;
  
  namespace OpenDental {
  
  	///<summary></summary>
  	public class ContrImages:System.Windows.Forms.UserControl {
  
  		#region Designer Generated Variables
  
  		private System.Windows.Forms.ImageList imageListTree;
  		private System.ComponentModel.IContainer components;
  		private System.Windows.Forms.ImageList imageListTools2;
  		private System.Windows.Forms.TreeView treeDocuments;
  		private System.Windows.Forms.MainMenu mainMenu1;
  		private System.Windows.Forms.MenuItem menuItem1;
  		private System.Windows.Forms.MenuItem menuExit;
  		private System.Windows.Forms.MenuItem menuPrefs;
  		private OpenDental.UI.ODToolBar ToolBarMain;
  		private System.Windows.Forms.MenuItem menuItem2;
  		private System.Windows.Forms.ContextMenu contextTree;
  		private System.Windows.Forms.MenuItem menuItem3;
  		private System.Windows.Forms.MenuItem menuItem4;
  		private Panel panelNote;
  		private Label label1;
  		private TextBox textNote;
  		private SignatureBox sigBox;
  		private Label label15;
  		private Label labelInvalidSig;
  		private ContrWindowingSlider sliderBrightnessContrast;
  		private ODToolBar ToolBarPaint;
  		private Panel panelUnderline;
  		private Panel panelVertLine;
  		private System.Windows.Forms.PictureBox pictureBoxMain;
  		///<summary></summary>
  		[Category("Data"),Description("Occurs when user changes current patient, usually by clicking on the Select Patient button.")]
  		public event PatientSelectedEventHandler PatientSelected=null;
  		private ContextMenu menuForms;
  		private ContextMenuStrip MountMenu;
  
  		#endregion
  
  		#region ManuallyCreatedVariables
  
  		///<summary>Used to display Topaz signatures on Windows. Is added dynamically to avoid native code references crashing MONO.</summary>
  		private Control SigBoxTopaz;
  		///<summary>Starts out as false. It's only used when repainting the toolbar, not to test mode.</summary>
  		private bool IsCropMode;
  		private Family FamCur;
  		///<summary>When dragging on Picturebox, this is the starting point in PictureBox coordinates.</summary>
  		private Point PointMouseDown;
  		private bool IsMouseDown;
  		///<summary>Set to true when the image in the picture box is currently being translated.</summary>
  		private bool IsDragging;
  		///<summary>In-memory copies of the images being viewed/edited. No changes are made to these images in memory, they are just kept resident to avoid having to reload the images from disk each time the screen needs to be redrawn.  If no mount, this will just be one image.  A mount will contain a series of images.</summary>
  		private Bitmap[] ImagesCur=new Bitmap[1];
  		///<summary>Used as a basis for calculating image translations.</summary>
  		private PointF PointImageCur;
  		///<summary>The true offset of the document image or mount image.</summary>
  		private PointF PointTranslation;
  		///<summary>The current zoom of the currently loaded image/mount. 1 implies normal size, less than 1 implies the image is shrunk, greater than 1 imples the image/mount is blown-up.</summary>
  		private float ZoomImage=1;
  		///<summary>The zoom level is 0 after the current image/mount is loaded.  User changes the zoom in integer increments.  ZoomOverall is then (initial image/mount zoom)*(2^ZoomLevel).</summary>
  		private int ZoomLevel=0;
  		///<summary>Represents the current factor for level of zoom from the initial zoom of the currently loaded image/mount. This is calculated directly as 2^ZoomLevel every time a zoom occurs. Recalculated from ZoomLevel each time, so that ZoomOverall always hits the exact same values for the exact same zoom levels (no loss of data).</summary>
  		private float ZoomOverall=1;
  		///<summary>Used to prevent concurrent access to the current images by multiple threads.  Each item in array corresponds to an image in a mount.</summary>
  		private int[] WidthsImagesCur=new int[1];
  		///<summary>Used to prevent concurrent access to the current images by multiple threads.  Each item in array corresponds to an image in a mount.</summary>
  		private int[] HeightsImagesCur=new int[1];
  		///<summary>The image currently on the screen.  If a mount, this will be an image representing the entire mount.</summary>
  		private Bitmap ImageRenderingNow=null;
  		private Rectangle RectCrop=new Rectangle(0,0,-1,-1);
  		///<summary>Used for performing an xRay image capture on an imaging device.</summary>
  		private SuniDeviceControl xRayImageController=null;
  		///<summary>Thread to handle updating the graphical image to the screen when the current document is an image.</summary>
  		private Thread ThreadImageUpdate=null;
  		private ImageSettingFlags ImageSettingFlagsInvalidated;
  		///<summary>Used as a thread-safe communication device between the main and worker threads.</summary>
  		private EventWaitHandle EventWaitHandleSettings=new EventWaitHandle(false,EventResetMode.AutoReset);
  		///<summary>Edited by the main thread to reflect selection changes. Read by worker thread.</summary>
  		private Document DocForSettings=null;
  		//<summary>Keeps track of the mount settings for the currently selected mount document.</summary>
  		//private Mount MountForSettings=new Mount();
  		///<summary>Edited by the main thread to reflect selection changes. Read by worker thread.</summary>
  		private ImageNodeType NodeTypeForSettings;
  		///<summary>Indicates which documents to update in the image worker thread. This variable must be locked before accessing it and it must also be the same length as DocsInMount at all times.</summary>
  		private bool[] MountIdxsFlaggedForUpdate=null;
  		///<summary>Set by the main thread and read by the image worker thread. Specifies which image processing tasks are to be performed by the worker thread.</summary>
  		private ImageSettingFlags ImageSettingFlagsForSettings=ImageSettingFlags.NONE;
  		///<summary>Used to perform mouse selections in the treeDocuments list.</summary>
  		private ImageNodeId NodeIdentifierDown;
  		///<summary>Used to keep track of the old document selection by document number (the only guaranteed unique idenifier). This is to help the code be compatible with both Windows and MONO.</summary>
  		private ImageNodeId NodeIdentifierOld;
  		///<summary>Used for Invoke() calls in RenderCurrentImage() to safely handle multi-thread access to the picture box.</summary>
  		private delegate void RenderImageCallback(Document docCopy,int originalWidth,int originalHeight,float zoom,PointF translation);
  		///<summary>Used to safe-guard against multi-threading issues when an image capture is completed.</summary>
  		private delegate void CaptureCallback(object sender,EventArgs e);
  		///<summary>Used to protect against multi-threading issues when refreshing a mount during an image capture.</summary>
  		private delegate void InvalidatesettingsCallback(ImageSettingFlags settings,bool reloadZoomTransCrop);
  		///<summary>Keeps track of the document settings for the currently selected document or mount.</summary>
  		private Document DocSelected=new Document();
  		///<summary>Keeps track of the currently selected mount object (only when a mount is selected).</summary>
  		private Mount MountSelected=new Mount();
  		///<summary>If a mount is currently selected, this is the list of the mount items on it.</summary>
  		private List<MountItem> MountItemsForSelected=null;
  		///<summary>The index of the currently selected item within a mount.</summary>
  		private int IdxSelectedInMount=0;
  		///<summary>List of documents within the currently selected mount (if any).</summary>
  		private Document[] DocsInMount=null;
  		///<summary>The idxSelectedInMount when it is copied.</summary>
  		int IdxDocToCopy=-1;
  		//private bool allowTopaz;
  		DateTime TimeMouseMoved=new DateTime(1,1,1);
  		///<summary></summary>
  		private Patient PatCur;
  		private bool InitializedOnStartup;
  		///<summary>Set with each module refresh, and that's where it's set if it doesn't yet exist.  For now, we are not using ImageStore.GetPatientFolder(), because we haven't tested whether it properly updates the patient object.  We don't want to risk using an outdated patient folder path.  And we don't want to waste time refreshing PatCur after every ImageStore.GetPatientFolder().</summary>
  		private string PatFolder;
  		private AxAcroPDFLib.AxAcroPDF axAcroPDF1=null;
  		private long PatNumPrev=0;
  		//private List<Def> DefListExpandedCats=new List<Def>();
  		private List<long> ExpandedCats=new List<long>();
  		///<summary>If this is not zero, then this indicates a different mode special for claimpayment.</summary>
  		private long ClaimPaymentNum;
  		///<summary>If this is not null, then this indicates a different mode special for amendments.</summary>
  		private EhrAmendment EhrAmendmentCur;
  		///<summary></summary>
  		[Category("Action"),Description("Occurs when the close button is clicked in the toolbar.")]
  		public event EventHandler CloseClick=null;
  		///<summary>Gets updated to PatCur.PatNum that the last security log was made with so that we don't make too many security logs for this patient.  When _patNumLast no longer matches PatCur.PatNum (e.g. switched to a different patient within a module), a security log will be entered.  Gets reset (cleared and the set back to PatCur.PatNum) any time a module button is clicked which will cause another security log to be entered.</summary>
  		private long _patNumLast;
  		#endregion ManuallyCreatedVariables
  
  		///<summary></summary>
  		public ContrImages() {
  			Logger.openlog.Log("Initializing Document Module...",Logger.Severity.INFO);
  			InitializeComponent();
  			//The context menu causes strange bugs in MONO when performing selections on the tree.
  			//Perhaps when MONO is more developed we can remove this check.
  			//Also, the SigPlusNet() object cannot be instantiated on 64-bit machines, because
  			//the code for instantiation exists in a 32-bit native dll. Therefore, we have put
  			//the creation code for the topaz box in CodeBase.TopazWrapper.GetTopaz() so that
  			//the native code does not exist or get called anywhere in the program unless we are running on a 
  			//32-bit version of Windows.
  			//bool is64=CodeBase.ODEnvironment.Is64BitOperatingSystem();
  			bool platformUnix=Environment.OSVersion.Platform==PlatformID.Unix;
  			//allowTopaz=(!platformUnix && !is64);
  			if(platformUnix) {
  				treeDocuments.ContextMenu=null;
  			}
  			//if(allowTopaz){//Windows OS
  			try {
  				SigBoxTopaz=CodeBase.TopazWrapper.GetTopaz();
  				panelNote.Controls.Add(SigBoxTopaz);
  				SigBoxTopaz.Location=sigBox.Location;//new System.Drawing.Point(437,15);
  				SigBoxTopaz.Name="sigBoxTopaz";
  				SigBoxTopaz.Size=new System.Drawing.Size(362,79);
  				SigBoxTopaz.TabIndex=93;
  				SigBoxTopaz.Text="sigPlusNET1";
  				SigBoxTopaz.DoubleClick+=new System.EventHandler(this.sigBoxTopaz_DoubleClick);
  				CodeBase.TopazWrapper.SetTopazState(SigBoxTopaz,0);
  			}
  			catch { }
  			//}
  			//We always capture with a Suni device for now.
  			//TODO: In the future use a device locator in the xImagingDeviceManager
  			//project to return the appropriate general device control.
  			xRayImageController=new SuniDeviceControl();
  			this.xRayImageController.OnCaptureReady+=new System.EventHandler(this.OnCaptureReady);
  			this.xRayImageController.OnCaptureComplete+=new System.EventHandler(this.OnCaptureComplete);
  			this.xRayImageController.OnCaptureFinalize+=new System.EventHandler(this.OnCaptureFinalize);
  			Logger.openlog.Log("Document Module initialization complete.",Logger.Severity.INFO);
  		}
  
  		///<summary></summary>
  		protected override void Dispose(bool disposing) {
  			if(disposing) {
  				if(components != null) {
  					components.Dispose();
  				}
  				xRayImageController.KillXRayThread();
  			}
  			base.Dispose(disposing);
  		}
  
  		#region Windows Form Designer generated code
  
  		private void InitializeComponent() {
  			this.components = new System.ComponentModel.Container();
  			System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(ContrImages));
  			this.treeDocuments = new System.Windows.Forms.TreeView();
  			this.contextTree = new System.Windows.Forms.ContextMenu();
  			this.menuItem2 = new System.Windows.Forms.MenuItem();
  			this.menuItem3 = new System.Windows.Forms.MenuItem();
  			this.menuItem4 = new System.Windows.Forms.MenuItem();
  			this.imageListTree = new System.Windows.Forms.ImageList(this.components);
  			this.imageListTools2 = new System.Windows.Forms.ImageList(this.components);
  			this.pictureBoxMain = new System.Windows.Forms.PictureBox();
  			this.MountMenu = new System.Windows.Forms.ContextMenuStrip(this.components);
  			this.mainMenu1 = new System.Windows.Forms.MainMenu(this.components);
  			this.menuItem1 = new System.Windows.Forms.MenuItem();
  			this.menuExit = new System.Windows.Forms.MenuItem();
  			this.menuPrefs = new System.Windows.Forms.MenuItem();
  			this.panelNote = new System.Windows.Forms.Panel();
  			this.labelInvalidSig = new System.Windows.Forms.Label();
  			this.sigBox = new OpenDental.UI.SignatureBox();
  			this.label15 = new System.Windows.Forms.Label();
  			this.label1 = new System.Windows.Forms.Label();
  			this.textNote = new System.Windows.Forms.TextBox();
  			this.panelUnderline = new System.Windows.Forms.Panel();
  			this.panelVertLine = new System.Windows.Forms.Panel();
  			this.ToolBarMain = new OpenDental.UI.ODToolBar();
  			this.ToolBarPaint = new OpenDental.UI.ODToolBar();
  			this.sliderBrightnessContrast = new OpenDental.UI.ContrWindowingSlider();
  			((System.ComponentModel.ISupportInitialize)(this.pictureBoxMain)).BeginInit();
  			this.panelNote.SuspendLayout();
  			this.SuspendLayout();
  			// 
  			// treeDocuments
  			// 
  			this.treeDocuments.AllowDrop = true;
  			this.treeDocuments.ContextMenu = this.contextTree;
  			this.treeDocuments.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
  			this.treeDocuments.FullRowSelect = true;
  			this.treeDocuments.HideSelection = false;
  			this.treeDocuments.ImageIndex = 2;
  			this.treeDocuments.ImageList = this.imageListTree;
  			this.treeDocuments.Indent = 20;
  			this.treeDocuments.Location = new System.Drawing.Point(0, 29);
  			this.treeDocuments.Name = "treeDocuments";
  			this.treeDocuments.SelectedImageIndex = 2;
  			this.treeDocuments.Size = new System.Drawing.Size(228, 519);
  			this.treeDocuments.TabIndex = 0;
  			this.treeDocuments.AfterCollapse += new System.Windows.Forms.TreeViewEventHandler(this.TreeDocuments_AfterCollapse);
  			this.treeDocuments.AfterExpand += new System.Windows.Forms.TreeViewEventHandler(this.TreeDocuments_AfterExpand);
  			this.treeDocuments.DragDrop += new System.Windows.Forms.DragEventHandler(this.treeDocuments_DragDrop);
  			this.treeDocuments.DragEnter += new System.Windows.Forms.DragEventHandler(this.treeDocuments_DragEnter);
  			this.treeDocuments.MouseDoubleClick += new System.Windows.Forms.MouseEventHandler(this.TreeDocuments_MouseDoubleClick);
  			this.treeDocuments.MouseDown += new System.Windows.Forms.MouseEventHandler(this.TreeDocuments_MouseDown);
  			this.treeDocuments.MouseLeave += new System.EventHandler(this.TreeDocuments_MouseLeave);
  			this.treeDocuments.MouseMove += new System.Windows.Forms.MouseEventHandler(this.TreeDocuments_MouseMove);
  			this.treeDocuments.MouseUp += new System.Windows.Forms.MouseEventHandler(this.TreeDocuments_MouseUp);
  			// 
  			// contextTree
  			// 
  			this.contextTree.MenuItems.AddRange(new System.Windows.Forms.MenuItem[] {
              this.menuItem2,
              this.menuItem3,
              this.menuItem4});
  			// 
  			// menuItem2
  			// 
  			this.menuItem2.Index = 0;
  			this.menuItem2.Text = "Print";
  			// 
  			// menuItem3
  			// 
  			this.menuItem3.Index = 1;
  			this.menuItem3.Text = "Delete";
  			// 
  			// menuItem4
  			// 
  			this.menuItem4.Index = 2;
  			this.menuItem4.Text = "Info";
  			// 
  			// imageListTree
  			// 
  			this.imageListTree.ImageStream = ((System.Windows.Forms.ImageListStreamer)(resources.GetObject("imageListTree.ImageStream")));
  			this.imageListTree.TransparentColor = System.Drawing.Color.Transparent;
  			this.imageListTree.Images.SetKeyName(0, "");
  			this.imageListTree.Images.SetKeyName(1, "");
  			this.imageListTree.Images.SetKeyName(2, "");
  			this.imageListTree.Images.SetKeyName(3, "");
  			this.imageListTree.Images.SetKeyName(4, "");
  			this.imageListTree.Images.SetKeyName(5, "");
  			this.imageListTree.Images.SetKeyName(6, "");
  			// 
  			// imageListTools2
  			// 
  			this.imageListTools2.ImageStream = ((System.Windows.Forms.ImageListStreamer)(resources.GetObject("imageListTools2.ImageStream")));
  			this.imageListTools2.TransparentColor = System.Drawing.Color.Transparent;
  			this.imageListTools2.Images.SetKeyName(0, "Pat.gif");
  			this.imageListTools2.Images.SetKeyName(1, "print.gif");
  			this.imageListTools2.Images.SetKeyName(2, "deleteX.gif");
  			this.imageListTools2.Images.SetKeyName(3, "info.gif");
  			this.imageListTools2.Images.SetKeyName(4, "scan.gif");
  			this.imageListTools2.Images.SetKeyName(5, "import.gif");
  			this.imageListTools2.Images.SetKeyName(6, "paste.gif");
  			this.imageListTools2.Images.SetKeyName(7, "");
  			this.imageListTools2.Images.SetKeyName(8, "ZoomIn.gif");
  			this.imageListTools2.Images.SetKeyName(9, "ZoomOut.gif");
  			this.imageListTools2.Images.SetKeyName(10, "Hand.gif");
  			this.imageListTools2.Images.SetKeyName(11, "flip.gif");
  			this.imageListTools2.Images.SetKeyName(12, "rotateL.gif");
  			this.imageListTools2.Images.SetKeyName(13, "rotateR.gif");
  			this.imageListTools2.Images.SetKeyName(14, "scanDoc.gif");
  			this.imageListTools2.Images.SetKeyName(15, "scanPhoto.gif");
  			this.imageListTools2.Images.SetKeyName(16, "scanXray.gif");
  			this.imageListTools2.Images.SetKeyName(17, "copy.gif");
  			this.imageListTools2.Images.SetKeyName(18, "ScanMulti.gif");
  			this.imageListTools2.Images.SetKeyName(19, "Export.gif");
  			// 
  			// pictureBoxMain
  			// 
  			this.pictureBoxMain.BackColor = System.Drawing.SystemColors.Window;
  			this.pictureBoxMain.BackgroundImageLayout = System.Windows.Forms.ImageLayout.None;
  			this.pictureBoxMain.BorderStyle = System.Windows.Forms.BorderStyle.Fixed3D;
  			this.pictureBoxMain.ContextMenuStrip = this.MountMenu;
  			this.pictureBoxMain.Cursor = System.Windows.Forms.Cursors.Hand;
  			this.pictureBoxMain.InitialImage = null;
  			this.pictureBoxMain.Location = new System.Drawing.Point(233, 54);
  			this.pictureBoxMain.Name = "pictureBoxMain";
  			this.pictureBoxMain.Size = new System.Drawing.Size(703, 370);
  			this.pictureBoxMain.TabIndex = 6;
  			this.pictureBoxMain.TabStop = false;
  			this.pictureBoxMain.SizeChanged += new System.EventHandler(this.PictureBox1_SizeChanged);
  			this.pictureBoxMain.MouseDown += new System.Windows.Forms.MouseEventHandler(this.PictureBox1_MouseDown);
  			this.pictureBoxMain.MouseHover += new System.EventHandler(this.PictureBox1_MouseHover);
  			this.pictureBoxMain.MouseMove += new System.Windows.Forms.MouseEventHandler(this.PictureBox1_MouseMove);
  			this.pictureBoxMain.MouseUp += new System.Windows.Forms.MouseEventHandler(this.PictureBox1_MouseUp);
  			// 
  			// MountMenu
  			// 
  			this.MountMenu.Name = "MountMenu";
  			this.MountMenu.Size = new System.Drawing.Size(61, 4);
  			this.MountMenu.Opening += new System.ComponentModel.CancelEventHandler(this.MountMenu_Opening);
  			// 
  			// mainMenu1
  			// 
  			this.mainMenu1.MenuItems.AddRange(new System.Windows.Forms.MenuItem[] {
              this.menuItem1,
              this.menuPrefs});
  			// 
  			// menuItem1
  			// 
  			this.menuItem1.Index = 0;
  			this.menuItem1.MenuItems.AddRange(new System.Windows.Forms.MenuItem[] {
              this.menuExit});
  			this.menuItem1.Text = "File";
  			// 
  			// menuExit
  			// 
  			this.menuExit.Index = 0;
  			this.menuExit.Text = "Exit";
  			// 
  			// menuPrefs
  			// 
  			this.menuPrefs.Index = 1;
  			this.menuPrefs.Text = "Preferences";
  			// 
  			// panelNote
  			// 
  			this.panelNote.Controls.Add(this.labelInvalidSig);
  			this.panelNote.Controls.Add(this.sigBox);
  			this.panelNote.Controls.Add(this.label15);
  			this.panelNote.Controls.Add(this.label1);
  			this.panelNote.Controls.Add(this.textNote);
  			this.panelNote.Location = new System.Drawing.Point(234, 485);
  			this.panelNote.Name = "panelNote";
  			this.panelNote.Size = new System.Drawing.Size(705, 64);
  			this.panelNote.TabIndex = 11;
  			this.panelNote.Visible = false;
  			this.panelNote.DoubleClick += new System.EventHandler(this.panelNote_DoubleClick);
  			// 
  			// labelInvalidSig
  			// 
  			this.labelInvalidSig.BackColor = System.Drawing.SystemColors.Window;
  			this.labelInvalidSig.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
  			this.labelInvalidSig.Location = new System.Drawing.Point(398, 31);
  			this.labelInvalidSig.Name = "labelInvalidSig";
  			this.labelInvalidSig.Size = new System.Drawing.Size(196, 59);
  			this.labelInvalidSig.TabIndex = 94;
  			this.labelInvalidSig.Text = "Invalid Signature -  Document or note has changed since it was signed.";
  			this.labelInvalidSig.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
  			this.labelInvalidSig.DoubleClick += new System.EventHandler(this.labelInvalidSig_DoubleClick);
  			// 
  			// sigBox
  			// 
  			this.sigBox.Location = new System.Drawing.Point(308, 20);
  			this.sigBox.Name = "sigBox";
  
gt: 			this.sigBox.Size = new System.Drawing.Size(362, 79);