<commit_before>/*
** Copyright 2014 Merethis
**
** This file is part of Centreon Broker.
**
** Centreon Broker is free software: you can redistribute it and/or
** modify it under the terms of the GNU General Public License version 2
** as published by the Free Software Foundation.
**
** Centreon Broker is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
** General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with Centreon Broker. If not, see
** <http://www.gnu.org/licenses/>.
*/

#include <ctime>
#include <iostream>
#include <QSqlError>
#include <QSqlQuery>
#include <QVariant>
#include <QTcpSocket>
#include <QTcpServer>
#include <sstream>
#include "com/centreon/broker/exceptions/msg.hh"
#include "config.hh"
#include "cbd.hh"
#include "vars.hh"
#include "generate.hh"
#include "misc.hh"
#include "vars.hh"
#include "engine.hh"
#include "external_command.hh"

using namespace com::centreon::broker;

#define STORAGE_DB_NAME "broker_influxdb_centreon_storage"
#define COMMAND_FILE "broker_influxdb_command_file"

#define INFLUXDB_DB_NAME "influxdb_unittest"
#define INFLUXDB_DB_PORT "6421"
#define INFLUXDB_DB_PORT_S 6421
#define INFLUXDB_DB_PASSWORD "influxdb_password"
#define INFLUXDB_DB_HOST "localhost"
#define INFLUXDB_DB_USER "influxdb_user"

static const char* expected_result =
    "POST /write?u=" INFLUXDB_DB_USER "&p="INFLUXDB_DB_PASSWORD" HTTP/1.0\n"
    "Content-Length: 143\n\n"
    "{\"database\":\""INFLUXDB_DB_NAME"\",\"points\":[{\"name\":\"influxdb_test\",\"tags\":{\"metric_id\":\"1\" },\"timestamp\":$timestamp$,\"fields\":{\"value\":0.8 } } ]}";

/**
 *  Check that the influxdb works.
 *
 *  @return EXIT_SUCCESS on success.
 */
int main() {
  // Error flag.
  bool error(true);

  // Variables that need cleaning.
  std::list<host> hosts;
  std::list<service> services;
  test_db db;
  external_command commander;
  engine monitoring;
  std::string engine_config_path(tmpnam(NULL));

  try {
    // Open the socket
    QTcpServer server;
    if (!server.listen(QHostAddress::Any, INFLUXDB_DB_PORT_S))
      throw exceptions::msg() << "couldn't listen to " << INFLUXDB_DB_PORT_S;

    // Prepare database.
    db.open(STORAGE_DB_NAME);

    // Create the config influxdb xml file.
    test_file file;
    file.set_template(
      PROJECT_SOURCE_DIR "/test/cfg/influxdb.xml.in");
    file.set("MYSQL_DB_NAME", STORAGE_DB_NAME);
    file.set("INFLUXDB_DB_NAME", INFLUXDB_DB_NAME);
    file.set("INFLUXDB_DB_PORT", INFLUXDB_DB_PORT);
    file.set("INFLUXDB_DB_PASSWORD", INFLUXDB_DB_PASSWORD);
    file.set("INFLUXDB_DB_HOST", INFLUXDB_DB_HOST);
    file.set("INFLUXDB_DB_USER", INFLUXDB_DB_USER);
    std::string config_file = file.generate();

    // Prepare monitoring engine configuration parameters.
    generate_hosts(hosts, 1);
    generate_services(services, hosts, 1);
    services.back().checks_enabled = 0;
    services.back().accept_passive_service_checks = 1;
    services.back().max_attempts = 1;
    commander.set_file(tmpnam(NULL));
    std::string additional_config;
    {
      std::ostringstream oss;
      oss << commander.get_engine_config()
          << "broker_module=" << CBMOD_PATH << " "
          << config_file << "\n";
      additional_config = oss.str();
    }
    config_write(
      engine_config_path.c_str(),
      additional_config.c_str(),
      &hosts,
      &services);

    std::cout << engine_config_path << std::endl;

    std::string engine_config_file(engine_config_path);
    engine_config_file.append("/nagios.cfg");
    monitoring.set_config_file(engine_config_file);
    monitoring.start();

    sleep_for(3 * MONITORING_ENGINE_INTERVAL_LENGTH);
    time_t first_timestamp_possible = std::time(NULL);
    commander.execute(
      "PROCESS_SERVICE_CHECK_RESULT;1;1;0;Submitted by unit test | influxdb_test=0.80");

    // Wait twice for an incoming connection. The first connection is the connection used
    // by influxdb module to check if the server exist, the second one is the data.
    if (!server.waitForNewConnection(8000 * MONITORING_ENGINE_INTERVAL_LENGTH))
      throw exceptions::msg()
            << "no incoming connection to " << INFLUXDB_DB_PORT_S;
    QTcpSocket* s = server.nextPendingConnection();
    if (!s)
      throw exceptions::msg()
            << "no incoming connection to " << INFLUXDB_DB_PORT_S;
    delete s;
    if (!server.waitForNewConnection(8000 * MONITORING_ENGINE_INTERVAL_LENGTH))
      throw exceptions::msg()
            << "no incoming connection to " << INFLUXDB_DB_PORT_S;
    s = server.nextPendingConnection();
    if (!s)
      throw exceptions::msg()
            << "no incoming connection to " << INFLUXDB_DB_PORT_S;
    QByteArray array;
    while (s->isOpen() && s->waitForReadyRead())
      array.append(s->readAll());
    QString data(array);

    time_t last_timestamp_possible = std::time(NULL);
    bool got = false;
    // Check the data got for everything is okay.
    for (;
         first_timestamp_possible <= last_timestamp_possible;
         ++first_timestamp_possible) {
      QString expected = expected_result;
      expected.replace("$timestamp$", QString::number(first_timestamp_possible));
      if (expected == data) {
        got = true;
        break;
      }
    }
    if (!got)
      throw exceptions::msg()
            << "incorrect influxdb data: got: "
            << data
            << "\nexpected: "
            << expected_result;

    // Success.
    error = false;
  }
  catch (std::exception const& e) {
    std::cerr << e.what() << std::endl;
  }
  catch (...) {
    std::cerr << "unknown exception" << std::endl;
  }

  // Cleanup.
  monitoring.stop();
  free_hosts(hosts);
  free_services(services);

  return (error ? EXIT_FAILURE : EXIT_SUCCESS);
}
<commit_msg>Influxdb: Fix influxdb unit test.<commit_after>/*
** Copyright 2014 Merethis
**
** This file is part of Centreon Broker.
**
** Centreon Broker is free software: you can redistribute it and/or
** modify it under the terms of the GNU General Public License version 2
** as published by the Free Software Foundation.
**
** Centreon Broker is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
** General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with Centreon Broker. If not, see
** <http://www.gnu.org/licenses/>.
*/

#include <ctime>
#include <iostream>
#include <QSqlError>
#include <QSqlQuery>
#include <QVariant>
#include <QTcpSocket>
#include <QTcpServer>
#include <sstream>
#include "com/centreon/broker/exceptions/msg.hh"
#include "config.hh"
#include "cbd.hh"
#include "vars.hh"
#include "generate.hh"
#include "misc.hh"
#include "vars.hh"
#include "engine.hh"
#include "external_command.hh"

using namespace com::centreon::broker;

#define STORAGE_DB_NAME "broker_influxdb_centreon_storage"
#define COMMAND_FILE "broker_influxdb_command_file"

#define INFLUXDB_DB_NAME "influxdb_unittest"
#define INFLUXDB_DB_PORT "6421"
#define INFLUXDB_DB_PORT_S 6421
#define INFLUXDB_DB_PASSWORD "influxdb_password"
#define INFLUXDB_DB_HOST "localhost"
#define INFLUXDB_DB_USER "influxdb_user"

static const char* expected_result =
    "POST /write?u=" INFLUXDB_DB_USER "&p="INFLUXDB_DB_PASSWORD" HTTP/1.0\n"
    "Content-Length: 143\n\n"
    "{\"database\":\""INFLUXDB_DB_NAME"\",\"points\":[{\"name\":\"influxdb_test\",\"tags\":{\"metric_id\":\"1\" },\"timestamp\":$timestamp$,\"fields\":{\"value\":0.8 } } ]}";

/**
 *  Check that the influxdb works.
 *
 *  @return EXIT_SUCCESS on success.
 */
int main() {
  // Error flag.
  bool error(true);

  // Variables that need cleaning.
  std::list<host> hosts;
  std::list<service> services;
  test_db db;
  external_command commander;
  engine monitoring;
  std::string engine_config_path(tmpnam(NULL));

  try {
    // Open the socket
    QTcpServer server;
    if (!server.listen(QHostAddress::Any, INFLUXDB_DB_PORT_S))
      throw exceptions::msg() << "couldn't listen to " << INFLUXDB_DB_PORT_S;

    // Prepare database.
    db.open(STORAGE_DB_NAME);

    // Create the config influxdb xml file.
    test_file file;
    file.set_template(
      PROJECT_SOURCE_DIR "/test/cfg/influxdb.xml.in");
    file.set("MYSQL_DB_NAME", STORAGE_DB_NAME);
    file.set("INFLUXDB_DB_NAME", INFLUXDB_DB_NAME);
    file.set("INFLUXDB_DB_PORT", INFLUXDB_DB_PORT);
    file.set("INFLUXDB_DB_PASSWORD", INFLUXDB_DB_PASSWORD);
    file.set("INFLUXDB_DB_HOST", INFLUXDB_DB_HOST);
    file.set("INFLUXDB_DB_USER", INFLUXDB_DB_USER);
    std::string config_file = file.generate();

    // Prepare monitoring engine configuration parameters.
    generate_hosts(hosts, 1);
    generate_services(services, hosts, 1);
    services.back().checks_enabled = 0;
    services.back().accept_passive_service_checks = 1;
    services.back().max_attempts = 1;
    commander.set_file(tmpnam(NULL));
    std::string additional_config;
    {
      std::ostringstream oss;
      oss << commander.get_engine_config()
          << "broker_module=" << CBMOD_PATH << " "
          << config_file << "\n";
      additional_config = oss.str();
    }
    config_write(
      engine_config_path.c_str(),
      additional_config.c_str(),
      &hosts,
      &services);

    std::string engine_config_file(engine_config_path);
    engine_config_file.append("/nagios.cfg");
    monitoring.set_config_file(engine_config_file);
    monitoring.start();

    sleep_for(3 * MONITORING_ENGINE_INTERVAL_LENGTH);
    time_t first_timestamp_possible = std::time(NULL);
    commander.execute(
      "PROCESS_SERVICE_CHECK_RESULT;1;1;0;Submitted by unit test | influxdb_test=0.80");

    // Wait twice for an incoming connection. The first connection is the connection used
    // by influxdb module to check if the server exist, the second one is the data.
    if (!server.waitForNewConnection(8000 * MONITORING_ENGINE_INTERVAL_LENGTH))
      throw exceptions::msg()
            << "no incoming connection to " << INFLUXDB_DB_PORT_S;
    QTcpSocket* s = server.nextPendingConnection();
    if (!s)
      throw exceptions::msg()
            << "no incoming connection to " << INFLUXDB_DB_PORT_S;
    delete s;
    if (!server.waitForNewConnection(8000 * MONITORING_ENGINE_INTERVAL_LENGTH))
      throw exceptions::msg()
            << "no incoming connection to " << INFLUXDB_DB_PORT_S;
    s = server.nextPendingConnection();
    if (!s)
      throw exceptions::msg()
            << "no incoming connection to " << INFLUXDB_DB_PORT_S;
    QByteArray array;
    while (s->isOpen() && s->waitForReadyRead())
      array.append(s->readAll());
    QString data(array);

    time_t last_timestamp_possible = std::time(NULL);
    bool got = false;
    // Check the data got for everything is okay.
    for (;
         first_timestamp_possible <= last_timestamp_possible;
         ++first_timestamp_possible) {
      QString expected = expected_result;
      expected.replace("$timestamp$", QString::number(first_timestamp_possible));
      if (expected == data) {
        got = true;
        break;
      }
    }
    if (!got)
      throw exceptions::msg()
            << "incorrect influxdb data: got: "
            << data
            << "\nexpected: "
            << expected_result;

    // Success.
    error = false;
  }
  catch (std::exception const& e) {
    std::cerr << e.what() << std::endl;
  }
  catch (...) {
    std::cerr << "unknown exception" << std::endl;
  }

  // Cleanup.
  monitoring.stop();
  free_hosts(hosts);
  free_services(services);
  config_remove(engine_config_path.c_str());

  return (error ? EXIT_FAILURE : EXIT_SUCCESS);
}
<|endoftext|>


