///// <summary>
        ///// respond only by header
        ///// </summary>
        ///// <param name="verb">GET or HEAD</param>
        ///// <param name="resource">Same as key or contentLocation</param>
        ///// <param name="senderList"></param>
        ///// <param name="contentLength"></param>
        ///// <param name="mimeType"></param>
        ///// <param name="lastVer"></param>
        ///// <param name="isDeleted">Indicates that the current entry is deleted</param>
        ///// <param name="willClose">Writes a close message in the header</param>
        ///// <param name="bufferedOutput">A memory buffer that will be filled with contents produced
        ///// from this method</param>
        //private void ResponseHeadStub(string verb, string resource, List<int> senderList, List<int> proxyResponsePath, int contentLength,
        //    string mimeType, ETag lastVer, bool isDeleted, bool willClose, MemoryStream bufferedOutput)
        //{
        //    StreamWriter writer = new StreamWriter(bufferedOutput, Encoding.ASCII);
        //        writer.NewLine = NEWLINE;
        //        if (isDeleted)
        //        {
        //            WriteResponseDeleted(bufferedOutput, resource, senderList, proxyResponsePath, lastVer.UID, lastVer.Revision);
        //        }
        //        else
        //        {
        //            WriteResponseHeader(writer, resource, mimeType, contentLength, lastVer.UID, lastVer.Revision, senderList, proxyResponsePath, verb, willClose);
        //        }
        //}
        // respond to a GET request, HEAD request, and push data on wire
        private void Response(string verb, string resource, List<int> senderList,List<int> proxyResponsePath,  DataEntry entry, MemoryStream bufferedOutput, bool willClose)
        {
            lock (entry)
                {
                    if (entry.IsEmpty)
                    {
                        WriteResponseDeleted(bufferedOutput, resource, senderList, proxyResponsePath, entry.lastOwnerID, entry.lastOwnerRevision);
                    }

                    else if (entry.IsSimpleValue || entry.type == DataEntry.ValueType.String)
                    {
                        StreamWriter writer = new StreamWriter(bufferedOutput, Encoding.ASCII);
                        writer.NewLine = NEWLINE;

                        string translation ="";
                        if (entry.value != null)
                            translation = entry.value.ToString();

                        byte[] bytesToWrite = System.Text.Encoding.UTF8.GetBytes(translation);

                        WriteResponseHeader(writer, resource, entry.GetMime(), bytesToWrite.Length, entry.lastOwnerID, entry.lastOwnerRevision, senderList, proxyResponsePath, verb, willClose);
                        writer.Flush();
                        if (verb == GET)
                        {
                            bufferedOutput.Write(bytesToWrite, 0, bytesToWrite.Length);
                            //StreamWriter tw = new StreamWriter(bufferedOutput, Encoding.UTF8);
                            //    tw.NewLine = NEWLINE;

                            //    tw.BaseStream.Seek(0, SeekOrigin.End);
                            //    tw.Write(translation);
                            //    tw.Flush();

                        }
                        writer.Flush();
                    }
                    else if (entry.IsComplexValue)
                    {
                        if (entry.type == DataEntry.ValueType.Binary)
                        {
                            StreamWriter writer = new StreamWriter(bufferedOutput, Encoding.ASCII);
                            writer.NewLine = NEWLINE;

                            byte[] bentry = (byte[])entry.value;
                            WriteResponseHeader(writer, resource, entry.GetMime(), bentry.Length, entry.lastOwnerID, entry.lastOwnerRevision, senderList, proxyResponsePath, verb, willClose);
                            writer.Flush();

                            if (verb == GET)
                            {
                                bufferedOutput.Write(bentry, 0, bentry.Length);
                            }

                        }
                        else if (entry.type == DataEntry.ValueType.Object)
                        {
                            StreamWriter writer = new StreamWriter(bufferedOutput, Encoding.ASCII);
                            writer.NewLine = NEWLINE;

                            MemoryStream bentry;
                            try
                            {
                                bentry = new MemoryStream();
                                BinaryFormatter formatter = new BinaryFormatter();
                                formatter.Serialize(bentry, entry.value);
                            }
                            catch
                            {
                                throw;
                            }

                            System.Diagnostics.Debug.Assert(bentry.Length <= int.MaxValue);

                            WriteResponseHeader(writer, resource, entry.GetMime(), (int)bentry.Length, entry.lastOwnerID, entry.lastOwnerRevision, senderList, proxyResponsePath, verb, willClose);
                            writer.Flush();

                            if (verb == GET)
                            {

                                bentry.WriteTo(bufferedOutput);
                            }
                        }
                        else if (entry.type == Data.ValueType.Unknown)
                        {
                            StreamWriter writer = new StreamWriter(bufferedOutput, Encoding.ASCII);
                            writer.NewLine = NEWLINE;

                            byte[] bentry = ((DataUnsupported) entry.value).GetPayload();
                            WriteResponseHeader(writer, resource, entry.GetMime(), bentry.Length, entry.lastOwnerID, entry.lastOwnerRevision, senderList, proxyResponsePath, verb, willClose);
                            writer.Flush();

                            if (verb == GET)
                            {
                                bufferedOutput.Write(bentry, 0, bentry.Length);
                            }
                        }
                        else
                        {
                            throw new NotImplementedException();
                        }

                    }

                    else
                    {
                        throw new NotImplementedException();
                    }
                }
        }
        /// <summary>
        /// TODO: add in some code to reduce round-trips to simple data types 
        /// </summary>
        /// <param name="reader">File to read</param>
        /// <param name="sentFromList">Sent from list</param>
        /// <param name="getEntriesFromSender">This function fills in a list of entries that need to be requested from the sender</param>
        /// <param name="addEntriesToSender">These are entries that the sender does not know about</param>
        /// <seealso cref="ReadHeadStub"/>
        private void ReadDictionaryTextFile(StreamReader reader, List<int> sentFromList, List<DataHeader> getEntriesFromSender, List<SendMemoryToPeer> addEntriesToSender)
        {
            // 0 - key name
            // 1 - owner
            // 2 - revision
            // 3 - rw flag
            // 4 - MIME type

            // WriteDebug(this.local_uid + " ReadDictionaryTextFile");

            string nsLine = reader.ReadLine();
            string[] nsLineParts = nsLine.Split('\t');

            System.Diagnostics.Debug.Assert(nsLineParts[0] == DATA_NAMESPACE + "/");

            // if the owner of the dictionary is the same as myself, skip reading the changes
            if (nsLineParts[1] == this.local_uid.ToString())
            {
                throw new NotSupportedException("ReadDictionaryTextFile cannot read itself");// i want to see if this actually can happen (only when multiple connections happen on the same server)

            }

            int itemCount = int.Parse(nsLineParts[4]); // count of all the items in the dictionary

            List<DataEntry> entriesCovered = new List<DataEntry>(itemCount + this.data.Count);

            for (int i = 0; i < itemCount; i++)
            {
                nsLine = reader.ReadLine();
                nsLineParts = nsLine.Split('\t');
                //WriteDebug(nsLine);

                DataHeader getEntry = null;
                SendMemoryToPeer addEntryToSender = null;

                ETag tag = new ETag(int.Parse(nsLineParts[1]), int.Parse(nsLineParts[2]));

                // this entry is used only to call ReadMimeSimpleData
                DataEntry fakeEntry = new DataEntry("/fake", tag, new List<int>(0));
                fakeEntry.ReadMimeSimpleData(nsLineParts[4]);

                dataLock.EnterReadLock();
                try
                {
                    if (this.data.ContainsKey(nsLineParts[0]))
                    {
                        entriesCovered.Add(this.data[nsLineParts[0]]);
                    }
                }
                finally { dataLock.ExitReadLock(); }

                // the dictionary does not report the current sender so let's tack it on
                List<int> listOfSenders = new List<int>(GetArrayOf(nsLineParts[5]));
                if (!listOfSenders.Contains(this.remote_uid))
                    listOfSenders.Add(this.remote_uid);

                ResponseAction action = ReadDataStub(nsLineParts[0], fakeEntry.GetMime(), nsLineParts[1] + "." + nsLineParts[2], new List<int>( listOfSenders), out getEntry, out addEntryToSender);

                if (getEntry != null)
                {
                    getEntriesFromSender.Add(getEntry);
                }
                if (addEntryToSender != null)
                {
                    addEntriesToSender.Add(addEntryToSender);
                }

                if (action == ResponseAction.ForwardToAll)
                {
                    listOfSenders.Clear();
                }
                if (action != ResponseAction.DoNotForward)
                {
                    DataEntry get = P2PDictionary.GetEntry( this.data, this.dataLock, nsLineParts[0]);
                    System.Diagnostics.Debug.Assert(get != null);

                    listOfSenders.Add(this.local_uid);
                    SendBroadcastMemory msg = new SendBroadcastMemory(get.key , listOfSenders);
                    WriteMethodPush(get.key, listOfSenders, null, 0, get.GetMime(), get.GetETag(), get.IsEmpty, false, msg.MemBuffer);
                    this.controller.BroadcastToWire(msg);
                }
            }

            // now check to see which dictionary entries that the sender does not have; i'll send my entries to the caller
            this.dataLock.EnterWriteLock();
            try
            {
                foreach (KeyValuePair<string, DataEntry> senderDoesNotHave in this.data.SkipWhile(x => entriesCovered.Contains(x.Value)))
                {
                    DataEntry get = senderDoesNotHave.Value;

                    // i know about something that the sender does not know
                    SendMemoryToPeer mem = new SendMemoryToPeer(get.key, sentFromList);
                    WriteMethodPush(get.key, GetListOfThisLocalID(), null, 0, get.GetMime(), get.GetETag(), get.IsEmpty, false, mem.MemBuffer);
                    addEntriesToSender.Add(mem);
                }
            }
            finally { this.dataLock.ExitWriteLock();}
        }