/// <summary>
        /// Fired by CompareService when data transfer is complete and actual comparison starts. We use
        /// this to update the user on the status of operation.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void CompareService_OnComparisonStarted(object sender, EventArgs e)
        {
            UploadInfo uploadInfo = Session["UploadInfo"] as UploadInfo;

            if (uploadInfo == null)
            {
                return;
            }

            uploadInfo.IsReady         = true;
            uploadInfo.PercentComplete = 75;
            uploadInfo.Message         = "Chunking complete. Comparison started ...";
        }
        public static object GetUploadStatus()
        {
            UploadInfo info = HttpContext.Current.Session["UploadInfo"] as UploadInfo;

            if (info == null || !info.IsReady)
            {
                //  not ready yet ...
                return(null);
            }

            int    percentComplete;
            string message;
            string pairInfo = info.PairInfo;

            if (info.UsePercentComplete == true)
            {
                percentComplete = info.PercentComplete;
                message         = info.Message;
            }
            else
            {
                // Get the length of the file and divide that by the total length

                int soFar = info.UploadedLength;
                int total = info.ContentLength;

                if (total == 0)
                {
                    percentComplete = 0;
                }
                else
                {
                    percentComplete = (int)Math.Ceiling((double)soFar / (double)total * 100);
                }

                message = string.Format("Uploading {0} ... {1} of {2} Bytes", info.FileName, soFar, total);
            }

            //  return the percentage
            return(new { percentComplete = percentComplete, message = message, pairInfo = pairInfo });
        }
        /// <summary>
        /// Fired by CompareService after sending each chunk of data. We use this event to calculate the
        /// progress of data transfer to the Compare Service. It is only for data transfer purposes.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void CompareService_OnDataSent(object sender, DataSentArgs e)
        {
            UploadInfo uploadInfo = Session["UploadInfo"] as UploadInfo;

            if (uploadInfo == null)
            {
                return;
            }

            uploadInfo.IsReady = true;

            long soFar           = e.BytesSent;
            long total           = e.BytesTotal;
            int  percentComplete = 0;

            if (total > 0)
            {
                percentComplete = (int)Math.Ceiling((double)soFar / total * 100);
            }

            uploadInfo.PercentComplete = percentComplete;
            string msg = "Chunking {0} - Number of bytes sent: {1} Bytes";

            if (e.IsOriginalFile)
            {
                msg = string.Format(msg, "Original file [ {0} ]", e.BytesSent);
                msg = string.Format(msg, _originalFileName);
            }
            else
            {
                msg = string.Format(msg, "Modified file [ {0} ]", e.BytesSent);
                msg = string.Format(msg, _modifiedFileName);
            }

            uploadInfo.Message = msg;
        }
        /// <summary>
        /// Actually calls into Control.dll to perform comparison. This call fires DataSent event and
        /// ComparisonStarted event. We need to set the client credentials for the call before it's executed.
        /// </summary>
        /// <param name="originalFile"></param>
        /// <param name="modifiedFile"></param>
        /// <param name="optionSet"></param>
        /// <param name="responseOptions"></param>
        /// <param name="uploadInfo"></param>
        /// <returns></returns>
        private CompareResults DoComparison(HttpPostedFile originalPostedFile, HttpPostedFile modifiedPostedFile, string optionSet, ResponseOptions responseOptions, ref UploadInfo uploadInfo)
        {
            ICompareService compareService = CreateAppropriateService();

            compareService.ComparisonStarted += new EventHandler(CompareService_OnComparisonStarted);
            compareService.DataSent          += new EventHandler <DataSentArgs>(CompareService_OnDataSent);

            uploadInfo.IsReady         = true;
            uploadInfo.PercentComplete = 10;
            uploadInfo.Message         = "Authenticating request ...";

            string username = (string)Session["UserName"];
            string domain   = (string)Session["Domain"];
            string password = (string)Session["Passw"];

            password = CodePassword(password);
            compareService.SetClientCredentials(username, password, domain);

            string serviceVersion;
            string compositorVersion;

            if (!compareService.VerifyConnection(out serviceVersion, out compositorVersion))
            {
                uploadInfo.IsReady = false;
                return(null);
            }

            uploadInfo.PercentComplete = 15;
            uploadInfo.Message         = "Authentication was successful ... reading files";

            uploadInfo.PercentComplete = 20;
            uploadInfo.Message         = "Chunking files ...";

            compareService.CompareOptions   = optionSet;
            compareService.ComparisonOutput = responseOptions;
            compareService.UseChunking      = true;
            compareService.ChunkSize        = _chunkSize;

            var originalFile = originalPostedFile.InputStream;
            var modifiedFile = modifiedPostedFile.InputStream;

            originalFile.Seek(0, SeekOrigin.Begin);
            modifiedFile.Seek(0, SeekOrigin.Begin);

            // As _lastModifiedFileIndex is zero-based, so increment it befor displaying
            uploadInfo.PairInfo = "Comparing File Pair " + (_lastModifiedFileIndex + 1).ToString();

            CompareResults results = compareService.CompareEx(originalFile, modifiedFile, CreateDocumentInfo(originalPostedFile.FileName), CreateDocumentInfo(modifiedPostedFile.FileName));

            uploadInfo.PercentComplete = 100;
            uploadInfo.Message         = "Comparison completed ...";
            uploadInfo.IsReady         = false;

            return(results);
        }
        /// <summary>
        /// Saves the file to web-server disk. Saves Original file on the root of session-based path,
        /// whereas we create an index-based subdirectory for each modified file and its resultant files, e.g.
        /// session-based-path/0 for first modified file and session-based-path/1 for second and so on.
        /// </summary>
        /// <param name="postedFile"></param>
        /// <param name="originalFile"></param>
        /// <param name="uploadInfo"></param>
        /// <returns></returns>
        private string ProcessFile(HttpPostedFile postedFile, bool originalFile, ref UploadInfo uploadInfo)
        {
            // Do some basic validation
            if (postedFile == null || postedFile.ContentLength == 0)
            {
                ShowMessage(GenerateScriptID("progress"), "error", "There was a problem with the file.");
                uploadInfo.IsReady = false;
                return(string.Empty);
            }

            string virtualFilePath = string.Empty;

            //  build the local path
            if (originalFile)
            {
                virtualFilePath = Path.Combine(_sessionBasePath, Path.GetFileName(postedFile.FileName));
            }
            else
            {
                virtualFilePath = Path.Combine(_sessionBasePath, _lastModifiedFileIndex.ToString());
                virtualFilePath = Path.Combine(virtualFilePath, Path.GetFileName(postedFile.FileName));
            }
            virtualFilePath = virtualFilePath.Replace('\\', '/');

            string filepath = Server.MapPath(virtualFilePath);

            //  build the structure and stuff it into session
            uploadInfo.ContentLength  = postedFile.ContentLength;
            uploadInfo.FileName       = Path.GetFileName(filepath);
            uploadInfo.UploadedLength = 0;

            // Let the polling process know that we are done initializing ...
            uploadInfo.IsReady = true;

            int bufferSize = 1024;

            byte[] buffer = new byte[bufferSize];

            string directoryPath = Path.GetDirectoryName(filepath);

            if (!Directory.Exists(directoryPath))
            {
                Directory.CreateDirectory(directoryPath);
            }
            if (File.Exists(filepath))
            {
                File.Delete(filepath);
            }
            // Write the bytes to disk
            using (FileStream fs = new FileStream(filepath, FileMode.Create))
            {
                // As long as we haven't written everything ...
                while (uploadInfo.UploadedLength < uploadInfo.ContentLength)
                {
                    // Fill the buffer from the input stream
                    int bytes = postedFile.InputStream.Read(buffer, 0, bufferSize);
                    // Write the bytes to the file stream
                    fs.Write(buffer, 0, bytes);
                    // Update the number the webservice is polling on
                    uploadInfo.UploadedLength += bytes;

                    // Its not a good idea to move Flush in the loop but in case of very large files,
                    // if Flush-ing is deffered untill end, it occupies a lot of memory, and takes quite
                    // long to Flush-out the complete buffer, hence giving an un-explainable delay when the
                    // progress bar is showing 100%. So user is unable to understand whats taking so long.
                    // So we keep on flushing. This will cause frequent H/D hits, and can increase the overall
                    // time, but will give a comparatively better user-experience.
                    fs.Flush();
                }
            }

            // Let the parent page know we have processed the upload
            string message = "{0} has been uploaded successfully.";

            message = string.Format(message, Path.GetFileName(filepath));
            ShowMessage(GenerateScriptID("progress"), "success", message);

            uploadInfo.IsReady = false;
            return(virtualFilePath);
        }
        /// <summary>
        /// Makes calls to process files and do Comparison.
        /// The files are placed in Files collection in the order of appearance on the HTML form.
        /// First of all Original file is saved. Then for each modified file, file is saved and compared
        /// against the original file. Modified files can be more than one.
        /// </summary>
        private void ProcessFilesAndDoComparison()
        {
            UploadInfo uploadInfo = null;

            try
            {
                // Validate the data.
                if (!IsDataValid())
                {
                    UpdatePageUI();
                    return;
                }

                // Upload object used by Default.aspx to report progress to the user
                uploadInfo = Session["UploadInfo"] as UploadInfo;

                uploadInfo.IsReady            = false;
                uploadInfo.UsePercentComplete = false;

                // Read output format
                ResponseOptions responseOptions = (ResponseOptions)Enum.Parse(typeof(ResponseOptions), ResponseOptionsDropDownList.SelectedValue);

                // Read rendering set from file
                string renderingSet            = RenderingSetDropDownList.SelectedValue;
                string optionSet               = File.ReadAllText(Request.MapPath(Path.Combine(_renderSetPath, renderingSet)));
                string originalFileVirtualPath = string.Empty;
                double originalFileSizeInKB    = 0;

                _resultantFiles.Clear();

                // Process original file first.
                HttpPostedFile originalPostedFile = Request.Files["OriginalFile"];
                if (originalPostedFile != null)
                {
                    originalFileVirtualPath = ProcessFile(originalPostedFile, true, ref uploadInfo);
                    _originalFileName       = Path.GetFileName(originalFileVirtualPath);
                    originalFileSizeInKB    = (double)originalPostedFile.ContentLength / 1024;
                }

                foreach (string postedFile in Request.Files.Keys)
                {
                    if (postedFile == "OriginalFile")
                    {
                        // We have already had it.
                        continue;
                    }
                    // Now the modified ones.
                    HttpPostedFile modifiedPostedFile = Request.Files[postedFile];
                    if (modifiedPostedFile.ContentLength <= 0)
                    {
                        continue;
                    }

                    string modifiedFileVirtualPath = ProcessFile(modifiedPostedFile, false, ref uploadInfo);
                    _modifiedFileName = Path.GetFileName(modifiedFileVirtualPath);
                    double modifiedFileSizeInKB = (double)modifiedPostedFile.ContentLength / 1024;

                    // Update progress
                    uploadInfo.IsReady            = true;
                    uploadInfo.UsePercentComplete = true;
                    uploadInfo.PercentComplete    = 3;
                    uploadInfo.Message            = "Starting comparison ...";

                    // Perform comparison
                    CompareResults results = DoComparison(originalPostedFile, modifiedPostedFile, optionSet, responseOptions, ref uploadInfo);

                    if (results != null)
                    {
                        ShowMessage(GenerateScriptID("comp"), "success", " Comparison completed successfully. Displaying results.");

                        // We save results for each modified file during the process, and sum up these
                        // intermediate results after we are done with comparing all the modified files
                        // provided by user.
                        HandleIntermediateResults(results, responseOptions, modifiedFileVirtualPath, modifiedFileSizeInKB);
                        _lastModifiedFileIndex++;

                        ShowMessage(GenerateScriptID("comp"), "success", " Comparison completed successfully.");
                    }
                    else
                    {
                        ShowMessage(GenerateScriptID("comp"), "error", " Comparison failed. One possible reason is failure of document format conversion.");
                    }
                }

                // Prepare final result structs
                ComparisonResult comparisonResult = HandleFinalResults(originalFileVirtualPath, originalFileSizeInKB, renderingSet);

                // Show the results.
                DisplayResults(comparisonResult);
            }
            catch (System.Security.SecurityException ex)
            {
                if (uploadInfo != null)
                {
                    uploadInfo.IsReady = false;
                }

                string message = " Credentials provided are either empty or invalid. " + ex.Message;
                ShowMessage(GenerateScriptID("comp"), "error", message);
                ToggleUploadButtonAndStatusPane(true);
            }
            catch (System.ServiceModel.EndpointNotFoundException ex)
            {
                if (uploadInfo != null)
                {
                    uploadInfo.IsReady = false;
                }

                string message = " Either Compare Service is not running or host/port address is invalid. " + ex.Message;
                ShowMessage(GenerateScriptID("comp"), "error", message);
                ToggleUploadButtonAndStatusPane(true);
            }
            catch (TimeoutException ex)
            {
                if (uploadInfo != null)
                {
                    uploadInfo.IsReady = false;
                }

                string message = " The connection between server and client is lost because of a timeout. " + ex.Message;
                ShowMessage(GenerateScriptID("comp"), "error", message);
                ToggleUploadButtonAndStatusPane(true);
            }
            catch (InvalidDataException ex)
            {
                if (uploadInfo != null)
                {
                    uploadInfo.IsReady = false;
                }

                string message = " There was an error processing the data. This might be because a document could not be converted. " + ex.Message;
                ShowMessage(GenerateScriptID("comp"), "error", message);
                ToggleUploadButtonAndStatusPane(true);
            }
            catch (System.ServiceModel.ServerTooBusyException ex)
            {
                if (uploadInfo != null)
                {
                    uploadInfo.IsReady = false;
                }

                string message = " Too many simultaneous requests. Try again after a while. " + ex.Message;
                ShowMessage(GenerateScriptID("comp"), "error", message);
                ToggleUploadButtonAndStatusPane(true);
            }
            catch (System.ServiceModel.FaultException <string> ex)
            {
                if (uploadInfo != null)
                {
                    uploadInfo.IsReady = false;
                }

                string message = " An error occurred while comparing documents. " + ex.Detail;
                ShowMessage(GenerateScriptID("comp"), "error", message);
                ToggleUploadButtonAndStatusPane(true);
            }
            catch (Exception ex)
            {
                if (uploadInfo != null)
                {
                    uploadInfo.IsReady = false;
                }

                string message = " An error occurred while comparing documents. " + ex.Message;
                ShowMessage(GenerateScriptID("comp"), "error", message);
                ToggleUploadButtonAndStatusPane(true);
            }
        }