/*
 * Fetch the UID list for a universe
 */
void OlaServerServiceImpl::GetUIDs(RpcController* controller,
                                   const ola::proto::UniverseRequest* request,
                                   ola::proto::UIDListReply* response,
                                   google::protobuf::Closure* done) {
  ClosureRunner runner(done);
  Universe *universe = m_universe_store->GetUniverse(request->universe());
  if (!universe)
    return MissingUniverseError(controller);

  response->set_universe(universe->UniverseId());
  UIDSet uid_set;
  universe->GetUIDs(&uid_set);

  UIDSet::Iterator iter = uid_set.Begin();
  for (; iter != uid_set.End(); ++iter) {
    ola::proto::UID *uid = response->add_uid();
    uid->set_esta_id(iter->ManufacturerId());
    uid->set_device_id(iter->DeviceId());
  }
}
/*
 * Fetch the UID list for a universe
 */
void OlaServerServiceImpl::GetUIDs(
    RpcController* controller,
    const ola::proto::UniverseRequest* request,
    ola::proto::UIDListReply* response,
    ola::rpc::RpcService::CompletionCallback* done) {
  ClosureRunner runner(done);
  Universe *universe = m_universe_store->GetUniverse(request->universe());
  if (!universe)
    return MissingUniverseError(controller);

  response->set_universe(universe->UniverseId());
  UIDSet uid_set;
  universe->GetUIDs(&uid_set);

  UIDSet::Iterator iter = uid_set.Begin();
  for (; iter != uid_set.End(); ++iter) {
    ola::proto::UID *uid = response->add_uid();
    SetProtoUID(*iter, uid);
  }
}
/**
 * Test RDM discovery for a universe/
 */
void UniverseTest::testRDMDiscovery() {
  Universe *universe = m_store->GetUniverseOrCreate(TEST_UNIVERSE);
  OLA_ASSERT(universe);

  // check the uid set is initially empty
  UIDSet universe_uids;
  universe->GetUIDs(&universe_uids);
  OLA_ASSERT_EQ(0u, universe_uids.Size());

  UID uid1(0x7a70, 1);
  UID uid2(0x7a70, 2);
  UID uid3(0x7a70, 3);
  UIDSet port1_uids, port2_uids;
  port1_uids.AddUID(uid1);
  port2_uids.AddUID(uid2);
  TestMockRDMOutputPort port1(NULL, 1, &port1_uids);
  // this port is configured to update the uids on patch
  TestMockRDMOutputPort port2(NULL, 2, &port2_uids, true);
  universe->AddPort(&port1);
  port1.SetUniverse(universe);
  universe->AddPort(&port2);
  port2.SetUniverse(universe);

  OLA_ASSERT_EQ((unsigned int) 0, universe->InputPortCount());
  OLA_ASSERT_EQ((unsigned int) 2, universe->OutputPortCount());
  universe->GetUIDs(&universe_uids);
  OLA_ASSERT_EQ(1u, universe_uids.Size());
  OLA_ASSERT(universe_uids.Contains(uid2));
  OLA_ASSERT(universe->IsActive());

  // now trigger discovery
  UIDSet expected_uids;
  expected_uids.AddUID(uid1);
  expected_uids.AddUID(uid2);

  universe->RunRDMDiscovery(
    NewSingleCallback(this, &UniverseTest::ConfirmUIDs, &expected_uids),
    true);

  // now add a uid to one port, and remove a uid from another
  port1_uids.AddUID(uid3);
  port2_uids.RemoveUID(uid2);

  expected_uids.AddUID(uid3);
  expected_uids.RemoveUID(uid2);

  universe->RunRDMDiscovery(
    NewSingleCallback(this, &UniverseTest::ConfirmUIDs, &expected_uids),
    true);

  // remove the first port from the universe and confirm there are no more UIDs
  universe->RemovePort(&port1);
  expected_uids.Clear();

  universe->RunRDMDiscovery(
    NewSingleCallback(this, &UniverseTest::ConfirmUIDs, &expected_uids),
    true);

  universe_uids.Clear();
  universe->GetUIDs(&universe_uids);
  OLA_ASSERT_EQ(0u, universe_uids.Size());

  universe->RemovePort(&port2);
  OLA_ASSERT_EQ((unsigned int) 0, universe->InputPortCount());
  OLA_ASSERT_EQ((unsigned int) 0, universe->OutputPortCount());
  OLA_ASSERT_FALSE(universe->IsActive());
}