/*
 * Created by SharpDevelop.
 * User: utente
 * Date: 24/07/2014
 * Time: 08:02
 * 
 * To change this template use Tools | Options | Coding | Edit Standard Headers.
 */
using System;
using System.Collections;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.Windows.Forms;
using iTextSharp.text;
using iTextSharp.text.pdf;
using iTextSharp.text.pdf.parser;
using System.IO;
using System.Text;
using System.Data.SQLite;
using System.Runtime.InteropServices;
using System.Threading;
using MainProject.Libs;
using System.Linq;
using System.Threading.Tasks;
using System.Globalization;
using ZXing;
using ZXing.Common;
using ZXing;

namespace MainProject
{

	/// <summary>
	/// Description of MainForm.
	/// </summary>
	public partial class frmPrincipale : Form
	{
    	[DllImport("Shlwapi.dll", SetLastError = true, CharSet = CharSet.Auto)]
    	static extern uint AssocQueryString(AssocF flags, AssocStr str, string pszAssoc, string pszExtra, [Out] StringBuilder pszOut, [In][Out] ref uint pcchOut);

    	public cSQLite inSQL = new cSQLite();
    	public cSQLite outSQL = new cSQLite();

    	bool processing = false;
		bool stopProcessing = false;
		
		Thread BgWorker = null;
		List<Task> taTasks = new List<Task>();
		public int maxTasks = 1;
		
		long processati = 0;

		
		public struct itemStruct {
			public string filename;
			public int page;
			
			public override string ToString() {
				return filename + " [" + page + "]";
			}
			
			public itemStruct(string file, int pageNr) {
				filename = file;
				page = pageNr;
			}
		}
		

    	[Flags]
    	public enum AssocF
    	{
    		Init_NoRemapCLSID = 0x1,
    		Init_ByExeName = 0x2,
    		Open_ByExeName = 0x2,
    		Init_DefaultToStar = 0x4,
    		Init_DefaultToFolder = 0x8,
    		NoUserSettings = 0x10,
    		NoTruncate = 0x20,
    		Verify = 0x40,
    		RemapRunDll = 0x80,
    		NoFixUps = 0x100,
    		IgnoreBaseClass = 0x200
    	}

    	public enum AssocStr
    	{
    		Command = 1,
    		Executable,
    		FriendlyDocName,
    		FriendlyAppName,
    		NoOpen,
    		ShellNewValue,
    		DDECommand,
    		DDEIfExec,
    		DDEApplication,
    		DDETopic
    	}


    	public frmPrincipale()
		{
			InitializeComponent();
    	}

