internal void EndAcceptControlConnection(IAsyncResult ar)
        {
            try {
                string _filePath     = (string)ar.AsyncState;
                Socket _clientSocket = controlSocket.EndAccept(ar);
                NetworkCommunicationManagers.Disconnect(controlSocket);
                controlSocket = _clientSocket;
                byte[] _buffer = packFileMetadata(_filePath);

                NetworkCommunicationManagers.SendIntOverSocket(dataSocket, _buffer.Length);
                NetworkCommunicationManagers.SendByteArrayOverSocket(dataSocket, _buffer);

                fileTransferContainer.FileTransferClassInstance = this;
                managedSendFileOverSockets(_filePath);
            }
            catch (Exception) {
                NetworkCommunicationManagers.Disconnect(controlSocket);
                NetworkCommunicationManagers.Disconnect(dataSocket);
                lock (RunningTransfers) {
                    if (fileTransferContainer.status != FileTransferStatus.Cancelled)
                    {
                        fileTransferContainer.status = FileTransferStatus.Error;
                    }
                }
                return;
            }
        }
        internal void EndAcceptDataConnection(IAsyncResult ar)
        {
            try {
                port2 = NetworkCommunicationManagers.FindNextFreeTcpPort();
                Socket _clientSocket = dataSocket.EndAccept(ar);
                NetworkCommunicationManagers.Disconnect(dataSocket);
                dataSocket = _clientSocket;
                NetworkCommunicationManagers.SendIntOverSocket(_clientSocket, port2);

                controlSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                controlSocket.Bind(new System.Net.IPEndPoint(System.Net.IPAddress.Any, port2));
                controlSocket.Listen(1);
                controlSocket.BeginAccept(new AsyncCallback(EndAcceptControlConnection), ar.AsyncState);
            }
            catch (Exception) {
                NetworkCommunicationManagers.Disconnect(dataSocket);
                lock (RunningTransfers) {
                    if (fileTransferContainer.status != FileTransferStatus.Cancelled)
                    {
                        fileTransferContainer.status = FileTransferStatus.Error;
                    }
                }
                return;
            }
        }
        internal void managedSendFileOverSockets(string filePath)
        {
            fileTransferContainer.filePath = filePath;

            short       _count   = 0;
            const short _INITIAL = 5000;

            Thread _thread = new Thread(() => monitorControlChannel());

            _thread.Name         = "Control Socket monitor for " + dataSocket.RemoteEndPoint.ToString();
            _thread.IsBackground = true;
            _thread.Start();

            using (FileStream _fs = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) {
                byte[] _fileBuffer = new byte[FILE_BUFFER_SIZE];

                long _size = _fs.Length;

                try {
                    long _index = 0;

                    //Send the initial chunk of data
                    while (dataSocket.Connected && controlSocket.Connected && _index < _size)
                    {
                        if (fileTransferContainer.status == FileTransferStatus.Paused)
                        {
                            resetEvent.WaitOne();
                        }

                        _fs.Position = _index;
                        int _read = _fs.Read(_fileBuffer, 0, _fileBuffer.Length);

                        try {
                            NetworkCommunicationManagers.SendIntOverSocket(dataSocket, _read);

                            if (_read != _fileBuffer.Length)
                            {
                                byte[] _temp = new byte[_read];
                                Buffer.BlockCopy(_fileBuffer, 0, _temp, 0, _read);
                                NetworkCommunicationManagers.SendByteArrayOverSocket(dataSocket, _temp);
                            }
                            else
                            {
                                NetworkCommunicationManagers.SendByteArrayOverSocket(dataSocket, _fileBuffer);
                            }
                        }
                        catch (SocketException) {
                            continue;
                        }

                        _index += _read;
                        _count++;
                        if (_count % 200 == 0)
                        {
                            lock (RunningTransfers) {
                                if (Math.Round(((((double)_index / _size) * 100) - fileTransferContainer.progress), 1) >= 0.1)
                                {
                                    fileTransferContainer.progress = (float)Math.Round(((double)_index / _size) * 100, 1);
                                }
                            }
                        }
                        if (_count == _INITIAL)
                        {
                            _count = 0;
                            break;
                        }
                    }

                    //Send the remaining data
                    while (dataSocket.Connected && controlSocket.Connected && _index < _size)
                    {
                        _fs.Position = _index;
                        int _read = _fs.Read(_fileBuffer, 0, _fileBuffer.Length);

                        try {
                            NetworkCommunicationManagers.SendIntOverSocket(dataSocket, _read);
                            if (_read != _fileBuffer.Length)
                            {
                                byte[] _temp = new byte[_read];
                                Buffer.BlockCopy(_fileBuffer, 0, _temp, 0, _read);
                                NetworkCommunicationManagers.SendByteArrayOverSocket(dataSocket, _temp);
                            }
                            else
                            {
                                NetworkCommunicationManagers.SendByteArrayOverSocket(dataSocket, _fileBuffer);
                            }
                        }
                        catch (SocketException) {
                            continue;
                        }

                        _index += _read;
                        _count++;
                        if (_count % 200 == 0)
                        {
                            lock (RunningTransfers){
                                if (Math.Round(((((double)_index / _size) * 100) - fileTransferContainer.progress), 1) >= 0.1)
                                {
                                    fileTransferContainer.progress = (float)Math.Round((((double)_index / _size) * 100), 1);
                                }
                            }
                            bool _wait = true;
                            while (true)
                            {
                                lock (syncObject) {
                                    if (acknowledgedTransfers > 0)
                                    {
                                        acknowledgedTransfers--;
                                        _wait = false;
                                        break;
                                    }
                                }
                                if (_wait)
                                {
                                    Thread.Sleep(100);
                                }
                            }
                        }
                    }
                    if (_index == _size)
                    {
                        lock (RunningTransfers) {
                            fileTransferContainer.progress = 100;
                            fileTransferContainer.status   = FileTransferStatus.Finished;
                        }
                    }
                    else
                    {
                        lock (RunningTransfers) {
                            if (fileTransferContainer.status != FileTransferStatus.Cancelled)
                            {
                                fileTransferContainer.status = FileTransferStatus.Error;
                            }
                        }
                    }
                }
                catch {
                    lock (RunningTransfers) {
                        if (fileTransferContainer.status != FileTransferStatus.Cancelled)
                        {
                            fileTransferContainer.status = FileTransferStatus.Error;
                        }
                    }
                }
            }
        }
        internal bool AcceptFileTransfer(Socket socket, int port1, MainWindow mainWindow)
        {
            int             _port2;
            SocketException _socketException;

            if (!NetworkCommunicationManagers.ConnectToEndPoint(port1, socket.RemoteEndPoint.ToString().Remove(socket.RemoteEndPoint.ToString().LastIndexOf(':')), out dataSocket, out _socketException))
            {
                return(false);
            }

            NetworkCommunicationManagers.ReceiveIntOverSocket(dataSocket, out _port2);

            if (!NetworkCommunicationManagers.ConnectToEndPoint(_port2, socket.RemoteEndPoint.ToString().Remove(socket.RemoteEndPoint.ToString().LastIndexOf(':')), out controlSocket, out _socketException))
            {
                return(false);
            }

            fileTransferContainer.FileTransferClassInstance = this;

            byte[] _buffer = null;
            int    _temp;
            long   _size;
            string _filename;

            try {
                NetworkCommunicationManagers.ReceiveIntOverSocket(dataSocket, out _temp);
                NetworkCommunicationManagers.ReceiveByteArrayOverSocket(dataSocket, out _buffer, _temp);
            }
            catch (ObjectDisposedException) {
                NetworkCommunicationManagers.Disconnect(dataSocket);
                NetworkCommunicationManagers.Disconnect(controlSocket);
                return(false);
            }
            catch (SocketException) {
                NetworkCommunicationManagers.Disconnect(dataSocket);
                NetworkCommunicationManagers.Disconnect(controlSocket);
                return(false);
            }

            unpackFileMetadata(_buffer, out _filename, out _size);

            fileTransferContainer.fileName    = _filename;
            fileTransferContainer.sizeInBytes = _size;
            fileTransferContainer.size        = Converters.DataConverter.bytesToReadableString(_size);

            if (_size > mainWindow.maxAcceptedFileSizeWithoutConfirmation)
            {
                ManualResetEvent _replyRecieved           = new ManualResetEvent(false);
                System.Windows.MessageBoxResult _continue = System.Windows.MessageBoxResult.No;
                mainWindow.Dispatcher.Invoke(DispatcherPriority.Normal, (Action)(() => {
                    Thread.Sleep(1000);
                    _continue = System.Windows.MessageBox.Show("Receive file \"" + _filename + "\" from " + socket.RemoteEndPoint.ToString().Remove(socket.RemoteEndPoint.ToString().LastIndexOf(':')) + " (Size: " + _size + " bytes)", "File Transfer", System.Windows.MessageBoxButton.YesNo);
                    _replyRecieved.Set();
                }));
                _replyRecieved.WaitOne();
                _replyRecieved.Dispose();
                if (_continue != System.Windows.MessageBoxResult.Yes)
                {
                    mainWindow.Dispatcher.Invoke(DispatcherPriority.Normal, (Action)(() => {
                        lock (RunningTransfers) {
                            RunningTransfers.Remove(fileTransferContainer);
                        }
                    }));
                    NetworkCommunicationManagers.Disconnect(dataSocket);
                    NetworkCommunicationManagers.Disconnect(controlSocket);
                    return(false);
                }
            }

            if (!Directory.Exists(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), "Downloads", "ChatApp")))
            {
                Directory.CreateDirectory(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), "Downloads", "ChatApp"));
            }
            ;

            string _filePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), "Downloads", "ChatApp", _filename);

            if (File.Exists(_filePath))
            {
                string _extension, _assignedFilename;
                if (_filename.LastIndexOf('.') == -1)
                {
                    _extension        = "";
                    _assignedFilename = _filename;
                }
                else
                {
                    _extension        = "." + _filename.Remove(0, _filename.LastIndexOf('.') + 1);
                    _assignedFilename = _filename.Remove(_filename.Length - _extension.Length, _extension.Length);
                }

                for (int i = 0; true; i++)
                {
                    _filePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), "Downloads", "ChatApp", _assignedFilename + "(" + i + ")" + _extension);
                    if (!File.Exists(_filePath))
                    {
                        break;
                    }
                }
            }

            fileTransferContainer.filePath = _filePath;

            return(managedReceiveFileOverSockets(_filePath, _size));
        }
        internal bool managedReceiveFileOverSockets(string filePath, long length)
        {
            short _count = 0;
            long  _index = 0;
            int   _size  = 1;

            Thread _thread = new Thread(() => monitorControlChannel());

            _thread.Name         = "Control Socket monitor for " + dataSocket.RemoteEndPoint.ToString();
            _thread.IsBackground = true;
            _thread.Start();

            try {
                using (FileStream _fs = new FileStream(filePath + ".temp", FileMode.CreateNew)) {
                    _fs.SetLength(length);
                    byte[] _buffer;

                    while (dataSocket.Connected && controlSocket.Connected && _index < length)
                    {
                        if (fileTransferContainer.status == FileTransferStatus.Paused)
                        {
                            resetEvent.WaitOne();
                        }
                        if (!NetworkCommunicationManagers.ReceiveIntOverSocket(dataSocket, out _size))
                        {
                            continue;
                        }
                        ;
                        _buffer = new byte[_size];
                        if (!NetworkCommunicationManagers.ReceiveByteArrayOverSocket(dataSocket, out _buffer, _size))
                        {
                            continue;
                        }
                        ;


                        _fs.Position = _index;
                        _fs.Write(_buffer, 0, _buffer.Length);
                        _index += _size;
                        _count++;
                        if (_count % 200 == 0)
                        {
                            lock (RunningTransfers) {
                                if (Math.Round(((((double)_index / length) * 100) - fileTransferContainer.progress), 1) >= 0.1)
                                {
                                    fileTransferContainer.progress = (float)Math.Round((((double)_index / length) * 100), 1);
                                }
                            }
                            _count = 0;
                            ThreadPool.QueueUserWorkItem(state => {
                                lock (controlSocket) {
                                    NetworkCommunicationManagers.SendByteArrayOverSocket(controlSocket, new byte[] { (byte)FileTransferCommands.BlockTransferred });
                                }
                            });
                        }
                    }
                }
                lock (controlSocket) {
                    NetworkCommunicationManagers.SendByteArrayOverSocket(controlSocket, new byte[] { (byte)FileTransferCommands.EndTransfer });
                }
            }
            catch (ObjectDisposedException) {
                NetworkCommunicationManagers.Disconnect(controlSocket);
                NetworkCommunicationManagers.Disconnect(dataSocket);
            }
            catch (SocketException) {
                NetworkCommunicationManagers.Disconnect(controlSocket);
                NetworkCommunicationManagers.Disconnect(dataSocket);
            }

            if (_index < length)
            {
                try {
                    File.Delete(filePath + ".temp");
                }
                catch { }
                lock (RunningTransfers) {
                    if (fileTransferContainer.status != FileTransferStatus.Cancelled)
                    {
                        fileTransferContainer.status = FileTransferStatus.Error;
                    }
                }
                return(false);
            }
            else
            {
                try {
                    File.Move(filePath + ".temp", filePath);
                }
                catch (IOException) {
                    try {
                        File.Delete(filePath + ".temp");
                    }
                    catch { }
                }
                lock (RunningTransfers) {
                    fileTransferContainer.status   = FileTransferStatus.Finished;
                    fileTransferContainer.progress = 100;
                }
            }
            return(true);
        }
        internal void monitorControlChannel()
        {
            try {
                byte[] arr;
                FileTransferCommands _command;
                while (controlSocket.Connected)
                {
                    if (!NetworkCommunicationManagers.ReceiveByteArrayOverSocket(controlSocket, out arr, 1))
                    {
                        continue;
                    }
                    _command = (FileTransferCommands)arr[0];
                    switch (_command)
                    {
                    case FileTransferCommands.BlockTransferred:
                        lock (syncObject) {
                            acknowledgedTransfers++;
                        }
                        break;

                    case FileTransferCommands.EndTransfer:
                        NetworkCommunicationManagers.Disconnect(controlSocket);
                        NetworkCommunicationManagers.Disconnect(dataSocket);
                        return;

                    case FileTransferCommands.Pause:
                        lock (RunningTransfers) {
                            fileTransferContainer.status = FileTransferStatus.Paused;

                            if (fileTransferContainer.pausedBy == PausedBy.None)
                            {
                                fileTransferContainer.pausedBy = PausedBy.OtherPeer;
                            }
                            else if (fileTransferContainer.pausedBy == PausedBy.User)
                            {
                                fileTransferContainer.pausedBy = PausedBy.Both;
                            }
                        }

                        ThreadPool.QueueUserWorkItem(state => {
                            lock (controlSocket) {
                                NetworkCommunicationManagers.SendByteArrayOverSocket(controlSocket, new byte[] { (byte)FileTransferCommands.PauseOrResumeRequestReceived });
                            }
                        });

                        break;

                    case FileTransferCommands.PauseOrResumeRequestReceived:
                        lock (RunningTransfers) {
                            if (fileTransferContainer.transferType == FileTransferType.Upload)
                            {
                                if (fileTransferContainer.status == FileTransferStatus.Paused && fileTransferContainer.pausedBy == PausedBy.None)
                                {
                                    fileTransferContainer.status = FileTransferStatus.Running;
                                    resetEvent.Set();
                                }
                            }
                            else if (fileTransferContainer.transferType == FileTransferType.Download)
                            {
                                if (fileTransferContainer.pausedBy != PausedBy.None && fileTransferContainer.status == FileTransferStatus.Running)
                                {
                                    fileTransferContainer.status = FileTransferStatus.Paused;
                                }
                            }
                        }
                        break;

                    case FileTransferCommands.Resume:
                        lock (RunningTransfers) {
                            if (fileTransferContainer.pausedBy == PausedBy.OtherPeer)
                            {
                                fileTransferContainer.pausedBy = PausedBy.None;
                                fileTransferContainer.status   = FileTransferStatus.Running;
                                resetEvent.Set();
                            }
                            else if (fileTransferContainer.pausedBy == PausedBy.Both)
                            {
                                fileTransferContainer.pausedBy = PausedBy.User;
                            }

                            ThreadPool.QueueUserWorkItem(state => {
                                lock (controlSocket) {
                                    NetworkCommunicationManagers.SendByteArrayOverSocket(controlSocket, new byte[] { (byte)FileTransferCommands.PauseOrResumeRequestReceived });
                                }
                            });
                        }
                        break;
                    }
                }
            }
            catch (ObjectDisposedException) {}
            catch (SocketException) {}
            finally {
                NetworkCommunicationManagers.Disconnect(controlSocket);
                NetworkCommunicationManagers.Disconnect(dataSocket);
            }
        }