<commit_before>/*
Copyright (c) 2013-2018 Ubidots.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

Developed and maintained by Jose Garcia and Cristian Arrieta for IoT Services
Inc
@jotathebest at github: https://github.com/jotathebest
@crisap94 at github: https://github.com/crisap94
*/

#include "UbiTcp.h"

/**************************************************************************
 * Overloaded constructors
 ***************************************************************************/

/**
 * @brief Construct a new UbiTCP object and power up the module
 *
 * @param token Users token
 * @param server Server addres
 * @param port Server port
 * @param user_agent Reference from the device being connected
 * @param apn GPRS network name
 * @param apnUser GPRS network username
 * @param apnPass GPRS network passwrod
 */
UbiTCP::UbiTCP(UbiToken token, UbiServer server, const int port, const char *user_agent, UbiApn apn, UbiApn apnUser,
               UbiApn apnPass) {

  _server = server;
  _user_agent = user_agent;
  _token = token;
  _port = port;
  _apn = apn;
  _apnUser = apnUser;
  _apnPass = apnPass;

  _serialAT = new SoftwareSerial(RX, TX); // RX, TX
  _modem = new TinyGsm(*_serialAT);
  _client_tcp = new TinyGsmClient(*_modem);

  _serialAT->begin(BAUDRATE);
}

/**************************************************************************
 * Destructor
 ***************************************************************************/

UbiTCP::~UbiTCP() {
  delete[] _server;
  delete[] _user_agent;
  delete[] _token;
  delete[] _apn;
  delete[] _apnUser;
  delete[] _apnPass;

  free(_serialAT);
  free(_modem);
  free(_client_tcp);
}

/**************************************************************************
 * Cloud Functions
 ***************************************************************************/

/**
 * @brief Post new data to ubidots server
 *
 * @param device_label Label of the device to be set or update in the ubidots
 * platform
 * @param device_name Device name to be published
 * @param payload Body to be processed by the Ubidot server
 * @return true The data was succesfully published
 * @return false Something went wrong with the sending.
 */
bool UbiTCP::sendData(const char *device_label, const char *device_name, char *payload) {

  if (!_preConnectionChecks()) {
    return false;
  }

  _client_tcp->print(payload);

  float value = _parseTCPAnswer("POST");

  return value != ERROR_VALUE;
}

/**
 * @brief Get request over TCP to Ubidots server
 *
 * @param device_label device label of the device
 * @param variable_label variable label to be fetched
 * @return float Response value from the server
 */
float UbiTCP::get(const char *device_label, const char *variable_label) {

  if (!_preConnectionChecks()) {
    return ERROR_VALUE;
  }

  if (_debug) {
    Serial.println(F("waiting to fetch..."));
  }

  uint16_t endpointLength = _endpointLength(device_label, variable_label);

  char *requestLine = (char *)malloc(sizeof(char) * endpointLength + 1);

  sprintf(requestLine, "%s|LV|%s|%s:%s|end HTTP/1.0\r\n\r\n", USER_AGENT, _token, device_label, variable_label);

  if (_debug) {
    Serial.print(F("Request: "));
    Serial.println(requestLine);
  }

  _client_tcp->print(requestLine);
  free(requestLine);

  float value = _parseTCPAnswer("LV");

  return value;
}
/**************************************************************************
 * Auxiliar Cloud Functions
 ***************************************************************************/

/**
 * @brief Calculate the lenght of the enpoint to be send over TCP to the server
 *
 * @param device_label device label of the device
 * @param variable_label variable label to be updated or fetched
 * @return uint16_t  Lenght of the enpoint
 */
uint16_t UbiTCP::_endpointLength(const char *device_label, const char *variable_label) {
  uint16_t endpointLength = strlen("|LV||:|end HTTP/1.0\r\n\r\n") + strlen(USER_AGENT) + strlen(_token) +
                            strlen(device_label) + strlen(variable_label);
  return endpointLength;
}

/**
 * @brief Parse the TCP host answer and saves it to the input char pointer.

 * @param request_type Type of request GET or POST
 * @param response [Mandatory] Buffer to contain the payload from the server
 * @return float Value from the response
 */
float UbiTCP::_parseTCPAnswer(const char *request_type) {

  if (_debug) {
    Serial.println("----------");
    Serial.println("Server's response:");
  }
  char *readFromServer = (char *)malloc(sizeof(char) * MAX_BUFFER_SIZE);

  readFromServer = strdup(_client_tcp->readString().c_str());

  if (_debug) {
    Serial.println(readFromServer);
    Serial.println("----------");
  }

  float result = ERROR_VALUE;

  // POST
  if (strcmp(request_type, "POST") == 0) {
    char *pch = strstr(readFromServer, "OK");
    if (pch != NULL) {
      result = 1;
    }
    return result;
  }

  // LV
  char *pch = strchr(readFromServer, '|');
  if (pch != NULL) {
    result = atof(pch + 1);
  }

  free(readFromServer);

  return result;
}

/**************************************************************************
 * Auxiliar GPRS functions
 ***************************************************************************/

void UbiTCP::_powerUpDown() {
  // power on pulse for SIM900 Shield
  digitalWrite(SIM900_POWER_UP_PIN, LOW);
  delay(1000);
  digitalWrite(SIM900_POWER_UP_PIN, HIGH);
  delay(2000);
  digitalWrite(SIM900_POWER_UP_PIN, LOW);
  delay(3000);
}
/**
 * @brief Check if the module is already powered on, if ! then it tries to
 * power it forever.
 *
 */
bool UbiTCP::_isPoweredOn() {
  if (!isPoweredOn) {
    if (_debug) {
      Serial.println(F("Checking Power status SIM900 module"));
      Serial.println(F("Sim900 is Powered Off"));
      Serial.println(F("Powering on SIM900"));
    }
    while (!isPoweredOn) {
      const uint8_t IMEI_MAX_DIGITS = 14;
      char *IMEI = (char *)malloc(sizeof(char) * IMEI_MAX_DIGITS + 1);
      sprintf(IMEI, "");
      sprintf(IMEI, _modem->getIMEI().c_str());

      isPoweredOn = strlen(IMEI) > 0;
      pinMode(SIM900_POWER_UP_PIN, OUTPUT);

      if (!isPoweredOn) {
        _powerUpDown();
      }

      if (_debug) {
        Serial.println(F("SIM900 Powered On"));
        Serial.print(F("Modem IMEI: "));
        Serial.println(_modem->getIMEI().c_str());
      }

      free(IMEI);
    }
  }

  if (_debug && isPoweredOn) {
    Serial.println(F("Module already Powered ON"));
  }

  return isPoweredOn;
}

/**
 * @brief Verify the status from the Simcard
 *
 * @return true The Simcard is correctle placed
 * @return false The Sim Card is not inserted correctly
 */
bool UbiTCP::_isSimCardInserted() {
  if (!isSimInserted) {
    isSimInserted = _modem->getSimStatus() == SIM_READY;

    if (_debug) {
      Serial.println(isSimInserted ? F("Sim Card Correctly installed") : F("[ERROR] Sim Card NOT FOUND"));
    }
  }

  return isSimInserted;
}

/**
 * @brief Do the initialization of the device
 *
 * @return true The device is responding to the commands
 * @return false The device is ! reponding, probably bad Serial communication
 */
bool UbiTCP::_initGPRS() {

  if (!isInitiatedModule) {
    const uint8_t MAX_INIT_ATTEMPS = 5;
    uint8_t attempts = 0;
    isInitiatedModule = true;
    if (_debug) {
      Serial.print(F("Initializing module...\r\n"));
    }

    // use DHCP
    while (!_modem->init() && attempts < MAX_INIT_ATTEMPS) {

      attempts += 1;
      if (attempts == MAX_INIT_ATTEMPS) {
        isInitiatedModule = false;
      }
      if (_debug) {
        Serial.print(F("Checking Serial connection ["));
        Serial.print(attempts);
        Serial.println(F("]"));
      }
    }
  } else {
    if (_debug) {
      Serial.println(F("Module already initialized"));
    }
  }

  return isInitiatedModule;
}

/**
 * @brief Check for Available networks to connect to
 *
 * @return true There is an available network to connect to
 * @return false There is no available network
 */
bool UbiTCP::_waitingForNetwork() {
  const uint8_t MAX_REGISTER_ATTEMPS = 5;
  bool isNetworkAvailable = false;
  if (_debug) {
    Serial.println(F("Waiting for Network"));
  }
  uint8_t attempts = 0;
  while (!isNetworkAvailable && attempts < MAX_REGISTER_ATTEMPS) {

    isNetworkAvailable = _modem->waitForNetwork();
    attempts += 1;

    if (_debug) {
      Serial.print(F("Waiting for network ["));
      Serial.print(attempts);
      Serial.println(F("]"));
    }
  }

  return isNetworkAvailable;
}

/**
 * @brief Extablish the phisical connection with the GPRS network
 *
 * @return true The network is accepted by the device
 * @return false The device could connect to it, probably the frequency
 */
bool UbiTCP::_isNetworkRegistered() {
  if (!isNetworkRegistered) {
    const uint8_t MAX_REGISTER_ATTEMPS = 5;
    if (_debug) {
      Serial.println(F("Registering Network into the module"));
    }
    uint8_t attempts = 0;
    isNetworkRegistered = true;

    if (!_waitingForNetwork())
      return false;

    while (!_modem->isNetworkConnected() && attempts < MAX_REGISTER_ATTEMPS) {

      attempts += 1;
      if (attempts == MAX_REGISTER_ATTEMPS) {
        isNetworkRegistered = false;
      }

      if (_debug) {
        Serial.print(F("Trying to register the network ["));
        Serial.print(attempts);
        Serial.println(F("]"));
      }
    }

    if (_debug) {
      Serial.println(isNetworkRegistered ? F("Network has been registered into the module")
                                         : F("[ERROR] Couldn't register into the network\n\n"));
    }

  } else {

    if (_debug) {
      Serial.println(F("Network already registered into the device"));
    }
  }

  return isNetworkRegistered;
}

/**
 * @brief Check for a proper connection to the network (Has Ping?)
 *
 * @return true There is ping
 * @return false There is no Ping
 */
bool UbiTCP::_hasConnectivity() {
  const uint8_t MAX_REGISTER_ATTEMPS = 5;
  bool isGPRSConnected = false;
  if (_debug) {
    Serial.println(F("Verifying network connectivity on SIM900"));
  }
  uint8_t attempts = 0;
  while (!isGPRSConnected && attempts < MAX_REGISTER_ATTEMPS) {

    attempts += 1;

    if (_debug) {
      Serial.print(F("Connecting SIM900 to the Network ["));
      Serial.print(attempts);
      Serial.println(F("]"));
    }

    isGPRSConnected = _modem->isGprsConnected();
  }

  return isGPRSConnected;
}

/**
 * @brief The GPRS establish a new connection with the service
 * TODO cast the _apn, _apnUser, _apnPass to the join method.
 *
 */
bool UbiTCP::_isJoinedToNetwork() {
  if (!isJoinedToNetwork) {
    const uint8_t MAX_JOIN_ATTEMPS = 5;
    if (_debug) {
      Serial.println(F("Joining module to the network"));
    }
    uint8_t attempts = 0;
    isJoinedToNetwork = true;

    if (_debug) {
      Serial.println(F("Simcard Credentials"));
      Serial.print(F("Apn: "));
      Serial.println(_apn);
      Serial.print(F("User: "));
      Serial.println(_apnUser);
      Serial.print(F("Pass: "));
      Serial.println(_apnPass);
      Serial.println();
    }

    while (!_modem->gprsConnect(_apn, _apnUser, _apnPass) && attempts < MAX_JOIN_ATTEMPS) {

      attempts += 1;
      if (attempts == MAX_JOIN_ATTEMPS) {
        isJoinedToNetwork = false;
      }

      if (_debug) {
        int16_t signal = _modem->getSignalQuality();
        Serial.print(F("Trying to join to the network ["));
        Serial.print(attempts);
        Serial.print(F("] "));
        Serial.print(F("Signal: "));
        Serial.print(F("-"));
        Serial.print(signal);
        Serial.println(signal < 75 ? F(" [EXCELLENT]")
                                   : signal < 85 ? F(" [GOOD]") : signal < 95 ? F(" [OK]") : F(" [WEAK]"));
      }
    }

    if (!_hasConnectivity())
      return false;

    if (_debug) {
      Serial.print(F("Network status: "));
      Serial.println(isJoinedToNetwork ? F("Joined") : F("[ERROR] Couldn't join the network\n\n"));
    }

  } else {
    if (_debug) {
      Serial.println(F("Module already joined to the network"));
    }
  }

  return isJoinedToNetwork;
}

/**
 * @brief Establish connection with Ubidots Server
 *
 * @return true Succesfull connection
 * @return false Failed connection
 */