    	void FrmPrincipaleLoad(object sender, EventArgs e)
		{
			var ExeVer = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version;
			this.Text += " [" + ExeVer.Major + "." + ExeVer.Minor + "." + ExeVer.Build + "]";

			cLang.LoadML();
    		
    		txtFolder.Text = System.Diagnostics.Debugger.IsAttached? "C:\\DataSearchTest" : "C:\\";
			tbCpuCore.Maximum = Environment.ProcessorCount;
			tbCpuCore.Value = Environment.ProcessorCount == 1 ? 1 : Environment.ProcessorCount - 1;
			
			string[] dbs = Directory.GetFiles(Application.StartupPath, "*.sqlite");
			foreach (string db in dbs) {
				cboInputDatabase.Items.Add(db);
				cboOutputDatabase.Items.Add(db);
			}
			cboInputDatabase.SelectedIndex = 0;
			cboOutputDatabase.SelectedIndex = 0;
			inSQL.Connect(cboInputDatabase.SelectedItem.ToString(), false);
			outSQL.Connect(cboInputDatabase.SelectedItem.ToString(), false);

			btnProcess.Text = cLang.ML("process");
			btnSearch.Text = cLang.ML("search");
			chkSubFolders.Text = cLang.ML("scan_subfolders");
			chkOnlyFirstPage.Text = cLang.ML("scan_first_page");
			chkDeleteData.Text = cLang.ML("delete_database_rows_before_process");
			chkSkipOcr.Text = cLang.ML("skip_ocr_recognition");
			chkSkipBarcode.Text = cLang.ML("skip_barcode_recognition");
			chkRegexp.Text = cLang.ML("use_regexp");
			tabAnalyze.Text = cLang.ML("analyze") + " ";
			tabSearch.Text = cLang.ML("search") + " ";
			lblCreationDate.Text = cLang.ML("date_creation") + ":";
			lblChangeDate.Text = cLang.ML("date_changed") + ":";
			lblCoresNumber.Text = cLang.ML("number_of_cores") + ":";
			chkFirstMatchPerFile.Text = cLang.ML("show_only_first_match_per_file");
			lblText.Text = cLang.ML("text") + ":";
    	}
		
		
    	void BgWorkerFunction() {
			//elenco file
			var files = Directory.GetFiles(txtFolder.Text, "*.*",chkSubFolders.Checked? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly).Where(s => s.EndsWith(".pdf", StringComparison.InvariantCultureIgnoreCase) || s.EndsWith(".odt", StringComparison.InvariantCultureIgnoreCase) || s.EndsWith(".ods", StringComparison.InvariantCultureIgnoreCase) ||  s.EndsWith(".png", StringComparison.InvariantCultureIgnoreCase) ||  s.EndsWith(".bmp", StringComparison.InvariantCultureIgnoreCase) ||  s.EndsWith(".jpg", StringComparison.InvariantCultureIgnoreCase) ||  s.EndsWith(".tif", StringComparison.InvariantCultureIgnoreCase) ||  s.EndsWith(".docx", StringComparison.InvariantCultureIgnoreCase) ||  s.EndsWith(".xlsx", StringComparison.InvariantCultureIgnoreCase) ||  s.EndsWith(".xlsm", StringComparison.InvariantCultureIgnoreCase));;

			this.Invoke((MethodInvoker)(() => {
				lblFile.Visible = true;
		                            }));
			
			processing = true;
			processati = 0;
			
			// processo e memorizzo tutti i files
			foreach (string srcFile in files) {
				Thread.MemoryBarrier();
				if (stopProcessing) break;
	
				int totalFiles = files.Count();

				this.Invoke((MethodInvoker)(() => {
                	this.Text= ((processati * 100F) / files.Count()).ToString("#0") + "% [" + processati + "/" + files.Count() + "]";
					lblFile.Text = srcFile;
					lblFile.Refresh();
					maxTasks = tbCpuCore.Value;
			                            }));
				processati++;
				
				
				Application.DoEvents();
				
				//accodo il task in parallelo
				while (taTasks.Count() >= maxTasks) {
					for (int i = taTasks.Count() - 1; i >= 0; --i) {
						if (taTasks[i].IsCompleted || taTasks[i].IsFaulted) taTasks.RemoveAt(i);
					}
					Application.DoEvents();
					Thread.Sleep(10);
				}
				
				string taskFile = srcFile;
				fileType taskFileType;
				switch (Path.GetExtension(taskFile.ToLower())) {
					case ".pdf" : taskFileType = fileType.Pdf; break;
					case ".jpg" : taskFileType = fileType.Jpeg; break;
					case ".png" : taskFileType = fileType.Png; break;
					case ".bmp" : taskFileType = fileType.Bmp; break;
					case ".tif" : taskFileType = fileType.Tiff; break;
					case ".odt" : taskFileType = fileType.Odt; break;
					case ".ods" : taskFileType = fileType.Ods; break;
					case ".docx" : taskFileType = fileType.Docx; break;
					case ".xlsx" : taskFileType = fileType.Xlsx; break;
					case ".xlsm" : taskFileType = fileType.Xlsm; break;
					default: taskFileType = fileType.Unknow; break;
				}
				
				Task newTask = new Task(() => TaskProcessFile(taskFile, taskFileType, totalFiles));
				taTasks.Add(newTask);
				newTask.Start();
				
			}

			//aspetto che tutti i Task siano completati
			while (taTasks.Count() >  0) {
				for (int i = taTasks.Count() - 1; i >= 0; --i) {
					if (taTasks[i].IsCompleted || taTasks[i].IsFaulted) taTasks.RemoveAt(i);
				}
				Application.DoEvents();
				Thread.Sleep(10);
			}
			
			processing = false;
			stopProcessing = false;
			
			this.Invoke((MethodInvoker)(() => {
            	this.Text= ((processati * 100F) / files.Count()).ToString("#0.0") + " % [" + processati + " di " + files.Count() + "]";
				lblFile.Visible = false;
				btnProcess.Enabled = true;
				cboOutputDatabase.Enabled = true;
				MessageBox.Show(cLang.ML("finish"));
			                            }));
			
    	}
    	
