// Expose Espressif SDK functionality
extern "C" {
//#include "user_interface.h"
  typedef void (*freedom_outside_cb_t)(uint8 status);
  int  wifi_register_send_pkt_freedom_cb(freedom_outside_cb_t cb);
  void wifi_unregister_send_pkt_freedom_cb(void);
  int  wifi_send_pkt_freedom(uint8 *buf, int len, bool sys_seq);
}
#include <WiFi.h>
#include "./structures.h"
#define MAX_APS_TRACKED 100
#define MAX_CLIENTS_TRACKED 200
#define MAX_KNOWN_TRACKED 100
char foundOne = 'n';
beaconInfo apsKnown[MAX_APS_TRACKED];                    // Array to save MACs of known APs
int apsKnownCount = 0;                                     // Number of known APs
int nothing_new = 0;                                     // Use not clear
clientInfo clientsKnown[MAX_CLIENTS_TRACKED];            // Array to save MACs of known CLIENTs
int clientsKnownCount = 0;                                 // Number of known CLIENTs
whoInfo whosKnown[MAX_KNOWN_TRACKED];                            // Identified MAC addresses 
int whosCount = 0;                                         // Number of known whos
//=========================================================================================================================
void registerWho (uint8_t whoStation[ETH_MAC_LEN], uint8_t whoName[8] ) {
    //memcpy(&clients_known[clients_known_count], &ci, sizeof(who[0]));
    for (int i = 0; i < 15; i++)   {
      whosKnown[whosCount].whoName[i] = whoName[i]; 
    }
    for (int i = 0; i < ETH_MAC_LEN; i++)   {
      whosKnown[whosCount].whoStation[i] = whoStation[i]; 
    }
    if ((unsigned int) whosCount == sizeof (whosKnown) / sizeof (whosKnown[0]) ) {
      Serial.printf("at max for Who Info.\n");
    }
    whosCount++;
}
//=========================================================================================================================
int registerBeacon(beaconInfo beacon) {
  int known = 0;   // Clear known flag
  for (int u = 0; u < apsKnownCount; u++)  {
    if (! memcmp(apsKnown[u].bssid, beacon.bssid, ETH_MAC_LEN)) {
      known = 1; // AP known => Set known flag
      break;
    }   
  }
  if (! known) { // AP is NEW, copy MAC to array and return it
    foundOne = 'y';
    memcpy(&apsKnown[apsKnownCount], &beacon, sizeof(beacon));
    apsKnownCount++;
    if ((unsigned int) apsKnownCount >=  sizeof (apsKnown) / sizeof (apsKnown[0]) ) {
      Serial.printf("exceeded max aps_known\n");
      apsKnownCount = 0;
    }
  }
  return known;
}
//=========================================================================================================================
int registerClient(clientInfo ci) {
  int known = 0;   // Clear known flag
  for (int u = 0; u < clientsKnownCount; u++){
    if (! memcmp(clientsKnown[u].station, ci.station, ETH_MAC_LEN)) {
      known = 1; // Client Known
      break;
    }
  }
  if (! known){
    foundOne = 'y';
    memcpy(&clientsKnown[clientsKnownCount], &ci, sizeof(ci));
    clientsKnownCount++;
    if ((unsigned int) clientsKnownCount >= sizeof (clientsKnown) / sizeof (clientsKnown[0]) ) {
      Serial.printf("exceeded max clients_known\n");
      clientsKnownCount = 0;
    }
  }
  return known;
}
//=========================================================================================================================
void printWho(whoInfo who)  {
    Serial.printf("[%15s] ", who.whoName);
    for (int i = 0; i < 6; i++) {
      if ( i < 5) {
        Serial.printf("%02x:", who.whoStation[i]);
      } else {
        Serial.printf("%02x", who.whoStation[i]);
      }
    }
    Serial.print('\n');
}
//=========================================================================================================================
void printBeacon(beaconInfo beacon)  {
  if (beacon.err != 0) {
    //Serial.printf("BEACON ERR: (%d)  ", beacon.err);
  } else {
    Serial.printf("BEACON:                   <== [%32s]  ", beacon.ssid);
    for (int i = 0; i < 6; i++) {
      if (i < 5) {
        Serial.printf("%02x:", beacon.bssid[i]);
      } else {
        Serial.printf("%02x", beacon.bssid[i]);
      }
    }
    Serial.printf("   %2d", beacon.channel);
    Serial.printf("   %4d\r\n", beacon.rssi);
  }
}
//=========================================================================================================================
void printClient(clientInfo ci) {
  int u = 0;
  int known = 0;                    //AP is known (1 => yes 0 => no)
  if (ci.err != 0) {
    // nothing
  } else {
    Serial.printf("DEVICE: ");
    for (int i = 0; i < 6; i++) {
      if (i < 5) {
        Serial.printf("%02x:", ci.station[i]);
      } else {
        Serial.printf("%02x", ci.station[i]);
      }
    }
    Serial.printf(" ==> ");
    for (u = 0; u < apsKnownCount; u++) {
      if (! memcmp(apsKnown[u].bssid, ci.bssid, ETH_MAC_LEN)) {
        Serial.printf("[%32s]", apsKnown[u].ssid);
        known = 1;     // AP known => Set known flag
        break;
      }
    }
    if (! known)  {                                            //above this is an integer flag here it is a boolean :(
      Serial.printf("   Unknown/Malformed packet \r\n");
      //  for (int i = 0; i < 6; i++) Serial.printf("%02x ", ci.bssid[i]);
    } else {
      Serial.printf("%2s", " ");
      for (int i = 0; i < 6; i++) {
        if (i < 5) {
          Serial.printf("%02x:", ci.ap[i]);
        } else {
          Serial.printf("%02x", ci.ap[i]);
        }
      }
      Serial.printf("  %3d", apsKnown[u].channel);
      Serial.printf("   %4d  ", ci.rssi);
      Serial.printf("[%15s]", ci.bssidWhoName);
      Serial.print("\n");
    }
  }
}
//=========================================================================================================================
void promisc_cb(uint8_t *buf, uint16_t len)  {
  int i = 0;
  uint16_t seq_n_new = 0;
  if (len == 12) { // Not beacon, not data, not QOS (unknown what it is)
    //struct RxControl *sniffer = (struct RxControl*) buf; // Do Nothing with this?? ==> comment for now
  } else if (len == 128) { //Beacon
    struct sniffer_buf2 *sniffer = (struct sniffer_buf2*) buf;
    struct beaconInfo beacon = parseBeacon(sniffer->buf, 112, sniffer->rx_ctrl.rssi);
    if (registerBeacon(beacon) == 0) {
      //printBeacon(beacon); // uses too much time
      nothing_new = 0;
    }
  } else { // Client (data or QOS)
    struct sniffer_buf *sniffer = (struct sniffer_buf*) buf;
    if ((sniffer->buf[0] == 0x08) || (sniffer->buf[0] == 0x88)) {      //Is it data?
      struct clientInfo ci = parseClient(sniffer->buf, 36, sniffer->rx_ctrl.rssi, sniffer->rx_ctrl.channel);
      if (memcmp(ci.bssid, ci.station, ETH_MAC_LEN)) {
        if (registerClient(ci) == 0) {
          //printClient(ci); // uses too much time
          nothing_new = 0;  // unkown use see other code to see why
        }
      }
    }
  }
  //Serial.print("$");
}


