Multipart Packets are used to send large amounts of data, bigger than will fit into a single Packet250CustomPayload.
They are designed to be tolerant of network faults such as dropped packets, out-of-order packets, duplicate copies
  of the same packet, loss of connection, etc
See MultipartPacket.png

Currently, the multipartpackets are organised using
MultipartOneAtATimeReceiver and
MultipartOneAtATimeSender.
They are designed to only handle one of each type of multipartpacket at a time (eg Selection, MapData, etc).

They are linked to the client and server code using "linkages".  This increases their flexibility because they aren't
   directly coupled to the classes that use them.  The key concepts are:
(1) when a packet is to be sent, the caller provides MultipartOneAtATimeSender with a "linkage", which the handler then
    uses to pass information back to the caller.
(2) when an incoming packet arrives at the receiver, it uses a LinkageFactory (provided by the caller) to create a linkage
    which then communicates information to the caller.
Each MultipartOneAtATime Handler can handle multiple different types of packets, once they are registered with it.

MultipartPacket is the entire payload.  It is broken into segments which fit into a Packet250CustomPayload.

  Packet250CustomPayload:
  Comprised of a header with
  - byte packet250CustomPayloadID (as per normal Packet250CustomPayload data[0])
  - int uniqueMultipartPacketID (in ascending order) - unique ID for the whole packet
  - byte command type (segment data, acknowledgement of segments, abort)

  For abort packets and "full acknowledgement" packets, no more data.
  For acknowledgement packets; the bitset showing which packets have been received
  For segment data packets:
  - short segmentNumber - the number of this segment
  - int segmentSize - size of the segment data itself (not including headers)
  - int totalSize - size of the entire Multipart rawData
  - byte array of the data

  MultipartPacket:
  specify packet size
  base class; overridden by the specific packet of interest
  processIncomingPacket(Packet250CustomPayload)
  getNextUnsentSegment - returns a Packet250CustomPayload
  getNextUnacknowledgedSegment - looks for the next segment that has been sent but not yet acknowledged
  resetToOldestUnacknowledgedSegment - the next call to getNextUnacknowledgedSegment will return the oldest unacknowledged segment

  getAcknowledgementPacket - returns a Packet250CustomPayload containing acknowledgement of all the packets received to date
  getAbortPacket - returns a Packet250CustomPayload to abort this packet.
  allSegmentsSent - true if all segments have been sent at least once
  allSegmentsAcknowledged - true if all segments have been sent & acknowledged
  allSegmentsReceived - true if all segments have been received (the packet is complete)
  acknowledgementReceivedFlag - has at least one acknowledgement been received since the flag was reset?
  resetAcknowledgementReceivedFlag - reset the "acknowledgement received" flag

  various methods to get & set the data in the packet as appropriate

  registerMultipartPacketType - called by the handler; when incoming Packet250 are received, it will compare the packet
     data to the registered types, choose the appropriate class to instantiate, and append it to the container provided

  MultipartPacketHandler (MultipartOneAtATimeSender and Receiver)
  sendMultipartPacket - start transmission, provide a callback linkage
  registerMultipartPacketType - tells the handler what class to call for newPacketStarted for a given MultipartPacket type
  processIncomingPacket - called by PacketHandler, which then calls MultipartPacket methods as appropriate
  onTick - sends new segments; checks for timeouts, resends segments if necessary

  The receiver keeps track of completed and aborted packets for a certain length of time, to ensure that late packets still
    trigger the correct response.
  The Sender will wait for an acknowledgement of an abort packet; if it doesn't get one, it will resend at periodic intervals.
  The Receiver only sends one abort packet.  If the Sender keeps sending segments, the receiver responds with aborts.

  Communications Protocol:
  Sender sends all segments without waiting for acknowledgement, but if it doesn't get acknowledgement within a certain
    length of time, it will resend a single unacknowledged segment every timeout until it gets acknowledgement
    Once acknowledgement is received, it will send all remaining unacknowledged segments without waiting for each one
    to be acknowledged (and the timeout will start again).
  Summary: 4 states
  a) sending initial segments
  b) waiting for acknowledgements (not yet timeout)
  c) timed out, waiting for acknowledgement of first resend
  d) first resend has been acknowledged, resending remainder
     once all are resent, return to state (b)
  The transmission of a packet can be aborted by either end.  Upon receiving an abort, the recipient will send an abort back to confirm.
    The sender will keep sending aborts until the receiver acknowledges.

  PacketSenderLinkage interface
  - progressUpdate (how many acknowledgements received)
  - packetCompleted (passes ownership of packet back to sender)
  - abort (to abort transmission of this packet)
  - packetAborted (transmission of this packet was aborted before completion)

  PacketReceiverLinkageFactory interface
  - newPacketStarted  (creates a new PacketReceiverLinkage which the receiving class will use to receive notification of progress)

  PacketReceiverLinkage interface
  - progressUpdate
  - packetCompleted (passes ownership of packet to receiver)
  - abort (to abort receiving / transmission of this packet)
  - packetAborted (transmission of this packet was aborted before completion)

  PacketSender interface
     - used to wrap NetClientHandler and NetServerHandler so that we can just send a packet to it without worrying about which side

Usage:

(1) Create MultipartPacketHandler, supply it with a suitable PacketSender (wraps a NetClientHandler or NetServerHandler)
(1a) Set handler options - packet size, timeout auto-resend, max transmission bandwidth
(1b) Set up the network packet handler to call MultipartPacketHandler.processIncomingPacket with any suitable incoming packets.
(2) Define a class implementing the PacketReceiverLinkageFactory for the type of MultipartPacket you are interested in;
    Register it with MultipartPacketHandler.registerPacketReceiverFactory
    This object will be called whenever the first incoming segment of the specified MultipartPacket type arrives
(3) Define a class implementing PacketLinkage for the receiver.  This object will be created (by the factory) every time a new packet starts, and is used to
    communicate progress to the receiver and provide the assembled packet when transmission is complete
(4) Define a class implementing PacketLinkage for the sender.  This object is used to communicate the progress of the transmission back to the sender
(5) To send a packet:
  (a) Create the MultipartPacket
  (b) call MultipartPacketHandler.sendMultipartPacket, providing the packet and the PacketLinkage
  (c) Progress report and completion is pushed from the MultipartPacket using the PacketLinkage
  (d) To abort transmission, use MultipartPacketHandler.abort()
(6) To receive a packet:
  (a) When the first part of the packet is received by MultipartPacketHandler, PacketReceiverLinkageFactory.newPacketStarted is called to create
      a PacketLinkage.
  (b) The PacketLinkage is used to keep the receiver informed of progress, and to provide the fully assembled packet when completed
  (c) to abort transmission, use MultipartPacketHandler.abort()

Handling of incoming packets:
(1) packet arrives at MultipartHandler
(2) -deleted-
(3) MultipartHandler looks up the uniqueID  to see if this packet already exists, if it has been aborted, or if it has been fully acknowledged
(3a) If it exists, the packet is passed to MultipartPacket.processIncomingPacket
(3b) If it doesn't exist, call the static method MultipartPacket.createFromPacket and add the MultipartPacket to the storage table.
     Look up the PacketReceiverLinkageFactory for that class, generate a PacketLinkage, and add it to the storage table.
(3c) If it has been aborted by the Receiver, an abort packet is sent
(3d) If it was completed, an acknowledgement packet is sent.

To add a new type of MultipartPacket:
(1) create class extending MultipartPacket
(2) register handler with PacketHandler - each extension of Multipart is given its own handler







