using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using System.IO;
using System.Text;
using Pervasive.Data.SqlClient;

namespace LongDataTypes
{
	/// <summary>
	/// Summary description for LongDataTypes.
	/// </summary>
	public class LongDataTypes : System.Windows.Forms.Form
	{
		private System.Windows.Forms.Button Start;
		private System.Windows.Forms.RichTextBox OutputWindow;
		private System.Windows.Forms.Button DoneButton;
		private System.Windows.Forms.Button StartStream;
		/// <summary>
		/// Required designer variable.
		/// </summary>
		private System.ComponentModel.Container components = null;

		public LongDataTypes()
		{
			//
			// Required for Windows Form Designer support
			//
			InitializeComponent();

			//
			// TODO: Add any constructor code after InitializeComponent call
			//
		}

		/// <summary>
		/// Clean up any resources being used.
		/// </summary>
		protected override void Dispose( bool disposing )
		{
			if( disposing )
			{
				if (components != null) 
				{
					components.Dispose();
				}
			}
			base.Dispose( disposing );
		}

		#region Windows Form Designer generated code
		/// <summary>
		/// Required method for Designer support - do not modify
		/// the contents of this method with the code editor.
		/// </summary>
		private void InitializeComponent()
		{
			this.Start = new System.Windows.Forms.Button();
			this.OutputWindow = new System.Windows.Forms.RichTextBox();
			this.DoneButton = new System.Windows.Forms.Button();
			this.StartStream = new System.Windows.Forms.Button();
			this.SuspendLayout();
			// 
			// Start
			// 
			this.Start.Location = new System.Drawing.Point(40, 24);
			this.Start.Name = "Start";
			this.Start.Size = new System.Drawing.Size(168, 23);
			this.Start.TabIndex = 0;
			this.Start.Text = "Start LongDataType Test";
			this.Start.Click += new System.EventHandler(this.Start_Click);
			// 
			// OutputWindow
			// 
			this.OutputWindow.Location = new System.Drawing.Point(40, 64);
			this.OutputWindow.Name = "OutputWindow";
			this.OutputWindow.ReadOnly = true;
			this.OutputWindow.Size = new System.Drawing.Size(416, 144);
			this.OutputWindow.TabIndex = 1;
			this.OutputWindow.Text = "";
			this.OutputWindow.TextChanged += new System.EventHandler(this.OutputWindow_TextChanged);
			// 
			// DoneButton
			// 
			this.DoneButton.Location = new System.Drawing.Point(208, 224);
			this.DoneButton.Name = "DoneButton";
			this.DoneButton.Size = new System.Drawing.Size(80, 24);
			this.DoneButton.TabIndex = 2;
			this.DoneButton.Text = "Done";
			this.DoneButton.Click += new System.EventHandler(this.DoneButton_Click);
			// 
			// StartStream
			// 
			this.StartStream.Location = new System.Drawing.Point(272, 24);
			this.StartStream.Name = "StartStream";
			this.StartStream.Size = new System.Drawing.Size(184, 23);
			this.StartStream.TabIndex = 1;
			this.StartStream.Text = "LongDataType as Stream Object";
			this.StartStream.Click += new System.EventHandler(this.StartStream_Click);
			// 
			// LongDataTypes
			// 
			this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
			this.ClientSize = new System.Drawing.Size(488, 266);
			this.Controls.AddRange(new System.Windows.Forms.Control[] {
																		  this.StartStream,
																		  this.DoneButton,
																		  this.OutputWindow,
																		  this.Start});
			this.Name = "LongDataTypes";
			this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
			this.Text = "LongDataTypes";
			this.Load += new System.EventHandler(this.LongDataTypes_Load);
			this.ResumeLayout(false);

		}
		#endregion

		/// <summary>
		/// The main entry point for the application.
		/// </summary>
		[STAThread]
		static void Main() 
		{
			Application.Run(new LongDataTypes());
		}

		private void LongDataTypes_Load(object sender, System.EventArgs e)
		{
		
		}

