 #include <Arduino.h>
#include "clock.h"

 
#include <SPI.h>
#include <Wire.h>

#define Anode0Pin 10
#define Anode1Pin 3
#define Anode2Pin 8

#define Anode0ON digitalWrite(Anode0Pin,HIGH)
#define Anode0OFF digitalWrite(Anode0Pin,LOW)

#define Anode1ON digitalWrite(Anode1Pin,HIGH)
#define Anode1OFF digitalWrite(Anode1Pin,LOW)

#define Anode2ON digitalWrite(Anode2Pin,HIGH)
#define Anode2OFF digitalWrite(Anode2Pin,LOW)

#define mosiPin 5
#define misoPin 9
#define sckPin  6
#define LEpin   7

 #define TimeIndex        0 
 #define DateIndex        1 
// #define AlarmIndex       2 
// #define hModeIndex       3 
// #define TimeHoursIndex   4 
// #define TimeMintuesIndex 5
// #define TimeSecondsIndex 6
// #define DateDayIndex     7
// #define DateMonthIndex   8
// #define DateYearIndex    9 
// #define AlarmHourIndex   10
// #define AlarmMinuteIndex 11
// #define AlarmSecondIndex 12
// #define Alarm01          13
// #define hModeValueIndex  14

String updateDateString();
String updateDisplayString();
// void doDotBlink();
// void checkAlarmTime();
// String PreZero(int digit);
word doEditBlink(int pos);
// byte decToBcd(byte val);
String antiPoisoning2(String fromStr, String toStr);
// String getTimeNow();
String antiPoisoning2(String fromStr, String toStr);
bool doTest();
// void getRTCTime();
void modesChanger();
void doIndication();

const word fpsLimit=16666; // 1/60*1.000.000 //limit maximum refresh rate on 60 fps

String stringToDisplay="000000";// Conten of this string will be displayed on tubes (must be 6 chars length)
int menuPosition=0; // 0 - time
                    // 1 - date
                    // 2 - alarm
                    // 3 - 12/24 hours mode
                    

//                      0      1      2      3      4      5      6      7      8       9
//word SymbolArray[10]={65534, 65533, 65531, 65527, 65519, 65503, 65471, 65407, 65279, 65023};
word SymbolArray[10]={1022, 1021, 1019, 1015, 1007, 991, 959, 895, 767, 511};

byte dotPattern=B00000000; //bit mask for separeting dots 
                          //B00000000 - turn off up and down dots 
                          //B1100000 - turn off all dots



int teststate = -1;
String testStringArray[12]={"000000","111111","222222","333333","444444","555555","666666","777777","888888","999999","",""};
unsigned long startOfTest;



/*******************************************************************************************************
Init Programm
*******************************************************************************************************/
void setup() 
{
 
  Serial.begin(115200);

  log_i("init hardware");

  pinMode(LEpin, OUTPUT);

  // SPI setup
  SPI.begin(mosiPin,misoPin,sckPin); // 
  SPI.setDataMode (SPI_MODE3); // Mode 3 SPI
  SPI.setClockDivider(SPI_CLOCK_DIV128); // SCK = 16MHz/128= 125kHz
 
  pinMode(Anode0Pin, OUTPUT);
  pinMode(Anode1Pin, OUTPUT);
  pinMode(Anode2Pin, OUTPUT);

  log_i("init clock");
  initClock();

  //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  while(!timeIsSet())
  {
    doTest();
    loopClock();
  }

  log_i("init done, GO!");

  //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!


}



//antipoisoning transaction 
bool modeChangedByUser=false;
bool transactionInProgress=false; 
#define timeModePeriod 60000
#define dateModePeriod 5000
long modesChangePeriod=timeModePeriod;
//antipoisoning end

/***************************************************************************************************************
MAIN Programm
***************************************************************************************************************/
void loop() {

  loopClock();

  if ((menuPosition==TimeIndex) || (modeChangedByUser==false) ) modesChanger();  
  doIndication();
     
  static bool updateDateTime=false;
  switch (menuPosition)
  {
    case TimeIndex: //time mode
        if (!transactionInProgress) stringToDisplay=updateDisplayString();
       break;
    case DateIndex: //date mode
      if (!transactionInProgress) stringToDisplay=updateDateString();
      dotPattern=B01000000;//turn on lower dots
      break;

  }
}

int dlay=500;
// bool test=1;
byte strIndex=-1;
// bool digitsLock=false;

bool doTest()
{
  if(!timeIsSet()) return true;

  if(teststate == -1) 
  {
    Serial.println(F("Start Test"));
    startOfTest=millis();
    teststate = 0;
    Serial.println(testStringArray[10]);
  }

  // byte b=1;

  if ((millis()-startOfTest)>dlay) 
  {
    startOfTest=millis();
    strIndex=strIndex+1;
    if (strIndex==10) dlay=3000;
  
    stringToDisplay=testStringArray[strIndex];
    Serial.print("stringToDisplay=");
    Serial.println(stringToDisplay);
    Serial.print("strIndex=");
    Serial.println(strIndex);
    Serial.print("i=");
    Serial.println(teststate);
    
    if (strIndex==11) strIndex = -1;

  }

  doIndication();
  
  return false;
}

