private final void work_status(final GearmanPacket packet, final ServerClient client) {
    /*
     * This is sent to update the server (and any listening clients)
     * of the status of a running job. The client should send these
     * periodically for long running jobs to update the percentage
     * complete. The job server should store this information so a client
     * who issued a background command may retrieve it later with a
     * GET_STATUS request.
     *
     * Arguments:
     * - NULL byte terminated job handle.
     * - NULL byte terminated percent complete numerator.
     * - Percent complete denominator.
     */

    final byte[] jobHandle = packet.getArgumentData(0);
    assert jobHandle != null;
    final ByteArray jobHandleBA = new ByteArray(jobHandle);

    final byte[] num = packet.getArgumentData(1);
    assert num != null;

    final byte[] den = packet.getArgumentData(2);
    assert den != null;

    final ServerJob job = ServerJobAbstract.getJob(jobHandleBA);
    if (job == null) {
      client.sendPacket(ServerStaticPackets.ERROR_JOB_NOT_FOUND, null /*TODO*/);
    } else {
      packet.setMagic(Magic.RES);
      job.setStatus(num, den);
      job.sendPacket(packet);
    }
  }
  private final void work_data(final GearmanPacket packet, final ServerClient client) {
    /*
     * This is sent to update the client with data from a running job. A
     * client should use this when it needs to send updates, send partial
     * results, or flush data during long running jobs. It can also be
     * used to break up a result so the client does not need to buffer
     * the entire result before sending in a WORK_COMPLETE packet.
     *
     * Arguments:
     * - NULL byte terminated job handle.
     * - Opaque data that is returned to the client.
     */

    final byte[] jobHandle = packet.getArgumentData(0);
    assert jobHandle != null;
    final ByteArray jobHandleBA = new ByteArray(jobHandle);

    final ServerJob job = ServerJobAbstract.getJob(jobHandleBA);
    if (job == null) {
      client.sendPacket(ServerStaticPackets.ERROR_JOB_NOT_FOUND, null /*TODO*/);
    } else {
      packet.setMagic(Magic.RES);
      job.sendPacket(packet);
    }
  }
  private final void option_req(final GearmanPacket packet, final ServerClient client) {
    /*
     * A client issues this to set an option for the connection in the
     * job server. Returns a OPTION_RES packet on success, or an ERROR
     * packet on failure.
     *
     * Arguments:
     * - Name of the option to set. Possibilities are:
     * 		"exceptions" - Forward WORK_EXCEPTION packets to the client.
     */

    final byte[] option = packet.getArgumentData(0);
    assert option != null;

    final byte[] exceptions = new byte[] {'e', 'x', 'c', 'e', 'p', 't', 'i', 'o', 'n', 's'};

    if (Arrays.equals(option, exceptions)) {
      // exceptions option
      client.setForwardsExceptions(true);

      client.sendPacket(ServerStaticPackets.OPTION_RES_EXCEPTIONS, null /*TODO*/);

    } else {
      // unknown option
      client.sendPacket(ServerStaticPackets.ERROR_UNKNOWN_OPTION, null /*TODO*/);
    }
  }
  private final void get_status(final GearmanPacket packet, final ServerClient client) {

    /*
     * A client issues this to get status information for a submitted job.
     *
     * Arguments:
     *  - Job handle that was given in JOB_CREATED packet.
     */

    final byte[] jobHandle = packet.getArgumentData(0);
    assert jobHandle != null;
    final ByteArray jobHandleBA = new ByteArray(jobHandle);

    final ServerJob job = ServerJobAbstract.getJob(jobHandleBA);
    if (job == null) {
      // Send unknown job STATUS_RES packet
      final byte[] unknown = new byte[] {'0'};
      final GearmanPacket status_res =
          new GearmanPacket(
              Magic.RES, Type.STATUS_RES, jobHandle, unknown, unknown, unknown, unknown);
      client.sendPacket(status_res, null /*TODO*/);
      return;
    }

    final GearmanPacket status = job.createStatusResPacket();

    client.sendPacket(status, null /*TODO*/);
  }
  private final void submit_job(
      final GearmanPacket packet,
      final ServerClient client,
      ServerJob.JobPriority priority,
      boolean isBackground) {

    /*
     * A client issues this when a job needs to be run. The server will
     * then assign a job handle and respond with a JOB_CREATED packet.
     *
     * If on of the BG versions is used, the client is not updated with
     * status or notified when the job has completed (it is detached).
     *
     * The Gearman job server queue is implemented with three levels:
     * normal, high, and low. Jobs submitted with one of the HIGH versions
     * always take precedence, and jobs submitted with the normal versions
     * take precedence over the LOW versions.
     *
     * Arguments:
     * - NULL byte terminated function name.
     * - NULL byte terminated unique ID.
     * - Opaque data that is given to the function as an argument.
     */

    // Argument: function name
    final byte[] funcName = packet.getArgumentData(0);
    assert funcName != null;
    final ByteArray funcNameBA = new ByteArray(funcName);

    // Argument: unique ID
    final byte[] uniqueID = packet.getArgumentData(1);
    assert uniqueID != null;
    final ByteArray uniqueIDBA = new ByteArray(uniqueID);

    // Argument: data
    final byte[] data = packet.getArgumentData(2);
    assert data != null;

    /*
     * FWIX CHANGE
     */
    // final ServerFunction func = this.funcSetHigh.getFunction(funcNameBA);

    funcSet.createJob(funcNameBA, uniqueIDBA, data, priority, client, isBackground);
  }
  /**
   * Called when a CANT_DO packet comes in.<br>
   * <br>
   * <i> This is sent to notify the server that the client is no longer able to perform the given
   * function.<br>
   * <br>
   * Arguments:<br>
   * - Function name.<br>
   * </i>
   *
   * @param packet The CANT_DO packet
   * @param client The client who aquired the packet
   */
  private final void cant_do(final GearmanPacket packet, final ServerClient client) {
    /*
     * This is sent to notify the server that the client is no longer able to
     * perform the given function.
     *
     * Arguments:
     * - Function name.
     */

    // Function Name
    final byte[] funcName = packet.getArgumentData(0);
    assert funcName != null;
    if (funcName.length == 0) {
      // TODO send error
    }

    client.cant_do(new ByteArray(funcName));
  }
  /**
   * Called when a CAN_DO packet comes in.<br>
   * <br>
   * <i> CAN_DO:<br>
   * This is sent to notify the server that the client is able to perform the given function. The
   * client is then put on a list to be waken up whenever the job server receives a job for that
   * function.<br>
   * <br>
   * Arguments:<br>
   * - Function name.<br>
   * </i>
   *
   * @param packet The CAN_DO packet
   * @param client The client who acquired the packet.
   */
  private final void can_do(final GearmanPacket packet, final ServerClient client) {

    // Note: Currently the CAN_DO_TIMEOUT maps to this method, the timeout
    // feature will be fully implemented in the future.

    // Function Name
    final byte[] funcName = packet.getArgumentData(0);
    assert funcName != null;

    if (funcName.length == 0) {
      // TODO send error
    }

    ByteArray funcNameBA = new ByteArray(funcName);
    // funcNameBA = GMServerFunctionMap.GM_TASK_BA;

    funcSet.registerClient(funcNameBA, client);
  }
  private final void work_fail(final GearmanPacket packet, final ServerClient client) {
    /*
     * This is to notify the server (and any listening clients) that
     * the job failed.
     *
     * Arguments:
     * - Job handle.
     */

    final byte[] jobHandle = packet.getArgumentData(0);
    assert jobHandle != null;
    final ByteArray jobHandleBA = new ByteArray(jobHandle);

    final ServerJob job = ServerJobAbstract.getJob(jobHandleBA);
    if (job == null) {
      client.sendPacket(ServerStaticPackets.ERROR_JOB_NOT_FOUND, null /*TODO*/);
    } else {
      job.workComplete(packet);
    }
  }
  private final void set_client_id(final GearmanPacket packet, final ServerClient client) {
    /*
     * This sets the client ID in a job server so monitoring and reporting
     * commands can uniquely identify the various clients, and different
     * connections to job servers from the same client.
     *
     * Arguments:
     * - Unique string to identify the client instance.
     */

    // Get Client ID from packet
    final byte[] clientIdBytes = packet.getArgumentData(0);
    assert clientIdBytes != null;

    // Convert the worker ID into a String
    final String clientId = new String(clientIdBytes, GearmanConstants.UTF_8);

    // Set the client's client ID
    client.setClientId(clientId);
  }
  private final void work_exception(final GearmanPacket packet, final ServerClient client) {
    /*
     * This is to notify the server (and any listening clients) that
     * the job failed with the given exception.
     *
     * Arguments:
     * - NULL byte terminated job handle.
     * - Opaque data that is returned to the client as an exception.
     */

    // Note: The protocol states this packet notifies the server that the specified job
    // has failed. However, the C server does not fail the Job.  It is effectively a
    // WORK_WARNING packet that is only sent to clients that have specified they want
    // exceptions forwarded to them.  This server will do the same as long as the C
    // server does so.

    /*
     * This is sent to update the client with data from a running job. A
     * client should use this when it needs to send updates, send partial
     * results, or flush data during long running jobs. It can also be
     * used to break up a result so the client does not need to buffer
     * the entire result before sending in a WORK_COMPLETE packet.
     *
     * Arguments:
     * - NULL byte terminated job handle.
     * - Opaque data that is returned to the client.
     */

    final byte[] jobHandle = packet.getArgumentData(0);
    ;
    assert jobHandle != null;
    final ByteArray jobHandleBA = new ByteArray(jobHandle);

    final ServerJob job = ServerJobAbstract.getJob(jobHandleBA);
    if (job == null) {
      client.sendPacket(ServerStaticPackets.ERROR_JOB_NOT_FOUND, null /*TODO*/);
    } else {
      packet.setMagic(Magic.RES);
      job.sendPacket(packet);
    }
  }
  private final void work_complete(final GearmanPacket packet, final ServerClient client) {
    /*
     * This is to notify the server (and any listening clients) that
     * the job completed successfully.
     *
     * Arguments:
     * - NULL byte terminated job handle.
     * - Opaque data that is returned to the client as a response.
     */

    final byte[] jobHandle = packet.getArgumentData(0);
    assert jobHandle != null;
    final ByteArray jobHandleBA = new ByteArray(jobHandle);

    final ServerJob job = ServerJobAbstract.getJob(jobHandleBA);
    if (job == null) {
      client.sendPacket(ServerStaticPackets.ERROR_JOB_NOT_FOUND, null /*TODO*/);
    } else {

      // Construct a WORK_COMPLETE response packet
      client.jobCOmplete();
      job.workComplete(packet);
    }
  }