#include <SD.h>

/**
 * This sketch was written in order to test the modifications I did to the SD card library
 * as well as testing it's stability
 * Created by Anatole SCHRAMM-HENRY the 12/12/2020
 * 
 * /!\ Do not forget to import the two reworked SD libraries in your Arduino librairies folder
 * /!\ Do not forget to create a /TEST folder at the root of your SD card
 */

void listDir(const char *dir)
{
  File parentDir = SD.open(dir);
  
  if(parentDir)
  {
    Serial.printf("Directory opened\nListing files :\n");
    do
    {
      File subFiles = parentDir.openNextFile();
    
      if(!subFiles)
        break;

      time_t tt = subFiles.getCreationTime();
      tm *ct = localtime(&tt);
      
      Serial.printf("- %s, %s, %d %s date : %d/%d/%d %d:%d:%d\n",subFiles.fullName(), subFiles.name(), subFiles.size(), subFiles.isDirectory() ? "Dir" : "File",
      ct->tm_mday,
      ct->tm_mon + 1,
      ct->tm_year + 1900,
      ct->tm_hour,
      ct->tm_min,
      ct->tm_sec);
      
      subFiles.close();
    }while(1);
    
    parentDir.close();
  }
  else
  {
    Serial.printf("Failed to list directory %s\n", dir);
  }
}

void displayCardInfo()
{
  FSInfo64 info;
  SD.info64(info);
  Serial.printf("Used space : %lu Bytes\n Total Space : %lu Bytes\n", info.usedBytes, info.totalBytes);
}

void createDir(const char *dir)
{
  if(SD.mkdir(dir))
  {
    Serial.println("Created new dir");
  }
  else
  {
    Serial.println("Failed to create new dir");
  }

  if(SD.exists(dir))
  {
    Serial.printf("%s exists\n", dir);
  }
  else
  {
    Serial.printf("%s does not exist\n", dir);
  }
}

void renameDir()
{
  if(SD.rename("/TEST/createdDir","/TEST/renamedDir"))
  {
    Serial.println("Renamed createdDir to renamedDir");
  }
  else
  {
    Serial.println("Failed to rename createdDir to renamedDir");
  }
}

void removeDir(const char *dir)
{
  if(SD.rmdir(dir))
  {
    Serial.printf("Removed %s\n", dir);
  }
  else
  {
    Serial.printf("Failed to remove %s", dir);
  }
}

void createFile()
{
  File f = SD.open("/TEST/newFile.md", FILE_WRITE);
  if(f)
  {
     Serial.println("newFile created successfully");
     f.close();
  }
  else
  {
    Serial.println("Failed to create newFile");
  }
}

void writeToFile()
{
  File f = SD.open("/TEST/newFile.md", FILE_WRITE);
  if(f)
  {
     Serial.println("Writing to file");
     f.print("This is the content of the newly created md file\nI hope you like it !\n");
     f.close();
  }
  else
  {
    Serial.println("Failed to write to newFile");
  }
}

void readFile()
{
  File f = SD.open("/TEST/newFile.md", FILE_READ);
  if(f)
  {
     Serial.println("File content :\n#");
     while(f.available())
     {
        Serial.write(f.read());
     }
     f.close();
     Serial.println("#");
  }
  else
  {
    Serial.println("Failed to read from newFile");
  }
}

void truncateFile()
{
  File f = SD.open("/TEST/newFile.md", FILE_WRITE);
  if(f)
  {
      Serial.println("Truncating file");
      f.truncate(15);
      f.close();
  }
  else
  {
    Serial.println("Failed to truncate newFile");
  }
}

void deleteFile()
{
  if(SD.exists("/TEST/newFile.md"))
  {
    if(SD.remove("/TEST/newFile.md"))
    {
      Serial.printf("Deleted newFile.md");
    }
    else
    {
      Serial.printf("Failed to delete newFile.md");
    }
  }
  else
  {
    Serial.printf("newFile.md does not exist");
  }
}

void testSuite()
{
  //displayCardInfo(); //Too slow ... 20 seconds at 80MHz on a 16GB card
  listDir("/TEST");
  createDir("/TEST/createdDir");
  listDir("/TEST");
  renameDir();
  listDir("/TEST");
  removeDir("/TEST/renamedDir");
  listDir("/TEST");
  createFile();
  listDir("/TEST");
  writeToFile();
  listDir("/TEST");
  readFile();
  truncateFile();
  readFile();
  listDir("/TEST");
  deleteFile();
  listDir("/TEST");

  //We test that the creation of a dir at the root of the card work
  createDir("/ROOT_DIR");
  listDir("/");
  removeDir("/ROOT_DIR");
  Serial.println("-----------------End of session--------------------");
}

//Sets the file creation or modification date and time
time_t timestampCB()
{
  return 1607774685;
}

void setup()
{
  Serial.begin(115200, SERIAL_8N1, SERIAL_TX_ONLY);
  Serial.println("Setup started");
  
  if(SD.begin(2,SPI_FULL_SPEED))
  {
    Serial.println("SDCard mounted");
    SD.setTimeCallback(&(timestampCB));
  }
  else
  {
    Serial.println("SDCard failed");
    return;
  }  
  Serial.println("Setup ended");
}

void loop()
{
  // nothing happens after setup finishes.
  testSuite();
  delay(5000);
}