<commit_before>/* bzflag
 * Copyright (c) 1993 - 2004 Tim Riker
 *
 * This package is free software;  you can redistribute it and/or
 * modify it under the terms of the license found in the file
 * named COPYING that should have accompanied this file.
 *
 * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 */

// common goes first
#include "common.h"

// implementation header
#include "LinkManager.h"

// system headers
#include <ctype.h>
#include <stdlib.h>
#include <assert.h>
#include <string>
#include <vector>
#include <iostream>

// common headers
#include "Pack.h"
#include "Teleporter.h"
#include "ObstacleMgr.h"

// simple globbing routines
static int match_object_name (const char *string, const char *objname);
static int match_multi (const char **string, const char **objname);
static const char MATCH_MULTI  = '*'; // matches any number of characters
static const char MATCH_SINGLE = '?'; // matches a single character

LinkManager::LinkManager()
{
  // do nothing
  return;
}

LinkManager::~LinkManager()
{
  clear();
  return;
}

void LinkManager::clear()
{
  linkNames.clear();
  linkNumbers.clear();
  return;
}

void LinkManager::makeLinkName(int number, std::string& name)
{
  name = "/t";
  char buffer[8];
  sprintf(buffer, "%i", (number / 2));
  name += buffer;
  name += ":";
  if ((number % 2) == 0) {
    name += "f";
  } else {
    name += "b";
  }
  return;
}

void LinkManager::addLink(int src, int dst)
{
  LinkNameSet link;
  makeLinkName(src, link.src);
  makeLinkName(dst, link.dst);
  linkNames.push_back(link);
  return;
}

void LinkManager::addLink(const std::string& src, const std::string& dst)
{
  LinkNameSet link;
  if ((src[0] >= '0') && (src[0] <= '9')) {
    int number = atoi(src.c_str());
    makeLinkName(number, link.src);
  } else {
    link.src = src;
  }
  if ((dst[0] >= '0') && (dst[0] <= '9')) {
    int number = atoi(dst.c_str());
    makeLinkName(number, link.dst);
  } else {
    link.dst = dst;
  }
  linkNames.push_back(link);
  return;
}

static bool inIntList(int value, const std::vector<int>& list)
{
  for (unsigned int i = 0; i < list.size(); i++) {
    if (value == list[i]) {
      return true;
    }
  }
  return false;
}

void LinkManager::doLinking()
{
  unsigned int i;

  // initial the destinations
  const ObstacleList& teles = OBSTACLEMGR.getTeles();
  // findTelesByName() can not return higher then this
  linkNumbers.resize(teles.size() * 2);
  for (i = 0; i < linkNumbers.size(); i++) {
    linkNumbers[i].dsts.clear();
  }

  for (i = 0; i < linkNames.size(); i++) {
    LinkNameSet& link = linkNames[i];
    std::vector<int> srcNumbers;
    std::vector<int> dstNumbers;
    findTelesByName(link.src, srcNumbers);
    findTelesByName(link.dst, dstNumbers);

    bool broken = false;
    if (srcNumbers.size() <= 0) {
      broken = true;
      DEBUG1("broken link src: %s\n", link.src.c_str());
    }
    if (dstNumbers.size() <= 0) {
      broken = true;
      DEBUG1("broken link dst: %s\n", link.dst.c_str());
    }
    if (broken) {
      continue;
    }

    for (unsigned s = 0; s < srcNumbers.size(); s++) {
      for (unsigned d = 0; d < dstNumbers.size(); d++) {
        std::vector<int>& dstsList = linkNumbers[srcNumbers[s]].dsts;
        if (!inIntList(dstNumbers[d], dstsList)) { // no duplicates
          dstsList.push_back(dstNumbers[d]);
        }
      }
    }
  }

  // fill in the blanks (passthru linkage)
  for (i = 0; i < linkNumbers.size(); i++) {
    std::vector<int>& dstsList = linkNumbers[i].dsts;
    if (dstsList.size() <= 0) {
      const int t = (i / 2) * 2; // tele number
      const int f = 1 - (i % 2); // opposite link
      dstsList.push_back(t + f);
    }
  }

  if (debugLevel >= 4) {
    for (i = 0; i < teles.size(); i++) {
      Teleporter* tele = (Teleporter*) teles[i];
      printf ("TELE(%i): %s\n", i, tele->getName().c_str());
    }
    for (i = 0; i < linkNames.size(); i++) {
      LinkNameSet& link = linkNames[i];
      printf ("LINKSRC: %-32sLINKDST: %s\n", link.src.c_str(), link.dst.c_str());
    }
    for (i = 0; i < linkNumbers.size(); i++) {
      printf ("SRC %3i%c:  DSTS", (i / 2), ((i % 2) == 0) ? 'f' : 'b');
      for (unsigned int j = 0; j < linkNumbers[i].dsts.size(); j++) {
        int dst = linkNumbers[i].dsts[j];
        printf (" %i%c", (dst / 2), ((dst % 2) == 0) ? 'f' : 'b');
      }
      printf ("\n");
    }
  }

  return;
}

void LinkManager::findTelesByName(const std::string& name,
                                  std::vector<int>& list) const
{
  list.clear();

  std::string glob = name;

  // no chars, no service
  if (glob.size() <= 0) {
    return;
  }

  // a leading ':' might be used to indicate absolute linking if
  // links are ever included in group definintions. strip it here
  // for forwards compatibiliy.
  if (glob[0] == ':') {
    glob.erase(0, 1); // erase 1 char from position 0
  }

  // setup for the faces types
  bool front = false;
  bool back = false;
  int lastchar = tolower(glob[glob.size() - 1]);
  if (lastchar == '*') {
    front = true;
    back = true;
  } else if (glob.size() > 1) {
    int secondlast = tolower(glob[glob.size() - 2]);
    if ((secondlast == ':') || (secondlast == '?') || (secondlast == '*')) {
      if (lastchar == '?') {
        front = true;
        back = true;
      }else if (lastchar == 'f') {
        front = true;
      } else if (lastchar == 'b') {
        back = true;
      }
      // clip the end
      if (secondlast == '*') {
        glob.resize(glob.size() - 1);
      } else {
        glob.resize(glob.size() - 2);
      }
    }
  }

  if (!front && !back) {
    return; // no possible matches
  }

  // add all teleporters that have matching names
  const ObstacleList& teles = OBSTACLEMGR.getTeles();
  for (unsigned int i = 0; i < teles.size(); i++) {
    Teleporter* tele = (Teleporter*) teles[i];
    if (match_object_name(glob.c_str(), tele->getName().c_str())) {
      if (front) {
        list.push_back((int)(i * 2) + 0);
      }
      if (back) {
        list.push_back((int)(i * 2) + 1);
      }
    }
  }

  return;
}

int LinkManager::getTeleportTarget(int source) const
{
  const ObstacleList& teles = OBSTACLEMGR.getTeles();
  assert(source < (int)(2 * teles.size()));

  const std::vector<int>& dstsList = linkNumbers[source].dsts;

  if (dstsList.size() == 1) {
    return dstsList[0];
  }
  else if (dstsList.size() > 1) {
    int target = rand() % int(dstsList.size());
    return dstsList[target];
  }
  else {
    assert(false);
    return 0;
  }
}

int LinkManager::getTeleportTarget(int source, unsigned int seed) const
{
  const ObstacleList& teles = OBSTACLEMGR.getTeles();
  assert(source < (int)(2 * teles.size()));

  const std::vector<int>& dstsList = linkNumbers[source].dsts;

  if (dstsList.size() == 1) {
    return dstsList[0];
  }
  else if (dstsList.size() > 1) {
    seed = (seed * 1103515245 + 12345) >> 8; // from POSIX rand() example
    seed = seed % (dstsList.size());
    return dstsList[seed];
  }
  else {
    assert(false);
    return 0;
  }
}

void* LinkManager::pack(void* buf) const
{
  buf = nboPackUInt(buf, (uint32_t) linkNames.size());
  for (unsigned int i = 0; i < linkNames.size(); i++) {
    buf = nboPackStdString(buf, linkNames[i].src);
    buf = nboPackStdString(buf, linkNames[i].dst);
  }
  return buf;
}

void* LinkManager::unpack(void* buf)
{
  clear(); // just in case
  unsigned int i, count;
  buf = nboUnpackUInt(buf, count);
  for (i = 0; i < count; i++) {
    LinkNameSet link;
    buf = nboUnpackStdString(buf, link.src);
    buf = nboUnpackStdString(buf, link.dst);
    linkNames.push_back(link);
  }
  return buf;
}

void LinkManager::print(std::ostream& out, const std::string& indent) const
{
  for (unsigned int i = 0; i < linkNames.size(); i++) {
    const LinkNameSet& link = linkNames[i];
    out << indent << "link" << std::endl;
    out << indent << "  from " << link.src << std::endl;
    out << indent << "  to   " << link.dst << std::endl;
    out << indent << "end" << std::endl << std::endl;
  }
  return;
}

int LinkManager::packSize() const
{
  int fullSize = sizeof(uint32_t);
  for (unsigned int i = 0; i < linkNames.size(); i++) {
    fullSize += nboStdStringPackSize(linkNames[i].src);
    fullSize += nboStdStringPackSize(linkNames[i].dst);
  }
  return fullSize;
}

/******************************************************************************/

static int
match_object_name (const char *string, const char *objname)
{
  if (string == NULL) {
    return 0;
  }
  if (objname == NULL) {
    return 0;
  }

  if ((string[0] == MATCH_MULTI) && (string[1] == '\0')) {
    DEBUG4 ("match_object_name --> %s || %s (instant match)\n",
            string, objname);
    return 1;
  }

  while (*string != '\0') {
    DEBUG4 ("match_object_name --> %s || %s\n", string, objname);

    if (*string == MATCH_MULTI) {
      string++;
      switch (match_multi (&string, &objname)) {
        case +1: {
          return 1;
        }
        case -1: {
          return 0;
        }
      }
    }
    else if (*objname == '\0') {
      return 0;
    }
    else if ((*string == MATCH_SINGLE) || (*string == *objname)) {
      string++;
      objname++;
    }
    else {
      return 0;
    }
  }

  if (*objname == '\0') {
    return 1;
  } else {
    return 0;
  }
}

/******************************************************************************/

static int
match_multi (const char **string, const char **objname)
{
  const char *str = *string;
  const char *obj = *objname;

  while ((*str != '\0') && (*str == MATCH_MULTI)) {
    str++; // get rid of multiple '*'s
  }

  if (*str == '\0') { // '*' was last, auto-match
    return +1;
  }

  const char *strtop = str;
  const char *objtop = obj;

  while (*str != '\0') {
    if (*str == MATCH_MULTI) {
      *string = str;
      *objname = obj;
      return 0; // matched this segment
    }
    else if (*obj == '\0') {
      return -1; // can't match
    }
    else {
      if ((*str == MATCH_SINGLE) || (*str == *obj)) {
        str++;
        obj++;
        if ((*str == '\0') && (*obj != '\0')) { // advanced check
          obj++;
          objtop++;
          obj = objtop;
          str = strtop;
        }
      }
      else {
        obj++;
        objtop++;
        obj = objtop;
        str = strtop;
      }
    }
  }

  *string = str;
  *objname = obj;

  return +1; // full match
}

