boolean BIT;
boolean STOP_LOOPING = false;

boolean ONLY_PRINT_ONCE_NO_POWER = true;
boolean ONLY_PRINT_ONCE_POWER_OK = true;

// millisFUN() - start
int INTERVAL_MESSAGE1 =  3000;
int INTERVAL_MESSAGE2 =  5000;
int INTERVAL_MESSAGE3 = 11000;
int INTERVAL_MESSAGE4 = 13000;

unsigned long time_1 = 0;
unsigned long time_2 = 0;
unsigned long time_3 = 0;
unsigned long time_4 = 0;
// milliaFUN() - end

void setup() {
  Serial.begin(115200);
  randomSeed(analogRead(A0));
  // toUpper();
  // toLower();
  // arrayofelements();
  // asciiprint();
  // bitShiftRight();
  // bodytemp();
  // hello_once();
  // floorplan();
  // findhighlow();
  // millisFUN();
  // numString();
  // onlyprintonce();
  // perm(6, 5);
  // pointers();
  rick();
  // rotateColorByte();
  // serialBlink(!BIT);
  // serialParseInt();
  // serialWrite();
  // stepperdegrees();
  // strCpyCat();
  // a2i();
  // zeropad();
  // spacepad();
  // add "STOP_LOOPING = true;" to function to stop after one looop
  // if (STOP_LOOPING) while (1);
}

void loop() {
  // serialPlotter();
  // onOff();
}

void rick() {
  char m[] = {"+mrrlvbsfd^kkldobsbK"}; //
  for (int i = 0; i < strlen(m) + 1; i++)
    Serial.write(m[strlen(m) - i] + 3);
  Serial.println();
}

void stepperdegrees() {
  for (int i = 0; i < 180 + 1; i++) {
    if (!((18 * i) % 90)) {
      Serial.print("Step: ");
      Serial.print(i);
      Serial.print(" Degree:");
      Serial.print(int(1.8 * i));
      Serial.println();
    }
  }
}

void zeropad() {
  float num = (random(1000) / 10);
  Serial.println(num);
  if (num < 1000) Serial.print("0");
  if (num < 100) Serial.print("0");
  if (num < 10) Serial.print("0");
  Serial.print(num);
}

void spacePad() {
  float num = (random(1000) / 10);
  if (num < 1000) Serial.print(" ");
  if (num < 100) Serial.print(" ");
  if (num < 10) Serial.print(" ");
  Serial.println(num);
}

void toUpper() {
  Serial.write(97 & ~0x20); // A = 65, a = 97, a - A = 32 (space), a & ~0x20 = A
  Serial.write(65 & ~0x20); // A = 65, a = 97, a - A = 32 (space), A & ~0x20 = A
}

void toLower() {
  Serial.write(97 | 0x20);  // A = 65, a = 97, a - A = 32 (space), a | 0x20 = a
  Serial.write(65 | 0x20);  // A = 65, a = 97, a - A = 32 (space), A | 0x20 = a
}

void serialPlotter() {
  int Data1 = analogRead(A0);
  int Data2 = 512;

  Serial.print("Trace1:");
  Serial.print(Data1);
  Serial.print(",");
  Serial.print("Trace2:");
  Serial.println(Data2);
}

void onOff() {
  digitalWrite(LED_BUILTIN, HIGH);
  Serial.print("ON ");
  delay(3000);
  digitalWrite(LED_BUILTIN, LOW);
  Serial.print("OFF ");
  delay(3000);
}

void a2i() {
  char a2i[] = {"876138974613847139328789982362865298249786327478741639741638746138761429783641928746129378461293746"};
  int x = sizeof(a2i) / sizeof(a2i[0]);
  for (int i = 0; i < x; i++) {
    // int y = a2i[i] - 48;
    int y = a2i[i] - '0';
    Serial.print(x);
  }
}

void asciiprint() {
  for (int ascii = 32; ascii < 128; ascii++)  {
    Serial.write(ascii);
    Serial.print(" dec ");
    Serial.print(ascii, DEC);   // default is DEC
    Serial.print(" hex ");
    Serial.print(ascii, HEX);
    Serial.print(" oct ");
    Serial.print(ascii, OCT);
    Serial.print(" bin ");
    Serial.print(ascii, BIN);
    Serial.println();
  }
}

