} // picture_bad2()

        /// <summary>
        ///
        /// </summary>
        /// <returns></returns>
        public BalanceResult GetBalance()
        {
            CCProtoPacket pack = null;

            if (_status != sCCC_PICTURE)
            {
                return(new BalanceResult(APIConstants.ccERR_STATUS));
            }

            pack         = new CCProtoPacket();
            pack.Command = CCProtoPacket.cmdCC_BALANCE;
            pack.Size    = 0;

            if (pack.PackTo(_stream) == false)
            {
                return(new BalanceResult(APIConstants.ccERR_NET_ERROR));
            }

            if (pack.UnpackFrom(_stream, -1, -1) == false)
            {
                return(new BalanceResult(APIConstants.ccERR_NET_ERROR));
            }

            switch (pack.Command)
            {
            case CCProtoPacket.cmdCC_BALANCE:
                return(new BalanceResult(APIConstants.ccERR_OK, Encoding.ASCII.GetString(pack.getData())));

            default:
                return(new BalanceResult(APIConstants.ccERR_UNKNOWN));
            }
        }
        /// <summary>
        ///
        /// </summary>
        /// <returns></returns>
        public int Close()
        {
            CCProtoPacket pack = new CCProtoPacket();

            pack.Command = CCProtoPacket.cmdCC_BYE;
            pack.Size    = 0;

            if (pack.PackTo(_stream) == false)
            {
                return(APIConstants.ccERR_NET_ERROR);
            }

            try
            {
                _client.Close();
            }
            catch (Exception) { }
            _status = sCCC_INIT;

            return(APIConstants.ccERR_OK);
        } // close()
        } // picture2()

        /// <summary>
        ///
        /// </summary>
        /// <param name="major_id"></param>
        /// <param name="minor_id"></param>
        /// <returns></returns>
        public int picture_bad2(int major_id, int minor_id)
        {
            CCProtoPacket pack = new CCProtoPacket();

            pack.Command = CCProtoPacket.cmdCC_PICTUREFL;

            CCPictDescr desc = new CCPictDescr();

            desc.setTimeout(APIConstants.ptoDEFAULT);
            desc.setType(APIConstants.ptUNSPECIFIED);
            desc.setMajorID(major_id);
            desc.setMinorID(minor_id);
            desc.calcSize();

            pack.setData(desc.pack());
            pack.calcSize();

            if (pack.PackTo(_stream) == false)
            {
                return(APIConstants.ccERR_NET_ERROR);
            }

            return(APIConstants.ccERR_NET_ERROR);
        } // picture_bad2()
        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public int Close()
        {
            CCProtoPacket pack = new CCProtoPacket();

            pack.Command = CCProtoPacket.cmdCC_BYE;
            pack.Size = 0;

            if (pack.PackTo(_stream) == false)
            {
                return APIConstants.ccERR_NET_ERROR;
            }

            try
            {
                _client.Close();
            }
            catch (Exception) { }
            _status = sCCC_INIT;

            return APIConstants.ccERR_OK;
        } // close()
        } // picture_bad2()


        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public BalanceResult GetBalance()
        {
            CCProtoPacket pack = null;

            if (_status != sCCC_PICTURE)
            {
                return new BalanceResult(APIConstants.ccERR_STATUS);
            }

            pack = new CCProtoPacket();
            pack.Command = CCProtoPacket.cmdCC_BALANCE;
            pack.Size = 0;

            if (pack.PackTo(_stream) == false)
            {
                return new BalanceResult(APIConstants.ccERR_NET_ERROR);
            }

            if (pack.UnpackFrom(_stream, -1, -1) == false)
            {
                return new BalanceResult(APIConstants.ccERR_NET_ERROR);
            }

            switch (pack.Command)
            {
                case CCProtoPacket.cmdCC_BALANCE:
                    return new BalanceResult(APIConstants.ccERR_OK, Encoding.ASCII.GetString(pack.getData()));
                default:
                    return new BalanceResult(APIConstants.ccERR_UNKNOWN);
            }
        }
        } // picture2()

        /// <summary>
        /// 
        /// </summary>
        /// <param name="major_id"></param>
        /// <param name="minor_id"></param>
        /// <returns></returns>
        public int picture_bad2(int major_id, int minor_id)
        {
            CCProtoPacket pack = new CCProtoPacket();

            pack.Command = CCProtoPacket.cmdCC_PICTUREFL;

            CCPictDescr desc = new CCPictDescr();
            desc.setTimeout(APIConstants.ptoDEFAULT);
            desc.setType(APIConstants.ptUNSPECIFIED);
            desc.setMajorID(major_id);
            desc.setMinorID(minor_id);
            desc.calcSize();

            pack.setData(desc.pack());
            pack.calcSize();

            if (pack.PackTo(_stream) == false)
            {
                return APIConstants.ccERR_NET_ERROR;
            }

            return APIConstants.ccERR_NET_ERROR;
        } // picture_bad2()
        /// <summary>  say "thanks" to Java incapability to pass values by reference in order to use them as multiple returns all arrays[] are used as workarond to get values out of the function, really </summary>
        /// <param name="pict"></param>
        /// <param name="pict_to"></param>
        /// <param name="pict_type"></param>
        /// <param name="text"></param>
        /// <param name="major_id"></param>
        /// <param name="minor_id"></param>
        /// <returns></returns>
        public int picture2(
         byte[] pict,   // IN  picture binary data
         int[] pict_to,   // IN/OUT timeout specifier to be used, on return - really used specifier, see ptoXXX constants, ptoDEFAULT in case of unrecognizable
         int[] pict_type,   // IN/OUT type specifier to be used, on return - really used specifier, see ptXXX constants, ptUNSPECIFIED in case of unrecognizable
         String[] text,   // OUT text
         int[] major_id,  // OUT OPTIONAL major part of the picture ID
         int[] minor_id  // OUT OPTIONAL minor part of the picture ID
        )
        {

            if (_status != sCCC_PICTURE)
                return APIConstants.ccERR_STATUS;

            CCProtoPacket pack = new CCProtoPacket();
            pack.Command = CCProtoPacket.cmdCC_PICTURE2;


            CCPictDescr desc = new CCPictDescr();
            desc.setTimeout(pict_to[0]);
            desc.setType(pict_type[0]);
            desc.setMajorID(0);
            desc.setMinorID(0);
            desc.setData(pict);
            desc.calcSize();

            pack.setData(desc.pack());
            pack.calcSize();

            if (pack.PackTo(_stream) == false)
            {
                return APIConstants.ccERR_NET_ERROR;
            }

            if (pack.UnpackFrom(_stream, -1, -1) == false)
            {
                return APIConstants.ccERR_NET_ERROR;
            }

            switch (pack.Command)
            {
                case CCProtoPacket.cmdCC_TEXT2:
                    desc.unpack(pack.getData());
                    pict_to[0] = desc.getTimeout();
                    pict_type[0] = desc.getType();
                    text[0] = desc.getData() == null ? "" : Encoding.ASCII.GetString(desc.getData());

                    if (major_id != null)
                        major_id[0] = desc.getMajorID();
                    if (minor_id != null)
                        minor_id[0] = desc.getMinorID();

                    return APIConstants.ccERR_OK;

                case CCProtoPacket.cmdCC_BALANCE:
                    // balance depleted
                    return APIConstants.ccERR_BALANCE;

                case CCProtoPacket.cmdCC_OVERLOAD:
                    // server's busy
                    return APIConstants.ccERR_OVERLOAD;

                case CCProtoPacket.cmdCC_TIMEOUT:
                    // picture timed out
                    return APIConstants.ccERR_TIMEOUT;

                case CCProtoPacket.cmdCC_FAILED:
                    // server's error
                    return APIConstants.ccERR_GENERAL;

                default:
                    // unknown error
                    return APIConstants.ccERR_UNKNOWN;
            }
        } // picture2()
        /// <summary>
        /// 
        /// </summary>
        /// <param name="hostname"></param>
        /// <param name="port"></param>
        /// <param name="username"></param>
        /// <param name="password"></param>
        /// <returns></returns>
        public int Login(string hostname, int port, string username, string password)
        {
            CCProtoPacket pack = null;
            var md5 = MD5.Create();
            var sha = SHA256.Create();

            int i = 0;
            int j = 0;

            _status = sCCC_INIT;

            try
            {
                _client = new TcpClient(hostname, port);
                _stream = _client.GetStream();
            }
            catch (Exception)
            {
                return APIConstants.ccERR_NET_ERROR;
            }
                
            pack = new CCProtoPacket();

            pack.Command = CCProtoPacket.cmdCC_LOGIN;
            pack.Size = username.Length;
            pack.setData(Encoding.ASCII.GetBytes(username));

            if (pack.PackTo(_stream) == false)
            {
                return APIConstants.ccERR_NET_ERROR;
            }

            if (pack.UnpackFrom(_stream, CCProtoPacket.cmdCC_RAND, CCProtoPacket.CC_RAND_SIZE) == false)
            {
                return APIConstants.ccERR_NET_ERROR;
            }

            byte[] md5bin = md5.ComputeHash(Encoding.ASCII.GetBytes(password));
            String md5str = "";
            char[] cvt = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
            for (i = 0; i < md5bin.Length; i++)
            {
                md5str += cvt[(md5bin[i] & 0xF0) >> 4];
                md5str += cvt[md5bin[i] & 0x0F];
            }

            byte[] shabuf = new byte[pack.getData().Length + md5str.Length + username.Length];
            j = 0;
            for (i = 0; i < pack.getData().Length; i++, j++)
            {
                shabuf[j] = pack.getData()[i];
            }
            for (i = 0; i < Encoding.ASCII.GetBytes(md5str).Length; i++, j++)
            {
                shabuf[j] = Encoding.ASCII.GetBytes(md5str)[i];
            }
            for (i = 0; i < Encoding.ASCII.GetBytes(username).Length; i++, j++)
            {
                shabuf[j] = Encoding.ASCII.GetBytes(username)[i];
            }

            pack = new CCProtoPacket();
            pack.Command = CCProtoPacket.cmdCC_HASH;
            pack.Size = CCProtoPacket.CC_HASH_SIZE;
            pack.setData(sha.ComputeHash(shabuf));

            if (pack.PackTo(_stream) == false)
            {
                return APIConstants.ccERR_NET_ERROR;
            }

            if (pack.UnpackFrom(_stream, CCProtoPacket.cmdCC_OK, 0) == false)
            {
                return APIConstants.ccERR_NET_ERROR;
            }

            _status = sCCC_PICTURE;

            return APIConstants.ccERR_OK;
        } // login()
        /// <summary>  say "thanks" to Java incapability to pass values by reference in order to use them as multiple returns all arrays[] are used as workarond to get values out of the function, really </summary>
        /// <param name="pict"></param>
        /// <param name="pict_to"></param>
        /// <param name="pict_type"></param>
        /// <param name="text"></param>
        /// <param name="major_id"></param>
        /// <param name="minor_id"></param>
        /// <returns></returns>
        public int picture2(
            byte[] pict,     // IN  picture binary data
            int[] pict_to,   // IN/OUT timeout specifier to be used, on return - really used specifier, see ptoXXX constants, ptoDEFAULT in case of unrecognizable
            int[] pict_type, // IN/OUT type specifier to be used, on return - really used specifier, see ptXXX constants, ptUNSPECIFIED in case of unrecognizable
            String[] text,   // OUT text
            int[] major_id,  // OUT OPTIONAL major part of the picture ID
            int[] minor_id   // OUT OPTIONAL minor part of the picture ID
            )
        {
            if (_status != sCCC_PICTURE)
            {
                return(APIConstants.ccERR_STATUS);
            }

            CCProtoPacket pack = new CCProtoPacket();

            pack.Command = CCProtoPacket.cmdCC_PICTURE2;


            CCPictDescr desc = new CCPictDescr();

            desc.setTimeout(pict_to[0]);
            desc.setType(pict_type[0]);
            desc.setMajorID(0);
            desc.setMinorID(0);
            desc.setData(pict);
            desc.calcSize();

            pack.setData(desc.pack());
            pack.calcSize();

            if (pack.PackTo(_stream) == false)
            {
                return(APIConstants.ccERR_NET_ERROR);
            }

            if (pack.UnpackFrom(_stream, -1, -1) == false)
            {
                return(APIConstants.ccERR_NET_ERROR);
            }

            switch (pack.Command)
            {
            case CCProtoPacket.cmdCC_TEXT2:
                desc.unpack(pack.getData());
                pict_to[0]   = desc.getTimeout();
                pict_type[0] = desc.getType();
                text[0]      = desc.getData() == null ? "" : Encoding.ASCII.GetString(desc.getData());

                if (major_id != null)
                {
                    major_id[0] = desc.getMajorID();
                }
                if (minor_id != null)
                {
                    minor_id[0] = desc.getMinorID();
                }

                return(APIConstants.ccERR_OK);

            case CCProtoPacket.cmdCC_BALANCE:
                // balance depleted
                return(APIConstants.ccERR_BALANCE);

            case CCProtoPacket.cmdCC_OVERLOAD:
                // server's busy
                return(APIConstants.ccERR_OVERLOAD);

            case CCProtoPacket.cmdCC_TIMEOUT:
                // picture timed out
                return(APIConstants.ccERR_TIMEOUT);

            case CCProtoPacket.cmdCC_FAILED:
                // server's error
                return(APIConstants.ccERR_GENERAL);

            default:
                // unknown error
                return(APIConstants.ccERR_UNKNOWN);
            }
        } // picture2()
        /// <summary>
        ///
        /// </summary>
        /// <param name="hostname"></param>
        /// <param name="port"></param>
        /// <param name="username"></param>
        /// <param name="password"></param>
        /// <returns></returns>
        public int Login(string hostname, int port, string username, string password)
        {
            CCProtoPacket pack = null;
            var           md5  = MD5.Create();
            var           sha  = SHA256.Create();

            int i = 0;
            int j = 0;

            _status = sCCC_INIT;

            try
            {
                _client = new TcpClient(hostname, port);
                _stream = _client.GetStream();
            }
            catch (Exception)
            {
                return(APIConstants.ccERR_NET_ERROR);
            }

            pack = new CCProtoPacket();

            pack.Command = CCProtoPacket.cmdCC_LOGIN;
            pack.Size    = username.Length;
            pack.setData(Encoding.ASCII.GetBytes(username));

            if (pack.PackTo(_stream) == false)
            {
                return(APIConstants.ccERR_NET_ERROR);
            }

            if (pack.UnpackFrom(_stream, CCProtoPacket.cmdCC_RAND, CCProtoPacket.CC_RAND_SIZE) == false)
            {
                return(APIConstants.ccERR_NET_ERROR);
            }

            byte[] md5bin = md5.ComputeHash(Encoding.ASCII.GetBytes(password));
            String md5str = "";

            char[] cvt = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
            for (i = 0; i < md5bin.Length; i++)
            {
                md5str += cvt[(md5bin[i] & 0xF0) >> 4];
                md5str += cvt[md5bin[i] & 0x0F];
            }

            byte[] shabuf = new byte[pack.getData().Length + md5str.Length + username.Length];
            j = 0;
            for (i = 0; i < pack.getData().Length; i++, j++)
            {
                shabuf[j] = pack.getData()[i];
            }
            for (i = 0; i < Encoding.ASCII.GetBytes(md5str).Length; i++, j++)
            {
                shabuf[j] = Encoding.ASCII.GetBytes(md5str)[i];
            }
            for (i = 0; i < Encoding.ASCII.GetBytes(username).Length; i++, j++)
            {
                shabuf[j] = Encoding.ASCII.GetBytes(username)[i];
            }

            pack         = new CCProtoPacket();
            pack.Command = CCProtoPacket.cmdCC_HASH;
            pack.Size    = CCProtoPacket.CC_HASH_SIZE;
            pack.setData(sha.ComputeHash(shabuf));

            if (pack.PackTo(_stream) == false)
            {
                return(APIConstants.ccERR_NET_ERROR);
            }

            if (pack.UnpackFrom(_stream, CCProtoPacket.cmdCC_OK, 0) == false)
            {
                return(APIConstants.ccERR_NET_ERROR);
            }

            _status = sCCC_PICTURE;

            return(APIConstants.ccERR_OK);
        } // login()