#include <Arduino.h>
#include <WiFi.h>
#include <WiFiClientSecure.h>
#include <HTTPClient.h>
#include <WebServer.h>
#include <FS.h>
#include "SPIFFS.h"
#include "ESPmDNS.h"
#include <Ticker.h>
#include <Audio.h>

Ticker myTicker;
//被读取的文件位置和名称
String flash_wifi = "/wifi.txt";
WebServer webServer(80);  // 创建网络服务器对象，HTTP服务的标准端口为：80
String ssid = "";
String passwd = "";
String html;
String espIp;
String localServerIP;

WiFiClient client;
String localserver;
// Digital I/O used
#define I2S_DOUT 25
#define I2S_BCLK 26
#define I2S_LRC 27
Audio audio;
void hexdump(const void *mem, uint32_t len, uint8_t cols = 16) {
  const uint8_t *src = (const uint8_t *)mem;
  Serial.printf("\n[HEXDUMP] Address: 0x%08X len: 0x%X (%d)", (ptrdiff_t)src, len, len);
  for (uint32_t i = 0; i < len; i++) {
    if (i % cols == 0) {
      Serial.printf("\n[0x%08X] 0x%08X: ", (ptrdiff_t)src, i);
    }
    Serial.printf("%02X ", *src);
    src++;
  }
  Serial.printf("\n");
}

void setup() {
  Serial.begin(115200);
  //Serial.setDebugOutput(true);
  if (FlashConnetWifi() == false) {
    HtmlSetWifi();
  }
  localserver = "http://" + localServerIP + "/apiview/everyday5english";
  audio.setPinout(I2S_BCLK, I2S_LRC, I2S_DOUT);
  audio.setVolume(19);  // 0...21   音量大小
  String ttmps1 = HttpPost(localserver, "MusicId=0");
  String tmps1 = "http://" + localServerIP + "/" + ttmps1;
  //Serial.println(tmps1);
  audio.connecttohost(tmps1.c_str());
  delay(500);
}

void loop() {
  audio.loop();
}

String HttpPost(String url, String postStr) {
  HTTPClient http;
  String response;
  http.begin(client, url);
  http.setTimeout(2000);
  //需要传输的数据
  char dataBuff[postStr.length()];
  strcpy(dataBuff, postStr.c_str());
  //头信息，需要的反注释就可以
  http.addHeader("Content-Type", "application/x-www-form-urlencoded");
  int httpCode = http.POST(dataBuff);
  if (httpCode == 200) {
    response = http.getString();
    return response;
  } else {
    return "";
  }
  http.end();
}
void HtmlSetWifi() {
  WifiScan();
  ApOpen();
  delay(1000);
  Serial.println("启动网页");
  //5分后重启 防止停电后复电，路由器连接WIFI速度慢于ESP导致ESP连接不到路由器进入无限AP模式，所以这里只让AP激活5分钟后就重启
  myTicker.once(300, EspRestart);
  delay(200);
  WebServerOpen();
  while (1) {
    webServer.handleClient();  // 检查网络服务请求并处理
  }
}

void EspRestart() {
  ESP.restart();
}
//扫描附件WIFI
void WifiScan() {
  WiFi.disconnect();
  Serial.begin(115200);
  WiFi.mode(WIFI_STA);
  delay(100);
  int n = WiFi.scanNetworks();
  if (n > 0) {
    Serial.println(n);
    String a = "附近WiFi <select id=\"ssid\">";
    for (int i = 0; i < n; i++) {
      Serial.println(WiFi.SSID(i));
      a = a + "<option value=\"" + WiFi.SSID(i) + "\">" + WiFi.SSID(i) + "</option>";
      delay(50);
    }
    String HtmlStart = String("") + "<!DOCTYPE html>" + "<html>" + "<head>" + "<meta charset=\"utf-8\">" + "<meta name=\"viewport\" content=\"width=device-width,initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no\" />" + "<title>设置WiFi</title>" + "<link rel=\"stylesheet\" href=\"\">" + "</head>" + "<script>" + "onload  = function() {" + "document.getElementById(\"up\").onclick = function(){" + "var ssida=document.getElementById(\"ssid\").value;" + "var ssid=ssida.replace(/\\s+/g, \" \");" + "var passwda=document.getElementsByTagName('input')[0].value;" + "var passwd=passwda.replace(/\\s+/g, \" \");" + "xhr = new XMLHttpRequest();" + "xhr.open(\"POST\",\"./SetWifi\",true);" + "var posts = (\"ssid=\"+ssid+\"&passwd=\"+ passwd);" + "xhr.setRequestHeader(\"Content-Type\",\"application/x-www-form-urlencoded\");" + "xhr.send(posts);" + "xhr.onreadystatechange = function(){" + "if(this.readyState == 4 && this.status == 200){" + "alert(this.responseText);" + "}" + "}" + "}" + "}" + "</script>" + "<body>";
    String HtmlEnd = String("") + "<p>WiFi密码<input type=\"text\" id=\"passwd\"></p>" + "<input type=\"submit\" id=\"up\" value=\"设 置\">" + "<hr/>" + "<div>如果附近WiFi没有显示到自己的WIFI<div>" + "<div>请重启或离信号近点</div>" + "<div>连接成功AP热点退出转WIFI_STA</div>" + "</body>" + "</html>";
    a = a + "</select>";
    html = HtmlStart + a + HtmlEnd;
  } else {
    html = "扫描不到网络";
    Serial.println("扫描不到网络");
  }
}
void SetWifi() {
  ssid = webServer.arg(0);
  passwd = webServer.arg(1);
  const char *Ssid = ssid.c_str();
  const char *Passwd = passwd.c_str();
  String sp = ssid + "&" + passwd;

  Serial.println(sp);
  Serial.begin(115200);
  delay(500);
  WiFi.begin(Ssid, Passwd);
  WiFi.mode(WIFI_STA);
  delay(200);
  Serial.println("wifi_connet");
  int ii = 0;
  for (ii; ii < 20; ii++) {
    delay(500);
    Serial.print(".");
    if (WiFi.status() == WL_CONNECTED) {
      webServer.send(200, "text/plane", "Wifi密码正确，ESP准备重启");
      webServer.close();
      delay(500);
      WiFi.disconnect();
      delay(500);
      //写入数据
      SPIFFS.format();
      delay(500);
      SPIFFS.begin();
      File dataFile = SPIFFS.open(flash_wifi, "w");
      dataFile.println(sp);
      dataFile.close();
      Serial.println("HTML连接成功");
      delay(1000);
      ESP.restart();
    }
  }
  webServer.send(200, "text/plane", "Wifi密码错误，请重新输入");
  //HtmlSetWifi();
}
//------- 展示页面-------
void handleRoot() {
  webServer.send(500, "text/html", html);
}
void handleNotFound(void) {
  webServer.send(404, "text/plain", "404-The page is not Found!");
}


