/*
  Copyright (c) 2025-2026 Kay Kasper
  under the MIT License (MIT)
*/

#ifndef ROTARYENCODER_TESTSWITCH
#define ROTARYENCODER_TESTSWITCH

#include "Common.h"

void doRotaryEncoderTests(int id){  // ID_ENCODERTEST = 5
  RotaryEncoderAnalyzer TestREAnalyzer = RotaryEncoderAnalyzer();
  TestRotaryEncoder stdEncoder(&TestREAnalyzer, true, INPUT_PIN, INPUT_PIN_B, 0, false);
  unsigned long tmpMicros, startmicro = 0;
  int seq;
  boolean tmpBool;

  stdEncoder.setMapping(REA_STATE_E_OFF, REA_STATE_E_OFF + 10);
  stdEncoder.setMapping(REA_STATE_E_DIRECTION_R, REA_STATE_E_DIRECTION_R + 10);
  stdEncoder.setMapping(REA_STATE_E_DIRECTION_L, REA_STATE_E_DIRECTION_L + 10);
  
  seq = 0; // no waits, positive logic
  stdEncoder.setReadCycleMillis(0);
  stdEncoder.setDebounceMillis(0);
  stdEncoder.setInvertRaw(false);
  stdEncoder.reset();
  check(stdEncoder.getState(),SW_STATE_UNDEFINED,id,seq+1);
  check(stdEncoder.getPrevState(),SW_STATE_UNDEFINED,id,seq+2);
  check(stdEncoder.getMappedState(),SW_STATE_UNDEFINED,id,seq+3);
  check(stdEncoder.getPrevMappedState(),SW_STATE_UNDEFINED,id,seq+4);

  // test full cycle OFF -> A -> AB -> B -> OFF
  seq = 10;
  stdEncoder.setRawState(0); // OFF
  check(stdEncoder.hasChanged(),true,id,seq+1);
  check(stdEncoder.getState(),REA_STATE_E_OFF,id,seq+2);
  check(stdEncoder.getPrevState(),SW_STATE_UNDEFINED,id,seq+3);
  check(stdEncoder.getMappedState(),PBDL_STATE_E_OFF + 10,id,seq+4);
  check(stdEncoder.getPrevMappedState(),SW_STATE_UNDEFINED,id,seq+5);
  stdEncoder.setRawState(1);  // A
  check(stdEncoder.hasChanged(),false,id,seq+6);
  check(stdEncoder.getState(),REA_STATE_E_OFF,id,seq+7);
  stdEncoder.setRawState(3);  // AB
  check(stdEncoder.hasChanged(),false,id,seq+8);
  check(stdEncoder.getState(),PBDL_STATE_E_OFF,id,seq+9);
  stdEncoder.setRawState(2);  // B
  check(stdEncoder.hasChanged(),false,id,seq+10);
  check(stdEncoder.getState(),PBDL_STATE_E_OFF,id,seq+11);
  stdEncoder.setRawState(0);  // OFF
  check(stdEncoder.hasChanged(),true,id,seq+12);
  check(stdEncoder.getState(),REA_STATE_E_DIRECTION_R,id,seq+13);
  check(stdEncoder.getPrevState(),PBDL_STATE_E_OFF,id,seq+14);
  check(stdEncoder.getMappedState(),REA_STATE_E_DIRECTION_R + 10,id,seq+15);
  check(stdEncoder.getPrevMappedState(),PBDL_STATE_E_OFF + 10,id,seq+16);

  // test full cycle OFF -> B -> AB -> A -> OFF
  seq = 30;
  stdEncoder.setRawState(0); // OFF
  check(stdEncoder.hasChanged(),true,id,seq+1);
  check(stdEncoder.getState(),REA_STATE_E_OFF,id,seq+2);
  stdEncoder.setRawState(2);  // B
  check(stdEncoder.hasChanged(),false,id,seq+6);
  check(stdEncoder.getState(),REA_STATE_E_OFF,id,seq+7);
  stdEncoder.setRawState(3);  // AB
  check(stdEncoder.hasChanged(),false,id,seq+8);
  check(stdEncoder.getState(),PBDL_STATE_E_OFF,id,seq+9);
  stdEncoder.setRawState(1);  // A
  check(stdEncoder.hasChanged(),false,id,seq+10);
  check(stdEncoder.getState(),PBDL_STATE_E_OFF,id,seq+11);
  stdEncoder.setRawState(0);  // OFF
  check(stdEncoder.hasChanged(),true,id,seq+12);
  check(stdEncoder.getState(),REA_STATE_E_DIRECTION_L,id,seq+13);
  check(stdEncoder.getPrevState(),PBDL_STATE_E_OFF,id,seq+14);
  check(stdEncoder.getMappedState(),REA_STATE_E_DIRECTION_L + 10,id,seq+15);
  check(stdEncoder.getPrevMappedState(),PBDL_STATE_E_OFF + 10,id,seq+16);

  // test reduced cycle OFF -> A -> AB -> OFF
  seq = 50;
  stdEncoder.reset();
  stdEncoder.setRawState(0); // OFF
  check(stdEncoder.hasChanged(),true,id,seq+1);
  check(stdEncoder.getState(),REA_STATE_E_OFF,id,seq+2);
  check(stdEncoder.getPrevState(),SW_STATE_UNDEFINED,id,seq+3);
  check(stdEncoder.getMappedState(),PBDL_STATE_E_OFF + 10,id,seq+4);
  check(stdEncoder.getPrevMappedState(),SW_STATE_UNDEFINED,id,seq+5);
  stdEncoder.setRawState(1);  // A
  check(stdEncoder.hasChanged(),false,id,seq+6);
  check(stdEncoder.getState(),REA_STATE_E_OFF,id,seq+7);
  stdEncoder.setRawState(3);  // AB
  check(stdEncoder.hasChanged(),false,id,seq+8);
  check(stdEncoder.getState(),PBDL_STATE_E_OFF,id,seq+9);
  stdEncoder.setRawState(0);  // OFF
  check(stdEncoder.hasChanged(),true,id,seq+10);
  check(stdEncoder.getState(),REA_STATE_E_DIRECTION_R,id,seq+11);
  check(stdEncoder.getPrevState(),PBDL_STATE_E_OFF,id,seq+12);
  check(stdEncoder.getMappedState(),REA_STATE_E_DIRECTION_R + 10,id,seq+13);
  check(stdEncoder.getPrevMappedState(),PBDL_STATE_E_OFF + 10,id,seq+14);

  // test reduced cycle OFF -> B -> AB -> OFF
  seq = 70;
  stdEncoder.setRawState(0); // OFF
  check(stdEncoder.hasChanged(),true,id,seq+1);
  check(stdEncoder.getState(),REA_STATE_E_OFF,id,seq+2);
  stdEncoder.setRawState(2);  // B
  check(stdEncoder.hasChanged(),false,id,seq+6);
  check(stdEncoder.getState(),REA_STATE_E_OFF,id,seq+7);
  stdEncoder.setRawState(3);  // AB
  check(stdEncoder.hasChanged(),false,id,seq+8);
  check(stdEncoder.getState(),PBDL_STATE_E_OFF,id,seq+9);
  stdEncoder.setRawState(0);  // OFF
  check(stdEncoder.hasChanged(),true,id,seq+10);
  check(stdEncoder.getState(),REA_STATE_E_DIRECTION_L,id,seq+11);
  check(stdEncoder.getPrevState(),PBDL_STATE_E_OFF,id,seq+12);
  check(stdEncoder.getMappedState(),REA_STATE_E_DIRECTION_L + 10,id,seq+13);
  check(stdEncoder.getPrevMappedState(),PBDL_STATE_E_OFF + 10,id,seq+14);

  // test reduced cycle OFF -> A -> OFF
  seq = 90;
  stdEncoder.reset();
  stdEncoder.setRawState(0); // OFF
  check(stdEncoder.hasChanged(),true,id,seq+1);
  check(stdEncoder.getState(),REA_STATE_E_OFF,id,seq+2);
  check(stdEncoder.getPrevState(),SW_STATE_UNDEFINED,id,seq+3);
  check(stdEncoder.getMappedState(),PBDL_STATE_E_OFF + 10,id,seq+4);
  check(stdEncoder.getPrevMappedState(),SW_STATE_UNDEFINED,id,seq+5);
  stdEncoder.setRawState(1);  // A
  check(stdEncoder.hasChanged(),false,id,seq+6);
  check(stdEncoder.getState(),REA_STATE_E_OFF,id,seq+7);
  stdEncoder.setRawState(0);  // OFF
  check(stdEncoder.hasChanged(),true,id,seq+8);
  check(stdEncoder.getState(),REA_STATE_E_DIRECTION_R,id,seq+9);
  check(stdEncoder.getPrevState(),PBDL_STATE_E_OFF,id,seq+10);
  check(stdEncoder.getMappedState(),REA_STATE_E_DIRECTION_R + 10,id,seq+11);
  check(stdEncoder.getPrevMappedState(),PBDL_STATE_E_OFF + 10,id,seq+12);

  // test reduced cycle OFF -> B -> OFF
  seq = 110;
  stdEncoder.setRawState(0); // OFF
  check(stdEncoder.hasChanged(),true,id,seq+1);
  check(stdEncoder.getState(),REA_STATE_E_OFF,id,seq+2);
  stdEncoder.setRawState(2);  // B
  check(stdEncoder.hasChanged(),false,id,seq+6);
  check(stdEncoder.getState(),REA_STATE_E_OFF,id,seq+7);
  stdEncoder.setRawState(0);  // OFF
  check(stdEncoder.hasChanged(),true,id,seq+8);
  check(stdEncoder.getState(),REA_STATE_E_DIRECTION_L,id,seq+9);
  check(stdEncoder.getPrevState(),PBDL_STATE_E_OFF,id,seq+10);
  check(stdEncoder.getMappedState(),REA_STATE_E_DIRECTION_L + 10,id,seq+11);
  check(stdEncoder.getPrevMappedState(),PBDL_STATE_E_OFF + 10,id,seq+12);

  // test reduced cycle OFF -> A -> B-> OFF
  seq = 130;
  stdEncoder.reset();
  stdEncoder.setRawState(0); // OFF
  check(stdEncoder.hasChanged(),true,id,seq+1);
  check(stdEncoder.getState(),REA_STATE_E_OFF,id,seq+2);
  check(stdEncoder.getPrevState(),SW_STATE_UNDEFINED,id,seq+3);
  check(stdEncoder.getMappedState(),PBDL_STATE_E_OFF + 10,id,seq+4);
  check(stdEncoder.getPrevMappedState(),SW_STATE_UNDEFINED,id,seq+5);
  stdEncoder.setRawState(1);  // A
  check(stdEncoder.hasChanged(),false,id,seq+6);
  check(stdEncoder.getState(),REA_STATE_E_OFF,id,seq+7);
  stdEncoder.setRawState(2);  // B
  check(stdEncoder.hasChanged(),false,id,seq+8);
  check(stdEncoder.getState(),REA_STATE_E_OFF,id,seq+9);
  stdEncoder.setRawState(0);  // OFF
  check(stdEncoder.hasChanged(),true,id,seq+10);
  check(stdEncoder.getState(),REA_STATE_E_DIRECTION_R,id,seq+11);
  check(stdEncoder.getPrevState(),PBDL_STATE_E_OFF,id,seq+12);
  check(stdEncoder.getMappedState(),REA_STATE_E_DIRECTION_R + 10,id,seq+13);
  check(stdEncoder.getPrevMappedState(),PBDL_STATE_E_OFF + 10,id,seq+14);

  // test reduced cycle OFF -> B -> A -> OFF
  seq = 150;
  stdEncoder.setRawState(0); // OFF
  check(stdEncoder.hasChanged(),true,id,seq+1);
  check(stdEncoder.getState(),REA_STATE_E_OFF,id,seq+2);
  stdEncoder.setRawState(2);  // B
  check(stdEncoder.hasChanged(),false,id,seq+6);
  check(stdEncoder.getState(),REA_STATE_E_OFF,id,seq+7);
  stdEncoder.setRawState(1);  // A
  check(stdEncoder.hasChanged(),false,id,seq+8);
  check(stdEncoder.getState(),REA_STATE_E_OFF,id,seq+9);
  stdEncoder.setRawState(0);  // OFF
  check(stdEncoder.hasChanged(),true,id,seq+10);
  check(stdEncoder.getState(),REA_STATE_E_DIRECTION_L,id,seq+11);
  check(stdEncoder.getPrevState(),PBDL_STATE_E_OFF,id,seq+12);
  check(stdEncoder.getMappedState(),REA_STATE_E_DIRECTION_L + 10,id,seq+13);
  check(stdEncoder.getPrevMappedState(),PBDL_STATE_E_OFF + 10,id,seq+14);

  // test reduced cycle OFF -> AB -> OFF
  seq = 170;
  stdEncoder.setRawState(0); // OFF
  check(stdEncoder.hasChanged(),true,id,seq+1);
  check(stdEncoder.getState(),REA_STATE_E_OFF,id,seq+2);
  stdEncoder.setRawState(3);  // AB
  check(stdEncoder.hasChanged(),false,id,seq+6);
  check(stdEncoder.getState(),REA_STATE_E_OFF,id,seq+7);
  stdEncoder.setRawState(0);  // OFF
  check(stdEncoder.hasChanged(),false,id,seq+8);
  check(stdEncoder.getState(),REA_STATE_E_OFF,id,seq+9);
  stdEncoder.setRawState(0); // OFF
  check(stdEncoder.hasChanged(),false,id,seq+10);

  // performance

  Serial.println("\nPerformance RotaryEncoder:");

  Serial.print("1000 * hasChanged() true: ");

  stdEncoder.setInvertRaw(false);
  stdEncoder.setReadCycleMillis(0);
  stdEncoder.setDebounceMillis(0);
  stdEncoder.reset();

  startmicro = micros();
  for(int i = 0 ; i < 1000 ; i++){
    stdEncoder.setRawState(i & 0x0003);
    tmpBool = stdEncoder.hasChanged();
  }
  Serial.print(micros() - startmicro);
  Serial.println(" micros");

  Serial.print("1000 * hasChanged() false: ");

  stdEncoder.setInvertRaw(false);
  stdEncoder.setReadCycleMillis(0);
  stdEncoder.setDebounceMillis(0);
  stdEncoder.reset();

  startmicro = micros();
  stdEncoder.setRawState(0);
  stdEncoder.hasChanged();
  for(int i = 0 ; i < 1000 ; i++){
    stdEncoder.setRawState(0);
    tmpBool = stdEncoder.hasChanged();
  }
  Serial.print(micros() - startmicro);
  Serial.println(" micros");
}

#endif