void serialParseInt() {
  if (Serial.available()) {
    int f = Serial.parseInt();
    if (f > 0) {
      Serial.println(f);
    }
  }
}

void pointers() {
  Serial.begin(115200);
  int myVar = 10;
  int *myPointer;
  myPointer = &myVar;
  *myPointer = 20;
  Serial.println(myVar);
}

void floorplan() {
  const byte H = 7;
  const byte W = 50;
  // byte room[H][W];

  for (int h = 0; h < H; h++) {
    for (int w = 0; w < W + 1 ; w++) { // +1 = endwalls
      if (h == 0 || h == H - 1) {
        if (w == 0 || w == W) {
          Serial.print("+"); // corner
        } else {
          Serial.print("-"); // sidewall
        }
      } else {
        if (w == 0 || w == W)
          Serial.print("|"); // endwall
        else
          Serial.print(" "); // floor
      }
    }
    Serial.println(); // end of row (W)
  }
}

void serialWrite() {
  byte payload = 42;

  // SERIAL.WRITE
  Serial.write("Serial.write(\"payload\"): ");
  Serial.write("payload"); // quotes/array of chars
  Serial.write("\n"); // quotes/array of chars
  Serial.write("Serial.write(payload): "); // quotes/array of chars
  Serial.write(payload); // ASCII value contained in 'payload'
  Serial.write("\n"); // quotes/array of chars
  // Serial.write(payload, HEX); // shows the char * buf error

  // SERIAL.PRINT
  Serial.print("Serial.print(\"payload\"): "); // quotes/string literal
  Serial.println("payload"); // quotes/string literal
  Serial.print("Serial.print(payload): "); // quotes/string literal
  Serial.println(payload); // value
  Serial.print("Serial.print(payload, HEX): "); // quotes/string literal
  Serial.print(payload, HEX); // convert value
}

void arrayofelements() {
  // remove one element from an array of strings.

  STOP_LOOPING = true;
  char *roomList[] = {"Bath", "Bed", "Beyond", "Closet"};
  int rooms = sizeof(roomList) / sizeof(roomList[0]); // element count in array

  for (int i = 0; i < rooms; i++) {
    Serial.print(roomList[i]);
    Serial.print(" ");
  }
  Serial.println();

  for (int i = 0; i < 4; i++) {
    if (roomList[i] != "Bed")
      Serial.println(roomList[i]);
    delay(100);
  }
}

void findhighlow() {
  // find highest and lowest and when they occurred in the count
  // only Serial.print()s when LOWEST or HIGHEST changes

  unsigned long reading = 0; // new reading
  unsigned long highest = 0; // highest value (set to lowest possible value)
  unsigned long lowest  = 1023;// lowest value (set highest possible value)
  unsigned long count = 0; // running count for when min/max occurrs
  unsigned long readCountHighest = 0; // the reading count when the highest value occurred
  unsigned long readCountLowest = 0; // the reading count when the lowest value occurred
  boolean newCurrentHighLow = 0; // signals a new high or low

  // randomSeed(analogRead(A0));

  while (1) {
    reading = analogRead(A0);
    count++;

    if (reading > highest)
    {
      highest = reading;
      newCurrentHighLow = true;
      readCountHighest = count;
    }

    if (reading < lowest)
    {
      lowest = reading;
      newCurrentHighLow = true;
      readCountLowest = count;
    }

    if (newCurrentHighLow) // only print when a new low or high ocurrs
    {
      newCurrentHighLow = false;
      Serial.print("(New value ");
      Serial.print(reading);
      Serial.print(" at count ");
      Serial.print(count);
      Serial.print(")");

      Serial.print(" (LOWEST value ");
      Serial.print(lowest);
      Serial.print(" at count ");
      Serial.print(readCountLowest);
      Serial.print(")");

      Serial.print(" (HIGHEST value ");
      Serial.print(highest);
      Serial.print(" at count ");
      Serial.print(readCountHighest);
      Serial.println(")");
    }
  }
}