bool UbiTCP::_isConnectedToServer() {
  if (_debug) {
    Serial.print("Start TCP Connection...\r\n");
  }

  if (!_client_tcp->connected()) {

    isConnectedToServer = _client_tcp->connect(UBI_INDUSTRIAL, UBIDOTS_TCP_PORT);

    if (_debug) {
      Serial.println(isConnectedToServer ? F("Connection to Ubidots server success!")
                                         : F("Error Connecting to Ubidots server"));
    }

  } else {
    if (_debug) {
      Serial.println(F("Connection to Ubidots server already established!"));
    }
  }
  return isConnectedToServer;
}

/**************************************************************************
 * Auxiliar Ubidots function
 ***************************************************************************/

/**
 * @brief Enable the debug
 *
 * @param debug Makes available debug traces
 */
void UbiTCP::setDebug(bool debug) { _debug = debug; }

/**
 * @brief Checks if the socket is still opened with the Ubidots Server through
 * the attribute
 *
 * @return true Server Connected
 * @return false Server Obviusly ! connected
 */
bool UbiTCP::serverConnected() { return isConnectedToServer; }

/**
 * @brief Handle the proper behavior of the SIM900 before fetching or sending
 * data to Ubidots
 *
 * @return true Everything was fine
 * @return false something went wrong.
 */
bool UbiTCP::_preConnectionChecks() {

  if (!_isPoweredOn()) {
    return false;
  }

  if (!_initGPRS()) {
    return false;
  }

  if (!_isSimCardInserted()) {
    return false;
  }

  if (!_isNetworkRegistered()) {
    return false;
  }

  if (!_isJoinedToNetwork()) {
    return false;
  }

  if (!_isConnectedToServer()) {
    return false;
  }

  return true;
}
<commit_msg>Cleaning Code<commit_after>/*
Copyright (c) 2013-2018 Ubidots.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

Developed and maintained by Jose Garcia and Cristian Arrieta for IoT Services
Inc
@jotathebest at github: https://github.com/jotathebest
@crisap94 at github: https://github.com/crisap94
*/

#include "UbiTcp.h"

/**************************************************************************
 * Overloaded constructors
 ***************************************************************************/

/**
 * @brief Construct a new UbiTCP object and power up the module
 *
 * @param token Users token
 * @param server Server addres
 * @param port Server port
 * @param user_agent Reference from the device being connected
 * @param apn GPRS network name
 * @param apnUser GPRS network username
 * @param apnPass GPRS network passwrod
 */
UbiTCP::UbiTCP(UbiToken token, UbiServer server, const int port, const char *user_agent, UbiApn apn, UbiApn apnUser,
               UbiApn apnPass) {

  _server = server;
  _user_agent = user_agent;
  _token = token;
  _port = port;
  _apn = apn;
  _apnUser = apnUser;
  _apnPass = apnPass;

  _serialAT = new SoftwareSerial(RX, TX); // RX, TX
  _modem = new TinyGsm(*_serialAT);
  _client_tcp = new TinyGsmClient(*_modem);

  _serialAT->begin(BAUDRATE);
}

/**************************************************************************
 * Destructor
 ***************************************************************************/

UbiTCP::~UbiTCP() {
  delete[] _server;
  delete[] _user_agent;
  delete[] _token;
  delete[] _apn;
  delete[] _apnUser;
  delete[] _apnPass;

  free(_serialAT);
  free(_modem);
  free(_client_tcp);
}

/**************************************************************************
 * Cloud Functions
 ***************************************************************************/

/**
 * @brief Post new data to ubidots server
 *
 * @param device_label Label of the device to be set or update in the ubidots
 * platform
 * @param device_name Device name to be published
 * @param payload Body to be processed by the Ubidot server
 * @return true The data was succesfully published
 * @return false Something went wrong with the sending.
 */
bool UbiTCP::sendData(const char *device_label, const char *device_name, char *payload) {

  if (!_preConnectionChecks()) {
    return false;
  }

  _client_tcp->print(payload);

  float value = _parseTCPAnswer("POST");

  return value != ERROR_VALUE;
}

/**
 * @brief Get request over TCP to Ubidots server
 *
 * @param device_label device label of the device
 * @param variable_label variable label to be fetched
 * @return float Response value from the server
 */
float UbiTCP::get(const char *device_label, const char *variable_label) {

  if (!_preConnectionChecks()) {
    return ERROR_VALUE;
  }

  uint16_t endpointLength = _endpointLength(device_label, variable_label);

  char *requestLine = (char *)malloc(sizeof(char) * endpointLength + 1);

  sprintf(requestLine, "%s|LV|%s|%s:%s|end HTTP/1.0\r\n\r\n", USER_AGENT, _token, device_label, variable_label);

  if (_debug) {
    Serial.print(F("Request: "));
    Serial.println(requestLine);
  }

  _client_tcp->print(requestLine);
  free(requestLine);

  float value = _parseTCPAnswer("LV");

  return value;
}
/**************************************************************************
 * Auxiliar Cloud Functions
 ***************************************************************************/

/**
 * @brief Calculate the lenght of the enpoint to be send over TCP to the server
 *
 * @param device_label device label of the device
 * @param variable_label variable label to be updated or fetched
 * @return uint16_t  Lenght of the enpoint
 */
uint16_t UbiTCP::_endpointLength(const char *device_label, const char *variable_label) {
  uint16_t endpointLength = strlen("|LV||:|end HTTP/1.0\r\n\r\n") + strlen(USER_AGENT) + strlen(_token) +
                            strlen(device_label) + strlen(variable_label);
  return endpointLength;
}

/**
 * @brief Parse the TCP host answer and saves it to the input char pointer.

 * @param request_type Type of request GET or POST
 * @param response [Mandatory] Buffer to contain the payload from the server
 * @return float Value from the response
 */
float UbiTCP::_parseTCPAnswer(const char *request_type) {

  if (_debug) {
    Serial.println("----------");
    Serial.println("Server's response:");
  }
  char *readFromServer = (char *)malloc(sizeof(char) * MAX_BUFFER_SIZE);

  readFromServer = strdup(_client_tcp->readString().c_str());

  if (_debug) {
    Serial.println(readFromServer);
    Serial.println("----------");
  }

  float result = ERROR_VALUE;

  // POST
  if (strcmp(request_type, "POST") == 0) {
    char *pch = strstr(readFromServer, "OK");
    if (pch != NULL) {
      result = 1;
    }
    return result;
  }

  // LV
  char *pch = strchr(readFromServer, '|');
  if (pch != NULL) {
    result = atof(pch + 1);
  }

  free(readFromServer);

  return result;
}

/**************************************************************************
 * Auxiliar GPRS functions
 ***************************************************************************/

void UbiTCP::_powerUpDown() {
  // power on pulse for SIM900 Shield
  digitalWrite(SIM900_POWER_UP_PIN, LOW);
  delay(1000);
  digitalWrite(SIM900_POWER_UP_PIN, HIGH);
  delay(2000);
  digitalWrite(SIM900_POWER_UP_PIN, LOW);
  delay(3000);
}
/**
 * @brief Check if the module is already powered on, if ! then it tries to
 * power it forever.
 *
 */
bool UbiTCP::_isPoweredOn() {
  if (!isPoweredOn) {
    if (_debug) {
      Serial.println(F("Checking Power status SIM900 module"));
      Serial.println(F("Sim900 is Powered Off"));
      Serial.println(F("Powering on SIM900"));
    }
    while (!isPoweredOn) {
      const uint8_t IMEI_MAX_DIGITS = 14;
      char *IMEI = (char *)malloc(sizeof(char) * IMEI_MAX_DIGITS + 1);
      sprintf(IMEI, "");
      sprintf(IMEI, _modem->getIMEI().c_str());

      isPoweredOn = strlen(IMEI) > 0;
      pinMode(SIM900_POWER_UP_PIN, OUTPUT);

      if (!isPoweredOn) {
        _powerUpDown();
      }

      if (_debug) {
        Serial.println(F("SIM900 Powered On"));
        Serial.print(F("Modem IMEI: "));
        Serial.println(_modem->getIMEI().c_str());
      }

      free(IMEI);
    }
  }

  if (_debug && isPoweredOn) {
    Serial.println(F("Module already Powered ON"));
  }

  return isPoweredOn;
}

/**
 * @brief Verify the status from the Simcard
 *
 * @return true The Simcard is correctle placed
 * @return false The Sim Card is not inserted correctly
 */
bool UbiTCP::_isSimCardInserted() {
  if (!isSimInserted) {
    isSimInserted = _modem->getSimStatus() == SIM_READY;

    if (_debug) {
      Serial.println(isSimInserted ? F("Sim Card Correctly installed") : F("[ERROR] Sim Card NOT FOUND"));
    }
  }

  return isSimInserted;
}

/**
 * @brief Do the initialization of the device
 *
 * @return true The device is responding to the commands
 * @return false The device is ! reponding, probably bad Serial communication
 */
bool UbiTCP::_initGPRS() {

  if (!isInitiatedModule) {
    const uint8_t MAX_INIT_ATTEMPS = 5;
    uint8_t attempts = 0;
    isInitiatedModule = true;
    if (_debug) {
      Serial.print(F("Initializing module...\r\n"));
    }

    // use DHCP
    while (!_modem->init() && attempts < MAX_INIT_ATTEMPS) {

      attempts += 1;
      if (attempts == MAX_INIT_ATTEMPS) {
        isInitiatedModule = false;
      }
      if (_debug) {
        Serial.print(F("Checking Serial connection ["));
        Serial.print(attempts);
        Serial.println(F("]"));
      }
    }
  } else {
    if (_debug) {
      Serial.println(F("Module already initialized"));
    }
  }

  return isInitiatedModule;
}

/**
 * @brief Check for Available networks to connect to
 *
 * @return true There is an available network to connect to
 * @return false There is no available network
 */
bool UbiTCP::_waitingForNetwork() {
  const uint8_t MAX_REGISTER_ATTEMPS = 5;
  bool isNetworkAvailable = false;
  if (_debug) {
    Serial.println(F("Waiting for Network"));
  }
  uint8_t attempts = 0;
  while (!isNetworkAvailable && attempts < MAX_REGISTER_ATTEMPS) {

    isNetworkAvailable = _modem->waitForNetwork();
    attempts += 1;

    if (_debug) {
      Serial.print(F("Waiting for network ["));
      Serial.print(attempts);
      Serial.println(F("]"));
    }
  }

  return isNetworkAvailable;
}

/**
 * @brief Extablish the phisical connection with the GPRS network
 *
 * @return true The network is accepted by the device
 * @return false The device could connect to it, probably the frequency
 */
bool UbiTCP::_isNetworkRegistered() {
  if (!isNetworkRegistered) {
    const uint8_t MAX_REGISTER_ATTEMPS = 5;
    if (_debug) {
      Serial.println(F("Registering Network into the module"));
    }
    uint8_t attempts = 0;
    isNetworkRegistered = true;

    if (!_waitingForNetwork())
      return false;

    while (!_modem->isNetworkConnected() && attempts < MAX_REGISTER_ATTEMPS) {

      attempts += 1;
      if (attempts == MAX_REGISTER_ATTEMPS) {
        isNetworkRegistered = false;
      }

      if (_debug) {
        Serial.print(F("Trying to register the network ["));
        Serial.print(attempts);
        Serial.println(F("]"));
      }
    }

    if (_debug) {
      Serial.println(isNetworkRegistered ? F("Network has been registered into the module")
                                         : F("[ERROR] Couldn't register into the network\n\n"));
    }

  } else {

    if (_debug) {
      Serial.println(F("Network already registered into the device"));
    }
  }

  return isNetworkRegistered;
}

/**
 * @brief Check for a proper connection to the network (Has Ping?)
 *
 * @return true There is ping
 * @return false There is no Ping
 */
bool UbiTCP::_hasConnectivity() {
  const uint8_t MAX_REGISTER_ATTEMPS = 5;
  bool isGPRSConnected = false;
  if (_debug) {
    Serial.println(F("Verifying network connectivity on SIM900"));
  }
  uint8_t attempts = 0;
  while (!isGPRSConnected && attempts < MAX_REGISTER_ATTEMPS) {

    attempts += 1;

    if (_debug) {
      Serial.print(F("Connecting SIM900 to the Network ["));
      Serial.print(attempts);
      Serial.println(F("]"));
    }

    isGPRSConnected = _modem->isGprsConnected();
  }

  return isGPRSConnected;
}

/**
 * @brief The GPRS establish a new connection with the service
 * TODO cast the _apn, _apnUser, _apnPass to the join method.
 *
 */
