#ifndef VIZBLOCKS_H
#define VIZBLOCKS_H
#include "Arduino.h"
#include "Behaviours.h"
#include "ServoBehaviours.h"
#include "LEDBehaviours.h"

#include <ESP8266WiFi.h>
#include "Adafruit_MQTT.h"
#include "Adafruit_MQTT_Client.h"

#define MQTT_topic  "new001"
#define NUM_BACKGROUND_BEHAVIOURS 5

class VizBlocks {
  char* _ssid;
  char* _wifi_pass;
  char* _id;
  char* _server;
  int _port;
  BehaviourTable _behaviours;
  Behaviour* _active = nullptr;
  Behaviour* _background[NUM_BACKGROUND_BEHAVIOURS];
  int _loop_time = 5;
  Adafruit_MQTT_Client* _mqtt;
  Adafruit_MQTT_Subscribe* _device_subscription;

  Adafruit_MQTT_Publish* _announce;
  Adafruit_MQTT_Publish* _my_announce;
  String _my_announce_channel;

  Adafruit_MQTT_Publish* _input;
  Adafruit_MQTT_Publish* _my_input;
  String _my_input_channel;

  WiFiClient* _client;
  boolean _wifi;

  String capabilitiesJSON[50];

public:
  VizBlocks(char* id, char* ssid="VizBlocksNet", char* wifi_pass="VizBlocksAP",
    char* server="172.20.10.8",int port=1883);

  void command_callback(char *data, uint16_t len);

  void set_wifi(boolean v);

  /*
   * Set up the VizBlocks node - WiFi, MQTT
   */
  void init();

  /*
   * Add a behaviour to the list of possible behaviours
   */
  void add(Behaviour *b);

  /*
   * This is the main loop. It should be called from within loop() - really
   * this function is the only thing you should need to call. It will manage
   * it's own delay, so you can call as often as possible.
   */
  void run();

  /*
   * Read a command from the serial input and process it
   */
  void serial_command();

  /*
   * Read a command from the serial input and process it. It only waits for
   * 50ms to allow other behaviours to continue.
   */
  void mqtt_command();

  /*
   * Process a command. This means:
   * - split the command name from the arguments
   * - call process_command with the separated command and argument string
   */
  String process(String input);

  String input_event(String input);

  /*
   * Process a command and its arguments. This means:
   * - look for a Behaviour with the right name
   * - if found, then call that behaviour with the arguments (which are still a single string)
   */
  String process_command(String command, String args);

  /*
  * Function to connect and reconnect as necessary to the MQTT server.
  */
  // Should be called in the loop function and it will take care if connecting.
  void MQTT_connect();

  void generateCapabilitiesJSON();

  void announce(String doc);

  void announce_capabilities();

  void setID(char* id);

  char* getId();

};

/*
 * These behaviours depend on VizBlocks class so they must be included after
 * it has been defined.
 */
#include "CommsBehaviours.h"
#include "ButtonBehaviours.h"
#include "PotentiometerBehaviours.h"
#include "RotaryEncoderBehaviours.h"

#endif