void doIndication()
{
  static byte b=1;
 
  static unsigned long lastTimeInterval1Started;
  if ((micros()-lastTimeInterval1Started)>5000)
  {
   lastTimeInterval1Started=micros();
   Anode0OFF; Anode1OFF; Anode2OFF;
   unsigned long var32;
   unsigned long tmpVar; 

   int curTube=b*2-2;
   var32=SymbolArray[stringToDisplay.substring(curTube, curTube+1).toInt()];
   tmpVar=SymbolArray[stringToDisplay.substring(curTube+1, curTube+2).toInt()];

   var32 |= tmpVar<<10;

   digitalWrite(LEpin, LOW);    // allow data input (Transparent mode)
    
   SPI.transfer(var32>>16); //[A3][A2][A1][A0][RC9][RC8][RC7][RC6]      - A5-A0 - anodes
   SPI.transfer(var32>>8); //[RC5][RC4][RC3][RC2][RC1][RC0][LC9][RC8]  - RC9-RC0 - Right tubes cathodes
   SPI.transfer(var32);

   digitalWrite(LEpin, HIGH);     // latching data 
    
   switch (b)
   {
    case 1:{Anode0ON; Anode1OFF; Anode2OFF; break;};
    case 2:{Anode0OFF; Anode1ON; Anode2OFF; break;};
    case 3:{Anode0OFF; Anode1OFF; Anode2ON; break;};
   }
    b=b+1;
    if (b==4) {b=1;}
  }
}


void doDotBlink()
{
  static unsigned long lastTimeBlink=millis();
  static bool dotState=0;
  if ((millis()-lastTimeBlink)>1000) 
  {
    lastTimeBlink=millis();
    dotState=!dotState;
    if (dotState) 
      {
        dotPattern=B11000000;
        /*digitalWrite(pinUpperDots, HIGH);
        digitalWrite(pinLowerDots, HIGH);*/
      }
      else 
      {
        dotPattern=B00000000;
        /*digitalWrite(pinUpperDots, LOW); 
        digitalWrite(pinLowerDots, LOW);*/
      }
  }
}


byte decToBcd(byte val){
// Convert normal decimal numbers to binary coded decimal
  return ( (val/10*16) + (val%10) );
}

byte bcdToDec(byte val)  {
// Convert binary coded decimal to normal decimal numbers
  return ( (val/16*10) + (val%16) );
}

void modesChanger()
{
  static unsigned long lastTimeModeChanged=millis();
  static unsigned long lastTimeAntiPoisoningIterate=millis();
  if ((millis()-lastTimeModeChanged)>modesChangePeriod) 
  {
    lastTimeModeChanged=millis();
    if (menuPosition==TimeIndex) {menuPosition=DateIndex; modesChangePeriod=dateModePeriod;}
      else {menuPosition=TimeIndex; modesChangePeriod=timeModePeriod;}
    if (modeChangedByUser==true) 
    {
      menuPosition=TimeIndex;
    }
    modeChangedByUser=false;
  }
  if ((millis()-lastTimeModeChanged)<2000) 
  {
    if ((millis()-lastTimeAntiPoisoningIterate)>100)  
    {
      lastTimeAntiPoisoningIterate=millis();
      if (menuPosition==TimeIndex)
        stringToDisplay=antiPoisoning2(updateDateString(), getTimeNow());
      else stringToDisplay=antiPoisoning2(getTimeNow(), updateDateString());
     // Serial.println("StrTDInToModeChng="+stringToDisplay);
    }
  } else transactionInProgress=false;
}

String antiPoisoning2(String fromStr, String toStr)
{
  //static bool transactionInProgress=false;
  //byte fromDigits[6];
  static byte toDigits[6];
  static byte currentDigits[6];
  static byte iterationCounter=0;
  if (!transactionInProgress) 
  {
    transactionInProgress=true;
    for (int i=0; i<6; i++)
    {
      currentDigits[i]=fromStr.substring(i, i+1).toInt();
      toDigits[i]=toStr.substring(i, i+1).toInt();
    }
  }
  for (int i=0; i<6; i++)
  {
    if (iterationCounter<10) currentDigits[i]++;
      else if (currentDigits[i]!=toDigits[i]) currentDigits[i]++;
    if (currentDigits[i]==10) currentDigits[i]=0;
  }
  iterationCounter++;
  if (iterationCounter==20)
  {
    iterationCounter=0;
    transactionInProgress=false;
  }
  String tmpStr;
  for (int i=0; i<6; i++)
    tmpStr+=currentDigits[i];
  return tmpStr;
}

String updateDisplayString()
{
  static  unsigned long lastTimeStringWasUpdated;
  if ((millis()-lastTimeStringWasUpdated)>1000)
  {
    lastTimeStringWasUpdated=millis();
    return getTimeNow();
  }
  return stringToDisplay;
}