/**
   * Decode calls.
   *
   * @param in Input data as byte buffer
   * @return List of pending calls
   */
  protected List<RemotingCall> decodeCalls(IoBuffer in) {
    log.debug("Decode calls");
    // in.getInt();
    List<RemotingCall> calls = new LinkedList<RemotingCall>();
    org.red5.io.amf.Input input;
    int count = in.getUnsignedShort();
    log.debug("Calls: {}", count);
    int limit = in.limit();
    // Loop over all the body elements
    for (int i = 0; i < count; i++) {
      in.limit(limit);

      String serviceString = org.red5.io.amf.Input.getString(in);
      String clientCallback = org.red5.io.amf.Input.getString(in);
      log.debug("callback: {}", clientCallback);

      Object[] args = null;
      boolean isAMF3 = false;

      @SuppressWarnings("unused")
      int length = in.getInt();
      // Set the limit and deserialize
      // NOTE: disabled because the FP sends wrong values here
      /*
       * if (length != -1) in.limit(in.position()+length);
       */
      byte type = in.get();
      if (type == AMF.TYPE_ARRAY) {
        int elements = in.getInt();
        List<Object> values = new ArrayList<Object>();
        RefStorage refStorage = null;
        for (int j = 0; j < elements; j++) {
          byte amf3Check = in.get();
          in.position(in.position() - 1);
          isAMF3 = (amf3Check == AMF.TYPE_AMF3_OBJECT);
          if (isAMF3) {
            if (refStorage == null) {
              input = new org.red5.io.amf3.Input(in);
            } else {
              input = new org.red5.io.amf3.Input(in, refStorage);
            }
          } else {
            input = new org.red5.io.amf.Input(in);
          }
          // prepare remoting mode
          input.reset();
          // add deserialized object to the value list
          values.add(Deserializer.deserialize(input, Object.class));
          if (isAMF3) {
            refStorage = ((org.red5.io.amf3.Input) input).getRefStorage();
          }
        }
        args = values.toArray(new Object[values.size()]);
        if (log.isDebugEnabled()) {
          for (Object element : args) {
            log.debug("> " + element);
          }
        }

      } else if (type == AMF.TYPE_NULL) {
        log.debug("Got null amf type");

      } else if (type != AMF.TYPE_ARRAY) {
        throw new RuntimeException("AMF0 array type expected but found " + type);
      }

      String serviceName;
      String serviceMethod;
      int dotPos = serviceString.lastIndexOf('.');
      if (dotPos != -1) {
        serviceName = serviceString.substring(0, dotPos);
        serviceMethod = serviceString.substring(dotPos + 1, serviceString.length());
      } else {
        serviceName = "";
        serviceMethod = serviceString;
      }

      boolean isMessaging = false;
      if ("".equals(serviceName) && "null".equals(serviceMethod)) {
        // Use fixed service and method name for Flex messaging requests,
        // this probably will change in the future.
        serviceName = FlexMessagingService.SERVICE_NAME;
        serviceMethod = "handleRequest";
        isMessaging = true;
      }
      log.debug("Service: {} Method: {}", serviceName, serviceMethod);

      // Add the call to the list
      calls.add(
          new RemotingCall(serviceName, serviceMethod, args, clientCallback, isAMF3, isMessaging));
    }
    return calls;
  }
 /** Resets map */
 @Override
 public void reset() {
   super.reset();
   // input must keep the String references for all parameters
   // refStorage.stringReferences.clear();
 }