bool accessPoint = false;
bool stationMode = false;

uint32_t stationModeStart = 0;
uint32_t apButtonStart = 0;


void startAccessPoint();
void startStationMode();


void initWiFi()
{
  WiFi.disconnect();
  WiFi.softAPdisconnect();

  accessPoint = connectionSettings->flag(AccessPoint);
  stationMode = connectionSettings->flag(StationMode) && connectionSettings->ssid() != nullptr;

  WiFi.mode(accessPoint && stationMode ? WIFI_AP_STA :
            accessPoint ? WIFI_AP :
            stationMode ? WIFI_STA :
            WIFI_OFF);

  if (accessPoint)
    startAccessPoint();

  if (stationMode)
    startStationMode();
}


void updateWiFi()
{
  if (stationModeStart > 0)
  {
    bool isConnected = WiFi.status() == WL_CONNECTED;

    if (isConnected)
    {
      _d("WiFi :: connected, IP address: ");
      _dln(WiFi.localIP());

      stationModeStart = 0;
    }
    else if (stationMode && accessPoint &&
             currentTime - stationModeStart >= StationModeTimeout)
    {
      _dln("WiFi :: unable to connect, switching off station mode, status:");
      _dln(WiFi.status());

      #ifdef SerialDebug
      WiFi.printDiag(Serial);
      #endif

      // Connecting to access point is taking too long and is blocking
      // the access point mode, stop trying
      stationMode = false;
      WiFi.disconnect();
      WiFi.mode(WIFI_AP);
    }
  }


  if (!accessPoint)
  {
    if (digitalRead(systemSettings->pinAPButton()) == LOW)
    {
      if (apButtonStart == 0)
        apButtonStart = currentTime;
      else if (currentTime - apButtonStart >= APButtonHoldTime)
      {
        connectionSettings->flag(AccessPoint, true);
        connectionSettings->write();

        startAccessPoint();
        apButtonStart = 0;
      }
    }
    else if (apButtonStart > 0)
      apButtonStart = 0;
  }
}


void startAccessPoint()
{
  _dln("WiFi :: starting access point");
  String ssidString = DefaultAPSSIDPrefix + String(ESP.getChipId(), HEX);
  if (WiFi.softAP((const char *)ssidString.c_str()))
  {
    _d("WiFi :: IP address: ");
    _dln(WiFi.softAPIP());
  }
  else
    _d("WiFi :: failed to start soft access point");
}


void startStationMode()
{
  _d("WiFi :: starting station mode to: ");
  _dln(connectionSettings->ssid());

  stationModeStart = currentTime;

  if (connectionSettings->hostname() != nullptr)
    WiFi.hostname(connectionSettings->hostname());

  if (WiFi.begin(connectionSettings->ssid(), connectionSettings->password()))
  {
    if (connectionSettings->flag(DHCP))
      // I've had the same issue as described here with config(0, 0, 0):
      // https://stackoverflow.com/questions/40069654/how-to-clear-static-ip-configuration-and-start-dhcp
      wifi_station_dhcpc_start();
    else
      WiFi.config(connectionSettings->ip(), connectionSettings->gateway(), connectionSettings->subnetMask());
  }
  else
    _d("WiFi :: failed to start station mode");
}
