// MQTT callback
void mqttCallback(char* topic, byte* payload, unsigned int length) {
  //Serial.print("Message arrived [");
  //Serial.print(topic);
  //Serial.println("] ");
  /*for (int i = 0; i < length; i++) {
    Serial.print((char)payload[i]);
    }
    Serial.println();*/

  if (strcmp(topic, mqtt_topic_in) == 0) { //if topic = mqtt_topic_in
    Serial.print("received MQTT topic: '");
    Serial.print(mqtt_topic_in);
    Serial.print("', payload: '");

    for (int i = 0; i < length; i++) {
      cmdPayload[i] = (char)payload[i];
    }
    cmdPayload[length] = '\0';

    Serial.print(cmdPayload);
    Serial.println("'");

    cmdInQueue = true;

  }//if topic = mqtt_topic_in

  else if (strcmp(topic, mqtt_topic_in_pcpwr) == 0) {
    Serial.print("received MQTT topic: '");
    Serial.print(mqtt_topic_in_pcpwr);
    Serial.print("', payload: '");
    for (int i = 0; i < length; i++) {
      cmdPayload[i] = (char)payload[i];
    }
    cmdPayload[length] = '\0';
    Serial.print(cmdPayload);
    Serial.println("'");
    if(strcmp(cmdPayload, "ON") == 0 || strcmp(cmdPayload, "on") == 0 || atoi(cmdPayload) == 1) {
      PC_pwrSwitchShort();
    }
  }

  else if (strcmp(topic, mqtt_topic_in_pcpwrh) == 0) {
    Serial.print("received MQTT topic: '");
    Serial.print(mqtt_topic_in_pcpwrh);
    Serial.print("', payload: '");
    for (int i = 0; i < length; i++) {
      cmdPayload[i] = (char)payload[i];
    }
    cmdPayload[length] = '\0';
    Serial.print(cmdPayload);
    Serial.println("'");
    if(strcmp(cmdPayload, "ON") == 0 || strcmp(cmdPayload, "on") == 0 || atoi(cmdPayload) == 1) {
      PC_pwrSwitchHold();
    }
  }
  
  else if (strcmp(topic, mqtt_topic_in_pcrst) == 0) {
    Serial.print("received MQTT topic: '");
    Serial.print(mqtt_topic_in_pcrst);
    Serial.print("', payload: '");
    for (int i = 0; i < length; i++) {
      cmdPayload[i] = (char)payload[i];
    }
    cmdPayload[length] = '\0';
    Serial.print(cmdPayload);
    Serial.println("'");
    if(strcmp(cmdPayload, "ON") == 0 || strcmp(cmdPayload, "on") == 0 || atoi(cmdPayload) == 1) {
      PC_resSwitch();
    }
  }

  else if (strcmp(topic, mqtt_topic_in_pconsleep) == 0) {
    Serial.print("received MQTT topic: '");
    Serial.print(mqtt_topic_in_pconsleep);
    Serial.print("', payload: '");
    for (int i = 0; i < length; i++) {
      cmdPayload[i] = (char)payload[i];
    }
    cmdPayload[length] = '\0';
    Serial.print(cmdPayload);
    Serial.println("'");
    if(strcmp(cmdPayload, "ON") == 0 || strcmp(cmdPayload, "on") == 0 || atoi(cmdPayload) == 1) {
      PC_toOn();
    }
    else if(strcmp(cmdPayload, "OFF") == 0 || strcmp(cmdPayload, "off") == 0 || atoi(cmdPayload) == 0 || strcmp(cmdPayload, "SLEEP") == 0 ) {
      PC_toSleep();
    }
  }
  
}//mqttCallback

void mqttPrepareConnection() {
  //Serial.print("MQTT connection with ");
  if (strlen(mqtt_user) > 0 && strlen(mqtt_willTopic) == 0) {
    // user and password, no Last Will
    //Serial.println("user and password, no Last Will");
    mqttMode = 2;
  }
  else if (strlen(mqtt_user) > 0 && strlen(mqtt_willTopic) > 0) {
    // user, password and Last Will
    //Serial.println("user, password and Last Will");
    mqttMode = 3;
  }
  else if (strlen(mqtt_user) == 0 && strlen(mqtt_willTopic) > 0) {
    // Last Will but no user and password
    //Serial.println("Last Will but no user and password");
    mqttMode = 4;
  }
  else {
    // no user, password and no Last Will
    //Serial.println("no user, password and no Last Will");
    mqttMode = 1;
  }

  sprintf(mqtt_topic_in_pcpwr, "%s/%s", mqtt_topic_in, "PC-POWER");
  sprintf(mqtt_topic_in_pcpwrh, "%s/%s", mqtt_topic_in, "PC-POWER-HOLD");
  sprintf(mqtt_topic_in_pcrst, "%s/%s", mqtt_topic_in, "PC-RESET");
  sprintf(mqtt_topic_in_pconsleep, "%s/%s", mqtt_topic_in, "PC-ON-SLEEP");
  
}