bool UbiTCP::_isJoinedToNetwork() {
  if (!isJoinedToNetwork) {
    const uint8_t MAX_JOIN_ATTEMPS = 5;
    if (_debug) {
      Serial.println(F("Joining module to the network"));
    }
    uint8_t attempts = 0;
    isJoinedToNetwork = true;

    if (_debug) {
      Serial.println(F("Simcard Credentials"));
      Serial.print(F("Apn: "));
      Serial.println(_apn);
      Serial.print(F("User: "));
      Serial.println(_apnUser);
      Serial.print(F("Pass: "));
      Serial.println(_apnPass);
      Serial.println();
    }

    while (!_modem->gprsConnect(_apn, _apnUser, _apnPass) && attempts < MAX_JOIN_ATTEMPS) {

      attempts += 1;
      if (attempts == MAX_JOIN_ATTEMPS) {
        isJoinedToNetwork = false;
      }

      if (_debug) {
        int16_t signal = _modem->getSignalQuality();
        Serial.print(F("Trying to join to the network ["));
        Serial.print(attempts);
        Serial.print(F("] "));
        Serial.print(F("Signal: "));
        Serial.print(F("-"));
        Serial.print(signal);
        Serial.println(signal < 75 ? F(" [EXCELLENT]")
                                   : signal < 85 ? F(" [GOOD]") : signal < 95 ? F(" [OK]") : F(" [WEAK]"));
      }
    }

    if (!_hasConnectivity())
      return false;

    if (_debug) {
      Serial.print(F("Network status: "));
      Serial.println(isJoinedToNetwork ? F("Joined") : F("[ERROR] Couldn't join the network\n\n"));
    }

  } else {
    if (_debug) {
      Serial.println(F("Module already joined to the network"));
    }
  }

  return isJoinedToNetwork;
}

/**
 * @brief Establish connection with Ubidots Server
 *
 * @return true Succesfull connection
 * @return false Failed connection
 */
bool UbiTCP::_isConnectedToServer() {
  if (_debug) {
    Serial.print("Start TCP Connection...\r\n");
  }

  if (!_client_tcp->connected()) {

    isConnectedToServer = _client_tcp->connect(UBI_INDUSTRIAL, UBIDOTS_TCP_PORT);

    if (_debug) {
      Serial.println(isConnectedToServer ? F("Connection to Ubidots server success!")
                                         : F("Error Connecting to Ubidots server"));
    }

  } else {
    if (_debug) {
      Serial.println(F("Connection to Ubidots server already established!"));
    }
  }
  return isConnectedToServer;
}

/**************************************************************************
 * Auxiliar Ubidots function
 ***************************************************************************/

/**
 * @brief Enable the debug
 *
 * @param debug Makes available debug traces
 */
void UbiTCP::setDebug(bool debug) { _debug = debug; }

/**
 * @brief Checks if the socket is still opened with the Ubidots Server through
 * the attribute
 *
 * @return true Server Connected
 * @return false Server Obviusly ! connected
 */
bool UbiTCP::serverConnected() { return isConnectedToServer; }

/**
 * @brief Handle the proper behavior of the SIM900 before fetching or sending
 * data to Ubidots
 *
 * @return true Everything was fine
 * @return false something went wrong.
 */
bool UbiTCP::_preConnectionChecks() {

  if (!_isPoweredOn()) {
    return false;
  }

  if (!_initGPRS()) {
    return false;
  }

  if (!_isSimCardInserted()) {
    return false;
  }

  if (!_isNetworkRegistered()) {
    return false;
  }

  if (!_isJoinedToNetwork()) {
    return false;
  }

  if (!_isConnectedToServer()) {
    return false;
  }

  return true;
}
<|endoftext|>


<commit_before>#ifndef GRAPH_HPP
#define GRAPH_HPP

/*
 * P4
 * Graph.hpp
 * Header file for Graph class
 *
 * Author: Jay Dey cs100vaj
 * Author: Joshua Yuen cs100vbc
 */

#include <string>
#include "Edge.hpp"
#include "Vertex.hpp"

using namespace std;

class Graph
{
  private:
    vector<Vertex *> vList;		/* list of vertices */
    bool cycle;				/* cycle detection flag */

  public:
    /* Constructor */
    Graph();

    /* Destructor */
    ~Graph();

    /* find min spanning tree */
    Graph* MST();

    /* Dijkstra's shortest path method */
    Graph* dijkstra();

    /* print list of vertices and connected edges */
    void displayGraph();

    /* total cost of graph */
    int totalCost();

    /* clear visited flags for all vertices */
    void reset();

    void addVertex( Vertex * newV );
    Vertex* findVertex( string name );
};

#endif //GRAPH_HPP
<commit_msg>constructor, destructor, transformer, more than meets the eye<commit_after>#ifndef GRAPH_HPP
#define GRAPH_HPP

/*
 * P4
 * Graph.hpp
 * Header file for Graph class
 *
 * Author: Jay Dey cs100vaj
 * Author: Joshua Yuen cs100vbc
 */

#include <string>
#include <vector>
#include "Edge.hpp"
#include "Vertex.hpp"

using namespace std;

class Graph
{
  private:
    vector<Vertex *> vList;		/* list of vertices */
    bool cycle;				/* cycle detection flag */

  public:
    /* Constructor */
    Graph()
    {
      cycle = false;
    }

    /* Destructor */
    ~Graph()
    {
      for (int i=0; i<vList.size(); i++)
        delete vList[i];

      vList.clear();
    }

    /* find min spanning tree */
    Graph* MST();

    /* Dijkstra's shortest path method */
    Graph* dijkstra();

    /* print list of vertices and connected edges */
    void displayGraph();

    /* total cost of graph */
    int totalCost();

    /* clear visited flags for all vertices */
    void reset();

    void addVertex( Vertex * newV );
    Vertex* findVertex( string name );
};

#endif //GRAPH_HPP
<|endoftext|>


<commit_before>/**
   MiracleGrue - Model Generator for toolpathing. <http://www.grue.makerbot.com>
   Copyright (C) 2011 Far McKon <Far@makerbot.com>, Hugo Boyer (hugo@makerbot.com)

   This program is free software: you can redistribute it and/or modify
   it under the terms of the GNU Affero General Public License as
   published by the Free Software Foundation, either version 3 of the
   License, or (at your option) any later version.

 **/

#include <list>
#include <vector>

#include "regioner.h"

using namespace mgl;
using namespace std;

Regioner::Regioner(const RegionerConfig& regionerConf, ProgressBar* progress)
		: Progressive(progress), regionerCfg(regionerConf) {
	roofLengthCutOff = 0.5 * regionerCfg.layerW;
}

void Regioner::generateSkeleton(const LayerLoops& layerloops,
		RegionList& regionlist) {
	int sliceCount = initRegionList(layerloops, regionlist);

	initProgress("rafts", regionerCfg.raftLayers + 2);
	rafts(layerloops.front(), layerloops.layerMeasure, regionlist);

	//this is to facilitate eventually operating on part of the layer list
	RegionList::iterator firstModelRegion =
		regionlist.begin() + regionerCfg.raftLayers;

	initProgress("insets", sliceCount);
	insets(layerloops.begin(), layerloops.end(),
		   firstModelRegion, regionlist.end());

	initProgress("flat surfaces", sliceCount);
	flatSurfaces(firstModelRegion, regionlist.end(), layerloops.grid);

	initProgress("roofing", sliceCount);
	roofing(firstModelRegion, regionlist.end(), layerloops.grid);

	initProgress("flooring", sliceCount);
	flooring(firstModelRegion, regionlist.end(), layerloops.grid);

	initProgress("infills", sliceCount);
	infills(firstModelRegion, regionlist.end(),	layerloops.grid);
}

size_t Regioner::initRegionList(const LayerLoops& layerloops,
							  RegionList &regionlist) {
	//TODO: take into account raft layers in the number of regions
	regionlist.resize(layerloops.size());
	return regionlist.size();
}

void Regioner::rafts(const LayerLoops::Layer &bottomLayer,
					 LayerMeasure &layerMeasure,
					 RegionList &regionlist) {
	//make convex hull of the bottom layer
	Loop convexLoop = createConvexLoop(bottomLayer);
	tick();

	SegmentTable outsetSegs;
	outsetSegs.push_back(std::vector<LineSegment2>());

	for(Loop::finite_cw_iterator iter = convexLoop.clockwiseFinite();
		iter != convexLoop.clockwiseEnd(); ++iter) {

		outsetSegs.back().push_back(convexLoop.segmentAfterPoint(iter));
	}

	//outset the convex hull by the configured distance
	ClipperInsetter().inset(outsetSegs, -regionerCfg.raftOutset, outsetSegs);
	tick();

	Loop raftLoop;
	for(std::vector<LineSegment2>::const_iterator iter =
			outsetSegs.back().begin();
		iter != outsetSegs.back().end();
		++iter) {
		raftLoop.insertPointBefore(iter->b, convexLoop.clockwiseEnd());
	}
	tick();

	//create a first layer measure with absolute positioning
    layer_measure_index_t baseIndex = layerMeasure.createAttributes();
	LayerMeasure::LayerAttributes &baseAttr =
		layerMeasure.getLayerAttributes(baseIndex);
	baseAttr.delta = 0;
	baseAttr.thickness = regionerCfg.raftBaseThickness;
	baseAttr.base = -1;

	//add interface raft layers in reverse order to the beginning of the list
	for (int raftnum = regionerCfg.raftLayers - 1; raftnum > 0; raftnum--) {
		layer_measure_index_t raftIndex = layerMeasure.createAttributes();
		LayerMeasure::LayerAttributes &raftAttr =
			layerMeasure.getLayerAttributes(raft_index);
		raftAttr.delta = (raftnum - 1) * regionerCfg.raftThickness;
		raftAttr.thickness = regionerCfg.raftThickness;
		raftAttr.base = baseIndex;

		regionlist.push_front(LayerRegions());
		LayerRegions &raftRegions = regionlist.front();
		raftRegions.supportLoops.push_back(raftLoop);
		raftRegions.layerMeasureId = raftIndex;

		tick();
	}

	//add the actual regionlist for the base layer
	regionlist.push_front(LayerRegions());
	LayerRegions &baseRegions = regionlist.front();
	baseRegions.supportLoops.push_back(raftLoop);
	baseRegions.layerMeasureId = baseIndex;

	//make the first layer of the model relative to the last raft layer
	layerMeasure.getAttributes(bottomLayer.getIndex()).base =
		regionlist[regionerCfg.raftLayers - 1].layerMeasureId;

	tick();
}

void Regioner::insetsForSlice(const LoopList& sliceOutlines,
		std::list<LoopList>& sliceInsets,
		const char* scadFile) {

	libthing::SegmentTable sliceOutlinesOld;
	libthing::Insets sliceInsetsOld;

	/*
	 This function makes use of inshelligence, which indirectly makes use of
	 clipper.cc, a machine translated Delphi library designed to make use of
	 SegmentTables. As it is currently not practical to quickly convert this
	 library to use the new Loop type, we instead elected to simply convert
	 the resulting SegmentTables into Loops
	 */

	//convert outline Loops into equivalent SegmentTables
	for (LoopList::const_iterator iter = sliceOutlines.begin();
			iter != sliceOutlines.end();
			++iter) {
		sliceOutlinesOld.push_back(std::vector<libthing::LineSegment2 > ());
		const Loop& currentLoop = *iter;
		//Convert current loop to a vector of segments
		for (Loop::const_finite_cw_iterator loopiter =
				currentLoop.clockwiseFinite();
				loopiter != currentLoop.clockwiseEnd();
				++loopiter) {
			sliceOutlinesOld.back().push_back(currentLoop.segmentAfterPoint(loopiter));
		}
	}

	//call the function with the equivalent SegmentTables
	bool writeDebugScadFiles = false;
	inshelligence(sliceOutlinesOld,
			regionerCfg.nbOfShells,
			regionerCfg.layerW,
			regionerCfg.insetDistanceMultiplier,
			scadFile,
			writeDebugScadFiles,
			sliceInsetsOld);

	//Recover loops from the resulting SegmentTable
	for (libthing::Insets::const_iterator iter = sliceInsetsOld.begin();
			iter != sliceInsetsOld.end();
			++iter) {
		sliceInsets.push_back(LoopList());
		LoopList& currentLoopList = sliceInsets.back();
		//Convert each group of insets into a list of Loops
		for (libthing::SegmentTable::const_iterator setIter = iter->begin();
				setIter != iter->end();
				++setIter) {
			currentLoopList.push_back(Loop());
			const std::vector<libthing::LineSegment2>& currentPoly = *setIter;
			Loop& currentLoop = currentLoopList.back();
			Loop::cw_iterator loopIter = currentLoop.clockwiseEnd();
			//Convert each individual inset to a Loop
			//Insert points 1 - N
			for (std::vector<libthing::LineSegment2>::const_iterator polyIter =
					currentPoly.begin();
					polyIter != currentPoly.end();
					++polyIter) {
				loopIter = currentLoop.insertPointAfter(polyIter->b, loopIter);
			}
			//Insert point 0
			if (!currentPoly.empty())
				loopIter = currentLoop.insertPointAfter(currentPoly.begin()->a, loopIter);
		}
	}
}

