int IMessageController.SendToPeer(SendMemoryToPeer message)
 {
     if (this.IsAlive)
     {
         return(CastTargetController.SendToPeer(message));
     }
     else
     {
         return(0);
     }
 }
        /// <summary>
        /// Closes the TCP connection as soon as possible.
        /// </summary>
        internal void Close(bool disposing)
        {
            // TODO: need to create an asymmetric close handshake
            SendMemoryToPeer endMsg = new SendMemoryToPeer(CLOSE_MESSAGE, new List<int>() { this.remote_uid });
            ResponseCode(endMsg.MemBuffer, CLOSE_MESSAGE, GetListOfThisLocalID(), 0, 0, 200);
            SendToRemoteClient(endMsg);

            if (!disposing)
            {
                // spin wait
                while (this.state != ConnectionState.Closed)
                {
                    Thread.Sleep(P2PDictionary.SLEEP_WAIT_TO_CLOSE);
                }
            }
        }
        private void HandleReadDelete(string contentLocation,string eTag, List<int> senders, List<int> responsePath )
        {
            // handle proxy messages
            if (contentLocation.StartsWith(PROXY_PREFIX + "/"))
            {
                contentLocation = contentLocation.Substring(PROXYPREFIX_REMOVE);
                if (!keysToListen.IsSubscribed(contentLocation))
                {
                    keysToListen.AddSubscription(contentLocation, SubscriptionInitiator.AutoProxyKey);
                }
            }

            // read
            ResponseAction status = ReadDelete(contentLocation, eTag, new List<int>(senders));

            if (status == ResponseAction.ForwardToAll)
            {
                //conflict happened in data somewhere
                // return new data to sender
                senders.Clear();
            }

            if (status != ResponseAction.DoNotForward)
            {
                // send a notification of deleted content immediately
                DataEntry entry = P2PDictionary.GetEntry(this.data, this.dataLock, contentLocation);
                System.Diagnostics.Debug.Assert(entry != null);

                // add to wire to send out
                senders.Add(this.local_uid);// add my sender to the packet
                SendBroadcastMemory sendMsg = new SendBroadcastMemory(entry.key, senders);
                WriteMethodDeleted(sendMsg.MemBuffer, contentLocation, senders, responsePath, entry.lastOwnerID, entry.lastOwnerRevision);
                controller.BroadcastToWire(sendMsg);
            }

            if (responsePath != null)
            {
                // well, i still have to send out this message because there is a path requested to follow
                DataEntry entry = P2PDictionary.GetEntry(this.data, this.dataLock, contentLocation);
                System.Diagnostics.Debug.Assert(entry != null);

                SendMemoryToPeer sendMsg = new SendMemoryToPeer(entry.key, responsePath);
                senders.Add(this.local_uid);// add my sender to the packet
                WriteMethodDeleted(sendMsg.MemBuffer, PROXY_PREFIX + contentLocation, senders, responsePath, entry.lastOwnerID, entry.lastOwnerRevision);

            }
        }
        /// <summary>
        /// Creates a message with LocalUID as the sender list
        /// </summary>
        /// <param name="proxyKey">The resource name to return, prefixed with proxy/* for a proxy response.</param>
        /// <param name="key">Any dictionary element in the data/* namespace, or the data dictionary itself.</param>
        /// <returns></returns>
        public SendMemoryToPeer CreateResponseMessage(string key, string proxyKey, List<int> senderPath, List<int>  includeList, List<int> proxyResponsePath)
        {
            SendMemoryToPeer msg = new SendMemoryToPeer(proxyKey, includeList);

            if (key == DATA_NAMESPACE)
            {
                ResponseDictionary(GET, msg.MemBuffer, senderPath, proxyResponsePath, false);
            }
            else
            {
                DataEntry entry = P2PDictionary.GetEntry( this.data, this.dataLock, key);
                System.Diagnostics.Debug.Assert(entry != null);
                if (!entry.subscribed)
                {
                    throw new NotImplementedException();
                }

                Response(GET, proxyKey, senderPath, proxyResponsePath, entry, msg.MemBuffer, false);
            }

            return msg;
        }
        /// <summary>
        /// Fills bufferedOutput with the response, or asks the controller to pull the contentLocation from another peer.
        /// </summary>
        /// <param name="contentLocation">A location prefixed with /proxy.</param>
        /// <param name="requestPath">Path that the request should follow.</param>
        /// <returns>A new object to reply to the sender</returns>
        private SendMemoryToPeer RespondOrForwardProxy(string contentLocation, List<int> senderList)
        {
            // first 6 characters of /proxy are removed
            bool proxyPart = contentLocation.StartsWith(PROXY_PREFIX + "/");

            if (proxyPart == false)
                throw new NotSupportedException("RespondOrForwardProxy no proxy part");

            string key = contentLocation.Substring(PROXYPREFIX_REMOVE);
            List<int> hintPath = null;

            // cannnot proxy request the whole dictionary
            if (key == DATA_NAMESPACE)
                throw new NotSupportedException("RespondOrForwardProxy DATA_NAMESPACE");

            bool responded = false;

            DataEntry e = P2PDictionary.GetEntry( this.data, this.dataLock, key);
            if (e != null)
            {
                WriteDebug(this.local_uid + " following proxy path, found content for " + key);

                lock (e)
                {
                    if (e.subscribed && !DataMissing.IsSingleton(e.value))
                    {
                        responded = true;

                    }

                }

                if (responded)
                {
                    // change the return path of the response message
                    List<int> followList = new List<int>(senderList);
                    followList.Remove(this.local_uid);

                    SendMemoryToPeer sendMsg = CreateResponseMessage(key, PROXY_PREFIX + key, GetListOfThisLocalID(), followList, followList);

                    return sendMsg;
                }

                hintPath = e.senderPath;

            }

            if (!responded)
            {
                // fix the requestPath with the hintPath if there is no requestPath,
                // or if the requestPath is now at the current peer
                if (hintPath == null || hintPath.Count  == 0)
                {
                    WriteDebug(this.local_uid + " forwarding request dropped " + key);
                }
                else
                {

                    // since the path contains all the nodes to contact in order,
                    // we don't have to broadcast a request. Instead, we just specify
                    // the path to the next peer and it will get to the destination.
                        senderList = new List<int>(senderList);
                        senderList.Add(this.local_uid);

                        WriteDebug(this.local_uid + " following proxy path " + key + " to " + GetStringOf(hintPath));
                        SendMemoryToPeer sendMsg = new SendMemoryToPeer(PROXY_PREFIX + key, hintPath);
                        ResponseFollowProxy(sendMsg.MemBuffer, PROXY_PREFIX + key, senderList);
                        return sendMsg;
                    }

            }

            return null;
        }
        /// <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();}
        }
        /// <summary>
        /// Reads data using only header information. Can be used by ReadDictionary
        /// so it handles deleted content too.
        /// </summary>
        /// <param name="contentLocation">Location of the data item without /proxy</param>
        /// <param name="contentType">GetMime()</param>
        /// <param name="eTag">Version number</param>
        /// <param name="addEntryToSender">These are entries that the sender does not know about</param>
        /// <param name="getEntryFromSender">This function fills in a list of entries that need to be requested from the sender</param>
        private ResponseAction ReadDataStub(string contentLocation, string contentType, string eTag, 
            List<int> sentFromList, out DataHeader getEntryFromSender, out SendMemoryToPeer addEntryToSender)
        {
            ResponseAction success = ResponseAction.DoNotForward;
            ETag tag = ReadETag(eTag);

            DataEntry get = null;
            getEntryFromSender = null;
            addEntryToSender = null;

            // create a stub of the item
            DataEntry create = new DataEntry(contentLocation, tag, sentFromList);
            create.subscribed = keysToListen.IsSubscribed(contentLocation);
            create.SetMime(contentType);

            // manually erase the value (TODO, don't erase the value)
            // always default to singleton because we assume that a GET is required to complete the request
            if (create.type != Data.ValueType.Removed)
                create.value = DataMissing.Singleton;

            this.dataLock.EnterUpgradeableReadLock();
            try
            {
                if (this.data.ContainsKey(contentLocation))
                {
                    // update the version number of the stub
                    get = this.data[contentLocation];
                }
                else
                {
                    this.dataLock.EnterWriteLock();
                    try
                    {
                        this.data.Add(contentLocation, create);
                    }
                    finally { this.dataLock.ExitWriteLock(); }

                    if (create.subscribed && DataMissing.IsSingleton(create.value))
                    {
                        // we'll have to wait for the data to arrive on the wire
                        // actually get the data
                        getEntryFromSender = new DataHeader(contentLocation, tag, sentFromList);
                        success = ResponseAction.DoNotForward;
                    }
                    else
                    {
                        success = ResponseAction.ForwardToSuccessor;
                    }

                }
            }

            finally
            {
                this.dataLock.ExitUpgradeableReadLock();
            }

            if (get != null)
            {
                lock (get)
                {
                    if (create.subscribed)
                    {
                        ETagCompare compareResult = ETag.CompareETags(tag, get.GetETag());

                        if (compareResult == ETagCompare.FirstIsNewer ||
                            compareResult == ETagCompare.Same || compareResult == ETagCompare.Conflict)
                        {
                            getEntryFromSender = new DataHeader(create.key, create.GetETag(), sentFromList);
                            success = ResponseAction.DoNotForward;
                        }
                        else //if (compareResult == ETagCompare.SecondIsNewer )
                        {
                            // i know about something newer than the sender, tell the sender
                            //SendMemoryToPeer mem = new SendMemoryToPeer(get.key,sentFromList);
                            //ResponseHeadStub(HEAD, get.key, GetListOfThisLocalID(), 0, get.GetMime(), get.GetETag(), get.IsEmpty, mem.MemBuffer, false);
                            //addEntryToSender = mem;

                            // well, predecessor already been handled above, so we only need to tell
                            // the others
                            success = ResponseAction.ForwardToAll;
                        }
                    }
                    else
                    {
                        // not subscribed
                        // just record the fact that there is newer data on the wire; cannot resolve conflicts without being a subscriber
                        ETagCompare compareResult = ETag.CompareETags(create.GetETag(), get.GetETag());
                        if (compareResult == ETagCompare.FirstIsNewer || compareResult == ETagCompare.Same || compareResult == ETagCompare.Conflict)
                        {
                            get.lastOwnerID = create.lastOwnerID;
                            get.lastOwnerRevision = create.lastOwnerRevision;
                            get.value = DataMissing.Singleton;

                            if (compareResult != ETagCompare.Same)
                            {
                                get.senderPath = create.senderPath;

                                success = ResponseAction.ForwardToSuccessor;
                            }
                            else
                                success = ResponseAction.DoNotForward;
                        }
                        else // if (compareResult == ETagCompare.SecondIsNewer )
                        {
                            //// i know about something newer than the sender
                            //SendMemoryToPeer mem = new SendMemoryToPeer(get.key,sentFromList);
                            //ResponseHeadStub(HEAD, get.key, GetListOfThisLocalID(), 0, get.GetMime(), get.GetETag(), get.IsEmpty, mem.MemBuffer, false);
                            //addEntryToSender = mem;

                            // tell the others too (already told predecessor above)
                            success = ResponseAction.ForwardToAll;
                        }
                    }
                }
            }

            return success;
        }
 int IMessageController.SendToPeer(SendMemoryToPeer message)
 {
     if (this.IsAlive)
         return CastTargetController.SendToPeer(message);
     else
         return 0;
 }