boolean mqttReconnect() {
  mqttclient.disconnect();
  delay(10);
  // Create a random MQTT client ID
  String mqttClientId = "ESP8266Client-";
  //mqttClientId += String(random(0xffff), HEX);
  mqttClientId += String(deviceName);

  if (serialdebug) Serial.print("connecting to MQTT broker with ");

  boolean connRes;
  mqttReconnectAttempts++;

  mqttPrepareConnection();
  switch (mqttMode) {
    case 1:
      if (serialdebug) Serial.println("no user, password and no Last Will");
      connRes = mqttclient.connect(mqttClientId.c_str());
      break;
    case 2:
      if (serialdebug) Serial.println("user and password, no Last Will");
      connRes = mqttclient.connect(mqttClientId.c_str(), mqtt_user, mqtt_pass);
      break;
    case 3:
      if (serialdebug) Serial.println("user, password and Last Will");
      connRes = mqttclient.connect(mqttClientId.c_str(), mqtt_user, mqtt_pass, mqtt_willTopic, mqtt_willQos, mqtt_willRetain, mqtt_willMsg);
      break;
    case 4:
      if (serialdebug) Serial.println("Last Will, no user and password");
      connRes = mqttclient.connect(mqttClientId.c_str(), mqtt_willTopic, mqtt_willQos, mqtt_willRetain, mqtt_willMsg);
      break;
  }

  if (serialdebug) {
    Serial.print("... attempt: ");
    Serial.print(mqttReconnectAttempts);
    Serial.println();
  }

  if (connRes) {
    if (serialdebug) {
      Serial.print("MQTT connected. Reconnects: ");
      Serial.println(mqttReconnects);
    }
    mqttReconnects++;

    // Once connected, publish an announcement...
    //    char outMsg[30];
    //    sprintf(outMsg, "connected, %d reconnects", mqttReconnects);
    //    mqttclient.publish(mqtt_topic_out, outMsg, mqtt_outRetain);

    if (strlen(mqtt_willTopic) > 4) {
      mqttclient.publish(mqtt_willTopic, mqtt_connMsg, mqtt_willRetain);
    }
    publishStatus();
    
    publishPCPowerState(true);
    
    //mqttclient.publish(mqtt_topic_out, "connected");
    // ... and resubscribe
    if (serialdebug) Serial.println("Subscribed to:");
    if (strlen(mqtt_topic_in) > 0) {
      if (mqttclient.subscribe(mqtt_topic_in)) {
        if (serialdebug) Serial.println(mqtt_topic_in);
      }
    }
    if (strlen(mqtt_topic_in_pcpwr) > 0) {
      if (mqttclient.subscribe(mqtt_topic_in_pcpwr)) {
        if (serialdebug) Serial.println(mqtt_topic_in_pcpwr);
      }
    }
    if (strlen(mqtt_topic_in_pcpwrh) > 0) {
      if (mqttclient.subscribe(mqtt_topic_in_pcpwrh)) {
        if (serialdebug) Serial.println(mqtt_topic_in_pcpwrh);
      }
    }
    if (strlen(mqtt_topic_in_pcrst) > 0) {
      if (mqttclient.subscribe(mqtt_topic_in_pcrst)) {
        if (serialdebug) Serial.println(mqtt_topic_in_pcrst);
      }
    }
    if (strlen(mqtt_topic_in_pconsleep) > 0) {
      if (mqttclient.subscribe(mqtt_topic_in_pconsleep)) {
        if (serialdebug) Serial.println(mqtt_topic_in_pconsleep);
      }
    }

    
    return mqttclient.connected();
  }
  else {
    if (serialdebug) {
      Serial.print("MQTT connect FAILED, rc=");
      Serial.println(mqttclient.state());
    }
  }
} //mqttReconnect




void mqttClientInit() {
  mqttclient.setServer(mqtt_server, mqtt_port);
  mqttclient.setCallback(mqttCallback);
  mqttLastReconnectAttempt = 0;
  mqttReconnectAttempts = 0;
}

int lastWifiStatus;

void mqttHandleConnection() {
  if ( WiFi.status() == WL_CONNECTED ) {
    // MQTT reconnect if not connected (nonblocking)
    if (!mqttclient.connected()) {
      if ((millis() - mqttLastReconnectAttempt) > 5000) {
        mqttLastReconnectAttempt = millis();
        if (mqttReconnect()) { // Attempt to reconnect
          //mqttLastReconnectAttempt = 0;
        }
      }
    } 
    else { // Client connected
      mqttclient.loop();
    }
  }
}

void publishStatus() {
  char outMsg[60];
  //long upTime = millis() / 1000;
  sprintf(outMsg, "MQTT connected, reconnects: %d, uptime: %s, free_heap: %d", mqttReconnects - 1, uptimeStr, ESP.getFreeHeap());
  mqttclient.publish(mqtt_topic_out, outMsg, mqtt_outRetain);
}