//void Regioner::insets(const std::vector<libthing::SegmentTable> & outlinesSegments,
//		std::vector<libthing::Insets> & insets) {
//
//	unsigned int sliceCount = outlinesSegments.size();
//	initProgress("insets", sliceCount);
//	insets.resize(sliceCount);
//
//	// slice id must be adjusted for
//	for (size_t i = 0; i < sliceCount; i++) {
//		tick();
//		const libthing::SegmentTable & sliceOutlines = outlinesSegments[i];
//		libthing::Insets & sliceInsets = insets[i];
//
//		insetsForSlice(sliceOutlines, sliceInsets);
//	}
//}

void Regioner::insets(const LayerLoops::const_layer_iterator outlinesBegin,
					  const LayerLoops::const_layer_iterator outlinesEnd,
					  RegionList::iterator regionsBegin,
					  RegionList::iterator regionsEnd) {

	LayerLoops::const_layer_iterator outline = outlinesBegin;
	RegionList::iterator region = regionsBegin;
	while(outline != outlinesEnd && region != regionsEnd) {
		tick();
		const LoopList& currentOutlines = outline->readLoops();

		insetsForSlice(currentOutlines, region->insetLoops, NULL);

		++outline;
		++region;
	}
}

void Regioner::flatSurfaces(RegionList::iterator regionsBegin,
							RegionList::iterator regionsEnd,
							const Grid& grid) {
	for (RegionList::iterator regions = regionsBegin;
		 regions != regionsEnd; regions++) {
		tick();
		const std::list<LoopList>& currentInsets = regions->insetLoops;
		GridRanges currentSurface;
		gridRangesForSlice(currentInsets, grid, regions->flatSurface);
		gridRangesForSlice(regions->supportLoops, grid, regions->support);
	}
}

void Regioner::floorForSlice(const GridRanges & currentSurface,
		const GridRanges & surfaceBelow,
		const Grid & grid,
		GridRanges & flooring) {
	GridRanges floor;
	grid.gridRangeDifference(currentSurface, surfaceBelow, floor);
	grid.trimGridRange(floor, roofLengthCutOff, flooring);
}

void Regioner::roofForSlice(const GridRanges & currentSurface, const GridRanges & surfaceAbove, const Grid & grid, GridRanges & roofing) {
	GridRanges roof;
	grid.gridRangeDifference(currentSurface, surfaceAbove, roof);
	grid.trimGridRange(roof, this->roofLengthCutOff, roofing);
}

void Regioner::roofing(RegionList::iterator regionsBegin,
					   RegionList::iterator regionsEnd,
					   const Grid& grid) {

	RegionList::iterator current = regionsBegin;
	RegionList::iterator above = current;
	++above;

	while (above != regionsEnd) {
		tick();
		const GridRanges & currentSurface = current->flatSurface;
		const GridRanges & surfaceAbove = above->flatSurface;
		GridRanges & roofing = current->roofing;

		GridRanges roof;
		roofForSlice(currentSurface, surfaceAbove, grid, roof);

		grid.trimGridRange(roof, roofLengthCutOff, roofing);

		++current;
		++above;
	}

	tick();
	current->roofing = current->flatSurface;
}

void Regioner::flooring(RegionList::iterator regionsBegin,
						RegionList::iterator regionsEnd,
						const Grid &grid) {
	RegionList::iterator below = regionsBegin;
	RegionList::iterator current = below;
	current++;

	while (current != regionsEnd) {
		tick();
		const GridRanges & currentSurface = current->flatSurface;
		const GridRanges & surfaceBelow = below->flatSurface;
		GridRanges & flooring = current->flooring;

		floorForSlice(currentSurface, surfaceBelow, grid, flooring);

		++below;
		++current;
	}

	tick();
	regionsBegin->flooring = regionsBegin->flatSurface;

}

void Regioner::infills(RegionList::iterator regionsBegin,
					   RegionList::iterator regionsEnd,
					   const Grid &grid) {

	for (RegionList::iterator current = regionsBegin;
		 current != regionsEnd; current++) {

		const GridRanges &surface = current->flatSurface;
		tick();

		// Solids
		GridRanges combinedSolid;

		combinedSolid.xRays.resize(surface.xRays.size());
		combinedSolid.yRays.resize(surface.yRays.size());

		//TODO: no reason to get bounds separately from the combination

		//find the bounds we will be combinging regions across
		RegionList::iterator firstFloor = current;
		for (int i = 0; i < regionerCfg.floorLayerCount &&
   				        firstFloor != regionsBegin; ++i)
			--firstFloor;

		RegionList::iterator lastRoof = current;
		for (int i = 0; i < regionerCfg.roofLayerCount &&
				        lastRoof != regionsEnd - 1; ++i)
			++lastRoof;

		//combine floors
		for (RegionList::iterator floor = firstFloor;
			 floor <= current; ++floor) {
			GridRanges multiFloor;

			grid.gridRangeUnion(combinedSolid, floor->flooring, multiFloor);
			combinedSolid = multiFloor;
		}

		//combine roofs
		for (RegionList::iterator roof = current;
			 roof <= lastRoof; ++roof) {
			GridRanges multiRoof;

			grid.gridRangeUnion(combinedSolid, roof->roofing, multiRoof);
			combinedSolid = multiRoof;
		}

		// solid now contains the combination of combinedSolid regions from
		// multiple slices. We need to extract the perimeter from it

		grid.gridRangeIntersection(surface, combinedSolid, current->solid);

		// TODO: move me to the slicer
		GridRanges sparseSupport;
		GridRanges sparseInfill;
		GridRanges all;
		size_t infillSkipCount = (int) (1 / regionerCfg.infillDensity) - 1;

		grid.subSample(surface, infillSkipCount, sparseInfill);
		grid.subSample(current->support, infillSkipCount, sparseSupport);

		grid.gridRangeUnion(current->solid, sparseInfill, all);
		grid.gridRangeUnion(current->support, all, current->infill);

		//TODO: this doesn't seem right, but its what it was doing before I
		//converted to iterators
		current->sparse = current->infill;

	}

}

void Regioner::gridRangesForSlice(const std::list<LoopList>& allInsetsForSlice,
		const Grid& grid,
		GridRanges & surface) {
	const LoopList& innerMostLoops = allInsetsForSlice.back();
	grid.createGridRanges(innerMostLoops, surface);
}

<commit_msg>Compilation fixes wip<commit_after>/**
   MiracleGrue - Model Generator for toolpathing. <http://www.grue.makerbot.com>
   Copyright (C) 2011 Far McKon <Far@makerbot.com>, Hugo Boyer (hugo@makerbot.com)

   This program is free software: you can redistribute it and/or modify
   it under the terms of the GNU Affero General Public License as
   published by the Free Software Foundation, either version 3 of the
   License, or (at your option) any later version.

 **/

#include <list>
#include <vector>

#include "regioner.h"
#include "loop_utils.h"

using namespace mgl;
using namespace std;
using namespace libthing;

Regioner::Regioner(const RegionerConfig& regionerConf, ProgressBar* progress)
		: Progressive(progress), regionerCfg(regionerConf) {
	roofLengthCutOff = 0.5 * regionerCfg.layerW;
}

void Regioner::generateSkeleton(const LayerLoops& layerloops,
								LayerMeasure &layerMeasure,
								RegionList& regionlist) {
	int sliceCount = initRegionList(layerloops, regionlist);

	initProgress("rafts", regionerCfg.raftLayers + 2);
	rafts(*(layerloops.begin()), layerMeasure, regionlist);

	RegionList::iterator firstModelRegion =
		regionlist.begin() + regionerCfg.raftLayers;

	initProgress("insets", sliceCount);
	insets(layerloops.begin(), layerloops.end(),
		   firstModelRegion, regionlist.end());

	initProgress("flat surfaces", sliceCount);
	flatSurfaces(regionlist.begin(), regionlist.end(), layerloops.grid);

	initProgress("roofing", sliceCount);
	roofing(firstModelRegion, regionlist.end(), layerloops.grid);

	initProgress("flooring", sliceCount);
	flooring(firstModelRegion, regionlist.end(), layerloops.grid);

	initProgress("infills", sliceCount);
	infills(regionlist.begin(), regionlist.end(),	layerloops.grid);
}

size_t Regioner::initRegionList(const LayerLoops& layerloops,
							  RegionList &regionlist) {
	//TODO: take into account raft layers in the number of regions
	regionlist.resize(layerloops.size());
	return regionlist.size();
}

void Regioner::rafts(const LayerLoops::Layer &bottomLayer,
					 LayerMeasure &layerMeasure,
					 RegionList &regionlist) {
	//make convex hull of the bottom layer
	Loop convexLoop = createConvexLoop(bottomLayer.readLoops());
	tick();

	SegmentTable outsetSegs;
	outsetSegs.push_back(std::vector<LineSegment2>());

	for(Loop::finite_cw_iterator iter = convexLoop.clockwiseFinite();
		iter != convexLoop.clockwiseEnd(); ++iter) {

		outsetSegs.back().push_back(convexLoop.segmentAfterPoint(iter));
	}

	//outset the convex hull by the configured distance
	ClipperInsetter().inset(outsetSegs, -regionerCfg.raftOutset, outsetSegs);
	tick();

	Loop raftLoop;
	for(std::vector<LineSegment2>::const_iterator iter =
			outsetSegs.back().begin();
		iter != outsetSegs.back().end();
		++iter) {
		raftLoop.insertPointBefore(iter->b, convexLoop.clockwiseEnd());
	}
	tick();

	//create a first layer measure with absolute positioning
    layer_measure_index_t baseIndex = layerMeasure.createAttributes();
	LayerMeasure::LayerAttributes &baseAttr =
		layerMeasure.getLayerAttributes(baseIndex);
	baseAttr.delta = 0;
	baseAttr.thickness = regionerCfg.raftBaseThickness;
	baseAttr.base = -1;

	//add interface raft layers in reverse order to the beginning of the list
	for (int raftnum = regionerCfg.raftLayers - 1; raftnum > 0; raftnum--) {
		layer_measure_index_t raftIndex = layerMeasure.createAttributes();
		LayerMeasure::LayerAttributes &raftAttr =
			layerMeasure.getLayerAttributes(raftIndex);
		raftAttr.delta = (raftnum - 1) * regionerCfg.raftInterfaceThickness;
		raftAttr.thickness = regionerCfg.raftInterfaceThickness;
		raftAttr.base = baseIndex;

		regionlist.insert(regionlist.begin(), LayerRegions());
		LayerRegions &raftRegions = regionlist.front();
		raftRegions.supportLoops.push_back(raftLoop);
		raftRegions.layerMeasureId = raftIndex;

		tick();
	}

	//add the actual regionlist for the base layer
	regionlist.insert(regionlist.begin(), LayerRegions());
	LayerRegions &baseRegions = regionlist.front();
	baseRegions.supportLoops.push_back(raftLoop);
	baseRegions.layerMeasureId = baseIndex;

	//make the first layer of the model relative to the last raft layer
	layerMeasure.getLayerAttributes(bottomLayer.getIndex()).base =
		regionlist[regionerCfg.raftLayers - 1].layerMeasureId;

	tick();
}

void Regioner::insetsForSlice(const LoopList& sliceOutlines,
		std::list<LoopList>& sliceInsets,
		const char* scadFile) {

	libthing::SegmentTable sliceOutlinesOld;
	libthing::Insets sliceInsetsOld;

	/*
	 This function makes use of inshelligence, which indirectly makes use of
	 clipper.cc, a machine translated Delphi library designed to make use of
	 SegmentTables. As it is currently not practical to quickly convert this
	 library to use the new Loop type, we instead elected to simply convert
	 the resulting SegmentTables into Loops
	 */

	//convert outline Loops into equivalent SegmentTables
	for (LoopList::const_iterator iter = sliceOutlines.begin();
			iter != sliceOutlines.end();
			++iter) {
		sliceOutlinesOld.push_back(std::vector<libthing::LineSegment2 > ());
		const Loop& currentLoop = *iter;
		//Convert current loop to a vector of segments
		for (Loop::const_finite_cw_iterator loopiter =
				currentLoop.clockwiseFinite();
				loopiter != currentLoop.clockwiseEnd();
				++loopiter) {
			sliceOutlinesOld.back().push_back(currentLoop.segmentAfterPoint(loopiter));
		}
	}

	//call the function with the equivalent SegmentTables
	bool writeDebugScadFiles = false;
	inshelligence(sliceOutlinesOld,
			regionerCfg.nbOfShells,
			regionerCfg.layerW,
			regionerCfg.insetDistanceMultiplier,
			scadFile,
			writeDebugScadFiles,
			sliceInsetsOld);

	//Recover loops from the resulting SegmentTable
	for (libthing::Insets::const_iterator iter = sliceInsetsOld.begin();
			iter != sliceInsetsOld.end();
			++iter) {
		sliceInsets.push_back(LoopList());
		LoopList& currentLoopList = sliceInsets.back();
		//Convert each group of insets into a list of Loops
		for (libthing::SegmentTable::const_iterator setIter = iter->begin();
				setIter != iter->end();
				++setIter) {
			currentLoopList.push_back(Loop());
			const std::vector<libthing::LineSegment2>& currentPoly = *setIter;
			Loop& currentLoop = currentLoopList.back();
			Loop::cw_iterator loopIter = currentLoop.clockwiseEnd();
			//Convert each individual inset to a Loop
			//Insert points 1 - N
			for (std::vector<libthing::LineSegment2>::const_iterator polyIter =
					currentPoly.begin();
					polyIter != currentPoly.end();
					++polyIter) {
				loopIter = currentLoop.insertPointAfter(polyIter->b, loopIter);
			}
			//Insert point 0
			if (!currentPoly.empty())
				loopIter = currentLoop.insertPointAfter(currentPoly.begin()->a, loopIter);
		}
	}
}