void onlyprintonce() {
  // Flags to say "this has been printed once"
  // boolean ONLY_PRINT_ONCE_NO_POWER = true; // must be global
  // boolean ONLY_PRINT_ONCE_POWER_OK = true; // must be global
  float voltage = .4; // change this to .4 to test NO POWER, .6 for POWER OK

  if (voltage >= 0.10 && voltage <= 0.49) {
    if (ONLY_PRINT_ONCE_NO_POWER) {
      ONLY_PRINT_ONCE_NO_POWER = false; // reset THIS print flag
      ONLY_PRINT_ONCE_POWER_OK = true; // set the other PRINT flag
      Serial.println("No power");
    }
    // delay(1000);
  }

  if (voltage >= 0.50 && voltage <= 0.90) {
    if (ONLY_PRINT_ONCE_POWER_OK) {
      ONLY_PRINT_ONCE_POWER_OK = false; // reset THIS print flag
      ONLY_PRINT_ONCE_NO_POWER = true; // set the other PRINT flag
      Serial.println("Power is OK");
    }
    // delay(1000);
  }
}

void bodytemp() {
  int ALIVE = 36.5;
  int DEAD = 35;
  for (float i = 35; i < 40; i += .1) { // temperature from 0c to 40c step 0.1c
    if (i >= 36.4 && i <= 36.6 ) { // Normal body temperature 36.4 to 36.6
      Serial.print("(");
      Serial.print(i);
      Serial.print(" alive)");
    } else {
      Serial.print("(");
      Serial.print(i);
      Serial.print(" dead)");
    }
    delay(100);
  }
  for (float i = 40; i > 35; i -= .1) { // temperature from 0c to 40c step 0.1c
    if (i >= 36.4 && i <= 36.6 ) { // Normal body temperature 36.4 to 36.6 C
      Serial.print("(");
      Serial.print(i);
      Serial.print(" alive)");
    } else {
      Serial.print("(");
      Serial.print(i);
      Serial.print(" dead)");
    }
    delay(100);
  }
}

void serialBlink(bool LED) {
  if (LED)  // if the LED needs to blink
  {
    // blinkLED();
    Serial.print("ON ");
  } else {
    Serial.print("off ");
  }
}

void strCpyCat() {
  char dirName[] = "myDIR";
  char str1[40]; // empty buffer
  strcpy (str1, "addSpace ");
  strcat(str1, "dirName: ");
  strcat (str1, dirName);
  Serial.println ( str1 );
  while (1);
}

void numString() {
  // test the flag for true
  if (STOP_LOOPING)
  {
    // clear flag to halt sketch
    STOP_LOOPING = false;

    unsigned long val = 456123;
    char intToAscii[10]; // create a buffer
    itoa(val, intToAscii, 10); // store the value in base 10 as a string in a buffer
    Serial.println(val);
    char numstring[] = {"1234567890"};
    Serial.print(numstring);
    Serial.print(" ");
    Serial.print(numstring[3] - '0'); // store index 3 and subtract 0x48 for an integer
    Serial.print(" ");
    Serial.print(numstring[3] - '0' + 8); // show it can do math
  }
}

void millisFUN() {
  if (millis() > time_1 + INTERVAL_MESSAGE1) {
    time_1 = millis();
    print_time(time_1);
    Serial.println("I'm message number one!");
  }

  if (millis() > time_2 + INTERVAL_MESSAGE2) {
    time_2 = millis();
    print_time(time_2);
    Serial.println("Hello, I'm the second message.");
  }

  if (millis() > time_3 + INTERVAL_MESSAGE3) {
    time_3 = millis();
    print_time(time_3);
    Serial.println("My name is Message the third.");
  }

  if (millis() > time_4 + INTERVAL_MESSAGE4) {
    time_4 = millis();
    print_time(time_4);
    Serial.println("Message four is in the house!");
  }
}

void print_time(unsigned long time_millis) {
  Serial.print("Time: ");
  Serial.print(time_millis / 1000);
  Serial.print("s - ");
}

void hello_once() {
  Serial.println("Hello, World!");
  Serial.println("¡Hola, Mundo!");
  Serial.println("Hallo, Welt!");
  Serial.println("Ciao, Mundi!");
}