void ApOpen() {
  Serial.begin(115200);
  WiFi.mode(WIFI_AP);
  IPAddress local_IP(192, 168, 168, 2);
  IPAddress gateway(192, 168, 168, 1);
  IPAddress subnet(255, 255, 255, 0);
  WiFi.softAPConfig(local_IP, gateway, subnet);

  //启动AP模式，并设置账号和密码
  boolean result = WiFi.softAP("192.168.168.2", "192.168.168.2");
  if (result) {
    //输出 soft-ap ip地址
    Serial.println(String("Soft-AP IP address = ") + WiFi.softAPIP());
  }
}
void WebServerOpen() {
  //-----------------启动webserver网络服务--------------------
  webServer.begin();              // 启用网络服务
  webServer.on("/", handleRoot);  // / 在HTTP中，表示请求首页服务，
  webServer.on("/SetWifi", SetWifi);
  webServer.onNotFound(handleNotFound);  // 当服务器没找到所需的服务，调用404函数
  Serial.println("webserver started");
}

bool FlashConnetWifi() {
  Serial.begin(115200);
  delay(500);
  //是否存在数据
  SPIFFS.begin();
  if (SPIFFS.exists(flash_wifi) == false) {
    Serial.print(flash_wifi);
    Serial.println(" NOT FOUND");
    return false;
  }

  File dateFile = SPIFFS.open(flash_wifi, "r");
  String result;
  for (int i = 0; i < dateFile.size(); i++) {
    //Serial.print((char)dateFile.read());
    result += (char)dateFile.read();
  }
  //去除前后空格
  result.trim();
  Serial.println(result);
  int i = result.indexOf("&");

  String wifiname = result.substring(0, i);
  String wifipw = result.substring(i + 1);
  const char *WifiName = wifiname.c_str();
  const char *WifiPw = wifipw.c_str();
  Serial.println(WifiName);
  Serial.println(WifiPw);
  WiFi.begin(WifiName, WifiPw);
  delay(500);
  WiFi.mode(WIFI_STA);
  Serial.println("FlashConnetWifi->connet");
  int ii = 0;
  for (ii; ii < 20; ii++) {
    delay(500);
    Serial.print(" . ");
    if (WiFi.status() == WL_CONNECTED) {
      Serial.println("FlashConnetWifi 闪存配置连接成功");
      espIp = WiFi.localIP().toString();
      localServerIP = espIp.substring(0, espIp.lastIndexOf(".")) + ".254";
      return true;
    }
  }
  Serial.println("FlashConnetWifi->false");
  return false;
}
// optional
void audio_info(const char *info) {
  // Serial.print("info        "); Serial.println(info);
  String str = info;
  if (str.indexOf("End of webstream") != -1) {
    delay(900);
    String ttmps = HttpPost(localserver, "MusicId=next");
    String tmps2 = "http://" + localServerIP + "/" + ttmps;
    audio.connecttohost(tmps2.c_str());
  }
}
void audio_id3data(const char *info) {  //id3 metadata
  Serial.print("id3data     ");
  Serial.println(info);
}
void audio_eof_mp3(const char *info) {  //end of file
  Serial.print("eof_mp3     ");
  Serial.println(info);
}
void audio_showstation(const char *info) {
  Serial.print("station     ");
  Serial.println(info);
}
void audio_showstreamtitle(const char *info) {
  Serial.print("streamtitle ");
  Serial.println(info);
}
void audio_bitrate(const char *info) {
  Serial.print("bitrate     ");
  Serial.println(info);
}
void audio_commercial(const char *info) {  //duration in sec
  Serial.print("commercial  ");
  Serial.println(info);
}
void audio_icyurl(const char *info) {  //homepage
  Serial.print("icyurl      ");
  Serial.println(info);
}
void audio_lasthost(const char *info) {  //stream URL played
  Serial.print("lasthost    ");
  Serial.println(info);
}