/// <summary>
        /// base function for communication with PhotoShop
        /// </summary>
        /// <param name="toSend">
        /// <see cref="DataBlock"/> containing data to pass to PhotoShop</param>
        /// <returns>PhotoShop Response w.r.t <paramref name="toSend"/></returns>
        /// <exception cref="ObjectDisposedException">
        /// thrown when invoking on disposed object
        /// </exception>
        private PhotoShopResponse SendAndReceive(
            DataBlock toSend)
        {
            // 01. check if object is disposed
            if (IsDisposed)
                throw
                    new ObjectDisposedException("IOHandler");

            var commError =
                new PhotoShopResponse()
                {
                    Status = CommunicationStatus.ERROR_COMMUNICATION
                };

            lock (_netStream)
            {
                // 02. send data to PS
                if (false == sendDataBlock(toSend))
                    return commError;

                // 03. receive data from PS for dedicated transaction ID
                return
                    getPhotoShopResponseUntil(toSend.TransactionID);
            }
        }
        /// <summary>
        /// change notification from PhotoShop is sent with transaction id,
        /// which is the transaction id when subscribing given event.
        /// Let's say, we subscribe foregroundColorChanged with transaction id 123,
        /// and toolChanged with transaction id 567.
        /// Then PhotoShop sends us foregroundColorChanged with transaction id 123,
        /// and toolChanged with transaction id 567 respectively.
        /// </summary>
        /// <param name="response">
        /// <see cref="PhotoShopResponse"/> to handle.
        /// </param>
        private void processNotification(
            PhotoShopResponse response)
        {
            if (CommunicationStatus.OK != response.Status)
                return;
            var isEventNotification =
                (1 + _notificationSubscribedTransactionID) >
                response.ResponseBlock.TransactionID;
            if (false == isEventNotification)
                return;

            var actionToInvoke = PhotoShopNotificationProc;
            if (null == actionToInvoke)
                return;

            var strNotification =
                response.ReturnString
                .Split(
                    new string[] { "\r", "\n" },
                    StringSplitOptions.RemoveEmptyEntries);
            if (null == strNotification ||
                strNotification.Length < 1)
                return;

            var psEvent = PhotoShopNotification.INVALID_NOTIFICATION;
            var isValidPhotoShopEvent =
                Enum.TryParse<PhotoShopNotification>(strNotification[0], out psEvent);
            //if (false == isValidPhotoShopEvent)
            //    return;
            var extraData =
                (strNotification.Length < 2) ?
                string.Empty :
                strNotification[1];

            try
            {
                switch (psEvent)
                {
                    case PhotoShopNotification.foregroundColorChanged:
                    case PhotoShopNotification.backgroundColorChanged:
                    case PhotoShopNotification.toolChanged:
                    case PhotoShopNotification.closedDocument:
                    case PhotoShopNotification.newDocumentViewCreated:
                    case PhotoShopNotification.currentDocumentChanged:
                    case PhotoShopNotification.activeViewChanged:
                    case PhotoShopNotification.documentNamesChanged:
                    case PhotoShopNotification.colorSettingsChanged:
                    case PhotoShopNotification.keyboardShortcutsChanged:
                    case PhotoShopNotification.preferencesChanged:
                    case PhotoShopNotification.quickMaskStateChanged:
                    case PhotoShopNotification.screenModeChanged:
                    case PhotoShopNotification.gaussianBlur:
                        actionToInvoke(psEvent, extraData);
                        break;
                    default:
                        actionToInvoke(PhotoShopNotification.INVALID_NOTIFICATION, response.ReturnString);
                        break;
                }
            }
            catch
            {
                // do nothing.
            }
        }
        /// <summary>
        /// construct new <see cref="PhotoShopResponse"/> from given parameters.
        /// </summary>
        /// <param name="commStatus">
        /// communication status returned from PhotoShop
        /// </param>
        /// <param name="replyBytes">
        /// byte array returned from PhotoShop
        /// </param>
        /// <returns>
        /// new <see cref="PhotoShopResponse"/> from given parameters.
        /// </returns>
        /// <exception cref="ArgumentNullException">
        /// thrown when <paramref name="replyBytes"/> is null
        /// </exception>
        private PhotoShopResponse constructPhotoShopResponse(
            int commStatus,
            byte[] replyBytes)
        {
            if (null == replyBytes)
                throw
                    new ArgumentNullException("replyBytes");

            try
            {
                switch (commStatus)
                {
                    // when PS reports no-error,
                    case PhotoShopConstants.NO_COMM_ERROR:
                        writeAsRunLog(
                            "Read this encrypted message : " +
                                replyBytes.Length,
                            replyBytes);

                        var recvDataBlock =
                            DataBlock.CreateNonErrorDataBlock(
                                _encryptDecrypt,
                                replyBytes);
                        writeAsRunLog(
                            "Decrypted Message : ",
                            recvDataBlock);

                        var resultOK =
                            new PhotoShopResponse()
                            {
                                Status = CommunicationStatus.OK,
                                ResponseBlock = recvDataBlock,
                            };
                        writeAsRunLog(
                            "PS Response" + Environment.NewLine +
                                resultOK.ToString());

                        return resultOK;
                    // when PS reports error of its own
                    default:
                        writeAsRunLog(
                            "Read this error message : " +
                                replyBytes.Length,
                            replyBytes);

                        var errorBlock =
                            DataBlock.CreateErrorDataBlock(replyBytes);
                        var resultError =
                            new PhotoShopResponse()
                            {
                                Status = CommunicationStatus.ERROR_PS_REPORT,
                                ResponseBlock = errorBlock
                            };
                        writeAsRunLog(
                            "PS Response" + Environment.NewLine +
                                resultError.ToString());

                        return resultError;
                }
            }
            catch
            {
                return
                    new PhotoShopResponse()
                    {
                        Status = CommunicationStatus.ERROR_COMMUNICATION
                    };
            }
        }