/******************************************************************************/

// Local Variables: ***
// mode:C++ ***
// tab-width: 8 ***
// c-basic-offset: 2 ***
// indent-tabs-mode: t ***
// End: ***
// ex: shiftwidth=2 tabstop=8
<commit_msg>remove some whacky DEBUG4s<commit_after>/* bzflag
 * Copyright (c) 1993 - 2004 Tim Riker
 *
 * This package is free software;  you can redistribute it and/or
 * modify it under the terms of the license found in the file
 * named COPYING that should have accompanied this file.
 *
 * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 */

// common goes first
#include "common.h"

// implementation header
#include "LinkManager.h"

// system headers
#include <ctype.h>
#include <stdlib.h>
#include <assert.h>
#include <string>
#include <vector>
#include <iostream>

// common headers
#include "Pack.h"
#include "Teleporter.h"
#include "ObstacleMgr.h"

// simple globbing routines
static int match_object_name (const char *string, const char *objname);
static int match_multi (const char **string, const char **objname);
static const char MATCH_MULTI  = '*'; // matches any number of characters
static const char MATCH_SINGLE = '?'; // matches a single character

LinkManager::LinkManager()
{
  // do nothing
  return;
}

LinkManager::~LinkManager()
{
  clear();
  return;
}

void LinkManager::clear()
{
  linkNames.clear();
  linkNumbers.clear();
  return;
}

void LinkManager::makeLinkName(int number, std::string& name)
{
  name = "/t";
  char buffer[8];
  sprintf(buffer, "%i", (number / 2));
  name += buffer;
  name += ":";
  if ((number % 2) == 0) {
    name += "f";
  } else {
    name += "b";
  }
  return;
}

void LinkManager::addLink(int src, int dst)
{
  LinkNameSet link;
  makeLinkName(src, link.src);
  makeLinkName(dst, link.dst);
  linkNames.push_back(link);
  return;
}

void LinkManager::addLink(const std::string& src, const std::string& dst)
{
  LinkNameSet link;
  if ((src[0] >= '0') && (src[0] <= '9')) {
    int number = atoi(src.c_str());
    makeLinkName(number, link.src);
  } else {
    link.src = src;
  }
  if ((dst[0] >= '0') && (dst[0] <= '9')) {
    int number = atoi(dst.c_str());
    makeLinkName(number, link.dst);
  } else {
    link.dst = dst;
  }
  linkNames.push_back(link);
  return;
}

static bool inIntList(int value, const std::vector<int>& list)
{
  for (unsigned int i = 0; i < list.size(); i++) {
    if (value == list[i]) {
      return true;
    }
  }
  return false;
}

void LinkManager::doLinking()
{
  unsigned int i;

  // initial the destinations
  const ObstacleList& teles = OBSTACLEMGR.getTeles();
  // findTelesByName() can not return higher then this
  linkNumbers.resize(teles.size() * 2);
  for (i = 0; i < linkNumbers.size(); i++) {
    linkNumbers[i].dsts.clear();
  }

  for (i = 0; i < linkNames.size(); i++) {
    LinkNameSet& link = linkNames[i];
    std::vector<int> srcNumbers;
    std::vector<int> dstNumbers;
    findTelesByName(link.src, srcNumbers);
    findTelesByName(link.dst, dstNumbers);

    bool broken = false;
    if (srcNumbers.size() <= 0) {
      broken = true;
      DEBUG1("broken link src: %s\n", link.src.c_str());
    }
    if (dstNumbers.size() <= 0) {
      broken = true;
      DEBUG1("broken link dst: %s\n", link.dst.c_str());
    }
    if (broken) {
      continue;
    }

    for (unsigned s = 0; s < srcNumbers.size(); s++) {
      for (unsigned d = 0; d < dstNumbers.size(); d++) {
        std::vector<int>& dstsList = linkNumbers[srcNumbers[s]].dsts;
        if (!inIntList(dstNumbers[d], dstsList)) { // no duplicates
          dstsList.push_back(dstNumbers[d]);
        }
      }
    }
  }

  // fill in the blanks (passthru linkage)
  for (i = 0; i < linkNumbers.size(); i++) {
    std::vector<int>& dstsList = linkNumbers[i].dsts;
    if (dstsList.size() <= 0) {
      const int t = (i / 2) * 2; // tele number
      const int f = 1 - (i % 2); // opposite link
      dstsList.push_back(t + f);
    }
  }

  if (debugLevel >= 4) {
    for (i = 0; i < teles.size(); i++) {
      Teleporter* tele = (Teleporter*) teles[i];
      printf ("TELE(%i): %s\n", i, tele->getName().c_str());
    }
    for (i = 0; i < linkNames.size(); i++) {
      LinkNameSet& link = linkNames[i];
      printf ("LINKSRC: %-32sLINKDST: %s\n", link.src.c_str(), link.dst.c_str());
    }
    for (i = 0; i < linkNumbers.size(); i++) {
      printf ("SRC %3i%c:  DSTS", (i / 2), ((i % 2) == 0) ? 'f' : 'b');
      for (unsigned int j = 0; j < linkNumbers[i].dsts.size(); j++) {
        int dst = linkNumbers[i].dsts[j];
        printf (" %i%c", (dst / 2), ((dst % 2) == 0) ? 'f' : 'b');
      }
      printf ("\n");
    }
  }

  return;
}

void LinkManager::findTelesByName(const std::string& name,
                                  std::vector<int>& list) const
{
  list.clear();

  std::string glob = name;

  // no chars, no service
  if (glob.size() <= 0) {
    return;
  }

  // a leading ':' might be used to indicate absolute linking if
  // links are ever included in group definintions. strip it here
  // for forwards compatibiliy.
  if (glob[0] == ':') {
    glob.erase(0, 1); // erase 1 char from position 0
  }

  // setup for the faces types
  bool front = false;
  bool back = false;
  int lastchar = tolower(glob[glob.size() - 1]);
  if (lastchar == '*') {
    front = true;
    back = true;
  } else if (glob.size() > 1) {
    int secondlast = tolower(glob[glob.size() - 2]);
    if ((secondlast == ':') || (secondlast == '?') || (secondlast == '*')) {
      if (lastchar == '?') {
        front = true;
        back = true;
      }else if (lastchar == 'f') {
        front = true;
      } else if (lastchar == 'b') {
        back = true;
      }
      // clip the end
      if (secondlast == '*') {
        glob.resize(glob.size() - 1);
      } else {
        glob.resize(glob.size() - 2);
      }
    }
  }

  if (!front && !back) {
    return; // no possible matches
  }

  // add all teleporters that have matching names
  const ObstacleList& teles = OBSTACLEMGR.getTeles();
  for (unsigned int i = 0; i < teles.size(); i++) {
    Teleporter* tele = (Teleporter*) teles[i];
    if (match_object_name(glob.c_str(), tele->getName().c_str())) {
      if (front) {
        list.push_back((int)(i * 2) + 0);
      }
      if (back) {
        list.push_back((int)(i * 2) + 1);
      }
    }
  }

  return;
}

int LinkManager::getTeleportTarget(int source) const
{
  const ObstacleList& teles = OBSTACLEMGR.getTeles();
  assert(source < (int)(2 * teles.size()));

  const std::vector<int>& dstsList = linkNumbers[source].dsts;

  if (dstsList.size() == 1) {
    return dstsList[0];
  }
  else if (dstsList.size() > 1) {
    int target = rand() % int(dstsList.size());
    return dstsList[target];
  }
  else {
    assert(false);
    return 0;
  }
}

int LinkManager::getTeleportTarget(int source, unsigned int seed) const
{
  const ObstacleList& teles = OBSTACLEMGR.getTeles();
  assert(source < (int)(2 * teles.size()));

  const std::vector<int>& dstsList = linkNumbers[source].dsts;

  if (dstsList.size() == 1) {
    return dstsList[0];
  }
  else if (dstsList.size() > 1) {
    seed = (seed * 1103515245 + 12345) >> 8; // from POSIX rand() example
    seed = seed % (dstsList.size());
    return dstsList[seed];
  }
  else {
    assert(false);
    return 0;
  }
}

void* LinkManager::pack(void* buf) const
{
  buf = nboPackUInt(buf, (uint32_t) linkNames.size());
  for (unsigned int i = 0; i < linkNames.size(); i++) {
    buf = nboPackStdString(buf, linkNames[i].src);
    buf = nboPackStdString(buf, linkNames[i].dst);
  }
  return buf;
}

void* LinkManager::unpack(void* buf)
{
  clear(); // just in case
  unsigned int i, count;
  buf = nboUnpackUInt(buf, count);
  for (i = 0; i < count; i++) {
    LinkNameSet link;
    buf = nboUnpackStdString(buf, link.src);
    buf = nboUnpackStdString(buf, link.dst);
    linkNames.push_back(link);
  }
  return buf;
}

void LinkManager::print(std::ostream& out, const std::string& indent) const
{
  for (unsigned int i = 0; i < linkNames.size(); i++) {
    const LinkNameSet& link = linkNames[i];
    out << indent << "link" << std::endl;
    out << indent << "  from " << link.src << std::endl;
    out << indent << "  to   " << link.dst << std::endl;
    out << indent << "end" << std::endl << std::endl;
  }
  return;
}

int LinkManager::packSize() const
{
  int fullSize = sizeof(uint32_t);
  for (unsigned int i = 0; i < linkNames.size(); i++) {
    fullSize += nboStdStringPackSize(linkNames[i].src);
    fullSize += nboStdStringPackSize(linkNames[i].dst);
  }
  return fullSize;
}

/******************************************************************************/

static int
match_object_name (const char *string, const char *objname)
{
  if (string == NULL) {
    return 0;
  }
  if (objname == NULL) {
    return 0;
  }

  if ((string[0] == MATCH_MULTI) && (string[1] == '\0')) {
    return 1;
  }

  while (*string != '\0') {
    if (*string == MATCH_MULTI) {
      string++;
      switch (match_multi (&string, &objname)) {
        case +1: {
          return 1;
        }
        case -1: {
          return 0;
        }
      }
    }
    else if (*objname == '\0') {
      return 0;
    }
    else if ((*string == MATCH_SINGLE) || (*string == *objname)) {
      string++;
      objname++;
    }
    else {
      return 0;
    }
  }

  if (*objname == '\0') {
    return 1;
  } else {
    return 0;
  }
}

/******************************************************************************/

static int
match_multi (const char **string, const char **objname)
{
  const char *str = *string;
  const char *obj = *objname;

  while ((*str != '\0') && (*str == MATCH_MULTI)) {
    str++; // get rid of multiple '*'s
  }

  if (*str == '\0') { // '*' was last, auto-match
    return +1;
  }

  const char *strtop = str;
  const char *objtop = obj;

  while (*str != '\0') {
    if (*str == MATCH_MULTI) {
      *string = str;
      *objname = obj;
      return 0; // matched this segment
    }
    else if (*obj == '\0') {
      return -1; // can't match
    }
    else {
      if ((*str == MATCH_SINGLE) || (*str == *obj)) {
        str++;
        obj++;
        if ((*str == '\0') && (*obj != '\0')) { // advanced check
          obj++;
          objtop++;
          obj = objtop;
          str = strtop;
        }
      }
      else {
        obj++;
        objtop++;
        obj = objtop;
        str = strtop;
      }
    }
  }

  *string = str;
  *objname = obj;

  return +1; // full match
}

/******************************************************************************/

// Local Variables: ***
// mode:C++ ***
// tab-width: 8 ***
// c-basic-offset: 2 ***
// indent-tabs-mode: t ***
// End: ***
// ex: shiftwidth=2 tabstop=8
<|endoftext|>


<commit_before>#include "gtest/gtest.h"

#include <yarp/os/all.h>
#include <yarp/dev/Drivers.h>
#include <yarp/dev/PolyDriver.h>