void perm(int a, int b) {
  /*
    int passTracker[3][5] {{1, 1, 0, 0, 0}, {2, 1, 0, 0, 0}, {3, 1, 0, 0, 0}};
    {1,1,0,0,0}, {2,1,0,0,0}, {3,1,0,0,0},
    {1,1,0,0,0}, {3,1,0,0,0}, {2,1,0,0,0}
    {2,1,0,0,0}, {1,1,0,0,0}, {3,1,0,0,0}
    {2,1,0,0,0}, {3,1,0,0,0}, {1,1,0,0,0}
    {3,1,0,0,0}, {1,1,0,0,0}, {2,1,0,0,0}
    {3,1,0,0,0}, {2,1,0,0,0}, {1,1,0,0,0}
  */
  int rows = a;
  int cols = b;
  Serial.println("--------");
  for (int i = 1; i < rows + 1; i++)
  {
    for (int j = 1; j < cols + 1; j++)
    {
      Serial.print(String(j) + String(i) + " ");
    }
    Serial.println();
  }
  Serial.println("--------");
}

/*
  projectile.c

  input
  - height above target
  - initial angle
  - initial velocity

  calculate
  - x vector
  - y vector

  x vector
  v(x) = v0x + axt >> v(x) = v0(x) (because a = 0)
  x = x0 + v0t + 1/2axt^2
  vx^2 = v0x^2 + 2ax(x-x0)

  y vector
  v(y) = v0y + ayt
  y = y0 + v0t + 1/2ayt^2
  vy^2 = v0y^2 + 2ay(y-y0)

  output
  - maximum height
  - distance from start to maximum height
  - time to reach maximum height
  - total distance
  - time to reach target

  float heightStart,   // initial height above target
        heightMax,      // maximum height (y vector)
        heightStop      // final height (target height)
        angleStart,     // initial angle
        angle,          // angle of flight (always changing)
        velocityStart,  // initial velocity
        vectorX,        // x vector (non-changing)
        vectorY,        // y vector (changes with time)
        gravity,        // acceleration due to gravity
        time0,          // initial time
        time1;          // final time

*/

void rotateColorByte() {
  int n = 16;
  int d = 2;
  Serial.print("Left Rotation of ");
  Serial.print( n );
  Serial.print(" by ");
  Serial.print( d );
  Serial.print(" is ");
  Serial.println(leftRotate(n, d));
  Serial.print("Right Rotation of ");
  Serial.print( n );
  Serial.print(" by ");
  Serial.print( d );
  Serial.print(" is ");
  // rightRotate(n, d);
  Serial.println(rightRotate(n, d));
  Serial.println();

  unsigned long RGB = 0xffeedd;
  Serial.print("RGB input  ");
  Serial.println(RGB, HEX);
  unsigned long r = (RGB & 0xff0000) >> 16;
  Serial.print("r ");
  Serial.print(r, HEX);
  unsigned long g = (RGB & 0x00ff00) >> 8;
  Serial.print(" g ");
  Serial.print(g, HEX);
  unsigned long b = (RGB & 0x0000ff) >> 0;
  Serial.print(" b ");
  Serial.println(b, HEX);

  unsigned long GBR = (g << 16) | (b << 8) | (r << 0);
  Serial.print("GBR output ");
  Serial.println(GBR, HEX);
}

int leftRotate(int n, unsigned int d) {
  unsigned long INT_BITS = 32;
  /* In n<<d, last d bits are 0. To put first 3 bits of n
    at last, do bitwise or of n<<d with n >>(INT_BITS -
    d) */
  return (n << d) | (n >> (INT_BITS - d));
}

int rightRotate(int n, unsigned int d) {
  unsigned long INT_BITS = 32;
  /* In n>>d, first d bits are 0. To put last 3 bits of at
  		first, do bitwise or of n>>d with n <<(INT_BITS
    - d) */
  return (n >> d) | (n << (INT_BITS - d));
}

void bitShiftRight() {
  int Sensor = 9;
  for (unsigned int onebit = B10000000; onebit; onebit >>= 1) {
    Serial.print(onebit & Sensor ? '1' : '0');
  }
}