    	void TaskProcessFile(string srcFile, fileType srcType, int totalFiles = 0) {
    		int NumOfPages = 1;
    		string md5 = string.Empty;
    		
    		//dati generali sui file
    		try {
	    		if (srcType == fileType.Pdf) NumOfPages = GetNumberOfPages(srcFile);
				md5 = cIO.GetFileMd5(srcFile);
    		} catch (Exception ex) {
				Logger.Append("Exception on '" + srcFile + "'\n" + ex.Message + "\n\n");
    			return;
    		}

			for (int page = 1; page <= NumOfPages; ++page) {
				Thread.MemoryBarrier();
				
				this.Invoke((MethodInvoker)(() => {
                	this.Text= ((processati * 100F) / totalFiles).ToString("#0") + "% [" + processati + "/" + totalFiles + ",P" + taTasks.Count() + "]";
                    }));
				
				StringBuilder parole = new StringBuilder();

				//estrazione del testo dal file pdf
				try {
					parole.Append(TextExtractor.GetText(srcFile, srcType, page));
				} catch (Exception ex) {
					Logger.Append("ExtractText() exception on '" + srcFile + "'\n" + ex.Message + "\n\n");
				}

				Bitmap bmp = null;
				
				// file già elaborato, passo al prossimo file
				if (page == 1 && outSQL.GetScalarLong("SELECT COUNT(*) FROM FILES WHERE LOWER(nome)=" + srcFile.ToLower().ToSql()) > 0) {
					if (outSQL.GetScalarStr("SELECT md5 FROM FILES WHERE LOWER(nome)=" + srcFile.ToLower().ToSql()) == md5 && md5 != string.Empty) {
						break;
					}
				}
				
				//estrazione immagine
				try {
					if (srcType == fileType.Pdf) {
						bmp = ExtractImagesFromPDF(srcFile, page);
					}
					if (srcType.IsImage()) {
						bmp = (Bitmap) Bitmap.FromFile(srcFile);
					}
				} catch (Exception ex) {
					Logger.Append("ExtractImage() exception on '" + srcFile + "'\n" + ex.Message + "\n\n");
					bmp = null;
				}

				
				if (bmp != null && !(chkSkipOcr.Checked && chkSkipBarcode.Checked)) {
					//converto in scala di grigi
					try {
						cImageFilter cif = new cImageFilter(ref bmp, 24);
						cif.Gray();
						cif.RemoveGrayArtefacts();
						// cif.BarcodeEnhanceVertical();
						cif.UnlockImage();
					} catch (Exception ex) {
						Logger.Append("ToGray() exception on '" + srcFile + "'\n" + ex.Message + "\n\n");
					}
					
					//salvo su TIFF (per TesserAct)
					if (!chkSkipOcr.Checked) {
						MemoryStream ms = new MemoryStream();
						bmp.Save(ms, ImageFormat.Tiff);
		
						byte[] buffer = new byte[ms.Length];
						ms.Seek(0, SeekOrigin.Begin);
						ms.Read(buffer, 0, buffer.Length);
						ms.Dispose();
						
						Application.DoEvents();
		
						//scansione con TesserAct
						try {
							string tact = Path.Combine(Application.StartupPath, "Tesseract", "tesseract.exe");
							if (!File.Exists(tact)) tact = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles), "Tesseract-OCR", "tesseract.exe");
							parole.Append(" " + cProcess.RunGetOutput(tact,  "stdin stdout", ref buffer).Trim());
						} catch (Exception ex) {
							Logger.Append("Ocr() exception on '" + srcFile + "'\n" + ex.Message + "\n\n");
						}
					}
					
					//scansione per codici a barre
					if (!chkSkipBarcode.Checked) {
						ArrayList barcodes = new ArrayList();
						
						// if (System.Diagnostics.Debugger.IsAttached) bmp.Save("C:\\DataSearchTest\\barcode.png", ImageFormat.Png);
						
						// Barcode Imaging
						try {
							BarcodeImaging.FullScanPage(ref barcodes, bmp, 200);
							foreach (string bc in barcodes) {
								parole.Append(" '" + bc + "'");
							}
						} catch (Exception ex) {
							Logger.Append("BarcodeImaging() exception on '" + srcFile + "'\n" + ex.Message + "\n\n");
						}
						
						// ZXing
						try {
							var bcr = new BarcodeReader();
							bcr.Options.TryHarder = true;
							bcr.Options.UseCode39ExtendedMode = true;
							Result[] resBcr = bcr.DecodeMultiple(bmp);
							foreach (var res in resBcr) {
								if (!barcodes.Contains(res.Text)) {
									parole.Append(" '" + res.Text + "'");
								}
							}
						} catch (Exception ex) {
							Logger.Append("ZXing() exception on '" + srcFile + "'\n" + ex.Message + "\n\n");
						}
					}
					
					bmp.Dispose();
				}
				