namespace teo
{

/**
 * @brief Test
 */
class ExampleLibraryTest : public testing::Test
{

    public:
        virtual void SetUp() {

            setenv("YARP_VERBOSE","1",1);  //-- Does not seem to have any additional effect in travis.

            //yarp::os::ResourceFinder::setVerbose();  //-- Way out of scope: not static, and we do not use ResourceFinder here.

            yarp::os::Property options;
			options.put("device","ExampleLibrary");

            device.open(options);
            if( ! device.isValid() ) {
                printf("device not valid: %s.\n",options.find("device").asString().c_str());
                return;
            }
        }

        virtual void TearDown()
        {
            device.close();
        }

    protected:
        yarp::dev::PolyDriver device;
};

TEST_F( ExampleLibraryTest, ExampleTest1)
{
    ASSERT_EQ(1, 1 );
}

}  // namespace teo

<commit_msg>format, more output<commit_after>#include "gtest/gtest.h"

#include <yarp/os/all.h>
#include <yarp/dev/Drivers.h>
#include <yarp/dev/PolyDriver.h>

namespace teo
{

/**
 * @brief Test
 */
class ExampleLibraryTest : public testing::Test
{

    public:
        virtual void SetUp() {

            printf("YARP_VERBOSE before forcing is: %s\n", std::getenv("YARP_VERBOSE") );
            setenv("YARP_VERBOSE","1",1);  //-- Does not seem to have any additional effect in travis.
            printf("YARP_VERBOSE after forcing is:  %s\n", std::getenv("YARP_VERBOSE") );

            //yarp::os::ResourceFinder::setVerbose();  //-- Way out of scope: not static, and we do not use ResourceFinder here.

            yarp::os::Property options;
            options.put("device","ExampleLibrary");

            device.open(options);
            if( ! device.isValid() ) {
                printf("device not valid: %s.\n",options.find("device").asString().c_str());
                return;
            }
        }

        virtual void TearDown()
        {
            device.close();
        }

    protected:
        yarp::dev::PolyDriver device;
};

TEST_F( ExampleLibraryTest, ExampleTest1)
{
    ASSERT_EQ(1, 1 );
}

}  // namespace teo

<|endoftext|>


<commit_before>/* bzflag
 * Copyright (c) 1993 - 2005 Tim Riker
 *
 * This package is free software;  you can redistribute it and/or
 * modify it under the terms of the license found in the file
 * named COPYING that should have accompanied this file.
 *
 * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 */

// common goes first
#include "common.h"

// implementation header
#include "LinkManager.h"

// system headers
#include <ctype.h>
#include <stdlib.h>
#include <assert.h>
#include <string>
#include <vector>
#include <iostream>

// common headers
#include "Pack.h"
#include "Teleporter.h"
#include "ObstacleMgr.h"

// simple globbing routines
static int match_object_name (const char *string, const char *objname);
static int match_multi (const char **string, const char **objname);
static const char MATCH_MULTI  = '*'; // matches any number of characters
static const char MATCH_SINGLE = '?'; // matches a single character

LinkManager::LinkManager()
{
  // do nothing
  return;
}

LinkManager::~LinkManager()
{
  clear();
  return;
}

void LinkManager::clear()
{
  linkNames.clear();
  linkNumbers.clear();
  return;
}

void LinkManager::makeLinkName(int number, std::string& name)
{
  name = "/t";
  char buffer[8];
  sprintf(buffer, "%i", (number / 2));
  name += buffer;
  name += ":";
  if ((number % 2) == 0) {
    name += "f";
  } else {
    name += "b";
  }
  return;
}

void LinkManager::addLink(int src, int dst)
{
  LinkNameSet link;
  makeLinkName(src, link.src);
  makeLinkName(dst, link.dst);
  linkNames.push_back(link);
  return;
}

void LinkManager::addLink(const std::string& src, const std::string& dst)
{
  LinkNameSet link;
  if ((src[0] >= '0') && (src[0] <= '9')) {
    int number = atoi(src.c_str());
    makeLinkName(number, link.src);
  } else {
    link.src = src;
  }
  if ((dst[0] >= '0') && (dst[0] <= '9')) {
    int number = atoi(dst.c_str());
    makeLinkName(number, link.dst);
  } else {
    link.dst = dst;
  }
  linkNames.push_back(link);
  return;
}

static bool inIntList(int value, const std::vector<int>& list)
{
  for (unsigned int i = 0; i < list.size(); i++) {
    if (value == list[i]) {
      return true;
    }
  }
  return false;
}

void LinkManager::doLinking()
{
  unsigned int i;

  // initial the destinations
  const ObstacleList& teles = OBSTACLEMGR.getTeles();
  // findTelesByName() can not return higher then this
  linkNumbers.resize(teles.size() * 2);
  for (i = 0; i < linkNumbers.size(); i++) {
    linkNumbers[i].dsts.clear();
  }

  for (i = 0; i < linkNames.size(); i++) {
    LinkNameSet& link = linkNames[i];
    std::vector<int> srcNumbers;
    std::vector<int> dstNumbers;
    findTelesByName(link.src, srcNumbers);
    findTelesByName(link.dst, dstNumbers);

    bool broken = false;
    if (srcNumbers.size() <= 0) {
      broken = true;
      DEBUG1("broken link src: %s\n", link.src.c_str());
    }
    if (dstNumbers.size() <= 0) {
      broken = true;
      DEBUG1("broken link dst: %s\n", link.dst.c_str());
    }
    if (broken) {
      continue;
    }

    for (unsigned s = 0; s < srcNumbers.size(); s++) {
      for (unsigned d = 0; d < dstNumbers.size(); d++) {
	std::vector<int>& dstsList = linkNumbers[srcNumbers[s]].dsts;
	if (!inIntList(dstNumbers[d], dstsList)) { // no duplicates
	  dstsList.push_back(dstNumbers[d]);
	}
      }
    }
  }

  // fill in the blanks (passthru linkage)
  for (i = 0; i < linkNumbers.size(); i++) {
    std::vector<int>& dstsList = linkNumbers[i].dsts;
    if (dstsList.size() <= 0) {
      const int t = (i / 2) * 2; // tele number
      const int f = 1 - (i % 2); // opposite link
      dstsList.push_back(t + f);
    }
  }

  if (debugLevel >= 4) {
    for (i = 0; i < teles.size(); i++) {
      Teleporter* tele = (Teleporter*) teles[i];
      printf ("TELE(%i): %s\n", i, tele->getName().c_str());
    }
    for (i = 0; i < linkNames.size(); i++) {
      LinkNameSet& link = linkNames[i];
      printf ("LINKSRC: %-32sLINKDST: %s\n", link.src.c_str(), link.dst.c_str());
    }
    for (i = 0; i < linkNumbers.size(); i++) {
      printf ("SRC %3i%c:  DSTS", (i / 2), ((i % 2) == 0) ? 'f' : 'b');
      for (unsigned int j = 0; j < linkNumbers[i].dsts.size(); j++) {
	int dst = linkNumbers[i].dsts[j];
	printf (" %i%c", (dst / 2), ((dst % 2) == 0) ? 'f' : 'b');
      }
      printf ("\n");
    }
  }

  return;
}

void LinkManager::findTelesByName(const std::string& name,
				  std::vector<int>& list) const
{
  list.clear();

  std::string glob = name;

  // no chars, no service
  if (glob.size() <= 0) {
    return;
  }

  // a leading ':' might be used to indicate absolute linking if
  // links are ever included in group definintions. strip it here
  // for forwards compatibiliy.
  if (glob[0] == ':') {
    glob.erase(0, 1); // erase 1 char from position 0
  }

  // setup for the faces types
  bool front = false;
  bool back = false;
  int lastchar = tolower(glob[glob.size() - 1]);
  if (lastchar == '*') {
    front = true;
    back = true;
  } else if (glob.size() > 1) {
    int secondlast = tolower(glob[glob.size() - 2]);
    if ((secondlast == ':') || (secondlast == '?') || (secondlast == '*')) {
      if (lastchar == '?') {
	front = true;
	back = true;
      }else if (lastchar == 'f') {
	front = true;
      } else if (lastchar == 'b') {
	back = true;
      }
      // clip the end
      if (secondlast == '*') {
	glob.resize(glob.size() - 1);
      } else {
	glob.resize(glob.size() - 2);
      }
    }
  }

  if (!front && !back) {
    return; // no possible matches
  }

  // add all teleporters that have matching names
  const ObstacleList& teles = OBSTACLEMGR.getTeles();
  for (unsigned int i = 0; i < teles.size(); i++) {
    Teleporter* tele = (Teleporter*) teles[i];
    if (match_object_name(glob.c_str(), tele->getName().c_str())) {
      if (front) {
	list.push_back((int)(i * 2) + 0);
      }
      if (back) {
	list.push_back((int)(i * 2) + 1);
      }
    }
  }

  return;
}

int LinkManager::getTeleportTarget(int source) const
{
  assert(source < (int)(2 * OBSTACLEMGR.getTeles().size()));

  const std::vector<int>& dstsList = linkNumbers[source].dsts;

  if (dstsList.size() == 1) {
    return dstsList[0];
  }
  else if (dstsList.size() > 1) {
    int target = rand() % int(dstsList.size());
    return dstsList[target];
  }
  else {
    assert(false);
    return 0;
  }
}

int LinkManager::getTeleportTarget(int source, unsigned int seed) const
{
  assert(source < (int)(2 * OBSTACLEMGR.getTeles().size()));

  const std::vector<int>& dstsList = linkNumbers[source].dsts;

  if (dstsList.size() == 1) {
    return dstsList[0];
  }
  else if (dstsList.size() > 1) {
    seed = (seed * 1103515245 + 12345) >> 8; // from POSIX rand() example
    seed = seed % (dstsList.size());
    return dstsList[seed];
  }
  else {
    assert(false);
    return 0;
  }
}

void* LinkManager::pack(void* buf) const
{
  buf = nboPackUInt(buf, (uint32_t) linkNames.size());
  for (unsigned int i = 0; i < linkNames.size(); i++) {
    buf = nboPackStdString(buf, linkNames[i].src);
    buf = nboPackStdString(buf, linkNames[i].dst);
  }
  return buf;
}

void* LinkManager::unpack(void* buf)
{
  clear(); // just in case
  unsigned int i;
  uint32_t count;
  buf = nboUnpackUInt(buf, count);
  for (i = 0; i < count; i++) {
    LinkNameSet link;
    buf = nboUnpackStdString(buf, link.src);
    buf = nboUnpackStdString(buf, link.dst);
    linkNames.push_back(link);
  }
  return buf;
}

void LinkManager::print(std::ostream& out, const std::string& indent) const
{
  for (unsigned int i = 0; i < linkNames.size(); i++) {
    const LinkNameSet& link = linkNames[i];
    out << indent << "link" << std::endl;
    out << indent << "  from " << link.src << std::endl;
    out << indent << "  to   " << link.dst << std::endl;
    out << indent << "end" << std::endl << std::endl;
  }
  return;
}

int LinkManager::packSize() const
{
  int fullSize = sizeof(uint32_t);
  for (unsigned int i = 0; i < linkNames.size(); i++) {
    fullSize += nboStdStringPackSize(linkNames[i].src);
    fullSize += nboStdStringPackSize(linkNames[i].dst);
  }
  return fullSize;
}

/******************************************************************************/

static int match_object_name (const char *string, const char *objname)
{
  if (string == NULL) {
    return 0;
  }
  if (objname == NULL) {
    return 0;
  }

  if ((string[0] == MATCH_MULTI) && (string[1] == '\0')) {
    return 1;
  }

  while (*string != '\0') {
    if (*string == MATCH_MULTI) {
      string++;
      switch (match_multi (&string, &objname)) {
	case +1: {
	  return 1;
	}
	case -1: {
	  return 0;
	}
      }
    }
    else if (*objname == '\0') {
      return 0;
    }
    else if ((*string == MATCH_SINGLE) || (*string == *objname)) {
      string++;
      objname++;
    }
    else {
      return 0;
    }
  }

  if (*objname == '\0') {
    return 1;
  } else {
    return 0;
  }
}