		/// <summary>
		/// Writes out all the information during 
		/// the test run onto the OutputWindow text box.
		/// </summary>
		/// <param name="writer"></param>
		private void flush (StringWriter writer)
		{
			OutputWindow.AppendText (writer.ToString ());
			OutputWindow.Refresh();
			writer.GetStringBuilder ().Length = 0;
		}

		private void Start_Click(object sender, System.EventArgs e)
		{
			// Clear the OutputWindow
			OutputWindow.Clear();

			// New String writer for all the output generated
			StringWriter writer = new StringWriter();
		
			// Psql Command
			PsqlCommand   DBCmd;
			// Change the connection string to match your servers
            PsqlConnection Conn = new PsqlConnection("Host=localhost;Port=1583;Database=demodata;");

			try
			{
				try 
				{
					// Open the connection
					Conn.Open();
				}
				catch (PsqlException ex)
				{
					// Connection failed
					writer.WriteLine(ex.Message);
					flush(writer);
					return;
				}

                DBCmd = new PsqlCommand("insert into myLongdbtypes values(?, ?)", Conn);
				DBCmd.Parameters.Add("@id", PsqlDbType.Integer, 10, "id");
                DBCmd.Parameters.Add("@longvarcharCol", PsqlDbType.NLongVarChar, 2050, "longvarcharCol");

                string longvarcharInput = buildString(2050, true);

                // Insert one row in the table
				try
				{
					DBCmd.Parameters[0].Value = 0;
                    DBCmd.Parameters[1].Value = longvarcharInput;
					DBCmd.ExecuteNonQuery();
					writer.WriteLine("Insert Successful!!");
					flush(writer);
				}
				catch (Exception ex)
				{
					// Insert failed. Display the exception.
					writer.WriteLine("Insert Failed.");
					writer.WriteLine(ex.Message);
					flush(writer);
				}

				// Fecthing long data and checking for the accuracy
				DBCmd = new PsqlCommand("select * from myLongdbtypes order by id", Conn);
				try
				{
					// Call ExecuteReader on the command object
					PsqlDataReader dataReader = DBCmd.ExecuteReader();
					// Read the result set from the DataReader object
					while (dataReader.Read())
					{
						// Data from long columns
                        string longvarcharFetch = dataReader["longvarcharcol"].ToString();
                        if (String.Equals(longvarcharInput, longvarcharFetch))
						{
							// Compare Passed
                            writer.WriteLine("longvarchar compare was a Sucess!!");
							flush(writer);
						}
						else
						{
							// Failure is fetching data
                            writer.WriteLine("DataMiscompare: longvarchar");
							flush(writer);
						}
					}
				}
				catch (Exception ex)
				{
					// Display any exception
					writer.WriteLine(ex.Message);
					flush(writer);
				}

				writer.WriteLine("End of Long Data Type Test!!");
				flush(writer);

				// Cleanup. Delete the row added.
				try
				{
					DBCmd = new PsqlCommand("delete from myLongdbtypes where id = 0", Conn);
					DBCmd.ExecuteNonQuery();
				}
				catch (Exception ex)
				{
					// Display any exception
					writer.WriteLine(ex.Message);
					flush(writer);
				}
			}
			catch (Exception ex)
			{
				// Display any exception
				writer.WriteLine(ex.Message);
				flush(writer);
			}
			finally
			{
				// Close the connection
				Conn.Close();
			}
		}

