/// <summary>
        /// constructor with params.
        /// actual object should be passed.
        /// </summary>
        /// <param name="encryptdecrypt">
        /// used for encrypt/decrypt. 
        /// should be valid object.
        /// </param>
        /// <param name="netStream">
        /// used for network communication.
        /// should be valid object AND connected to host.
        /// </param>
        /// <exception cref="ArgumentNullException">
        /// thrown when <paramref name="encryptdecrypt"/> is null
        /// </exception>
        /// <exception cref="ArgumentNullException">
        /// thrown when <paramref name="netStream"/> is null
        /// </exception>
        /// <exception cref="ArgumentException">
        /// thrown when <paramref name="netStream"/> is not connected
        /// </exception>
        protected IOHandler(
            EncryptDecrypt encryptdecrypt,
            NetworkStream netStream)
            : this()
        {
            if (null == encryptdecrypt)
                throw
                    new ArgumentNullException("encryptdecrypt");

            if (null == netStream)
                throw
                    new ArgumentNullException("netStream");

            if (false == netStream.CanRead ||
                false == netStream.CanWrite)
                throw
                    new ArgumentException(
                        "should be open and connected to PhotoShop",
                        "netStream");

            this._encryptDecrypt = encryptdecrypt;
            this._netStream = netStream;

            queueCheckNotification();
        }
 /// <summary>
 /// generate encrypted byte array from current object's fields's values.
 /// </summary>
 /// <param name="encryptor">used for enscryption</param>
 /// <returns>
 /// encrypted byte array representation of current object
 /// </returns>
 public byte[] GetEncryptedBuffer(
     EncryptDecrypt encryptor)
 {
     return encryptor.Encrypt(GetPlainBuffer());
 }
        /// <summary>
        /// create new <see cref="IOHandler"/> object from given parameters.
        /// </summary>
        /// <param name="password">password used with encrypt/decrypt</param>
        /// <param name="hostName">communication target</param>
        /// <param name="writer">
        /// as run logger, 
        /// Actually, 
        /// <seealso cref="TextWriter.WriteLine(string)"/> is the only function used.
        /// </param>
        /// <param name="localPort">
        /// local host port, when establishing communication socket
        /// </param>
        /// <returns>
        /// newly created <see cref="IOHandler"/> object 
        /// </returns>
        /// <exception cref="ArgumentNullException">
        /// thrown when <paramref name="password"/> is null or empty
        /// </exception>
        /// <exception cref="ArgumentOutOfRangeException">
        /// thrown when password argument contains characters 
        /// except ascii visible characters ([\x20-\x7E]) 
        /// </exception>
        /// <exception cref="ArgumentNullException">
        /// thrown when <paramref name="hostName"/> is null or empty
        /// </exception>
        public static IOHandler CreateNew(
            string password,
            string hostName,
            TextWriter writer = null,
            int localPort = Constants.LOCAL_PORT_DEFAULT)
        {
            if (string.IsNullOrEmpty(password))
                throw
                    new ArgumentNullException("password");

            if (false == password.IsPhotoShopPBKDF2AcceptableString())
                throw
                    new ArgumentOutOfRangeException(
                        "password",
                        "password should be composed of " +
                            "ascii visible characters ([\x20-\x7E]).");

            if (string.IsNullOrEmpty(hostName))
                throw
                    new ArgumentNullException("hostName");

            var encryptDecrypt = new EncryptDecrypt(password);

            var tcpclient =
                new TcpClient(
                    new IPEndPoint(
                        IPAddress.Parse("0.0.0.0"),
                        localPort));
            tcpclient.Connect(hostName, PhotoShopConstants.COMMUNICATION_PORT);
            var netStream = tcpclient.GetStream();

            return
                new IOHandler(encryptDecrypt, netStream)
                {
                    AsRunLogger = writer
                };
        }
        /// <summary>
        /// create new <see cref="DataBlock"/> from given encrypted byte array
        /// </summary>
        /// <param name="decryptor">
        /// used for descryption of given encrypted byte array</param>
        /// <param name="encryptedBytes">
        /// encrypted byte array to decrypt</param>
        /// <returns>
        /// new <see cref="DataBlock"/> from given encrypted byte array
        /// </returns>
        /// <exception cref="ArgumentNullException">
        /// thrown when given "decryptor" parameter is null
        /// </exception>
        /// <exception cref="ArgumentNullException">
        /// thrown when given "encryptedBytes" parameter is null
        /// </exception>
        /// <exception cref="ArgumentOutOfRangeException">
        /// thrown when given "encryptedBytes" parameter is shorter than 
        /// <seealso cref="PhotoShopConstants.PROTOCOL_LENGTH"/>
        /// </exception>
        public static DataBlock CreateNonErrorDataBlock(
            EncryptDecrypt decryptor,
            byte[] encryptedBytes)
        {
            // check for required conditions
            if (null == decryptor)
                throw new ArgumentNullException("decryptor");
            if (null == encryptedBytes)
                throw new ArgumentNullException("encryptedBytes");
            if (encryptedBytes.Length < PhotoShopConstants.PROTOCOL_LENGTH)
                throw new ArgumentOutOfRangeException("encryptedBytes");

            using (var msStream = new MemoryStream(decryptor.Decrypt(encryptedBytes)))
            {
                var result = new DataBlock();
                using (var brReader = new BinaryReader(msStream))
                {
                    // protocol version, transaction id, content type are passed
                    // with Big-Endian byte order
                    // so need to convert to host byte order, ie little-endian
                    result.ProtocolVersion =
                        IPAddress.NetworkToHostOrder(
                            brReader.ReadInt32());
                    result.TransactionID =
                        IPAddress.NetworkToHostOrder(
                            brReader.ReadInt32());
                    var contentTypeValue =
                        IPAddress.NetworkToHostOrder(
                            brReader.ReadInt32());
                    switch (contentTypeValue)
                    {
                        case (int)ContentType.ERRORSTRING:
                        case (int)ContentType.JAVASCRIPT:
                        case (int)ContentType.IMAGE:
                        case (int)ContentType.PROFILE:
                        case (int)ContentType.DATA:
                            result.ContentType = (ContentType)contentTypeValue;
                            break;
                        default:
                            break;
                    }
                    var toRead =
                        (int)(msStream.Length - PhotoShopConstants.PROTOCOL_LENGTH);
                    result.Content =
                        (0 == toRead) ?
                        null :
                        brReader.ReadBytes(toRead);

                    return result;
                }
            }
        }