/******************************************************************************/

static int match_multi (const char **string, const char **objname)
{
  const char *str = *string;
  const char *obj = *objname;

  while ((*str != '\0') && (*str == MATCH_MULTI)) {
    str++; // get rid of multiple '*'s
  }

  if (*str == '\0') { // '*' was last, auto-match
    return +1;
  }

  const char *strtop = str;
  const char *objtop = obj;

  while (*str != '\0') {
    if (*str == MATCH_MULTI) {
      *string = str;
      *objname = obj;
      return 0; // matched this segment
    }
    else if (*obj == '\0') {
      return -1; // can't match
    }
    else {
      if ((*str == MATCH_SINGLE) || (*str == *obj)) {
	str++;
	obj++;
	if ((*str == '\0') && (*obj != '\0')) { // advanced check
	  obj++;
	  objtop++;
	  obj = objtop;
	  str = strtop;
	}
      }
      else {
	obj++;
	objtop++;
	obj = objtop;
	str = strtop;
      }
    }
  }

  *string = str;
  *objname = obj;

  return +1; // full match
}

/******************************************************************************/

// Local Variables: ***
// mode:C++ ***
// tab-width: 8 ***
// c-basic-offset: 2 ***
// indent-tabs-mode: t ***
// End: ***
// ex: shiftwidth=2 tabstop=8
<commit_msg>simplify<commit_after>/* bzflag
 * Copyright (c) 1993 - 2005 Tim Riker
 *
 * This package is free software;  you can redistribute it and/or
 * modify it under the terms of the license found in the file
 * named COPYING that should have accompanied this file.
 *
 * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 */

// common goes first
#include "common.h"

// implementation header
#include "LinkManager.h"

// system headers
#include <ctype.h>
#include <stdlib.h>
#include <assert.h>
#include <string>
#include <vector>
#include <iostream>

// common headers
#include "Pack.h"
#include "Teleporter.h"
#include "ObstacleMgr.h"

// simple globbing routines
static int match_object_name (const char *string, const char *objname);
static int match_multi (const char **string, const char **objname);
static const char MATCH_MULTI  = '*'; // matches any number of characters
static const char MATCH_SINGLE = '?'; // matches a single character

LinkManager::LinkManager()
{
  // do nothing
  return;
}

LinkManager::~LinkManager()
{
  clear();
  return;
}

void LinkManager::clear()
{
  linkNames.clear();
  linkNumbers.clear();
  return;
}

void LinkManager::makeLinkName(int number, std::string& name)
{
  name = "/t";
  char buffer[8];
  sprintf(buffer, "%i", (number / 2));
  name += buffer;
  name += ":";
  if ((number % 2) == 0) {
    name += "f";
  } else {
    name += "b";
  }
  return;
}

void LinkManager::addLink(int src, int dst)
{
  LinkNameSet link;
  makeLinkName(src, link.src);
  makeLinkName(dst, link.dst);
  linkNames.push_back(link);
  return;
}

void LinkManager::addLink(const std::string& src, const std::string& dst)
{
  LinkNameSet link;
  if ((src[0] >= '0') && (src[0] <= '9')) {
    int number = atoi(src.c_str());
    makeLinkName(number, link.src);
  } else {
    link.src = src;
  }
  if ((dst[0] >= '0') && (dst[0] <= '9')) {
    int number = atoi(dst.c_str());
    makeLinkName(number, link.dst);
  } else {
    link.dst = dst;
  }
  linkNames.push_back(link);
  return;
}

static bool inIntList(int value, const std::vector<int>& list)
{
  for (unsigned int i = 0; i < list.size(); i++) {
    if (value == list[i]) {
      return true;
    }
  }
  return false;
}

void LinkManager::doLinking()
{
  unsigned int i;

  // initial the destinations
  const ObstacleList& teles = OBSTACLEMGR.getTeles();
  // findTelesByName() can not return higher then this
  linkNumbers.resize(teles.size() * 2);
  for (i = 0; i < linkNumbers.size(); i++) {
    linkNumbers[i].dsts.clear();
  }

  for (i = 0; i < linkNames.size(); i++) {
    LinkNameSet& link = linkNames[i];
    std::vector<int> srcNumbers;
    std::vector<int> dstNumbers;
    findTelesByName(link.src, srcNumbers);
    findTelesByName(link.dst, dstNumbers);

    bool broken = false;
    if (srcNumbers.size() <= 0) {
      broken = true;
      DEBUG1("broken link src: %s\n", link.src.c_str());
    }
    if (dstNumbers.size() <= 0) {
      broken = true;
      DEBUG1("broken link dst: %s\n", link.dst.c_str());
    }
    if (broken) {
      continue;
    }

    for (unsigned s = 0; s < srcNumbers.size(); s++) {
      for (unsigned d = 0; d < dstNumbers.size(); d++) {
	std::vector<int>& dstsList = linkNumbers[srcNumbers[s]].dsts;
	if (!inIntList(dstNumbers[d], dstsList)) { // no duplicates
	  dstsList.push_back(dstNumbers[d]);
	}
      }
    }
  }

  // fill in the blanks (passthru linkage)
  for (i = 0; i < linkNumbers.size(); i++) {
    std::vector<int>& dstsList = linkNumbers[i].dsts;
    if (dstsList.size() <= 0) {
      const int t = (i / 2) * 2; // tele number
      const int f = 1 - (i % 2); // opposite link
      dstsList.push_back(t + f);
    }
  }

  if (debugLevel >= 4) {
    for (i = 0; i < teles.size(); i++) {
      Teleporter* tele = (Teleporter*) teles[i];
      printf ("TELE(%i): %s\n", i, tele->getName().c_str());
    }
    for (i = 0; i < linkNames.size(); i++) {
      LinkNameSet& link = linkNames[i];
      printf ("LINKSRC: %-32sLINKDST: %s\n", link.src.c_str(), link.dst.c_str());
    }
    for (i = 0; i < linkNumbers.size(); i++) {
      printf ("SRC %3i%c:  DSTS", (i / 2), ((i % 2) == 0) ? 'f' : 'b');
      for (unsigned int j = 0; j < linkNumbers[i].dsts.size(); j++) {
	int dst = linkNumbers[i].dsts[j];
	printf (" %i%c", (dst / 2), ((dst % 2) == 0) ? 'f' : 'b');
      }
      printf ("\n");
    }
  }

  return;
}

void LinkManager::findTelesByName(const std::string& name,
				  std::vector<int>& list) const
{
  list.clear();

  std::string glob = name;

  // no chars, no service
  if (glob.size() <= 0) {
    return;
  }

  // a leading ':' might be used to indicate absolute linking if
  // links are ever included in group definintions. strip it here
  // for forwards compatibiliy.
  if (glob[0] == ':') {
    glob.erase(0, 1); // erase 1 char from position 0
  }

  // add all teleporters that have matching names
  const ObstacleList& teles = OBSTACLEMGR.getTeles();
  for (unsigned int i = 0; i < teles.size(); i++) {
    Teleporter* tele = (Teleporter*) teles[i];
    const std::string teleName = tele->getName();

    std::string front = teleName;
    front += ":f";
    if (match_object_name(glob.c_str(), front.c_str())) {
      list.push_back((int)(i * 2) + 0);
    }

    std::string back = teleName;
    back += ":b";
    if (match_object_name(glob.c_str(), back.c_str())) {
      list.push_back((int)(i * 2) + 1);
    }
  }

  return;
}

int LinkManager::getTeleportTarget(int source) const
{
  assert(source < (int)(2 * OBSTACLEMGR.getTeles().size()));

  const std::vector<int>& dstsList = linkNumbers[source].dsts;

  if (dstsList.size() == 1) {
    return dstsList[0];
  }
  else if (dstsList.size() > 1) {
    int target = rand() % int(dstsList.size());
    return dstsList[target];
  }
  else {
    assert(false);
    return 0;
  }
}

int LinkManager::getTeleportTarget(int source, unsigned int seed) const
{
  assert(source < (int)(2 * OBSTACLEMGR.getTeles().size()));

  const std::vector<int>& dstsList = linkNumbers[source].dsts;

  if (dstsList.size() == 1) {
    return dstsList[0];
  }
  else if (dstsList.size() > 1) {
    seed = (seed * 1103515245 + 12345) >> 8; // from POSIX rand() example
    seed = seed % (dstsList.size());
    return dstsList[seed];
  }
  else {
    assert(false);
    return 0;
  }
}

void* LinkManager::pack(void* buf) const
{
  buf = nboPackUInt(buf, (uint32_t) linkNames.size());
  for (unsigned int i = 0; i < linkNames.size(); i++) {
    buf = nboPackStdString(buf, linkNames[i].src);
    buf = nboPackStdString(buf, linkNames[i].dst);
  }
  return buf;
}

void* LinkManager::unpack(void* buf)
{
  clear(); // just in case
  unsigned int i;
  uint32_t count;
  buf = nboUnpackUInt(buf, count);
  for (i = 0; i < count; i++) {
    LinkNameSet link;
    buf = nboUnpackStdString(buf, link.src);
    buf = nboUnpackStdString(buf, link.dst);
    linkNames.push_back(link);
  }
  return buf;
}

void LinkManager::print(std::ostream& out, const std::string& indent) const
{
  for (unsigned int i = 0; i < linkNames.size(); i++) {
    const LinkNameSet& link = linkNames[i];
    out << indent << "link" << std::endl;
    out << indent << "  from " << link.src << std::endl;
    out << indent << "  to   " << link.dst << std::endl;
    out << indent << "end" << std::endl << std::endl;
  }
  return;
}

int LinkManager::packSize() const
{
  int fullSize = sizeof(uint32_t);
  for (unsigned int i = 0; i < linkNames.size(); i++) {
    fullSize += nboStdStringPackSize(linkNames[i].src);
    fullSize += nboStdStringPackSize(linkNames[i].dst);
  }
  return fullSize;
}

/******************************************************************************/

static int match_object_name (const char *string, const char *objname)
{
  if (string == NULL) {
    return 0;
  }
  if (objname == NULL) {
    return 0;
  }

  if ((string[0] == MATCH_MULTI) && (string[1] == '\0')) {
    return 1;
  }

  while (*string != '\0') {
    if (*string == MATCH_MULTI) {
      string++;
      switch (match_multi (&string, &objname)) {
	case +1: {
	  return 1;
	}
	case -1: {
	  return 0;
	}
      }
    }
    else if (*objname == '\0') {
      return 0;
    }
    else if ((*string == MATCH_SINGLE) || (*string == *objname)) {
      string++;
      objname++;
    }
    else {
      return 0;
    }
  }

  if (*objname == '\0') {
    return 1;
  } else {
    return 0;
  }
}

/******************************************************************************/

static int match_multi (const char **string, const char **objname)
{
  const char *str = *string;
  const char *obj = *objname;

  while ((*str != '\0') && (*str == MATCH_MULTI)) {
    str++; // get rid of multiple '*'s
  }

  if (*str == '\0') { // '*' was last, auto-match
    return +1;
  }

  const char *strtop = str;
  const char *objtop = obj;

  while (*str != '\0') {
    if (*str == MATCH_MULTI) {
      *string = str;
      *objname = obj;
      return 0; // matched this segment
    }
    else if (*obj == '\0') {
      return -1; // can't match
    }
    else {
      if ((*str == MATCH_SINGLE) || (*str == *obj)) {
	str++;
	obj++;
	if ((*str == '\0') && (*obj != '\0')) { // advanced check
	  obj++;
	  objtop++;
	  obj = objtop;
	  str = strtop;
	}
      }
      else {
	obj++;
	objtop++;
	obj = objtop;
	str = strtop;
      }
    }
  }

  *string = str;
  *objname = obj;

  return +1; // full match
}

/******************************************************************************/