		// This method call builds long strings, unicode and non-unicode (depending in the number of 
		// characters specified) to be inserted into the LongDbTypes table.
		private static string buildString(int numChars, bool unicode) 
		{
			int numTimes = numChars / 10; 
			char[] ansiValues1252 = new char[8] {'A', 'm', '\u00C6', '\u00E6', '\u00D6', '\u00F6', '4', '7'};
			char[] unicodeValues = new char[8] {'A', '\u3044', '\u00C6', '\u00E6', '\u3068','\u00D6', '4', '\u00F6'};
			char[] hexValue = new char[2] { '\u0041', '\u0041' };
			StringBuilder builder = new StringBuilder (10 * numTimes);
			for (int i = 0; i < numTimes; ++i) 
			{
				if (!unicode) 
				{
					builder.Append (ansiValues1252);
				}
				else 
				{
					builder.Append (unicodeValues);
				}
				builder.Append (hexValue);
				int k = (int) hexValue[0];
				int l = (int) hexValue[1];
				if (k == 0x50) 
				{
					k = 0x41;
					if (l == 0x50) 
					{
						l = 0x41;
					}
					else 
					{
						++l;
					}
				}
				else 
				{
					++k;
				}
				hexValue[0] = (char) k;
				hexValue[1] = (char) l;
			}
			return builder.ToString ();
		}

		private void OutputWindow_TextChanged(object sender, System.EventArgs e)
		{
		
		}

		private void DoneButton_Click(object sender, System.EventArgs e)
		{
			this.Close();
		}