//void Regioner::insets(const std::vector<libthing::SegmentTable> & outlinesSegments,
//		std::vector<libthing::Insets> & insets) {
//
//	unsigned int sliceCount = outlinesSegments.size();
//	initProgress("insets", sliceCount);
//	insets.resize(sliceCount);
//
//	// slice id must be adjusted for
//	for (size_t i = 0; i < sliceCount; i++) {
//		tick();
//		const libthing::SegmentTable & sliceOutlines = outlinesSegments[i];
//		libthing::Insets & sliceInsets = insets[i];
//
//		insetsForSlice(sliceOutlines, sliceInsets);
//	}
//}

void Regioner::insets(const LayerLoops::const_layer_iterator outlinesBegin,
					  const LayerLoops::const_layer_iterator outlinesEnd,
					  RegionList::iterator regionsBegin,
					  RegionList::iterator regionsEnd) {

	LayerLoops::const_layer_iterator outline = outlinesBegin;
	RegionList::iterator region = regionsBegin;
	while(outline != outlinesEnd && region != regionsEnd) {
		tick();
		const LoopList& currentOutlines = outline->readLoops();

		insetsForSlice(currentOutlines, region->insetLoops, NULL);

		++outline;
		++region;
	}
}

void Regioner::flatSurfaces(RegionList::iterator regionsBegin,
							RegionList::iterator regionsEnd,
							const Grid& grid) {
	for (RegionList::iterator regions = regionsBegin;
		 regions != regionsEnd; regions++) {
		tick();
		const std::list<LoopList>& currentInsets = regions->insetLoops;
		GridRanges currentSurface;
		gridRangesForSlice(currentInsets, grid, regions->flatSurface);
		gridRangesForSlice(regions->supportLoops, grid, regions->support);
	}
}

void Regioner::floorForSlice(const GridRanges & currentSurface,
		const GridRanges & surfaceBelow,
		const Grid & grid,
		GridRanges & flooring) {
	GridRanges floor;
	grid.gridRangeDifference(currentSurface, surfaceBelow, floor);
	grid.trimGridRange(floor, roofLengthCutOff, flooring);
}

void Regioner::roofForSlice(const GridRanges & currentSurface, const GridRanges & surfaceAbove, const Grid & grid, GridRanges & roofing) {
	GridRanges roof;
	grid.gridRangeDifference(currentSurface, surfaceAbove, roof);
	grid.trimGridRange(roof, this->roofLengthCutOff, roofing);
}

void Regioner::roofing(RegionList::iterator regionsBegin,
					   RegionList::iterator regionsEnd,
					   const Grid& grid) {

	RegionList::iterator current = regionsBegin;
	RegionList::iterator above = current;
	++above;

	while (above != regionsEnd) {
		tick();
		const GridRanges & currentSurface = current->flatSurface;
		const GridRanges & surfaceAbove = above->flatSurface;
		GridRanges & roofing = current->roofing;

		GridRanges roof;
		roofForSlice(currentSurface, surfaceAbove, grid, roof);

		grid.trimGridRange(roof, roofLengthCutOff, roofing);

		++current;
		++above;
	}

	tick();
	current->roofing = current->flatSurface;
}

void Regioner::flooring(RegionList::iterator regionsBegin,
						RegionList::iterator regionsEnd,
						const Grid &grid) {
	RegionList::iterator below = regionsBegin;
	RegionList::iterator current = below;
	current++;

	while (current != regionsEnd) {
		tick();
		const GridRanges & currentSurface = current->flatSurface;
		const GridRanges & surfaceBelow = below->flatSurface;
		GridRanges & flooring = current->flooring;

		floorForSlice(currentSurface, surfaceBelow, grid, flooring);

		++below;
		++current;
	}

	tick();
	regionsBegin->flooring = regionsBegin->flatSurface;

}

void Regioner::infills(RegionList::iterator regionsBegin,
					   RegionList::iterator regionsEnd,
					   const Grid &grid) {

	for (RegionList::iterator current = regionsBegin;
		 current != regionsEnd; current++) {

		const GridRanges &surface = current->flatSurface;
		tick();

		// Solids
		GridRanges combinedSolid;

		combinedSolid.xRays.resize(surface.xRays.size());
		combinedSolid.yRays.resize(surface.yRays.size());

		//TODO: no reason to get bounds separately from the combination

		//find the bounds we will be combinging regions across
		RegionList::iterator firstFloor = current;
		for (int i = 0; i < regionerCfg.floorLayerCount &&
   				        firstFloor != regionsBegin; ++i)
			--firstFloor;

		RegionList::iterator lastRoof = current;
		for (int i = 0; i < regionerCfg.roofLayerCount &&
				        lastRoof != regionsEnd - 1; ++i)
			++lastRoof;

		//combine floors
		for (RegionList::iterator floor = firstFloor;
			 floor <= current; ++floor) {
			GridRanges multiFloor;

			grid.gridRangeUnion(combinedSolid, floor->flooring, multiFloor);
			combinedSolid = multiFloor;
		}

		//combine roofs
		for (RegionList::iterator roof = current;
			 roof <= lastRoof; ++roof) {
			GridRanges multiRoof;

			grid.gridRangeUnion(combinedSolid, roof->roofing, multiRoof);
			combinedSolid = multiRoof;
		}

		// solid now contains the combination of combinedSolid regions from
		// multiple slices. We need to extract the perimeter from it

		grid.gridRangeIntersection(surface, combinedSolid, current->solid);

		// TODO: move me to the slicer
		GridRanges sparseSupport;
		GridRanges sparseInfill;
		GridRanges all;
		size_t infillSkipCount = (int) (1 / regionerCfg.infillDensity) - 1;

		grid.subSample(surface, infillSkipCount, sparseInfill);
		grid.subSample(current->support, infillSkipCount, sparseSupport);

		grid.gridRangeUnion(current->solid, sparseInfill, all);
		grid.gridRangeUnion(current->support, all, current->infill);

		//TODO: this doesn't seem right, but its what it was doing before I
		//converted to iterators
		current->sparse = current->infill;

	}

}

void Regioner::gridRangesForSlice(const std::list<LoopList>& allInsetsForSlice,
		const Grid& grid,
		GridRanges & surface) {
	const LoopList& innerMostLoops = allInsetsForSlice.back();
	grid.createGridRanges(innerMostLoops, surface);
}

<|endoftext|>


<commit_before>#include "cpu.h"

#include "opcode_cycles.h"
#include "../util/bitwise.h"
#include "../util/log.h"

using bitwise::compose_bytes;

CPU::CPU(MMU& inMMU) :
    mmu(inMMU),
    af(a, f),
    bc(b, c),
    de(d, e),
    hl(h, l)
{
}

Cycles CPU::tick() {
    log_trace("PC: 0x%04X", pc.value());
    auto opcode = get_byte_from_pc();
    return execute_opcode(opcode);
}

Cycles CPU::execute_opcode(const u8 opcode) {
    branch_taken = false;

    if (opcode == 0xCB) {
        execute_cb_opcode();
        unsigned cycles = opcode_cycles_cb[opcode];
        return cycles;
    }

    execute_normal_opcode(opcode);

    unsigned cycles = !branch_taken ?
        opcode_cycles[opcode] :
        opcode_cycles_branched[opcode];

    return cycles;
}

u8 CPU::get_byte_from_pc() {
    u8 byte = mmu.read(Address(pc));
    pc.increment();

    return byte;
}

s8 CPU::get_signed_byte_from_pc() {
    u8 byte = get_byte_from_pc();
    return static_cast<s8>(byte);
}

u16 CPU::get_word_from_pc() {
    u8 low_byte = get_byte_from_pc();
    u8 high_byte = get_byte_from_pc();

    return compose_bytes(high_byte, low_byte);
}

void CPU::set_flag_zero(bool set) {
    f.set_bit_to(7, set);
}

void CPU::set_flag_subtract(bool set) {
    f.set_bit_to(6, set);
}

void CPU::set_flag_half_carry(bool set) {
    f.set_bit_to(5, set);
}

void CPU::set_flag_carry(bool set) {
    f.set_bit_to(4, set);
}

void CPU::reset_flags() {
    set_flag_zero(false);
    set_flag_subtract(false);
    set_flag_half_carry(false);
    set_flag_carry(false);
}

bool CPU::flag_zero() const {
    return f.check_bit(7);
}

bool CPU::flag_subtract() const {
    return f.check_bit(6);
}

bool CPU::flag_half_carry() const {
    return f.check_bit(5);
}

bool CPU::flag_carry() const {
    return f.check_bit(4);
}

bool CPU::is_condition(Condition condition) {
    bool should_branch;

    switch (condition) {
        case Condition::C:
            should_branch = flag_carry();
            break;
        case Condition::NC:
            should_branch = !flag_carry();
            break;
        case Condition::Z:
            should_branch = flag_zero();
            break;
        case Condition::NZ:
            should_branch = !flag_zero();
            break;
    }

    /* If the branch is taken, remember so that the correct processor cycles
     * can be used */
    branch_taken = should_branch;
    return should_branch;
}

u8 CPU::flag_half_carry_value() const {
    return static_cast<u8>(flag_half_carry() ? 1 : 0);
}

u8 CPU::flag_carry_value() const {
    return static_cast<u8>(flag_carry() ? 1 : 0);
}

void CPU::stack_push(const WordRegister& reg) {
    sp.decrement();
    mmu.write(Address(sp), reg.high());
    sp.decrement();
    mmu.write(Address(sp), reg.low());
}

void CPU::stack_pop(WordRegister& reg) {
    u8 low_byte = mmu.read(Address(sp));
    sp.increment();
    u8 high_byte = mmu.read(Address(sp));
    sp.increment();

    u16 value = compose_bytes(high_byte, low_byte);
    reg.set(value);
}

/* TODO: reduce duplication with a WordValue interface */
void CPU::stack_push(const RegisterPair& reg) {
    sp.decrement();
    mmu.write(Address(sp), reg.high());
    sp.decrement();
    mmu.write(Address(sp), reg.low());
}

void CPU::stack_pop(RegisterPair& reg) {
    u8 low_byte = mmu.read(Address(sp));
    sp.increment();
    u8 high_byte = mmu.read(Address(sp));
    sp.increment();

    u16 value = compose_bytes(high_byte, low_byte);
    reg.set(value);
}
<commit_msg>Add a TODO<commit_after>#include "cpu.h"

#include "opcode_cycles.h"
#include "../util/bitwise.h"
#include "../util/log.h"

using bitwise::compose_bytes;

CPU::CPU(MMU& inMMU) :
    mmu(inMMU),
    af(a, f),
    bc(b, c),
    de(d, e),
    hl(h, l)
{
}

Cycles CPU::tick() {
    log_trace("PC: 0x%04X", pc.value());
    auto opcode = get_byte_from_pc();
    return execute_opcode(opcode);
}

Cycles CPU::execute_opcode(const u8 opcode) {
    branch_taken = false;

    if (opcode == 0xCB) {
        execute_cb_opcode();
        unsigned cycles = opcode_cycles_cb[opcode];
        return cycles;
    }

    execute_normal_opcode(opcode);

    unsigned cycles = !branch_taken ?
        opcode_cycles[opcode] :
        opcode_cycles_branched[opcode];

    return cycles;
}

u8 CPU::get_byte_from_pc() {
    u8 byte = mmu.read(Address(pc));
    pc.increment();

    return byte;
}

s8 CPU::get_signed_byte_from_pc() {
    u8 byte = get_byte_from_pc();
    return static_cast<s8>(byte);
}

u16 CPU::get_word_from_pc() {
    u8 low_byte = get_byte_from_pc();
    u8 high_byte = get_byte_from_pc();

    return compose_bytes(high_byte, low_byte);
}

void CPU::set_flag_zero(bool set) {
    f.set_bit_to(7, set);
}

void CPU::set_flag_subtract(bool set) {
    f.set_bit_to(6, set);
}

void CPU::set_flag_half_carry(bool set) {
    f.set_bit_to(5, set);
}

void CPU::set_flag_carry(bool set) {
    f.set_bit_to(4, set);
}

void CPU::reset_flags() {
    set_flag_zero(false);
    set_flag_subtract(false);
    set_flag_half_carry(false);
    set_flag_carry(false);
}

bool CPU::flag_zero() const {
    return f.check_bit(7);
}

bool CPU::flag_subtract() const {
    return f.check_bit(6);
}