// Local Variables: ***
// mode:C++ ***
// tab-width: 8 ***
// c-basic-offset: 2 ***
// indent-tabs-mode: t ***
// End: ***
// ex: shiftwidth=2 tabstop=8
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: e3dsphereproperties.cxx,v $
 *
 *  $Revision: 1.4 $
 *
 *  last change: $Author: rt $ $Date: 2005-09-09 00:13:48 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#ifndef _SDR_PROPERTIES_E3DSPHEREPROPERTIES_HXX
#include <svx/sdr/properties/e3dsphereproperties.hxx>
#endif

#ifndef _SFXITEMSET_HXX
#include <svtools/itemset.hxx>
#endif

#ifndef _E3D_SPHERE3D_HXX
#include <sphere3d.hxx>
#endif

//////////////////////////////////////////////////////////////////////////////

namespace sdr
{
    namespace properties
    {
        E3dSphereProperties::E3dSphereProperties(SdrObject& rObj)
        :   E3dCompoundProperties(rObj)
        {
        }

        E3dSphereProperties::E3dSphereProperties(const E3dSphereProperties& rProps, SdrObject& rObj)
        :   E3dCompoundProperties(rProps, rObj)
        {
        }

        E3dSphereProperties::~E3dSphereProperties()
        {
        }

        BaseProperties& E3dSphereProperties::Clone(SdrObject& rObj) const
        {
            return *(new E3dSphereProperties(*this, rObj));
        }

        void E3dSphereProperties::PostItemChange(const sal_uInt16 nWhich)
        {
            // call parent
            E3dCompoundProperties::PostItemChange(nWhich);

            // handle value change
            E3dSphereObj& rObj = (E3dSphereObj&)GetSdrObject();

            switch(nWhich)
            {
                case SDRATTR_3DOBJ_HORZ_SEGS:
                {
                    rObj.InvalidateGeometry();
                    break;
                }
                case SDRATTR_3DOBJ_VERT_SEGS:
                {
                    rObj.InvalidateGeometry();
                    break;
                }
            }
        }
    } // end of namespace properties
} // end of namespace sdr

//////////////////////////////////////////////////////////////////////////////
// eof
<commit_msg>INTEGRATION: CWS pchfix02 (1.4.536); FILE MERGED 2006/09/01 17:47:16 kaib 1.4.536.1: #i68856# Added header markers and pch files<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: e3dsphereproperties.cxx,v $
 *
 *  $Revision: 1.5 $
 *
 *  last change: $Author: obo $ $Date: 2006-09-17 05:42:36 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_svx.hxx"

#ifndef _SDR_PROPERTIES_E3DSPHEREPROPERTIES_HXX
#include <svx/sdr/properties/e3dsphereproperties.hxx>
#endif

#ifndef _SFXITEMSET_HXX
#include <svtools/itemset.hxx>
#endif

#ifndef _E3D_SPHERE3D_HXX
#include <sphere3d.hxx>
#endif

//////////////////////////////////////////////////////////////////////////////

namespace sdr
{
    namespace properties
    {
        E3dSphereProperties::E3dSphereProperties(SdrObject& rObj)
        :   E3dCompoundProperties(rObj)
        {
        }

        E3dSphereProperties::E3dSphereProperties(const E3dSphereProperties& rProps, SdrObject& rObj)
        :   E3dCompoundProperties(rProps, rObj)
        {
        }

        E3dSphereProperties::~E3dSphereProperties()
        {
        }

        BaseProperties& E3dSphereProperties::Clone(SdrObject& rObj) const
        {
            return *(new E3dSphereProperties(*this, rObj));
        }

        void E3dSphereProperties::PostItemChange(const sal_uInt16 nWhich)
        {
            // call parent
            E3dCompoundProperties::PostItemChange(nWhich);

            // handle value change
            E3dSphereObj& rObj = (E3dSphereObj&)GetSdrObject();

            switch(nWhich)
            {
                case SDRATTR_3DOBJ_HORZ_SEGS:
                {
                    rObj.InvalidateGeometry();
                    break;
                }
                case SDRATTR_3DOBJ_VERT_SEGS:
                {
                    rObj.InvalidateGeometry();
                    break;
                }
            }
        }
    } // end of namespace properties
} // end of namespace sdr

//////////////////////////////////////////////////////////////////////////////
// eof
<|endoftext|>


<commit_before>#include "RenderItemMatcher.hpp"

double RenderItemMatcher::computeMatching(const RenderItemList & lhs, const RenderItemList & rhs) const {
		for (int i = 0; i < lhs.size();i++) {
			int j;
			for (j = 0; j < rhs.size();j++)
				_weights[i][j] = _distanceFunction(lhs[i], rhs[j]);
			for (; j < lhs.size();j++)
				_weights[i][j] = RenderItemDistanceMetric::NOT_COMPARABLE_VALUE;
		}

		const double error = _hungarianMethod(_weights, lhs.size());
		//std::cout << "[computeMatching] total error is " << error << std::endl;
		return error;
}

void RenderItemMatcher::setMatches
	(const RenderItemList & lhs_src, const RenderItemList & rhs_src) const {

	  for (int i = 0; i < lhs_src.size();i++) {
		const int j = _hungarianMethod.matching(i);
		if (_weights[i][j] == RenderItemDistanceMetric::NOT_COMPARABLE_VALUE) {
 			_results.unmatchedLeft.push_back(lhs_src[i]);
			_results.unmatchedRight.push_back(rhs_src[i]);
		} else {
		    _results.matches.push_back(std::make_pair(lhs_src[i], rhs_src[j]));
		}
	  }
}<commit_msg>make everything unmatchable.<commit_after>#include "RenderItemMatcher.hpp"

double RenderItemMatcher::computeMatching(const RenderItemList & lhs, const RenderItemList & rhs) const {
		for (int i = 0; i < lhs.size();i++) {
			int j;
			for (j = 0; j < rhs.size();j++)
				_weights[i][j] = _distanceFunction(lhs[i], rhs[j]);
			for (; j < lhs.size();j++)
				_weights[i][j] = RenderItemDistanceMetric::NOT_COMPARABLE_VALUE;
		}

		const double error = _hungarianMethod(_weights, lhs.size());
		//std::cout << "[computeMatching] total error is " << error << std::endl;
		return error;
}

void RenderItemMatcher::setMatches
	(const RenderItemList & lhs_src, const RenderItemList & rhs_src) const {

	  for (int i = 0; i < lhs_src.size();i++) {
		const int j = _hungarianMethod.matching(i);

		// hack
		if (true || _weights[i][j] == RenderItemDistanceMetric::NOT_COMPARABLE_VALUE) {
 			_results.unmatchedLeft.push_back(lhs_src[i]);
			_results.unmatchedRight.push_back(rhs_src[i]);
		} else {
		    _results.matches.push_back(std::make_pair(lhs_src[i], rhs_src[j]));
		}
	  }
}<|endoftext|>


<commit_before>#define BOOST_POLYGON_NO_DEPS

// Example from http://whyalgorithm.com/blog/2015/08/26/reliable-voronoi-implementation/

#include <iostream>

#include <boost/polygon/voronoi.hpp>

#include <GL/glut.h>

using namespace boost::polygon;

typedef double coordinate_type;
typedef point_data<coordinate_type> Point;
typedef voronoi_diagram<double> VD;

VD vd;
std::vector<Point> points;

void displayMe(void)
{
  glClear(GL_COLOR_BUFFER_BIT);
  glBegin(GL_LINES);
  for (VD::const_edge_iterator it = vd.edges().begin(); it != vd.edges().end(); ++it)
  {
    if (it->is_primary())
    {
      if (it->is_finite())
      {
        glVertex2d(it->vertex0()->x(), it->vertex0()->y());
        glVertex2d(it->vertex1()->x(), it->vertex1()->y());
      }
      else
      {
        Point p1 = points[it->cell()->source_index()];
        Point p2 = points[it->twin()->cell()->source_index()];
        Point origin;
        Point direction;
        coordinate_type koef = 1.0;

        origin.x((p1.x() + p2.x()) * 0.5);
        origin.y((p1.y() + p2.y()) * 0.5);
        direction.x(p1.y() - p2.y());
        direction.y(p2.x() - p1.x());
        if (it->vertex0() == NULL) {
          glVertex2d(origin.x() - direction.x() * koef, origin.y() - direction.y() * koef);
        }
        else {
          glVertex2d(it->vertex0()->x(), it->vertex0()->y());
        }

        if (it->vertex1() == NULL) {
          glVertex2d(origin.x() + direction.x() * koef, origin.y() + direction.y() * koef);
        }
        else {
          glVertex2d(it->vertex1()->x(), it->vertex1()->y());
        }
      }
    }
  }
  glEnd();
  glFlush();
}

int main(int argc, char* argv[])
{

  points.push_back(Point(0, 0));
  points.push_back(Point(100, 0));
  points.push_back(Point(0, 100));
  points.push_back(Point(100, 100));
  points.push_back(Point(800, 800));

  construct_voronoi(points.begin(), points.end(), &vd);

  int width = 800, height = 800;
  glutInit(&argc, argv);
  glutInitDisplayMode(GLUT_SINGLE);
  glutInitWindowSize(width, height);
  glutInitWindowPosition(100, 100);
  glutCreateWindow("Hello world :D");
  glViewport(0, 0, width, height);
  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();
  glOrtho(0, width, height, 0, 1, -1);
  glMatrixMode(GL_MODELVIEW);
  glLoadIdentity();
  glutDisplayFunc(displayMe);
  glutMainLoop();

  return 0;
}
<commit_msg>Generate points for voronoi pseudo-randomly<commit_after>#define BOOST_POLYGON_NO_DEPS

// Example from http://whyalgorithm.com/blog/2015/08/26/reliable-voronoi-implementation/

#include <iostream>
#include <random>

#include <boost/polygon/voronoi.hpp>

#include <GL/glut.h>

using namespace boost::polygon;

typedef double coordinate_type;
typedef point_data<coordinate_type> Point;
typedef voronoi_diagram<double> VD;

VD vd;
std::vector<Point> points;

void displayMe(void)
{
  glClear(GL_COLOR_BUFFER_BIT);
  glBegin(GL_LINES);
  for (VD::const_edge_iterator it = vd.edges().begin(); it != vd.edges().end(); ++it)
  {
    if (it->is_primary())
    {
      if (it->is_finite())
      {
        glVertex2d(it->vertex0()->x(), it->vertex0()->y());
        glVertex2d(it->vertex1()->x(), it->vertex1()->y());
      }
      else
      {
        Point p1 = points[it->cell()->source_index()];
        Point p2 = points[it->twin()->cell()->source_index()];
        Point origin;
        Point direction;
        coordinate_type koef = 1.0;

        origin.x((p1.x() + p2.x()) * 0.5);
        origin.y((p1.y() + p2.y()) * 0.5);
        direction.x(p1.y() - p2.y());
        direction.y(p2.x() - p1.x());
        if (it->vertex0() == NULL) {
          glVertex2d(origin.x() - direction.x() * koef, origin.y() - direction.y() * koef);
        }
        else {
          glVertex2d(it->vertex0()->x(), it->vertex0()->y());
        }

        if (it->vertex1() == NULL) {
          glVertex2d(origin.x() + direction.x() * koef, origin.y() + direction.y() * koef);
        }
        else {
          glVertex2d(it->vertex1()->x(), it->vertex1()->y());
        }
      }
    }
  }
  glEnd();
  glFlush();
}

#define CHUNK_SIZE 800

int chunkSeed(int chunkX, int chunkY, int seed) {
  return (chunkX * 31 + chunkY * CHUNK_SIZE) * 31 * seed;
}
void insertRandomPoints(int chunkX, int chunkY, int count, int seed) {
  std::random_device rd;
  std::mt19937 gen(chunkSeed(chunkX, chunkY, seed));
  std::uniform_int_distribution<> dis(0, CHUNK_SIZE - 1);
  for (int i = 0; i < count; i++) {
    int x = dis(gen);
    int y = dis(gen);
    points.push_back(Point(CHUNK_SIZE * chunkX + x, CHUNK_SIZE * chunkY + y));
  }
}