				//salvo il file
				FileInfo fi = new FileInfo(srcFile);
				long newIdFile = outSQL.GetScalarLong("INSERT INTO FILES (nome,testo,datac,datam, md5, pagina) VALUES (" + srcFile.ToSql() + "," + parole.ToString().ToSql() + ", @datac,@datam, @hash, @pagina)", new SQLiteParameter("datac", fi.CreationTime), new SQLiteParameter("datam", fi.LastWriteTime), new SQLiteParameter("hash", md5), new SQLiteParameter("pagina", page));

				//cancello eventuali dati precedenti
				outSQL.Execute("DELETE FROM Exif WHERE idFile = @id", new SQLiteParameter("id", newIdFile));

				if (srcType.IsImage()) {
					try {
						//carico l'immagine
						using (FileStream fs = new FileStream(srcFile, FileMode.Open)) {
							System.Drawing.Image img = (Bitmap) System.Drawing.Image.FromStream(fs, false, false);
							
							//memorizzo le dimensioni dell'immagine
							long idProp = 0;
							outSQL.Execute("INSERT INTO Exif (idfile, idprop, valore) VALUES (@id, @prop, @val)", new SQLiteParameter("id", newIdFile), new SQLiteParameter("prop", idProp), new SQLiteParameter("val", img.Width + "x" + img.Height)); 
							
							//se è un JPEG provo ad estrarre anche i dati EXIF
							if (srcType == fileType.Jpeg) {
								
								PropertyItem[] propItems = img.PropertyItems;
								ASCIIEncoding encoding = new ASCIIEncoding();
					
								foreach (var propItem in propItems) {
									if (propItem.Id == null) continue;
									string val = string.Empty;
									switch (propItem.Id) {
										case 269: val = encoding.GetString(propItem.Value).RemoveLast(); break;
										case 270: val = encoding.GetString(propItem.Value).RemoveLast(); break;
										case 271: val = encoding.GetString(propItem.Value).RemoveLast(); break;
										case 272: val = encoding.GetString(propItem.Value).RemoveLast(); break;
										case 274: val = BitConverter.ToInt16(propItem.Value, 0).ToString(); break;
										case 305: val = encoding.GetString(propItem.Value).RemoveLast(); break;
										case 306: val = encoding.GetString(propItem.Value).RemoveLast().FromExifDate(); break;
										case 315: val = encoding.GetString(propItem.Value).RemoveLast(); break;
										case 32781: val = encoding.GetString(propItem.Value).RemoveLast(); break;
										case 33432: val = encoding.GetString(propItem.Value).RemoveLast(); break;
										case 42033: val = encoding.GetString(propItem.Value).RemoveLast(); break;
										case 42035: val = encoding.GetString(propItem.Value).RemoveLast(); break;
										case 42036: val = encoding.GetString(propItem.Value).RemoveLast(); break;
										case 42037: val = encoding.GetString(propItem.Value).RemoveLast(); break;
									}
									if (val != string.Empty) outSQL.Execute("INSERT INTO Exif (idfile, idprop, valore) VALUES (@id, @prop, @val)", new SQLiteParameter("id", newIdFile), new SQLiteParameter("prop", propItem.Id), new SQLiteParameter("val", val)); 
								}
								
							}
							
							fs.Close();
							fs.Dispose();
							img.Dispose();
						}
					
					} catch (Exception ex) {
						Logger.Append("Exif() exception on '" + srcFile + "'\n" + ex.Message + "\n\n");
						System.Diagnostics.Debug.Print(ex.Message);
					}
				
				}
			}
			
    	}
    	
		void BtnProcessClick(object sender, EventArgs e)
		{
			
			if (processing) {
				stopProcessing = true;
				btnProcess.Enabled = false;
				return;
			}
			
			//verifica preliminare
			if (!Directory.Exists(txtFolder.Text)) {
				MessageBox.Show(cLang.ML("missing_folder"));
				return;
			}
			if (chkDeleteData.Checked) {
				if (MessageBox.Show(cLang.ML("delete_database_contents"), cLang.ML("delete"), MessageBoxButtons.YesNo) == DialogResult.No) return;
				outSQL.Execute("DELETE FROM Files");
				outSQL.Execute("DELETE FROM Exif");
				outSQL.Execute("VACUUM");
			}
			
			cboOutputDatabase.Enabled = false;
			BgWorker = new Thread(BgWorkerFunction);
			BgWorker.Start();
			
		}
		
		public string GetTextFromPage(String pdfPath, int pageNumber)
		{
			string res = string.Empty;
			using (PdfReader reader = new PdfReader(pdfPath)) {
				res = PdfTextExtractor.GetTextFromPage(reader, pageNumber, new SimpleTextExtractionStrategy());
				reader.Close();
				reader.Dispose();
			}
			return res;
		}
		
		public int GetNumberOfPages(string sourcePdf) {
			try {
				int res = 1;
				using (PdfReader pdf = new PdfReader(sourcePdf)) {
					res = pdf.NumberOfPages;
					if (res > 1 && chkOnlyFirstPage.Checked) res = 1;
					pdf.Close();
					pdf.Dispose();
				}
				return res;
			} catch {
				return 1;
			}
		}

		public Bitmap ExtractImagesFromPDF(string sourcePdf, int pageNumber)
		{
			try {
	            PdfReader pdf = new PdfReader(sourcePdf);
	            PdfDictionary pg = pdf.GetPageN(pageNumber);
	            PdfDictionary res = (PdfDictionary)PdfReader.GetPdfObject(pg.Get(PdfName.RESOURCES));
	            PdfDictionary xobj = (PdfDictionary)PdfReader.GetPdfObject(res.Get(PdfName.XOBJECT));
	            if (xobj == null) return null;
	            
	            foreach (PdfName name in xobj.Keys)
	            {
	                PdfObject obj = xobj.Get(name);
	                if (obj.IsIndirect())
	                {
	                    PdfDictionary tg = (PdfDictionary)PdfReader.GetPdfObject(obj);
	                    string width = tg.Get(PdfName.WIDTH).ToString();
	                    string height = tg.Get(PdfName.HEIGHT).ToString();
	                    ImageRenderInfo imgRI = ImageRenderInfo.CreateForXObject(new Matrix(float.Parse(width), float.Parse(height)), (PRIndirectReference)obj, tg);
	                    
				        PdfImageObject image = imgRI.GetImage();
				        using (System.Drawing.Image dotnetImg = image.GetDrawingImage())
				        {
				            if (dotnetImg != null)
				            {
				                using (MemoryStream ms = new MemoryStream())
				                {
				                    // dotnetImg.Save(ms, ImageFormat.Tiff);
				                    Bitmap newBmp24 = new Bitmap(dotnetImg.Width, dotnetImg.Height, PixelFormat.Format24bppRgb);
				                    using (Graphics gr = Graphics.FromImage(newBmp24)) {
					                    gr.DrawImage(dotnetImg, new System.Drawing.Rectangle(0, 0, dotnetImg.Width, dotnetImg.Height));
				                    }
				                    dotnetImg.Dispose();
				                    pdf.Close();
				                    return newBmp24;
				                }
				            }
				        }                    
	                }
	            }
	            pdf.Close();
			} catch (Exception ex) {
				Logger.Append("ExtractImage() exception on '" + sourcePdf + "' : " + ex.Message +"\n\n");
			}

			return null;


		}
		
		void BtnSearchClick(object sender, EventArgs e)
		{	
			lbFiles.Items.Clear();
			
			SQLiteDataReader dr = null;
			string sql = "SELECT DISTINCT nome, pagina FROM Files LEFT JOIN Exif ON Files.idFile=Exif.idFile WHERE 1=1 ";
			
			string[] tokens = txtSearch.Text.Split(' ');
			if (chkRegexp.Checked) {
				for (int i = 0; i < tokens.Length; ++i) {
					sql += " AND (testo REGEXP " + tokens[i].ToSql() + " OR GetFileNameWithoutExt(nome) REGEXP " + tokens[i].ToSql() + " OR Valore REGEXP " + tokens[i].ToSql() + ")" ;
				}
			} else {
				for (int i = 0; i < tokens.Length; ++i) {
					sql += " AND (testo LIKE '%" + tokens[i] + "%' OR GetFileNameWithoutExt(nome) LIKE '%" + tokens[i] + "%' OR Valore LIKE '%" + tokens[i] + "%')" ;
				}
			}
			
			if (dtCreatedFrom.Checked) sql += " AND datac >= @createdfrom ";
			if (dtCreatedTo.Checked) sql += " AND datac <= @createdto ";
			if (dtChangedFrom.Checked) sql += " AND datam >= @changedfrom ";
			if (dtChangedTo.Checked) sql += " AND datam >= @changedto ";
			
			sql += " ORDER BY nome, pagina";
			string lastFile = string.Empty;
			
			using (SQLiteCommand cmd = inSQL.GetReader(sql, ref dr, new SQLiteParameter("createdfrom", dtCreatedFrom.Value), new SQLiteParameter("createdto", dtCreatedTo.Value), new SQLiteParameter("changedfrom", dtChangedFrom.Value), new SQLiteParameter("changedto", dtChangedTo.Value))) {
				while (dr.Read()) {
					if (chkFirstMatchPerFile.Checked && lastFile == dr.GetString(0)) continue;
					lbFiles.Items.Add(new itemStruct(dr.GetString(0), dr.GetInt32(1)));
					lastFile = dr.GetString(0);
				}
			}
	
		}
		void LbFilesDoubleClick(object sender, EventArgs e)
		{
			
			if (lbFiles.SelectedIndex != -1) {
				itemStruct itmX = (itemStruct) lbFiles.SelectedItem;
				if (!File.Exists(itmX.filename)) return;
				string fileExt = Path.GetExtension(itmX.filename.ToLower());
				
				if (cProcess.IsRunning("winlogon")) {
					string res = FileExtensionInfo(AssocStr.Executable, fileExt).ToLower();
					
					if (fileExt == ".pdf") {
						if (res.IndexOf("sumatrapdf") > 0) {
							cProcess.Run(res, " -page " + itmX.page + " \""  + itmX.filename + "\"", -2);
						} else {
							cProcess.Run(res, "/A \"page=" + itmX.page +"\" \""  + itmX.filename + "\"", -2);
						}
					} else {
						// altri programmi (non PDF)
						if (res.ToLower().EndsWith(".exe")) {
							cProcess.Run(res, " \""  + itmX.filename + "\"", -2);
						} else {
							cProcess.Run(itmX.filename, string.Empty, -2, shellExec: true);
						}
					}
				} else {
					// Linux
					// MessageBox.Show(itmX.filename.ToUnixPath());

					if (fileExt == ".pdf") {
						if (!cProcess.AsyncRun("cmd", " /c start /unix /usr/bin/xreader \"" + itmX.filename.ToUnixPath() + "\"")) {
							if (!cProcess.AsyncRun("cmd", " /c start /unix /usr/bin/evince \"" + itmX.filename.ToUnixPath() + "\"")) {
								if (!cProcess.AsyncRun("cmd", " /c start /unix /usr/bin/atril \"" + itmX.filename.ToUnixPath() + "\"")) {
									MessageBox.Show("Application not found");
								}
							}
						}
					}
					if (fileExt.In(".jpg", ".bmp", ".png", ".tif")) {
						if (!cProcess.AsyncRun("cmd", " /c start /unix /usr/bin/xviewer \"" + itmX.filename.ToUnixPath() + "\"")) {
							if (!cProcess.AsyncRun("cmd", " /c start /unix /usr/bin/gthumb \"" + itmX.filename.ToUnixPath() + "\"")) {
								if (!cProcess.AsyncRun("cmd", " /c start /unix /usr/bin/gimp \"" + itmX.filename.ToUnixPath() + "\"")) {
									MessageBox.Show("Application not found");
								}
							}
						}
					}
					if (fileExt.In(".odt", ".ods", ".docx", ".xlsx")) {
						if (!cProcess.AsyncRun("cmd", " /c start /unix /usr/bin/soffice \"" + itmX.filename.ToUnixPath() + "\"")) {
							MessageBox.Show("Application not found");
						}
					}
				}
			}
		}
		void LbFilesSelectedIndexChanged(object sender, EventArgs e)
		{
	
		}

		private string FileExtensionInfo(AssocStr assocStr, string doctype)
    	{
    		uint pcchOut = 0;
    		AssocQueryString(AssocF.Verify, assocStr, doctype, null, null, ref pcchOut);

    		StringBuilder pszOut = new StringBuilder((int)pcchOut);
    		AssocQueryString(AssocF.Verify, assocStr, doctype, null, pszOut, ref pcchOut);
    		return pszOut.ToString();
    	}
		
		void CboInputDatabaseSelectedIndexChanged(object sender, EventArgs e)
		{
			inSQL.Close();
			inSQL.Connect(cboInputDatabase.SelectedItem.ToString(), false);
		}
		
		void CboOutputDatabaseSelectedIndexChanged(object sender, EventArgs e)
		{
			outSQL.Close();
			outSQL.Connect(cboOutputDatabase.SelectedItem.ToString(), false);
		}

		
	}
}