bool CPU::flag_half_carry() const {
    return f.check_bit(5);
}

bool CPU::flag_carry() const {
    return f.check_bit(4);
}

bool CPU::is_condition(Condition condition) {
    bool should_branch;

    switch (condition) {
        case Condition::C:
            should_branch = flag_carry();
            break;
        case Condition::NC:
            should_branch = !flag_carry();
            break;
        case Condition::Z:
            should_branch = flag_zero();
            break;
        case Condition::NZ:
            should_branch = !flag_zero();
            break;
    }

    /* If the branch is taken, remember so that the correct processor cycles
     * can be used */
    branch_taken = should_branch;
    return should_branch;
}

u8 CPU::flag_half_carry_value() const {
    return static_cast<u8>(flag_half_carry() ? 1 : 0);
}

u8 CPU::flag_carry_value() const {
    return static_cast<u8>(flag_carry() ? 1 : 0);
}

void CPU::stack_push(const WordRegister& reg) {
    sp.decrement();
    mmu.write(Address(sp), reg.high());
    sp.decrement();
    mmu.write(Address(sp), reg.low());
}

void CPU::stack_pop(WordRegister& reg) {
    u8 low_byte = mmu.read(Address(sp));
    sp.increment();
    u8 high_byte = mmu.read(Address(sp));
    sp.increment();

    u16 value = compose_bytes(high_byte, low_byte);
    reg.set(value);
}

/* TODO: reduce duplication with a WordValue interface */
/* TODO: Should this write the value before decrementing the stack pointer? */
void CPU::stack_push(const RegisterPair& reg) {
    sp.decrement();
    mmu.write(Address(sp), reg.high());
    sp.decrement();
    mmu.write(Address(sp), reg.low());
}

void CPU::stack_pop(RegisterPair& reg) {
    u8 low_byte = mmu.read(Address(sp));
    sp.increment();
    u8 high_byte = mmu.read(Address(sp));
    sp.increment();

    u16 value = compose_bytes(high_byte, low_byte);
    reg.set(value);
}
<|endoftext|>


<commit_before>/*
*Horseshoes
By 2MB Solutions: https//2mb.solutions
Released under the terms of the unlicense: http://unlicense.org
Billy: https://stormdragon.tk/
Michael: https://michaeltaboada.me
*/
//#define ALLEGRO_STATICLINK 1
#include <allegro5/allegro.h>
#include "dynamic_menu.h"
#include <keyboard.h>
#include <stdlib.h>
#include <sound.h>
#include <string>
#include <time.h>
#include <iostream>
using namespace std;
#include <menu_helper.h>
#include <misc.h>
#include <soundplayer.h>

void play(int mode, int diff);

int main(int argc, char** argv) {
srand ( time(NULL) ); //initialize the random seed
/*
if(!al_install_system(ALLEGRO_VERSION_INT, NULL)) {
log("Could not initialize allegro.\n");
return 1;
}
ALLEGRO_DISPLAY* disp = al_create_display(640, 480);
if(!disp) {
log("Could not create display.\n");
return 1;
}
if(!al_install_keyboard()) {
log("Could not install keyboard hooks.\n");
al_destroy_display(disp);
al_uninstall_system();
return 1;
}
if(!al_install_audio()) {
log("Could not install audio hooks.\n");
al_uninstall_keyboard();
al_destroy_display(disp);
al_uninstall_system();
return 1;
}
if(!al_init_acodec_addon()) {
log("Could not initialize codec routines.\n");
al_uninstall_audio();
al_uninstall_keyboard();
al_destroy_display(disp);
al_uninstall_system();;
return 1;
}
*/
ALLEGRO_DISPLAY* disp = game_window("Horseshoes");
if(!disp) {
log_close();
	return 1;
}
sound* s = new sound();
if(!s->load("sounds/select.ogg")) {
log("Could not load selection sound.\n");
delete s;
s = NULL;
}
sound* o = new sound();
if(!o->load("sounds/option.ogg")) {
log("Could not load option sound.\n");
delete o;
o = NULL;
}
sound* b = new sound();
if(!b->load("sounds/back.ogg")) {
log("Could not load navigation back sound.\n");
delete b;
b = NULL;
}
sound* m = new sound();
if(!m->load("sounds/music.ogg")) {
log("Could not load menu music.\n");
delete m;
m = NULL;
}
else {
m->set_loop(true);
}
int r;
string mainm[] = {"Play game", "credits", "exit"};
dynamic_menu* mainMenu = create_menu(vector<string>(mainm, mainm+3), vector<string>(0));
mainMenu->set_display(disp);
mainMenu->select = s;
mainMenu->move = o;
string mode[] = {"Player versus computer", "Player versus player", "Computer versus computer", "back to main menu."};
dynamic_menu* modeMenu = create_menu(vector<string>(mode, mode+4), vector<string>(0));
modeMenu->set_display(disp);
modeMenu->select = s;
modeMenu->move = o;
string difficulty[] = {"Easy", "Normal", "Hard", "Alan Francis mode", "Back to main menu"};
dynamic_menu* difficultyMenu = create_menu(vector<string>(difficulty, difficulty+5), vector<string>(0));
difficultyMenu->set_display(disp);
difficultyMenu->select = s;
difficultyMenu->move = o;
do {
if(m) {
m->set_gain(0);
m->play();
}
r = mainMenu->run_extended("", "Use your arrow keys to navigate the menu, and the enter key to select.", 1, true);
if (r == 2)
{
credits(disp, "Horseshoes");
}
if(r == 1) {
int gameMode,gameDifficulty;
int r2 = modeMenu->run_extended("", "Use your arrow keys to navigate the menu, and the enter key to select.", 1, true);
if(r2 == 1 || r2 == 3)
{
int r3 = difficultyMenu->run_extended("", "Use your arrow keys to navigate the menu, and the enter key to select.", 2, true);
if(r2 < 4 && r2 > 0)
gameMode = r2-1;
if (r3 != 5 && r3 != 0 && r3 != -1 && r3 != 4)
{
gameDifficulty = r3*2+3;
if(m) {
fade(m);
}
play(gameMode, gameDifficulty);
}
else if(r3 == 4) {
if(m) {
fade(m);
}
play(gameMode, 19);
}
else {
if(b) {
b->stop();
b->play();
}
}
}
else if(r2 != -1 && r2 != 0 && r2 != 4) {
if(m) {
fade(m);
}
play(r2-1, 0);
}
else {
if(b) {
b->stop();
b->play();
}
}
}
else {
if(b) {
b->stop();
b->play();
}
}
}
while((r >= 1) && (r <= 2));
if(m) {
fade(m);
}
delete difficultyMenu;
delete modeMenu;
delete mainMenu;
if(b)
delete b;
if(s)
delete s;
if(o)
delete o;
if(m)
delete m;
end_game(disp);
return 0;
}

<commit_msg>Less verbose menus.<commit_after>/*
*Horseshoes
By 2MB Solutions: https//2mb.solutions
Released under the terms of the unlicense: http://unlicense.org
Billy: https://stormdragon.tk/
Michael: https://michaeltaboada.me
*/
//#define ALLEGRO_STATICLINK 1
#include <allegro5/allegro.h>
#include "dynamic_menu.h"
#include <keyboard.h>
#include <stdlib.h>
#include <sound.h>
#include <string>
#include <time.h>
#include <iostream>
using namespace std;
#include <menu_helper.h>
#include <misc.h>
#include <soundplayer.h>

void play(int mode, int diff);

int main(int argc, char** argv) {
srand ( time(NULL) ); //initialize the random seed
/*
if(!al_install_system(ALLEGRO_VERSION_INT, NULL)) {
log("Could not initialize allegro.\n");
return 1;
}
ALLEGRO_DISPLAY* disp = al_create_display(640, 480);
if(!disp) {
log("Could not create display.\n");
return 1;
}
if(!al_install_keyboard()) {
log("Could not install keyboard hooks.\n");
al_destroy_display(disp);
al_uninstall_system();
return 1;
}
if(!al_install_audio()) {
log("Could not install audio hooks.\n");
al_uninstall_keyboard();
al_destroy_display(disp);
al_uninstall_system();
return 1;
}
if(!al_init_acodec_addon()) {
log("Could not initialize codec routines.\n");
al_uninstall_audio();
al_uninstall_keyboard();
al_destroy_display(disp);
al_uninstall_system();;
return 1;
}
*/
ALLEGRO_DISPLAY* disp = game_window("Horseshoes");
if(!disp) {
log_close();
	return 1;
}
sound* s = new sound();
if(!s->load("sounds/select.ogg")) {
log("Could not load selection sound.\n");
delete s;
s = NULL;
}
sound* o = new sound();
if(!o->load("sounds/option.ogg")) {
log("Could not load option sound.\n");
delete o;
o = NULL;
}
sound* b = new sound();
if(!b->load("sounds/back.ogg")) {
log("Could not load navigation back sound.\n");
delete b;
b = NULL;
}
sound* m = new sound();
if(!m->load("sounds/music.ogg")) {
log("Could not load menu music.\n");
delete m;
m = NULL;
}
else {
m->set_loop(true);
}
int r;
string mainm[] = {"Play game", "credits", "exit"};
dynamic_menu* mainMenu = create_menu(vector<string>(mainm, mainm+3), vector<string>(0));
mainMenu->set_display(disp);
mainMenu->select = s;
mainMenu->move = o;
string mode[] = {"Player versus computer", "Player versus player", "Computer versus computer", "back to main menu."};
dynamic_menu* modeMenu = create_menu(vector<string>(mode, mode+4), vector<string>(0));
modeMenu->set_display(disp);
modeMenu->select = s;
modeMenu->move = o;
string difficulty[] = {"Easy", "Normal", "Hard", "Alan Francis mode", "Back to main menu"};
dynamic_menu* difficultyMenu = create_menu(vector<string>(difficulty, difficulty+5), vector<string>(0));
difficultyMenu->set_display(disp);
difficultyMenu->select = s;
difficultyMenu->move = o;
do {
if(m) {
m->set_gain(0);
m->play();
}
r = mainMenu->run_extended("", "Use your arrow keys to navigate the menu, and the enter key to select.", 1, true);
if (r == 2)
{
credits(disp, "Horseshoes");
}
if(r == 1) {
int gameMode,gameDifficulty;
int r2 = modeMenu->run_extended("", "", 1, true);
if(r2 == 1 || r2 == 3)
{
int r3 = difficultyMenu->run_extended("", "", 2, true);
if(r2 < 4 && r2 > 0)
gameMode = r2-1;
if (r3 != 5 && r3 != 0 && r3 != -1 && r3 != 4)
{
gameDifficulty = r3*2+3;
if(m) {
fade(m);
}
play(gameMode, gameDifficulty);
}
else if(r3 == 4) {
if(m) {
fade(m);
}
play(gameMode, 19);
}
else {
if(b) {
b->stop();
b->play();
}
}
}
else if(r2 != -1 && r2 != 0 && r2 != 4) {
if(m) {
fade(m);
}
play(r2-1, 0);
}
else {
if(b) {
b->stop();
b->play();
}
}
}
else {
if(b) {
b->stop();
b->play();
}
}
}
while((r >= 1) && (r <= 2));
if(m) {
fade(m);
}
delete difficultyMenu;
delete modeMenu;
delete mainMenu;
if(b)
delete b;
if(s)
delete s;
if(o)
delete o;
if(m)
delete m;
end_game(disp);
return 0;
}

<|endoftext|>


<commit_before>#include "game.hpp"

#include <iostream>
#include <ncursesw/ncurses.h>

#include "alphabeta_pv.hpp"
#include "position.hpp"

using namespace std;

enum color { null = 1, black, white };

class selection_window {
  WINDOW *win;
  const int height;

public:
  selection_window(int rows, int cols)
      : win{newwin(rows - 2, cols - 15, 1, 14)}, height(rows - 4) {
    wborder(win, '|', '|', '-', '-', '+', '+', '+', '+');
    refresh();
    wrefresh(win);
  }
  selection_window(const selection_window &) = delete;
  ~selection_window() { delwin(win); }
  void operator()(const vector<string> &s, int n) {
    wclear(win);
    wborder(win, '|', '|', '-', '-', '+', '+', '+', '+');

    for (int i = s.size(); i--;) {
      if (n == i)
        wattron(win, COLOR_PAIR(null));
      mvwprintw(win, height - i, 1, s[i].c_str());
      if (n == i)
        wattroff(win, COLOR_PAIR(null));
    }

    refresh();
    wrefresh(win);
  }
};

