/*
 * Handle the list of candidate ports
 * @param response the HTTPResponse that is associated with the request.
 * @param devices the possbile devices & ports
 * @param error an error string.
 */
void OladHTTPServer::HandleCandidatePorts(
    HTTPResponse *response,
    const client::Result &result,
    const vector<OlaDevice> &devices) {
  if (!result.Success()) {
    m_server.ServeError(response, result.Error());
    return;
  }

  vector<OlaDevice>::const_iterator iter = devices.begin();
  vector<OlaInputPort>::const_iterator input_iter;
  vector<OlaOutputPort>::const_iterator output_iter;

  JsonArray json;
  for (; iter != devices.end(); ++iter) {
    const vector<OlaInputPort> &input_ports = iter->InputPorts();
    for (input_iter = input_ports.begin(); input_iter != input_ports.end();
         ++input_iter) {
      JsonObject *obj = json.AppendObject();
      PortToJson(obj, *iter, *input_iter, false);
    }

    const vector<OlaOutputPort> &output_ports = iter->OutputPorts();
    for (output_iter = output_ports.begin();
         output_iter != output_ports.end(); ++output_iter) {
      JsonObject *obj = json.AppendObject();
      PortToJson(obj, *iter, *output_iter, true);
    }
  }

  response->SetNoCache();
  response->SetContentType(HTTPServer::CONTENT_TYPE_PLAIN);
  response->SendJson(json);
  delete response;
}
/*
 * Handle the plugin description response.
 * @param response the HTTPResponse that is associated with the request.
 * @param description the plugin description.
 * @param error an error string.
 */
void OladHTTPServer::HandlePluginInfo(HTTPResponse *response,
                                      string description,
                                      const client::Result &result,
                                      const ola::client::PluginState &state) {
  if (!result.Success()) {
    m_server.ServeError(response, result.Error());
    return;
  }
  string escaped_description = description;
  Escape(&escaped_description);

  JsonObject json;
  json.Add("description", description);
  json.Add("name", state.name);
  json.Add("enabled", state.enabled);
  json.Add("active", state.active);
  json.Add("preferences_source", state.preferences_source);
  JsonArray *plugins = json.AddArray("conflicts_with");
  vector<OlaPlugin>::const_iterator iter = state.conflicting_plugins.begin();
  for (; iter != state.conflicting_plugins.end(); ++iter) {
    JsonObject *plugin = plugins->AppendObject();
    plugin->Add("active", iter->IsActive());
    plugin->Add("id", iter->Id());
    plugin->Add("name", iter->Name());
  }

  response->SetNoCache();
  response->SetContentType(HTTPServer::CONTENT_TYPE_PLAIN);
  response->SendJson(json);
  delete response;
}
/*
 * Handle the universe info
 * @param response the HTTPResponse that is associated with the request.
 * @param universe the OlaUniverse object
 * @param error an error string.
 */
void OladHTTPServer::HandleUniverseInfo(HTTPResponse *response,
                                        const client::Result &result,
                                        const OlaUniverse &universe) {
  if (!result.Success()) {
    m_server.ServeError(response, result.Error());
    return;
  }

  JsonObject *json = new JsonObject();

  // fire off the device/port request now. the main server is running in a
  // separate thread.
  m_client.FetchDeviceInfo(
      ola::OLA_PLUGIN_ALL,
      NewSingleCallback(this,
                        &OladHTTPServer::HandlePortsForUniverse,
                        response,
                        json,
                        universe.Id()));

  json->Add("id", universe.Id());
  json->Add("name", universe.Name());
  json->Add("merge_mode",
           (universe.MergeMode() == OlaUniverse::MERGE_HTP ? "HTP" : "LTP"));
}
/*
 * Handle the plugin list callback
 * @param response the HTTPResponse that is associated with the request.
 * @param plugins a list of plugins
 * @param error an error string.
 */