int main(int argc, char* argv[])
{

  points.push_back(Point(0, 0));
  points.push_back(Point(800, 0));
  points.push_back(Point(0, 800));
  points.push_back(Point(800, 800));
  insertRandomPoints(0, 0, 100, 0);

  construct_voronoi(points.begin(), points.end(), &vd);

  int width = 800, height = 800;
  glutInit(&argc, argv);
  glutInitDisplayMode(GLUT_SINGLE);
  glutInitWindowSize(width, height);
  glutInitWindowPosition(100, 100);
  glutCreateWindow("Hello world :D");
  glViewport(0, 0, width, height);
  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();
  glOrtho(0, width, height, 0, 1, -1);
  glMatrixMode(GL_MODELVIEW);
  glLoadIdentity();
  glutDisplayFunc(displayMe);
  glutMainLoop();

  return 0;
}
<|endoftext|>


<commit_before>/*      _______   __   __   __   ______   __   __   _______   __   __
 *     / _____/\ / /\ / /\ / /\ / ____/\ / /\ / /\ / ___  /\ /  |\/ /\
 *    / /\____\// / // / // / // /\___\// /_// / // /\_/ / // , |/ / /
 *   / / /__   / / // / // / // / /    / ___  / // ___  / // /| ' / /
 *  / /_// /\ / /_// / // / // /_/_   / / // / // /\_/ / // / |  / /
 * /______/ //______/ //_/ //_____/\ /_/ //_/ //_/ //_/ //_/ /|_/ /
 * \______\/ \______\/ \_\/ \_____\/ \_\/ \_\/ \_\/ \_\/ \_\/ \_\/
 *
 * Copyright (c) 2004 - 2008 Olof Naessn and Per Larsson
 *
 *
 * Per Larsson a.k.a finalman
 * Olof Naessn a.k.a jansem/yakslem
 *
 * Visit: http://guichan.sourceforge.net
 *
 * License: (BSD)
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 * 3. Neither the name of Guichan nor the names of its contributors may
 *    be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
 * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

/*
 * For comments regarding functions please see the header file.
 */

#include "guichan/widgets/tabbedarea.hpp"

#include "guichan/exception.hpp"
#include "guichan/focushandler.hpp"
#include "guichan/font.hpp"
#include "guichan/graphics.hpp"

#include "guichan/widgets/container.hpp"
#include "guichan/widgets/tab.hpp"

#include <algorithm>

namespace gcn
{
    TabbedArea::TabbedArea()
            :mSelectedTab(NULL),
             mOpaque(false)
    {
        setFocusable(true);
        addKeyListener(this);
        addMouseListener(this);

        mTabContainer = new Container();
        mTabContainer->setOpaque(false);
        mWidgetContainer = new Container();

        add(mTabContainer);
        add(mWidgetContainer);
    }

    TabbedArea::~TabbedArea()
    {
        remove(mTabContainer);
        remove(mWidgetContainer);

        delete mTabContainer;
        delete mWidgetContainer;

        for (unsigned int i = 0; i < mTabsToDelete.size(); i++)
        {
            delete mTabsToDelete[i];
        }
    }

    void TabbedArea::addTab(const std::string& caption, Widget* widget)
    {
        Tab* tab = new Tab();
        tab->setCaption(caption);
        mTabsToDelete.push_back(tab);

        addTab(tab, widget);
    }

    void TabbedArea::addTab(Tab* tab, Widget* widget)
    {
        tab->setTabbedArea(this);
        tab->addActionListener(this);

        mTabContainer->add(tab);
        mTabs.push_back(std::pair<Tab*, Widget*>(tab, widget));

        if (mSelectedTab == NULL)
        {
            setSelectedTab(tab);
        }

        adjustTabPositions();
        adjustSize();
    }

    void TabbedArea::removeTabWithIndex(unsigned int index)
    {
        if (index >= mTabs.size())
        {
            throw GCN_EXCEPTION("No such tab index.");
        }

        removeTab(mTabs[index].first);
    }

    void TabbedArea::removeTab(Tab* tab)
    {
        int tabIndexToBeSelected = - 1;

        if (tab == mSelectedTab)
        {
            int index = getSelectedTabIndex();

            if (index == (int)mTabs.size() - 1
                && mTabs.size() >= 2)
            {
                tabIndexToBeSelected = index--;
            }
            else if (index == (int)mTabs.size() - 1
                     && mTabs.size() == 1)
            {
                tabIndexToBeSelected = -1;
            }
            else
            {
                tabIndexToBeSelected = index;
            }
        }

        std::vector<std::pair<Tab*, Widget*> >::iterator iter;
        for (iter = mTabs.begin(); iter != mTabs.end(); iter++)
        {
            if (iter->first == tab)
            {
                mTabContainer->remove(tab);
                mTabs.erase(iter);
                break;
            }
        }

        std::vector<Tab*>::iterator iter2;
        for (iter2 = mTabsToDelete.begin(); iter2 != mTabsToDelete.end(); iter2++)
        {
            if (*iter2 == tab)
            {
                mTabsToDelete.erase(iter2);
                delete tab;
                break;
            }
        }

        if (tabIndexToBeSelected == -1)
        {
            mSelectedTab = NULL;
            mWidgetContainer->clear();
        }
        else
        {
            setSelectedTab(tabIndexToBeSelected);
        }

        adjustSize();
        adjustTabPositions();
    }

    bool TabbedArea::isTabSelected(unsigned int index) const
    {
        if (index >= mTabs.size())
        {
            throw GCN_EXCEPTION("No such tab index.");
        }

        return mSelectedTab == mTabs[index].first;
    }

    bool TabbedArea::isTabSelected(Tab* tab)
    {
        return mSelectedTab == tab;
    }

    void TabbedArea::setSelectedTab(unsigned int index)
    {
        if (index >= mTabs.size())
        {
            throw GCN_EXCEPTION("No such tab index.");
        }

        setSelectedTab(mTabs[index].first);
    }

    void TabbedArea::setSelectedTab(Tab* tab)
    {
        unsigned int i;
        for (i = 0; i < mTabs.size(); i++)
        {
            if (mTabs[i].first == mSelectedTab)
            {
                mWidgetContainer->remove(mTabs[i].second);
            }
        }

        for (i = 0; i < mTabs.size(); i++)
        {
            if (mTabs[i].first == tab)
            {
                mSelectedTab = tab;
                mWidgetContainer->add(mTabs[i].second);
            }
        }
    }

    int TabbedArea::getSelectedTabIndex() const
    {
        unsigned int i;
        for (i = 0; i < mTabs.size(); i++)
        {
            if (mTabs[i].first == mSelectedTab)
            {
                return i;
            }
        }

        return -1;
    }

    Tab* TabbedArea::getSelectedTab()
    {
        return mSelectedTab;
    }

    void TabbedArea::setOpaque(bool opaque)
    {
        mOpaque = opaque;
    }

    bool TabbedArea::isOpaque() const
    {
        return mOpaque;
    }

    void TabbedArea::draw(Graphics *graphics)
    {
        const Color &faceColor = getBaseColor();
        const int alpha = getBaseColor().a;
        Color highlightColor = faceColor + 0x303030;
        highlightColor.a = alpha;
        Color shadowColor = faceColor - 0x303030;
        shadowColor.a = alpha;

        // Draw a border.
        graphics->setColor(highlightColor);
        graphics->drawLine(0,
                           mTabContainer->getHeight(),
                           0,
                           getHeight() - 2);
        graphics->setColor(shadowColor);
        graphics->drawLine(getWidth() - 1,
                           mTabContainer->getHeight() + 1,
                           getWidth() - 1,
                           getHeight() - 1);
        graphics->drawLine(1,
                           getHeight() - 1,
                           getWidth() - 1,
                           getHeight() - 1);

        if (isOpaque())
        {
            graphics->setColor(getBaseColor());
            graphics->fillRectangle(Rectangle(1, 1,
                                              getWidth() - 2,
                                              getHeight() - 2));
        }

        // Draw a line underneath the tabs.
        graphics->setColor(highlightColor);
        graphics->drawLine(1,
                           mTabContainer->getHeight(),
                           getWidth() - 1,
                           mTabContainer->getHeight());

        // If a tab is selected, remove the line right underneath
        // the selected tab.
        if (mSelectedTab != NULL)
        {
            graphics->setColor(getBaseColor());
            graphics->drawLine(mSelectedTab->getX() + 1,
                               mTabContainer->getHeight(),
                               mSelectedTab->getX() + mSelectedTab->getWidth() - 2,
                               mTabContainer->getHeight());

        }

        drawChildren(graphics);
    }

    void TabbedArea::logic()
    {
    }

    void TabbedArea::adjustSize()
    {
        int maxTabHeight = 0;

        for (unsigned int i = 0; i < mTabs.size(); i++)
        {
            if (mTabs[i].first->getHeight() > maxTabHeight)
            {
                maxTabHeight = mTabs[i].first->getHeight();
            }
        }

        mTabContainer->setSize(getWidth() - 2,
                               maxTabHeight);

        mWidgetContainer->setPosition(1, maxTabHeight + 1);
        mWidgetContainer->setSize(getWidth() - 2,
                                  getHeight() - maxTabHeight - 2);
    }

    void TabbedArea::adjustTabPositions()
    {
        int maxTabHeight = 0;
        unsigned int i;
        for (i = 0; i < mTabs.size(); i++)
        {
            if (mTabs[i].first->getHeight() > maxTabHeight)
            {
                maxTabHeight = mTabs[i].first->getHeight();
            }
        }

        int x = 0;
        for (i = 0; i < mTabs.size(); i++)
        {
            Tab* tab = mTabs[i].first;
            tab->setPosition(x, maxTabHeight - tab->getHeight());
            x += tab->getWidth();
        }
    }

    void TabbedArea::setWidth(int width)
    {
        Widget::setWidth(width);
        adjustSize();
    }

    void TabbedArea::setHeight(int height)
    {
        Widget::setHeight(height);
        adjustSize();
    }

    void TabbedArea::setSize(int width, int height)
    {
        Widget::setSize(width, height);
        adjustSize();
    }

    void TabbedArea::setDimension(const Rectangle& dimension)
    {
        Widget::setDimension(dimension);
        adjustSize();
    }

    void TabbedArea::keyPressed(KeyEvent& keyEvent)
    {
        if (keyEvent.isConsumed() || !isFocused())
        {
            return;
        }

        if (keyEvent.getKey().getValue() == Key::LEFT)
        {
            int index = getSelectedTabIndex();
            index--;

            if (index < 0)
            {
                return;
            }
            else
            {
                setSelectedTab(mTabs[index].first);
            }

            keyEvent.consume();
        }
        else if (keyEvent.getKey().getValue() == Key::RIGHT)
        {
            int index = getSelectedTabIndex();
            index++;

            if (index >= (int)mTabs.size())
            {
                return;
            }
            else
            {
                setSelectedTab(mTabs[index].first);
            }

            keyEvent.consume();
        }
    }

    void TabbedArea::mousePressed(MouseEvent& mouseEvent)
    {
        if (mouseEvent.isConsumed()
            && mouseEvent.getSource()->isFocusable())
        {
            return;
        }

        if (mouseEvent.getButton() == MouseEvent::LEFT)
        {
            Widget* widget = mTabContainer->getWidgetAt(mouseEvent.getX(), mouseEvent.getY());
            Tab* tab = dynamic_cast<Tab*>(widget);

            if (tab != NULL)
            {
                setSelectedTab(tab);
            }
        }

        requestFocus();
    }

    void TabbedArea::death(const Event& event)
    {
        Widget* source = event.getSource();
        Tab* tab = dynamic_cast<Tab*>(source);

        if (tab != NULL)
        {
            removeTab(tab);
        }
        else
        {
            BasicContainer::death(event);
        }
    }