		private void StartStream_Click(object sender, System.EventArgs e)
		{
			// New String Writer for the output generated
			StringWriter writer = new StringWriter();
			
			// Create and Open a connection
            PsqlConnection scon = new PsqlConnection("Host=localhost;Port=1583;Database=demodata;"); ;
			scon.Open();

			try
			{
				// Clear the OutputWindow
				OutputWindow.Clear();

				// Local Variables
				string lineCmp = "";
				string lineOut = "";
				int countText = 0;
				bool status = true;
				string outText = "..\\..\\outText.txt";
				string outImage = "..\\..\\outImage.jpg";
				bool ifFile = false;
				int BUF_SIZE = 100000;
				char[] bufferText = new char[BUF_SIZE];
				byte[] bufferImage = new byte[BUF_SIZE];
				int charsRead = 0;
				int	bytesRead = 0;
				int	InChunk;

				// Create Input stream objects
				string textFile = "..\\..\\ntext.txt";
				string imageFile = "..\\..\\image.jpg";

				// NTEXT input object
				StreamReader sr = File.OpenText(textFile);
				// IMAGE input object
				FileStream fs = File.OpenRead(imageFile);

				// Create a command object
				PsqlCommand scom;

				try 
				{
					scom = new PsqlCommand("drop table clobblobtest", scon);
					scom.ExecuteNonQuery ();
				}
				catch 
				{
					// Don't do anything. Exception is expected when the table does not exist.
				}

				try
				{
					scom = new PsqlCommand("create table clobblobtest (id int, textfile longvarchar, imagefile longvarbinary)", scon);
					scom.ExecuteNonQuery ();
					writer.WriteLine("Table Created Successfully!!");
					flush(writer);
				}
				catch (Exception ex)
				{
					// Display the exception
					writer.WriteLine("CREATE TABLE failed");
					writer.WriteLine(ex.Message);
					flush(writer);
				}

				// Bind the parameters to the input stream objects
				try
				{
					scom = new PsqlCommand("insert into clobblobtest (id, textfile, imagefile) values (?, ?, ?)", scon);
					scom.Parameters.Add ("id", PsqlDbType.Integer).Value = 1;
					scom.Parameters.Add ("textfile", PsqlDbType.LongVarChar).Value = sr;
					scom.Parameters.Add ("imagefile", PsqlDbType.LongVarBinary).Value = fs;
					scom.ExecuteNonQuery ();
					scom.Parameters.Clear ();
					writer.WriteLine("INSERT Successful!!");
					flush(writer);
				}
				catch (Exception ex)
				{
					// Display the exception
					writer.WriteLine("INSERT failed");
					writer.WriteLine(ex.Message);
					flush(writer);
				}

				// Close the stream objects
				sr.Close ();
				fs.Close ();

				// Check for output file in the directory. If old files found, delete them.
				ifFile = File.Exists(outText);
				if ( ifFile )
				{
					File.Delete(outText);
				}
				ifFile = File.Exists(outImage);
				if ( ifFile )
				{
					File.Delete(outImage);
				}

				// Create output files for dumping the data retrieved from Fetch
				StreamWriter srout = File.CreateText(outText);
				FileStream fsout = File.Create(outImage);

				// Fetch LONG data
				scom = new PsqlCommand("select * from clobblobtest where id = 1", scon);
				PsqlDataReader sreader = scom.ExecuteReader ();
				sreader.Read ();

				do 
				{
					// longvarchar Data is the second column in the DataReader resultset
					InChunk = (int) sreader.GetChars (1, charsRead, bufferText, 0, bufferText.Length); 
					if (InChunk != 0) 
					{
						srout.Write (bufferText, 0, InChunk);
						charsRead += InChunk;
					}
				} while (InChunk == BUF_SIZE);

				do 
				{
					// IMAGE Data is the third column in the DataReader resultset
					InChunk = (int) sreader.GetBytes (2, bytesRead, bufferImage, 0, bufferImage.Length); 
					if (InChunk != 0) 
					{
						fsout.Write (bufferImage, 0, InChunk);
						bytesRead += InChunk;
					}
				} while (InChunk == BUF_SIZE);

				// Close the  reader and the output files
				sreader.Close();
				srout.Close ();
				fsout.Close ();

				// Compare the two output files with the input files
				// Input Text File
				StreamReader tc = File.OpenText(textFile);
				// Get the line count of input text file
				while ( (lineCmp = tc.ReadLine()) != null )
				{
					countText++;
				}
				tc.Close();

				// Compare IMAGE
				FileStream fsO = new FileStream(outImage, FileMode.Open, FileAccess.Read);
				FileStream fsC = new FileStream(imageFile, FileMode.Open, FileAccess.Read);
				BinaryReader otC = new BinaryReader(fsC);
				BinaryReader otO = new BinaryReader(fsO);
				for ( int k = 0; k < fsC.Length; k++ )
				{
					if ( otC.ReadByte() != otO.ReadByte() )
					{
						// Compare failed. No need to compare further.
						writer.WriteLine("Error in fetching IMAGE data to output file. Please check the output file " + outImage);
						k = (int)fsC.Length;
						status = false;
						flush(writer);
					}
				}
							
				if ( status)
				{
					try
					{
						otO.ReadByte();
						writer.WriteLine("Error: This should have thrown an exception.");
						writer.WriteLine("IMAGE Fetch Data bigger than the expected data.");
						flush(writer);
					}
					catch
					{
						// Do nothing
						writer.WriteLine("Fetch IMAGE data matched with the inserted data");
						flush(writer);
					}
				}
				// Close all the files
				otC.Close();
				fsC.Close();
				otO.Close();
				fsO.Close();

				// Check the status of the compare
				if ( status )
				{
					// Delete the output file...Clean Up
					File.Delete(outImage);
				}

				// Compare textfile
				status = true;
				StreamReader tc1 = File.OpenText(textFile);
				StreamReader to = File.OpenText(outText);
				for ( int j = 0; j < countText; j++ )
				{
					lineCmp = tc1.ReadLine();
					lineOut = to.ReadLine();
					if ( !(String.Equals(lineCmp, lineOut)) )
					{
						// Compare failed. No need to compare further.
						j = countText;
						writer.WriteLine("Error in fetching TEXTFILE data to output file. Please check the output file " + outText);
						flush(writer);
						status = false;
					}
				}
				// Close all the files
				tc1.Close();
				to.Close();

				// Check the status of compare
				if ( status )
				{
					writer.WriteLine("Fetch TEXTFILE data matched with the inserted data");
					flush(writer);
				}
				// Delete the output file...Clean Up
				File.Delete(outText);
			}
			catch (Exception ex)
			{
				// Display any exception thrown
				writer.WriteLine(ex.Message);
				flush(writer);
			}
			finally
			{
				// Close the connection
				scon.Close();
			}
		}
	}
}