void OladHTTPServer::HandlePluginList(HTTPResponse *response,
                                      const client::Result &result,
                                      const vector<OlaPlugin> &plugins) {
  if (!result.Success()) {
    m_server.ServeError(response, result.Error());
    return;
  }

  JsonObject *json = new JsonObject();

  // fire off the universe request now. the main server is running in a
  // separate thread.
  m_client.FetchUniverseList(
      NewSingleCallback(this,
                        &OladHTTPServer::HandleUniverseList,
                        response,
                        json));

  JsonArray *plugins_json = json->AddArray("plugins");
  vector<OlaPlugin>::const_iterator iter;
  for (iter = plugins.begin(); iter != plugins.end(); ++iter) {
    JsonObject *plugin = plugins_json->AppendObject();
    plugin->Add("name", iter->Name());
    plugin->Add("id", iter->Id());
  }
}
void OlaCallbackClient::HandleFetchDmx(
    SingleUseCallback2<void, const DmxBuffer&, const string&> *callback,
    const client::Result &result,
    const client::DMXMetadata&,
    const DmxBuffer &data) {
  callback->Run(data, result.Error());
}
void OlaCallbackClient::HandleUniverseList(
    SingleUseCallback2<void, const vector<OlaUniverse>&,
                       const string &> *callback,
    const client::Result &result,
    const vector<OlaUniverse> &universes) {
  callback->Run(universes, result.Error());
}
void OlaCallbackClient::HandleDeviceInfo(
    SingleUseCallback2<void, const vector<OlaDevice>&, const string&>
        *callback,
    const client::Result &result,
    const vector<OlaDevice> &devices) {
  callback->Run(devices, result.Error());
}
void OlaCallbackClient::HandlePluginList(
    SingleUseCallback2<void, const vector<OlaPlugin>&,
                       const string&> *callback,
    const client::Result &result,
    const vector<OlaPlugin> &plugins) {
  callback->Run(plugins, result.Error());
}
void OlaCallbackClient::HandleDiscovery(
    ola::SingleUseCallback2<void,
                            const ola::rdm::UIDSet&,
                            const string&> *callback,
    const client::Result &result,
    const ola::rdm::UIDSet &uids) {
  callback->Run(uids, result.Error());
}
/*
 * Handle the set DMX response.
 * @param response the HTTPResponse that is associated with the request.
 * @param error an error string.
 */
void OladHTTPServer::HandleBoolResponse(HTTPResponse *response,
                                        const client::Result &result) {
  if (!result.Success()) {
    m_server.ServeError(response, result.Error());
    return;
  }
  response->SetContentType(HTTPServer::CONTENT_TYPE_PLAIN);
  response->Append("ok");
  response->Send();
  delete response;
}
void OlaCallbackClient::HandlePluginState(
    PluginStateCallback *callback,
    const client::Result &result,
    const client::PluginState &core_state) {
  PluginState state;
  state.name = core_state.name;
  state.enabled = core_state.enabled;
  state.active = core_state.active;
  state.preferences_source = core_state.preferences_source;
  state.conflicting_plugins = core_state.conflicting_plugins;

  callback->Run(state, result.Error());
}
/*
 * Handle the plugin description response.
 * @param response the HTTPResponse that is associated with the request.
 * @param description the plugin description.
 * @param error an error string.
 */
void OladHTTPServer::HandlePartialPluginInfo(HTTPResponse *response,
                                             int plugin_id,
                                             const client::Result &result,
                                             const string &description) {
  if (!result.Success()) {
    m_server.ServeError(response, result.Error());
    return;
  }
  m_client.FetchPluginState(
      (ola_plugin_id) plugin_id,
      NewSingleCallback(this,
                        &OladHTTPServer::HandlePluginInfo,
                        response, description));
}
void OlaCallbackClient::HandleUniverseInfo(
    SingleUseCallback2<void, OlaUniverse&, const string&> *callback,
    const client::Result &result,
    const OlaUniverse &universe) {
  // There was a bug in the API and universe isn't const.
  OlaUniverse new_universe(
      universe.Id(),
      universe.MergeMode(),
      universe.Name(),
      universe.InputPorts(),
      universe.OutputPorts(),
      universe.RDMDeviceCount());
  callback->Run(new_universe, result.Error());
}
/*
 * Callback for m_client.FetchDmx called by GetDmx
 * @param response the HTTPResponse
 * @param buffer the DmxBuffer
 * @param error Error message
 */
void OladHTTPServer::HandleGetDmx(HTTPResponse *response,
                                  const client::Result &result,
                                  const client::DMXMetadata &,
                                  const DmxBuffer &buffer) {
  // rather than adding 512 JsonValue we cheat and use raw here
  stringstream str;
  str << "[" << buffer.ToString() << "]";
  JsonObject json;
  json.AddRaw("dmx", str.str());
  json.Add("error", result.Error());

  response->SetNoCache();
  response->SetContentType(HTTPServer::CONTENT_TYPE_PLAIN);
  response->SendJson(json);
  delete response;
}
void OlaCallbackClient::HandleConfigureDevice(
    SingleUseCallback2<void, const string&, const string&> *callback,
    const client::Result &result,
    const string &reply) {
  callback->Run(reply, result.Error());
}
void OlaCallbackClient::HandlePluginDescription(
    SingleUseCallback2<void, const string&, const string&> *callback,
    const client::Result &result,
    const string &description) {
  callback->Run(description, result.Error());
}