IPromise <ProtoMessage> mergePromise(IEnumerable <ProtoMessage> partialMessages)
        {
            var promise = new Promise <ProtoMessage>((resolve, reject) =>
            {
                var fullMessage = new ProtoMessage();
                foreach (var pm in partialMessages)
                {
                    if (pm != null)
                    {
                        fullMessage.AddProtoObjects(pm);
                    }
                }

                resolve(fullMessage);
            });

            return(promise);
        }
        //most complicated logic we have. Need to loop over the routing objects and handle
        //objects coming in the stream in order
        //therefore we construct a series of promises
        public IPromise <ProtoMessage> RouteMessage(ProtoMessage protoMessage)
        {
            var allPromises = new List <Promise <ProtoMessage> >();

            // we're going to loop over each message sent
            // and for each handler of those objects
            // processing each partial response in order
            // and sending back the full response in the end
            Debug.Log($"Objects to route:  {protoMessage.ProtoObjectList.Count}");
            foreach (var msgTuple in protoMessage.ProtoObjectList)
            {
                var objIx       = msgTuple.Item1.ProtoType;
                var objHandlers = this.handlers[objIx];

                Debug.Log($"Obj Type {objIx}, handler count {objHandlers.Count}");

                foreach (var methodAndObj in objHandlers)
                {
                    var methodToCall = methodAndObj.Item1;
                    var objToCall    = methodAndObj.Item2;

                    Debug.Log($"Promising to send the object to {objToCall.GetType().Name}");
                    allPromises.Add((Promise <ProtoMessage>)methodToCall.Invoke(objToCall, new object[] { msgTuple.Item2 }));
                }
            }

            //here we guarantee to return eventually -- so this can be async handled
            //first fullfill all of our promises,
            //then take the collection of results and merge them into a single return message
            return(Promise <ProtoMessage>
                   .All(allPromises)
                   .Then(protoCollection =>
            {
                Debug.Log("All messages routed and responded to");
                return mergePromise(protoCollection);
            }));
        }
 //merge in another message
 public ProtoMessage AddProtoObjects(ProtoMessage other)
 {
     this.AddProtoObjects(other.ProtoObjectList);
     return(this);
 }
        // Here we simply decode our byte buffer into a collection of proto objects
        // then we return a holder of all the proto objects, to be processed elsewhere (the router)
        public ProtoMessage DecodeByteToProto(byte[] byteArray)
        {
            ProtoMessage incomingMessage = new ProtoMessage();

            ByteOperations.ByteReader byteBuffer = new ByteOperations.ByteReader(byteArray);

            try
            {
                Debug.Log($"littel end {BitConverter.IsLittleEndian}");
                //get info about the header
                Int32 headerLength = byteBuffer.ReadInt();


                Debug.Log($"Reading header of size: {headerLength}, total size: {byteBuffer.Length}");
                var header = byteBuffer.ReadBytes(headerLength);

                // parse out the header information from the above clue
                var protoHeader = ProtoHeader.Parser.ParseFrom(header.ToArray());

                Debug.Log($"header len: {headerLength}, 'val' : {protoHeader}");

                // now we have a list of objects in our header, and we can ready each length
                foreach (var protoItem in protoHeader.ProtoItems)
                {
                    var pid        = protoItem.ProtoId;
                    var pType      = protoItem.ProtoType;
                    var readLength = protoItem.ProtoSize;

                    Debug.Log($"Reading next item: obj id: {pid} type: {pType}, length: {readLength}");
                    //get our next object bytes according to sizes
                    var nextObjectBytes = byteBuffer.ReadBytes(readLength);

                    //use our type info to get the static parser and parse
                    //from the bytes we just read

                    //get the static parser property
                    var parserInfo = ixToClass[pType].GetProperty("Parser", System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static);

                    Debug.Log($"Reading next item: type: {ixToClass[pType]}");
                    Debug.Log($"Reading next item parser: {ixToClass[pType].GetProperty("Parser", System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static)}");

                    //get the ParseFrom internal method in the protobuf message class
                    var parseStringMethod = parserInfo.PropertyType.GetMethod("ParseFrom", new[] { typeof(byte[]) });
                    Debug.Log($"Reading next item parse method: {parseStringMethod}");

                    //get the static parser
                    object parser = parserInfo.GetValue(null, null);

                    //now actuall parse from the bytes
                    var obj     = parseStringMethod.Invoke(parser, new object[] { nextObjectBytes });
                    var objType = obj.GetType();

                    incomingMessage.AddProtoObject(protoItem, obj);

                    Debug.Log($"Finished item #{pid}, type: {pType}, length: {readLength}, parsed obj: {obj}");
                }
            }
            catch (Exception e)
            {
                Debug.Log($"exception reading {e}");
                Debug.Log($"exception reading ST: {e.StackTrace}");
            }

            // send back the message with all the proto objects inside
            Debug.Log("Finished deconstructing message");
            return(incomingMessage);
        }