#include <GithubDownloader.h>
#include <FS.h>
  
Stream& GithubDownloader::streamFile(const String& path) {
  if (!client.connect(GITHUB_RAW_DOMAIN, 443)) {
    Serial.println("Failed to connect to github over HTTPS.");
  }
  
  if (!client.verify(GITHUB_SSL_FINGERPRINT, GITHUB_RAW_DOMAIN)) {
    Serial.println("Failed to verify github certificate");
  }
  
  client.print(String("GET ") + path + " HTTP/1.1\r\n" +
               "Host: " + GITHUB_RAW_DOMAIN + "\r\n" +
               "Connection: close\r\n\r\n");
               
  return client;
}
  
Stream& GithubDownloader::streamFile(const String& username, const String& repo, const String& path) {
  return streamFile(buildPath(username, repo, path));
}
  
bool GithubDownloader::downloadFile(const String& path, Stream& dest) {
  Stream& client = streamFile(path);
  
  if (client.available()) {
    if (!client.find("\r\n\r\n")) {
      Serial.println("Error seeking to body");
      return false;
    }
  } else {
    Serial.println("Failed to open stream to Github");
    return false;
  }
  
  printf("Downloading...\n");
  size_t bytes = 0;
  size_t nextCheckpoint = 4096;
               
  while (client.available()) {
    size_t l = client.readBytes(buffer, GITHUB_DOWNLOADER_BUFFER_SIZE);
    size_t w = dest.write(buffer, l);
    
    dest.flush();
    
    if (w != l) {
      printf("Error writing to stream. Expected to write %d bytes, but only wrote %d\n", l, w);
      return false;
    }
    
    bytes += w;
    printf(".");
    
    if (bytes >= nextCheckpoint) {
      printf(" [%d KB]\n", bytes/1024);
      nextCheckpoint += 4096;
    }
    
    yield();
  }
  
  printf("\n");
  
  return true;
}

bool GithubDownloader::downloadFile(const String& username, const String& repo, const String& repoPath, Stream& dest) {
  return downloadFile(buildPath(username, repo, repoPath), dest);
}

bool GithubDownloader::downloadFile(const String& username, const String& repo, const String& repoPath, const String& fsPath) {
  String tmpFile = fsPath + ".download_tmp";
  File f = SPIFFS.open(tmpFile.c_str(), "w");
  
  if (!f) {
    Serial.print("ERROR - could not open file for downloading: ");
    Serial.println(fsPath);
    return false;
  }
  
  if (!downloadFile(buildPath(username, repo, repoPath), f)) {
    f.close();
    return false;
  }
  
  f.flush();
  f.close();
  
  SPIFFS.remove(fsPath);
  SPIFFS.rename(tmpFile, fsPath);
  
  printf("Finished downloading file: %s\n", fsPath.c_str());
  
  return true;
}
  
String GithubDownloader::buildPath(const String& username, const String& repo, const String& repoPath) {
  String path = String("/") + username + "/" + repo + "/master/" + repoPath;
  return path;
}