class game_window {
  WINDOW *win;

public:
  game_window(int row) : win{newwin(10, 10, row, 2)} {
    wborder(win, '|', '|', '-', '-', '+', '+', '+', '+');
    refresh();
    wrefresh(win);
  }
  game_window(const game_window &) = delete;
  ~game_window() { delwin(win); }
  void operator()(const position &p) {
    wmove(win, 1, 1);
    int y = 1;
    for (unsigned piece = 1; piece; piece <<= 1) {
      if (piece & 0x0f0f0f0fu) {
        wattron(win, COLOR_PAIR(null));
        waddch(win, ' ');
        wattroff(win, COLOR_PAIR(null));
      }

      if (piece & p[0]) {
        wattron(win, COLOR_PAIR(black));
        waddstr(win, "●");
        wattroff(win, COLOR_PAIR(black));
      } else if (piece & p[1]) {
        wattron(win, COLOR_PAIR(white));
        waddstr(win, "●");
        wattroff(win, COLOR_PAIR(white));
      } else if (piece & p[2]) {
        wattron(win, COLOR_PAIR(black));
        waddstr(win, "♣");
        wattroff(win, COLOR_PAIR(black));
      } else if (piece & p[3]) {
        wattron(win, COLOR_PAIR(white));
        waddstr(win, "♣");
        wattroff(win, COLOR_PAIR(white));
      } else {
        wattron(win, COLOR_PAIR(white));
        waddch(win, ' ');
        wattroff(win, COLOR_PAIR(white));
      }

      if (piece & 0xf0f0f0f0u) {
        wattron(win, COLOR_PAIR(null));
        waddch(win, ' ');
        wattroff(win, COLOR_PAIR(null));
      }
      if (piece & 0x88888888u)
        wmove(win, ++y, 1);
    }
    refresh();
    wrefresh(win);
  }
  void clear() {
    wclear(win);
    wborder(win, '|', '|', '-', '-', '+', '+', '+', '+');
    refresh();
    wrefresh(win);
  }
};

class game_manager {
  game_window move_win;
  game_window current_win;
  selection_window sel_win;
  alphabeta_pv agent;

public:
  game_manager(int rows, int cols, alphabeta_pv &&a)
      : move_win{rows - 11}, current_win{rows - 22}, sel_win{rows, cols},
        agent(move(a)) {}

  void operator()() {
    position p;

    try {
      for (int i = 0; i < 256; i++) {
        if (p.player() == agent.get_side())
          p = agent.get_move(p);
        current_win(p);

        const vector<position> moves{p.moves()};
        if (moves.empty()) {
          move_win.clear();
          sel_win({"You have been defeated."}, 0);
          getch();
          return;
        }

        vector<string> move_str;
        for (unsigned j = 0; j < moves.size(); j++)
          move_str.emplace_back(to_string(j) + ". " +
                                to_string(moves[j].hash()));

        int n = 0;
        while (1) {
          move_win(moves[n]);
          sel_win(move_str, n);

          int ch = getch();
          if (ch == KEY_DOWN) {
            if (--n < 0)
              n = 0;
          } else if (ch == KEY_UP) {
            if (++n >= (int)moves.size())
              n = moves.size() - 1;
          } else if (ch == 10) {
            break;
          }
        }
        p = moves[n];
      }
      move_win.clear();
      sel_win({"The game has ended in a draw."}, 0);
      getch();
      return;
    } catch (agent::resign) {
      move_win.clear();
      sel_win({"The computer has resigned. You win!"}, 0);
      getch();
      return;
    }
  }
};

void play_game() {
  int row, col;

  int depth = 0;
  do {
    cout << "Enter the desired search depth: ";
    cin >> depth;
  } while (depth <= 0 && depth >= 20);

  int player = 0;
  do {
    cout << "Enter 2 to play as black, 1 to play as white: ";
    cin >> player;
  } while (player < 1 || player > 2);

  initscr();
  if (has_colors() == FALSE) {
    endwin();
    cout << "Terminal does not support colors." << endl;
    return;
  }
  cbreak();
  noecho();
  keypad(stdscr, TRUE);
  start_color();

  init_pair(null, COLOR_BLACK, COLOR_WHITE);
  init_pair(black, COLOR_RED, COLOR_GREEN);
  init_pair(white, COLOR_WHITE, COLOR_GREEN);

  getmaxyx(stdscr, row, col);

  game_manager w{row, col, {best_heuristic(), depth, (char)(player - 1)}};
  w();

  endwin();
}
<commit_msg>Fixed another brain fart.<commit_after>#include "game.hpp"

#include <iostream>
#include <ncursesw/ncurses.h>

#include "alphabeta_pv.hpp"
#include "position.hpp"

using namespace std;

enum color { null = 1, black, white };

class selection_window {
  WINDOW *win;
  const int height;

public:
  selection_window(int rows, int cols)
      : win{newwin(rows - 2, cols - 15, 1, 14)}, height(rows - 4) {
    wborder(win, '|', '|', '-', '-', '+', '+', '+', '+');
    refresh();
    wrefresh(win);
  }
  selection_window(const selection_window &) = delete;
  ~selection_window() { delwin(win); }
  void operator()(const vector<string> &s, int n) {
    wclear(win);
    wborder(win, '|', '|', '-', '-', '+', '+', '+', '+');

    for (int i = s.size(); i--;) {
      if (n == i)
        wattron(win, COLOR_PAIR(null));
      mvwprintw(win, height - i, 1, s[i].c_str());
      if (n == i)
        wattroff(win, COLOR_PAIR(null));
    }

    refresh();
    wrefresh(win);
  }
};

class game_window {
  WINDOW *win;

public:
  game_window(int row) : win{newwin(10, 10, row, 2)} {
    wborder(win, '|', '|', '-', '-', '+', '+', '+', '+');
    refresh();
    wrefresh(win);
  }
  game_window(const game_window &) = delete;
  ~game_window() { delwin(win); }
  void operator()(const position &p) {
    wmove(win, 1, 1);
    int y = 1;
    for (unsigned piece = 1; piece; piece <<= 1) {
      if (piece & 0x0f0f0f0fu) {
        wattron(win, COLOR_PAIR(null));
        waddch(win, ' ');
        wattroff(win, COLOR_PAIR(null));
      }

      if (piece & p[0]) {
        wattron(win, COLOR_PAIR(black));
        waddstr(win, "●");
        wattroff(win, COLOR_PAIR(black));
      } else if (piece & p[1]) {
        wattron(win, COLOR_PAIR(white));
        waddstr(win, "●");
        wattroff(win, COLOR_PAIR(white));
      } else if (piece & p[2]) {
        wattron(win, COLOR_PAIR(black));
        waddstr(win, "♣");
        wattroff(win, COLOR_PAIR(black));
      } else if (piece & p[3]) {
        wattron(win, COLOR_PAIR(white));
        waddstr(win, "♣");
        wattroff(win, COLOR_PAIR(white));
      } else {
        wattron(win, COLOR_PAIR(white));
        waddch(win, ' ');
        wattroff(win, COLOR_PAIR(white));
      }

      if (piece & 0xf0f0f0f0u) {
        wattron(win, COLOR_PAIR(null));
        waddch(win, ' ');
        wattroff(win, COLOR_PAIR(null));
      }
      if (piece & 0x88888888u)
        wmove(win, ++y, 1);
    }
    refresh();
    wrefresh(win);
  }
  void clear() {
    wclear(win);
    wborder(win, '|', '|', '-', '-', '+', '+', '+', '+');
    refresh();
    wrefresh(win);
  }
};

class game_manager {
  game_window move_win;
  game_window current_win;
  selection_window sel_win;
  alphabeta_pv agent;

public:
  game_manager(int rows, int cols, alphabeta_pv &&a)
      : move_win{rows - 11}, current_win{rows - 22}, sel_win{rows, cols},
        agent(move(a)) {}

  void operator()() {
    position p;

    try {
      for (int i = 0; i < 256; i++) {
        if (p.player() == agent.get_side())
          p = agent.get_move(p);
        current_win(p);

        const vector<position> moves{p.moves()};
        if (moves.empty()) {
          move_win.clear();
          sel_win({"You have been defeated."}, 0);
          getch();
          return;
        }

        vector<string> move_str;
        for (unsigned j = 0; j < moves.size(); j++)
          move_str.emplace_back(to_string(j) + ". " +
                                to_string(moves[j].hash()));

        int n = 0;
        while (1) {
          move_win(moves[n]);
          sel_win(move_str, n);

          int ch = getch();
          if (ch == KEY_DOWN) {
            if (--n < 0)
              n = 0;
          } else if (ch == KEY_UP) {
            if (++n >= (int)moves.size())
              n = moves.size() - 1;
          } else if (ch == 10) {
            break;
          }
        }
        p = moves[n];
      }
      move_win.clear();
      sel_win({"The game has ended in a draw."}, 0);
      getch();
      return;
    } catch (agent::resign) {
      move_win.clear();
      sel_win({"The computer has resigned. You win!"}, 0);
      getch();
      return;
    }
  }
};

void play_game() {
  int row, col;

  int depth = 0;
  do {
    cout << "Enter the desired search depth: ";
    cin >> depth;
  } while (depth <= 0 || depth >= 20);

  int player = 0;
  do {
    cout << "Enter 2 to play as black, 1 to play as white: ";
    cin >> player;
  } while (player < 1 || player > 2);

  initscr();
  if (has_colors() == FALSE) {
    endwin();
    cout << "Terminal does not support colors." << endl;
    return;
  }
  cbreak();
  noecho();
  keypad(stdscr, TRUE);
  start_color();

  init_pair(null, COLOR_BLACK, COLOR_WHITE);
  init_pair(black, COLOR_RED, COLOR_GREEN);
  init_pair(white, COLOR_WHITE, COLOR_GREEN);

  getmaxyx(stdscr, row, col);

  game_manager w{row, col, {best_heuristic(), depth, (char)(player - 1)}};
  w();

  endwin();
}
<|endoftext|>


<commit_before>#include "multithread.h"

#include <iostream>
using namespace std;

Multithread::Multithread(int num_threads)
	: num_threads(num_threads), next_thread_id(0)
{
	threads = new pthread_t[num_threads];
}

Multithread::~Multithread()
{
	delete[] threads;
}

void Multithread::start()
{
	for (int i = 0; i < num_threads; i++) {
		int thread_id = next_thread_id++;
		cerr << "Start thread, id " << thread_id << endl;
    create_thread(&threads[i], thread_id);
	}
}

void Multithread::join_all()
{
	for (int i = 0; i < num_threads; i++) {
		pthread_join(threads[i], NULL);
		cerr << "Joined thread " << i << endl;
	}
}
<commit_msg>Remove extraneous debugging output.<commit_after>#include "multithread.h"

#include <iostream>
using namespace std;

Multithread::Multithread(int num_threads)
	: num_threads(num_threads), next_thread_id(0)
{
	threads = new pthread_t[num_threads];
}

Multithread::~Multithread()
{
	delete[] threads;
}

void Multithread::start()
{
        for (int i = 0; i < num_threads; i++) {
                int thread_id = next_thread_id++;
                create_thread(&threads[i], thread_id);
        }
}

void Multithread::join_all()
{
        for (int i = 0; i < num_threads; i++) {
                pthread_join(threads[i], NULL);
        }
}
<|endoftext|>


<commit_before>// Copyright (c) 2015 The Brick Authors.

#include "brick/download_client.h"

#include <ctime>
#include <fstream>

#include "include/cef_parser.h"
#include "include/base/cef_logging.h"
#include "brick/brick_types.h"
#include "brick/client_handler.h"
#include "brick/platform_util.h"
#include "brick/helper.h"

namespace {
  const char kTmpSuffix[] = ".brdown";
  const char kPageType[] = "text/html";
  const char kJsonType[] = "application/json";
  const char kDispositionHeaderName[] = "Content-Disposition";

  const int kHighPercentBound = 10 * 1024 * 1024;
  const int kMiddleBytesBound = 5 * 1024 * 1024;
  const int kHighBytesBound = 100 * 1024 * 1024;
  const int kLowPercentLimit = 5;
  const int kHighPercentLimit = 1;
  const int kLowBytesLimit = 512 * 1024;
  const int kMiddleBytesLimit = 1024 * 1024;
  const int kHighBytesLimit = 10 * 1024 * 1024;

  bool
  IsDownloadResponse(CefRefPtr<CefResponse> response) {
    // ToDo: checks Content-Disposition for all responses?
    const std::string mime_type = response->GetMimeType().ToString();

    if (mime_type.find(kPageType) == 0 || mime_type.find(kJsonType) == 0)
      return response->GetHeader(kDispositionHeaderName).ToString().find("attachment") == 0;

    return true;
  }

}  // namespace

DownloadClient::DownloadClient(const std::string& id, const std::string& path, const std::string& name)
    : id_ (id),
      file_path_ (path),
      file_name_ (name),
      last_percent_ (-1),
      last_bytes_ (-1) {

  CEF_REQUIRE_UI_THREAD();

  start_time_ = std::chrono::system_clock::now();
  tmp_file_path_ = path + kTmpSuffix;
  tmp_file_.open(tmp_file_path_, std::ofstream::binary);
}

void
DownloadClient::Detach() {
  CEF_REQUIRE_UI_THREAD();

  tmp_file_.close();
}

