private void HandleDataValueMessage(Stream s)
        {
            // construct a binary reader
            BinaryReader reader = new BinaryReader(s);

            // get the sequence number
            int seqNo = reader.ReadInt32();

            // calculate how many packet we've missed
            // we are expecting a difference of 1 in the sequence numbers
            int missed = seqNo - lastSeqNo - 1;

            // if the difference is less than zero, something stuff is going on
            if (missed > 0 && lastSeqNo != -1)
            {
                missedCount += missed;
            }

            // set the last sequence number
            lastSeqNo = seqNo;

            // increment the received count
            receivedCount++;

            // get the data item name
            string diName = reader.ReadString();
            // get the time
            CarTimestamp t = reader.ReadDouble();

            // read the data type code
            DataTypeCode dtc = (DataTypeCode)reader.ReadInt32();

            // handle the type appropriately
            object value = null;

            switch (dtc)
            {
            case DataTypeCode.Double:
                value = reader.ReadDouble();
                break;

            case DataTypeCode.Single:
                value = reader.ReadSingle();
                break;

            case DataTypeCode.Int8:
                value = reader.ReadSByte();
                break;

            case DataTypeCode.Int16:
                value = reader.ReadInt16();
                break;

            case DataTypeCode.Int32:
                value = reader.ReadInt32();
                break;

            case DataTypeCode.Int64:
                value = reader.ReadInt64();
                break;

            case DataTypeCode.UInt8:
                value = reader.ReadByte();
                break;

            case DataTypeCode.UInt16:
                value = reader.ReadUInt16();
                break;

            case DataTypeCode.UInt32:
                value = reader.ReadUInt32();
                break;

            case DataTypeCode.UInt64:
                value = reader.ReadUInt64();
                break;

            case DataTypeCode.Boolean:
                value = reader.ReadBoolean();
                break;

            case DataTypeCode.DateTime:
                value = DateTime.FromBinary(reader.ReadInt64());
                break;

            case DataTypeCode.TimeSpan:
                value = new TimeSpan(reader.ReadInt64());
                break;

            case DataTypeCode.Coordinates:
                value = new Coordinates(reader.ReadDouble(), reader.ReadDouble());
                break;

            case DataTypeCode.Circle:
                value = new Circle(reader.ReadDouble(), new Coordinates(reader.ReadDouble(), reader.ReadDouble()));
                break;

            case DataTypeCode.Line:
                value = new Line(new Coordinates(reader.ReadDouble(), reader.ReadDouble()), new Coordinates(reader.ReadDouble(), reader.ReadDouble()));
                break;

            case DataTypeCode.LineSegment:
                value = new LineSegment(new Coordinates(reader.ReadDouble(), reader.ReadDouble()), new Coordinates(reader.ReadDouble(), reader.ReadDouble()));
                break;

            case DataTypeCode.Polygon: {
                CoordinateMode coordMode = (CoordinateMode)reader.ReadInt32();
                int            count     = reader.ReadInt32();
                Polygon        pg        = new Polygon(coordMode);
                for (int i = 0; i < count; i++)
                {
                    pg.Add(new Coordinates(reader.ReadDouble(), reader.ReadDouble()));
                }
                value = pg;
            }
            break;

            case DataTypeCode.Bezier: {
                value = new CubicBezier(
                    new Coordinates(reader.ReadDouble(), reader.ReadDouble()),
                    new Coordinates(reader.ReadDouble(), reader.ReadDouble()),
                    new Coordinates(reader.ReadDouble(), reader.ReadDouble()),
                    new Coordinates(reader.ReadDouble(), reader.ReadDouble()));
            }
            break;

            case DataTypeCode.LineList: {
                LineList linelist = new LineList();
                int      ll_count = reader.ReadInt32();
                linelist.Capacity = ll_count;
                for (int i = 0; i < ll_count; i++)
                {
                    linelist.Add(new Coordinates(reader.ReadDouble(), reader.ReadDouble()));
                }
                value = linelist;
            }
            break;

            case DataTypeCode.CoordinatesArray: {
                int           numPts = reader.ReadInt32();
                Coordinates[] pts    = new Coordinates[numPts];
                for (int i = 0; i < numPts; i++)
                {
                    pts[i] = new Coordinates(reader.ReadDouble(), reader.ReadDouble());
                }
                value = pts;
            }
            break;

            case DataTypeCode.LineListArray: {
                int        numLineList = reader.ReadInt32();
                LineList[] lineLists   = new LineList[numLineList];
                for (int i = 0; i < numLineList; i++)
                {
                    int numPoints = reader.ReadInt32();
                    lineLists[i] = new LineList(numPoints);
                    for (int j = 0; j < numPoints; j++)
                    {
                        lineLists[i].Add(new Coordinates(reader.ReadDouble(), reader.ReadDouble()));
                    }
                }
                value = lineLists;
            }
            break;

            case DataTypeCode.PolygonArray: {
                int       numPolys = reader.ReadInt32();
                Polygon[] polys    = new Polygon[numPolys];
                for (int i = 0; i < numPolys; i++)
                {
                    int numPoints = reader.ReadInt32();
                    polys[i] = new Polygon(numPoints);
                    for (int j = 0; j < numPoints; j++)
                    {
                        polys[i].Add(ReadReducedCoord(reader));
                    }
                }
                value = polys;
            }
            break;

            case DataTypeCode.ObstacleArray: {
                int numObs = reader.ReadInt32();
                OperationalObstacle[] obstacles = new OperationalObstacle[numObs];
                for (int i = 0; i < numObs; i++)
                {
                    OperationalObstacle obs = new OperationalObstacle();
                    obs.age           = reader.ReadInt32();
                    obs.obstacleClass = (ObstacleClass)reader.ReadInt32();
                    obs.ignored       = reader.ReadBoolean();
                    obs.headingValid  = reader.ReadBoolean();
                    obs.heading       = reader.ReadDouble();

                    int numPoints = reader.ReadInt32();
                    obs.poly = new Polygon(numPoints);
                    for (int j = 0; j < numPoints; j++)
                    {
                        obs.poly.Add(ReadReducedCoord(reader));
                    }

                    obstacles[i] = obs;
                }

                value = obstacles;
            }
            break;

            case DataTypeCode.BinarySerialized:
                if (reader.ReadByte() == 0)
                {
                    value = formatter.Deserialize(s);
                }
                else
                {
                    DeflateStream ds = new DeflateStream(s, CompressionMode.Decompress, true);
                    value = formatter.Deserialize(ds);
                }
                break;

            default:
                // unknown type
                throw new InvalidOperationException();
            }

            // check if there is no value
            if (value == null)
            {
                return;
            }

            // check if we have the data item
            IDataItemClient diObj;

            if (!items.TryGetValue(diName, out diObj))
            {
                // build the data item
                Type diGenType = typeof(DataItemClient <>);
                Type diType    = diGenType.MakeGenericType(value.GetType());
                diObj = (IDataItemClient)Activator.CreateInstance(diType, diName);

                Add(diName, diObj);
            }

            diObj.AddDataItem(value, t);
        }