/*
   * Delete an LB
   */
  @DELETE
  @Path("/{id}")
  @Produces("application/json")
  public void deleteLb(@PathParam("id") String id) {
    // delete the LB, send worker delete, finally clear device when worker responds ( not here )

    logger.info("DELETE loadbalancer : " + id);
    LoadBalancerDataModel model = new LoadBalancerDataModel();
    Integer lbId = new Integer(id);
    LoadBalancer lb = model.getLoadBalancer(lbId);
    if (lb == null) {
      throw new LBaaSException("could not find id : " + id, 404); //  not found
    }
    int deleteCount = model.deleteLoadBalancer(lbId);
    if (deleteCount == 0) {
      throw new LBaaSException("could not find id on delete: " + id, 404); //  not found
    }

    // have the device process the job
    try {
      lbaasTaskManager.sendJob(lb.getDevice(), LbToJson(lb, ACTION_DELETE));
    } catch (JSONException jsone) {
      throw new LBaaSException(
          "internal server error JSON exception :" + jsone.toString(), 500); //  internal error
    }
  }
  /*
   * Create a new LB
   */
  @POST
  @Consumes("application/json")
  @Produces("application/json")
  public String post(String content) {
    logger.info("POST loadbalancers");

    Device device = null;

    // process POSTed body
    LoadBalancerDataModel lbModel = new LoadBalancerDataModel();
    LoadBalancer lb = new LoadBalancer();
    Integer lbId = 0;
    int x = 0;
    try {
      JSONObject jsonObject = new JSONObject(content);
      String name = (String) jsonObject.get("name");
      lb.setName(name);
      logger.info("   name = " + name);

      // minimally request needs nodes
      if (!jsonObject.has("nodes")) {
        throw new LBaaSException("nodes are required", 400); //  bad request			
      }

      // check to ensure protocol is supported
      if (jsonObject.has("protocol")) {
        String protocol = (String) jsonObject.get("protocol");
        if (!ProtocolHandler.exists(protocol)) {
          throw new LBaaSException(
              "protocol specified not supported : " + protocol, 400); //  bad request				
        } else {
          logger.info("   protocol = " + protocol);
          lb.setProtocol(protocol);
          lb.setPort(ProtocolHandler.getPort(protocol));
          logger.info("   port = " + lb.getPort());
        }
      }

      // nodes
      Nodes nodes = new Nodes();
      JSONArray jsonNodesArray = (JSONArray) jsonObject.get("nodes");
      for (x = 0; x < jsonNodesArray.length(); x++) {
        Node node = new Node();
        // logger.info("node["+x+"] = "+ jsonNodesArray.getJSONObject(x));
        JSONObject jsonNode = jsonNodesArray.getJSONObject(x);
        String address = (String) jsonNode.get("address");
        node.setAddress(address);
        String port = (String) jsonNode.get("port");
        node.setPort(Integer.valueOf(port));
        node.setStatus("ONLINE");
        node.setId(new Integer(x + 1));
        logger.info("   Node[" + x + "]");
        logger.info("      address = " + address);
        logger.info("      port = " + port);
        logger.info("      status = " + node.getStatus());
        nodes.getNodes().add(node);
      }
      lb.setNodes(nodes);

      // vips
      VirtualIps virtualIps = new VirtualIps();
      if (jsonObject.has("virtualIps")) {
        JSONArray jsonVIPArray = (JSONArray) jsonObject.get("virtualIps");
        for (x = 0; x < jsonVIPArray.length(); x++) {
          VirtualIp virtualIp = new VirtualIp();
          // logger.info("vip["+x+"] = "+ jsonVIPArray.getJSONObject(x));
          JSONObject jsonVip = jsonVIPArray.getJSONObject(x);

          String address = (String) jsonVip.get("address");
          virtualIp.setAddress(address);

          if (jsonVip.get("ipVersion").toString().equalsIgnoreCase("IPV4"))
            virtualIp.setIpVersion(IpVersion.IPV_4);
          else virtualIp.setIpVersion(IpVersion.IPV_6);

          if (jsonVip.get("type").toString().equalsIgnoreCase("public"))
            virtualIp.setType(VipType.PUBLIC);
          else virtualIp.setType(VipType.PRIVATE);

          virtualIp.setId(new Integer(x + 1));

          logger.info("   VIP[" + x + "]");
          logger.info("      address = " + virtualIp.getAddress());
          logger.info("      ipversion = " + virtualIp.getIpVersion().toString());
          logger.info("      type = " + virtualIp.getType().toString());
          virtualIps.getVirtualIps().add(virtualIp);
        }
        lb.setVirtualIps(virtualIps);
      }

      // find free device to use
      DeviceDataModel deviceModel = new DeviceDataModel();
      device = deviceModel.findFreeDevice();
      if (device == null) {
        throw new LBaaSException("cannot find free device available", 503); //  not available
      }

      logger.info("found free device at id : " + device.getId().toString());

      // create new LB
      lb.setDevice(device.getId()); // set lb device id
      lbId = lbModel.createLoadBalancer(lb); // write it to datamodel

      // set device lb and write it back to data model
      device.setLbId(lbId);
      deviceModel.setDevice(device);

    } catch (JSONException e) {
      return e.toString();
    }

    // read LB back from data model, it will now have valid id
    LoadBalancer lbResponse = lbModel.getLoadBalancer(lbId);

    // have the device process the request
    try {
      lbaasTaskManager.sendJob(lbResponse.getDevice(), LbToJson(lb, ACTION_CREATE));
    } catch (JSONException jsone) {
      throw new LBaaSException(
          "internal server error JSON exception :" + jsone.toString(), 500); //  internal error
    }

    // respond with JSON
    try {
      return LbToJson(lbResponse, null);
    } catch (JSONException jsone) {
      throw new LBaaSException(
          "internal server error JSON exception :" + jsone.toString(), 500); //  internal error
    }
  }
  /*
   * Update a specific LB
   * only allows changing name or algorithm
   */
  @PUT
  @Path("/{id}")
  @Consumes("application/json")
  public void updateLb(@PathParam("id") String id, String content) {
    logger.info("PUT loadbalancer : " + id);
    LoadBalancerDataModel model = new LoadBalancerDataModel();

    // attempt to read lb top be updated
    Integer lbId = new Integer(id);
    LoadBalancer lb = model.getLoadBalancer(lbId);
    if (lb == null) {
      throw new LBaaSException("could not find id : " + id, 404); //  not found	
    }

    String name, algorithm;
    JSONObject jsonObject = null;

    // decode JSON
    try {
      jsonObject = new JSONObject(content);
    } catch (JSONException e) {
      throw new LBaaSException("bad json request", 400); //  bad request
    }

    // look for name
    try {
      name = (String) jsonObject.get("name");
      lb.setName(name);
      logger.info("   name = " + name);
    } catch (JSONException e) {
      name = null;
    }

    // look for algorithm
    try {
      algorithm = (String) jsonObject.get("algorithm");
      lb.setName(name);
      logger.info("   algorithm = " + algorithm);
    } catch (JSONException e) {
      algorithm = null;
    }

    // must have one of these fields
    if ((name == null) && (algorithm == null)) {
      throw new LBaaSException("name and algorithm missing", 400); //  bad request		
    }

    if (name != null) lb.setName(name);

    if (algorithm != null) lb.setAlgorithm(algorithm);

    // mark as change pending
    lb.setStatus(LoadBalancer.STATUS_PENDING_UPDATE);

    // write changes to DB
    model.setLoadBalancer(lb);

    // have the device process the job
    try {
      lbaasTaskManager.sendJob(lb.getDevice(), LbToJson(lb, ACTION_UPDATE));
    } catch (JSONException jsone) {
      throw new LBaaSException(
          "internal server error JSON exception :" + jsone.toString(), 500); //  internal error
    }
  }