    void TabbedArea::action(const ActionEvent& actionEvent)
    {
        Widget* source = actionEvent.getSource();
        Tab* tab = dynamic_cast<Tab*>(source);

        if (tab == NULL)
        {
            throw GCN_EXCEPTION("Received an action from a widget that's not a tab!");
        }

        setSelectedTab(tab);
    }
}
<commit_msg>http://code.google.com/p/guichan/issues/detail?id=43<commit_after>/*      _______   __   __   __   ______   __   __   _______   __   __
 *     / _____/\ / /\ / /\ / /\ / ____/\ / /\ / /\ / ___  /\ /  |\/ /\
 *    / /\____\// / // / // / // /\___\// /_// / // /\_/ / // , |/ / /
 *   / / /__   / / // / // / // / /    / ___  / // ___  / // /| ' / /
 *  / /_// /\ / /_// / // / // /_/_   / / // / // /\_/ / // / |  / /
 * /______/ //______/ //_/ //_____/\ /_/ //_/ //_/ //_/ //_/ /|_/ /
 * \______\/ \______\/ \_\/ \_____\/ \_\/ \_\/ \_\/ \_\/ \_\/ \_\/
 *
 * Copyright (c) 2004 - 2008 Olof Naessn and Per Larsson
 *
 *
 * Per Larsson a.k.a finalman
 * Olof Naessn a.k.a jansem/yakslem
 *
 * Visit: http://guichan.sourceforge.net
 *
 * License: (BSD)
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 * 3. Neither the name of Guichan nor the names of its contributors may
 *    be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
 * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

/*
 * For comments regarding functions please see the header file.
 */

#include "guichan/widgets/tabbedarea.hpp"

#include "guichan/exception.hpp"
#include "guichan/focushandler.hpp"
#include "guichan/font.hpp"
#include "guichan/graphics.hpp"

#include "guichan/widgets/container.hpp"
#include "guichan/widgets/tab.hpp"

#include <algorithm>

namespace gcn
{
    TabbedArea::TabbedArea()
            :mSelectedTab(NULL),
             mOpaque(false)
    {
        setFocusable(true);
        addKeyListener(this);
        addMouseListener(this);

        mTabContainer = new Container();
        mTabContainer->setOpaque(false);
        mWidgetContainer = new Container();

        add(mTabContainer);
        add(mWidgetContainer);
    }

    TabbedArea::~TabbedArea()
    {
        remove(mTabContainer);
        remove(mWidgetContainer);

        delete mTabContainer;
        delete mWidgetContainer;

        for (unsigned int i = 0; i < mTabsToDelete.size(); i++)
        {
            delete mTabsToDelete[i];
        }
    }

    void TabbedArea::addTab(const std::string& caption, Widget* widget)
    {
        Tab* tab = new Tab();
        tab->setCaption(caption);
        mTabsToDelete.push_back(tab);

        addTab(tab, widget);
    }

    void TabbedArea::addTab(Tab* tab, Widget* widget)
    {
        tab->setTabbedArea(this);
        tab->addActionListener(this);

        mTabContainer->add(tab);
        mTabs.push_back(std::pair<Tab*, Widget*>(tab, widget));

        if (mSelectedTab == NULL)
        {
            setSelectedTab(tab);
        }

        adjustTabPositions();
        adjustSize();
    }

    void TabbedArea::removeTabWithIndex(unsigned int index)
    {
        if (index >= mTabs.size())
        {
            throw GCN_EXCEPTION("No such tab index.");
        }

        removeTab(mTabs[index].first);
    }

    void TabbedArea::removeTab(Tab* tab)
    {
        int tabIndexToBeSelected = - 1;

        if (tab == mSelectedTab)
        {
            int index = getSelectedTabIndex();

            if (index == (int)mTabs.size() - 1
                && mTabs.size() >= 2)
            {
                tabIndexToBeSelected = index--;
            }
            else if (index == (int)mTabs.size() - 1
                     && mTabs.size() == 1)
            {
                tabIndexToBeSelected = -1;
            }
            else
            {
                tabIndexToBeSelected = index;
            }
        }

        std::vector<std::pair<Tab*, Widget*> >::iterator iter;
        for (iter = mTabs.begin(); iter != mTabs.end(); iter++)
        {
            if (iter->first == tab)
            {
                mTabContainer->remove(tab);
                mTabs.erase(iter);
                break;
            }
        }

        std::vector<Tab*>::iterator iter2;
        for (iter2 = mTabsToDelete.begin(); iter2 != mTabsToDelete.end(); iter2++)
        {
            if (*iter2 == tab)
            {
                mTabsToDelete.erase(iter2);
                delete tab;
                break;
            }
        }

        if (tabIndexToBeSelected == -1)
        {
            mSelectedTab = NULL;
            mWidgetContainer->clear();
        }
        else
        {
            setSelectedTab(tabIndexToBeSelected);
        }

        adjustSize();
        adjustTabPositions();
    }

    bool TabbedArea::isTabSelected(unsigned int index) const
    {
        if (index >= mTabs.size())
        {
            throw GCN_EXCEPTION("No such tab index.");
        }

        return mSelectedTab == mTabs[index].first;
    }

    bool TabbedArea::isTabSelected(Tab* tab)
    {
        return mSelectedTab == tab;
    }

    void TabbedArea::setSelectedTab(unsigned int index)
    {
        if (index >= mTabs.size())
        {
            throw GCN_EXCEPTION("No such tab index.");
        }

        setSelectedTab(mTabs[index].first);
    }

    void TabbedArea::setSelectedTab(Tab* tab)
    {
        unsigned int i;
        for (i = 0; i < mTabs.size(); i++)
        {
            if (mTabs[i].first == mSelectedTab)
            {
                mWidgetContainer->remove(mTabs[i].second);
            }
        }

        for (i = 0; i < mTabs.size(); i++)
        {
            if (mTabs[i].first == tab)
            {
                mSelectedTab = tab;
                mWidgetContainer->add(mTabs[i].second);
            }
        }
    }

    int TabbedArea::getSelectedTabIndex() const
    {
        unsigned int i;
        for (i = 0; i < mTabs.size(); i++)
        {
            if (mTabs[i].first == mSelectedTab)
            {
                return i;
            }
        }

        return -1;
    }

    Tab* TabbedArea::getSelectedTab()
    {
        return mSelectedTab;
    }

    void TabbedArea::setOpaque(bool opaque)
    {
        mOpaque = opaque;
    }

    bool TabbedArea::isOpaque() const
    {
        return mOpaque;
    }

    void TabbedArea::draw(Graphics *graphics)
    {
        const Color &faceColor = getBaseColor();
        const int alpha = getBaseColor().a;
        Color highlightColor = faceColor + 0x303030;
        highlightColor.a = alpha;
        Color shadowColor = faceColor - 0x303030;
        shadowColor.a = alpha;

        // Draw a border.
        graphics->setColor(highlightColor);
        graphics->drawLine(0,
                           mTabContainer->getHeight(),
                           0,
                           getHeight() - 2);
        graphics->setColor(shadowColor);
        graphics->drawLine(getWidth() - 1,
                           mTabContainer->getHeight() + 1,
                           getWidth() - 1,
                           getHeight() - 1);
        graphics->drawLine(1,
                           getHeight() - 1,
                           getWidth() - 1,
                           getHeight() - 1);

        if (isOpaque())
        {
            graphics->setColor(getBaseColor());
            graphics->fillRectangle(Rectangle(1, 1,
                                              getWidth() - 2,
                                              getHeight() - 2));
        }

        // Draw a line underneath the tabs.
        graphics->setColor(highlightColor);
        graphics->drawLine(1,
                           mTabContainer->getHeight(),
                           getWidth() - 1,
                           mTabContainer->getHeight());

        // If a tab is selected, remove the line right underneath
        // the selected tab.
        if (mSelectedTab != NULL)
        {
            graphics->setColor(getBaseColor());
            graphics->drawLine(mSelectedTab->getX() + 1,
                               mTabContainer->getHeight(),
                               mSelectedTab->getX() + mSelectedTab->getWidth() - 2,
                               mTabContainer->getHeight());

        }

        drawChildren(graphics);
    }

    void TabbedArea::logic()
    {
    }

    void TabbedArea::adjustSize()
    {
        int maxTabHeight = 0;

        for (unsigned int i = 0; i < mTabs.size(); i++)
        {
            if (mTabs[i].first->getHeight() > maxTabHeight)
            {
                maxTabHeight = mTabs[i].first->getHeight();
            }
        }

        mTabContainer->setSize(getWidth() - 2,
                               maxTabHeight);

        mWidgetContainer->setPosition(1, maxTabHeight + 1);
        mWidgetContainer->setSize(getWidth() - 2,
                                  getHeight() - maxTabHeight - 2);
    }

    void TabbedArea::adjustTabPositions()
    {
        int maxTabHeight = 0;
        unsigned int i;
        for (i = 0; i < mTabs.size(); i++)
        {
            if (mTabs[i].first->getHeight() > maxTabHeight)
            {
                maxTabHeight = mTabs[i].first->getHeight();
            }
        }

        int x = 0;
        for (i = 0; i < mTabs.size(); i++)
        {
            Tab* tab = mTabs[i].first;
            tab->setPosition(x, maxTabHeight - tab->getHeight());
            x += tab->getWidth();
        }
    }

    void TabbedArea::setWidth(int width)
    {
        Widget::setWidth(width);
        adjustSize();
    }

    void TabbedArea::setHeight(int height)
    {
        Widget::setHeight(height);
        adjustSize();
    }

    void TabbedArea::setSize(int width, int height)
    {
        Widget::setSize(width, height);
        adjustSize();
    }

    void TabbedArea::setDimension(const Rectangle& dimension)
    {
        Widget::setDimension(dimension);
        adjustSize();
    }

    void TabbedArea::keyPressed(KeyEvent& keyEvent)
    {
        if (keyEvent.isConsumed() || !isFocused())
        {
            return;
        }

        if (keyEvent.getKey().getValue() == Key::LEFT)
        {
            int index = getSelectedTabIndex();
            index--;

            if (index < 0)
            {
                return;
            }
            else
            {
                setSelectedTab(mTabs[index].first);
            }

            keyEvent.consume();
        }
        else if (keyEvent.getKey().getValue() == Key::RIGHT)
        {
            int index = getSelectedTabIndex();
            index++;

            if (index >= (int)mTabs.size())
            {
                return;
            }
            else
            {
                setSelectedTab(mTabs[index].first);
            }

            keyEvent.consume();
        }
    }

    void TabbedArea::mousePressed(MouseEvent& mouseEvent)
    {
        if (mouseEvent.isConsumed())
        {
            return;
        }

        if (mouseEvent.getButton() == MouseEvent::LEFT)
        {
            Widget* widget = mTabContainer->getWidgetAt(mouseEvent.getX(), mouseEvent.getY());
            Tab* tab = dynamic_cast<Tab*>(widget);

            if (tab != NULL)
            {
                setSelectedTab(tab);
            }
        }

        // Request focus only if the source of the event
        // is not focusble. If the source of the event
        // is focused we don't want to steal the focus.
        if (!mouseEvent.getSource()->isFocusable())
        {
            requestFocus();
        }
    }

    void TabbedArea::death(const Event& event)
    {
        Widget* source = event.getSource();
        Tab* tab = dynamic_cast<Tab*>(source);

        if (tab != NULL)
        {
            removeTab(tab);
        }
        else
        {
            BasicContainer::death(event);
        }
    }

    void TabbedArea::action(const ActionEvent& actionEvent)
    {
        Widget* source = actionEvent.getSource();
        Tab* tab = dynamic_cast<Tab*>(source);

        if (tab == NULL)
        {
            throw GCN_EXCEPTION("Received an action from a widget that's not a tab!");
        }

        setSelectedTab(tab);
    }
}
<|endoftext|>