void
DownloadClient::OnRequestComplete(CefRefPtr<CefURLRequest> request) {
  CEF_REQUIRE_UI_THREAD();

  tmp_file_.close();
  DownloadClientStatus status;
  DownloadClientReason reason;

  if (request->GetRequestError() == ERR_NONE && request->GetResponse()->GetStatus() == 200) {
    if (!IsDownloadResponse(request->GetResponse())) {
      status = DC_STATUS_FAILED;
      reason = DC_REASON_NOT_ATTACHMENT;
      LOG(WARNING) << "Strange response type, not a file? ID: " << id_ << ". "
                   << "Url: " << request->GetRequest()->GetURL().ToString() << ". "
                   << "Type: " << request->GetResponse()->GetMimeType().ToString();

    } else if (rename(tmp_file_path_.c_str(), file_path_.c_str()) != 0) {
      status = DC_STATUS_FAILED;
      reason = DC_REASON_UNKNOWN;
      LOG(WARNING) << "Can't rename downloaded file. ID: " << id_ << ". "
                   << "Tmp path: " << tmp_file_path_ << "."
                   << "Result path: " << file_path_;

    } else {
      status = DC_STATUS_SUCCESS;
      reason = DC_REASON_NONE;
    }
  } else if (request->GetRequestError() == ERR_ABORTED) {
    status = DC_STATUS_FAILED;
    reason = DC_REASON_ABORTED;
    LOG(INFO) << "Download aborted. ID: " << id_ << ". "
              << "Url: " << request->GetRequest()->GetURL().ToString();

  } else {
    status = DC_STATUS_FAILED;
    reason = DC_REASON_HTTP;
    LOG(WARNING) << "Download failed. ID: " << id_ << ". "
                 << "Url: " << request->GetRequest()->GetURL().ToString() << "."
                 << "Reason: " << request_util::GetErrorString(request->GetRequestError());
  }

  if (status != DC_STATUS_SUCCESS) {
    unlink(tmp_file_path_.c_str());
  }

  DownloadCompleteEvent e(id_, file_path_, status, reason);
  EventBus::FireEvent(e);
}

void
DownloadClient::OnDownloadProgress(CefRefPtr<CefURLRequest> request, int64 current, int64 total) {
  bool percent_mode = (total > 0);

  int progress = 0;
  if (percent_mode) {
    progress = static_cast<int>(current * 100.0 / total);
    if (last_percent_ != -1) {
      const int delta_progress = progress - last_percent_;
      int limit;
      if (current < kHighPercentBound) {
        limit = kLowPercentLimit;
      } else {
        limit = kHighPercentLimit;
      }

      if (delta_progress < limit)
        return;
    }

    last_percent_ = progress;
  } else {
    if (last_bytes_ != -1) {
      const int64 delta_bytes = current - last_bytes_;
      int limit;
      if (current < kMiddleBytesBound) {
        limit = kLowBytesLimit;
      } else if (current < kHighBytesBound) {
        limit = kMiddleBytesLimit;
      } else {
        limit = kHighBytesLimit;
      }

      if (delta_bytes < limit)
        return;
    }

    last_bytes_ = current;
  }

  const auto diff_time = std::chrono::system_clock::now() - start_time_;
  const auto time_elapsed =
      std::chrono::duration_cast<std::chrono::milliseconds>(diff_time).count();

  int64 speed = 0;
  if (time_elapsed > 0) {
    speed = static_cast<int>(current * 1000 / time_elapsed);
  }

  DownloadProgressEvent e(id_, progress, speed, current, total);
  EventBus::FireEvent(e);
}

void
DownloadClient::OnDownloadData(CefRefPtr<CefURLRequest> request,
                             const void* data,
                             size_t data_length) {

  CEF_REQUIRE_UI_THREAD();
  tmp_file_.write(static_cast<const char*>(data), data_length);
}

// static methods

CefRefPtr<CefURLRequest>
DownloadClient::CreateRequest(
    const std::string& id,
    const std::string& url,
    const std::string& path,
    const std::string& name) {

  CEF_REQUIRE_UI_THREAD();

  if (!platform_util::MakeDirectory(helper::BaseDir(path)))
    return NULL;

// ToDo: What we must todo in this case?
//  if (platform_util::IsPathExists(path + kTmpSuffix))
//    return NULL;  // Probably we already started downloading

  CefRefPtr<CefRequest> request = CefRequest::Create();
  request->SetURL(url);
  request->SetMethod("GET");
  request->SetFlags(UR_FLAG_ALLOW_CACHED_CREDENTIALS|UR_FLAG_NO_RETRY_ON_5XX|UR_FLAG_SKIP_CACHE);

  // Create and start the new CefURLRequest.
  return CefURLRequest::Create(request, new DownloadClient(id, path, name), NULL);
}

DownloadClientDialogCallback::DownloadClientDialogCallback(std::string url)
  : url_ (url) {

}

void
DownloadClientDialogCallback::Continue(
    int selected_accept_filter,
    const std::vector<CefString>& file_paths) {

  if (file_paths.empty())
    return;

  std::string file = file_paths.cbegin()->ToString();
  std::string filename = helper::GetFileName(file);
  std::string id = std::to_string(helper::HashString(url_));

  CefRefPtr<CefURLRequest> request = DownloadClient::CreateRequest(
      id,
      url_,
      file,
      filename
  );

  if (request.get()) {
    ClientHandler::GetInstance()->RegisterDownload(id , request);
    DownloadStartEvent e(id, filename, file, url_, std::time(nullptr));
    EventBus::FireEvent(e);
  }
}
<commit_msg>Скорость в int64, исправлен type casting<commit_after>// Copyright (c) 2015 The Brick Authors.

#include "brick/download_client.h"

#include <ctime>
#include <fstream>

#include "include/cef_parser.h"
#include "include/base/cef_logging.h"
#include "brick/brick_types.h"
#include "brick/client_handler.h"
#include "brick/platform_util.h"
#include "brick/helper.h"

namespace {
  const char kTmpSuffix[] = ".brdown";
  const char kPageType[] = "text/html";
  const char kJsonType[] = "application/json";
  const char kDispositionHeaderName[] = "Content-Disposition";

  const int kHighPercentBound = 10 * 1024 * 1024;
  const int kMiddleBytesBound = 5 * 1024 * 1024;
  const int kHighBytesBound = 100 * 1024 * 1024;
  const int kLowPercentLimit = 5;
  const int kHighPercentLimit = 1;
  const int kLowBytesLimit = 512 * 1024;
  const int kMiddleBytesLimit = 1024 * 1024;
  const int kHighBytesLimit = 10 * 1024 * 1024;

  bool
  IsDownloadResponse(CefRefPtr<CefResponse> response) {
    // ToDo: checks Content-Disposition for all responses?
    const std::string mime_type = response->GetMimeType().ToString();

    if (mime_type.find(kPageType) == 0 || mime_type.find(kJsonType) == 0)
      return response->GetHeader(kDispositionHeaderName).ToString().find("attachment") == 0;

    return true;
  }

}  // namespace

DownloadClient::DownloadClient(const std::string& id, const std::string& path, const std::string& name)
    : id_ (id),
      file_path_ (path),
      file_name_ (name),
      last_percent_ (-1),
      last_bytes_ (-1) {

  CEF_REQUIRE_UI_THREAD();

  start_time_ = std::chrono::system_clock::now();
  tmp_file_path_ = path + kTmpSuffix;
  tmp_file_.open(tmp_file_path_, std::ofstream::binary);
}

void
DownloadClient::Detach() {
  CEF_REQUIRE_UI_THREAD();

  tmp_file_.close();
}

void
DownloadClient::OnRequestComplete(CefRefPtr<CefURLRequest> request) {
  CEF_REQUIRE_UI_THREAD();

  tmp_file_.close();
  DownloadClientStatus status;
  DownloadClientReason reason;

  if (request->GetRequestError() == ERR_NONE && request->GetResponse()->GetStatus() == 200) {
    if (!IsDownloadResponse(request->GetResponse())) {
      status = DC_STATUS_FAILED;
      reason = DC_REASON_NOT_ATTACHMENT;
      LOG(WARNING) << "Strange response type, not a file? ID: " << id_ << ". "
                   << "Url: " << request->GetRequest()->GetURL().ToString() << ". "
                   << "Type: " << request->GetResponse()->GetMimeType().ToString();

    } else if (rename(tmp_file_path_.c_str(), file_path_.c_str()) != 0) {
      status = DC_STATUS_FAILED;
      reason = DC_REASON_UNKNOWN;
      LOG(WARNING) << "Can't rename downloaded file. ID: " << id_ << ". "
                   << "Tmp path: " << tmp_file_path_ << "."
                   << "Result path: " << file_path_;

    } else {
      status = DC_STATUS_SUCCESS;
      reason = DC_REASON_NONE;
    }
  } else if (request->GetRequestError() == ERR_ABORTED) {
    status = DC_STATUS_FAILED;
    reason = DC_REASON_ABORTED;
    LOG(INFO) << "Download aborted. ID: " << id_ << ". "
              << "Url: " << request->GetRequest()->GetURL().ToString();

  } else {
    status = DC_STATUS_FAILED;
    reason = DC_REASON_HTTP;
    LOG(WARNING) << "Download failed. ID: " << id_ << ". "
                 << "Url: " << request->GetRequest()->GetURL().ToString() << "."
                 << "Reason: " << request_util::GetErrorString(request->GetRequestError());
  }

  if (status != DC_STATUS_SUCCESS) {
    unlink(tmp_file_path_.c_str());
  }

  DownloadCompleteEvent e(id_, file_path_, status, reason);
  EventBus::FireEvent(e);
}

void
DownloadClient::OnDownloadProgress(CefRefPtr<CefURLRequest> request, int64 current, int64 total) {
  bool percent_mode = (total > 0);

  int progress = 0;
  if (percent_mode) {
    progress = static_cast<int>(current * 100.0 / total);
    if (last_percent_ != -1) {
      const int delta_progress = progress - last_percent_;
      int limit;
      if (current < kHighPercentBound) {
        limit = kLowPercentLimit;
      } else {
        limit = kHighPercentLimit;
      }

      if (delta_progress < limit)
        return;
    }

    last_percent_ = progress;
  } else {
    if (last_bytes_ != -1) {
      const int64 delta_bytes = current - last_bytes_;
      int limit;
      if (current < kMiddleBytesBound) {
        limit = kLowBytesLimit;
      } else if (current < kHighBytesBound) {
        limit = kMiddleBytesLimit;
      } else {
        limit = kHighBytesLimit;
      }

      if (delta_bytes < limit)
        return;
    }

    last_bytes_ = current;
  }

  const auto diff_time = std::chrono::system_clock::now() - start_time_;
  const auto time_elapsed =
      std::chrono::duration_cast<std::chrono::milliseconds>(diff_time).count();

  int64 speed = 0;
  if (time_elapsed > 0) {
    speed = static_cast<int64>(current * 1000 / time_elapsed);
  }

  DownloadProgressEvent e(id_, progress, speed, current, total);
  EventBus::FireEvent(e);
}

void
DownloadClient::OnDownloadData(CefRefPtr<CefURLRequest> request,
                             const void* data,
                             size_t data_length) {

  CEF_REQUIRE_UI_THREAD();
  tmp_file_.write(static_cast<const char*>(data), data_length);
}

// static methods

CefRefPtr<CefURLRequest>
DownloadClient::CreateRequest(
    const std::string& id,
    const std::string& url,
    const std::string& path,
    const std::string& name) {

  CEF_REQUIRE_UI_THREAD();

  if (!platform_util::MakeDirectory(helper::BaseDir(path)))
    return NULL;

// ToDo: What we must todo in this case?
//  if (platform_util::IsPathExists(path + kTmpSuffix))
//    return NULL;  // Probably we already started downloading

  CefRefPtr<CefRequest> request = CefRequest::Create();
  request->SetURL(url);
  request->SetMethod("GET");
  request->SetFlags(UR_FLAG_ALLOW_CACHED_CREDENTIALS|UR_FLAG_NO_RETRY_ON_5XX|UR_FLAG_SKIP_CACHE);

  // Create and start the new CefURLRequest.
  return CefURLRequest::Create(request, new DownloadClient(id, path, name), NULL);
}

DownloadClientDialogCallback::DownloadClientDialogCallback(std::string url)
  : url_ (url) {

}

void
DownloadClientDialogCallback::Continue(
    int selected_accept_filter,
    const std::vector<CefString>& file_paths) {

  if (file_paths.empty())
    return;

  std::string file = file_paths.cbegin()->ToString();
  std::string filename = helper::GetFileName(file);
  std::string id = std::to_string(helper::HashString(url_));

  CefRefPtr<CefURLRequest> request = DownloadClient::CreateRequest(
      id,
      url_,
      file,
      filename
  );

  if (request.get()) {
    ClientHandler::GetInstance()->RegisterDownload(id , request);
    DownloadStartEvent e(id, filename, file, url_, std::time(nullptr));
    EventBus::FireEvent(e);
  }
}
<|endoftext|>