#include <lists.h>
#include <mechButton.h>
#include <runningAvg.h>



// **********************************
// Define the class..


class ditDot : public linkListObj {

   public:
            ditDot(float inMs);
   virtual  ~ditDot(void);

   virtual  bool  isGreaterThan(linkListObj* compObj);// Are we greater than the obj being passed in? Primary sorting function.
   virtual  bool  isLessThan(linkListObj* compObj);// Are we less than the obj being passed in 

            float ms;
};


ditDot::ditDot(float inMs) { ms = inMs; }

ditDot::~ditDot(void) {  }

bool ditDot::isGreaterThan(linkListObj* compObj) { return ms>((ditDot*)compObj)->ms;}

bool ditDot::isLessThan(linkListObj* compObj) { return ms<((ditDot*)compObj)->ms; }



// **********************************
// Now for the program..


enum ourStates { waiting, doingDits, doingDahs };

mechButton    theKey(2);
linkList      ourList;
ourStates     ourState;
float         resultDit;
float         resultDah;
unsigned long startMicros;
int           count;


void setup(void) {

  Serial.begin(57600);
  Serial.println("Hit the button for about a dozen dits. Then type return.");
  theKey.setCallback(keyHit);
  count = 1;
  ourState = doingDits;
}


void keyHit(void) {

   ditDot*  newObj;

   if (!theKey.trueFalse()) {
      switch (ourState) {
         case waiting :
            Serial.println("I'm not listining...");
         break;
         case doingDits :
         case doingDahs :
            startMicros = micros();
         break;
      }
     } else {
      switch (ourState) {
         case waiting :
            Serial.println("I'm still not listining.");
         break;
         case doingDits :
         case doingDahs :
            newObj = new ditDot(micros()-startMicros);
            ourList.addToTop(newObj);
            Serial.println(count++);
         break;
      }
   }
}


float calcualte(void) {

   ditDot*     oldObj;
   runningAvg* avgListPtr;
   float       avarage;
   
   ourList.sort(true);                                // Sort them by time.
   for(byte i=0;i<3;i++) {                            // We trim 3 from each end.
      oldObj = (ditDot*)ourList.getFirst();           // Grab the fist object.
      ourList.unlinkObj(ourList.getFirst());          // Unhook the object.
      delete(oldObj);                                 // Drop object into the acid bath.
      oldObj = (ditDot*)ourList.getLast();            // Grab the last object.
      ourList.unlinkObj(ourList.getLast());           // Unhook the object.
      delete(oldObj);                                 // And recycle the object.
   }                                                  //
   avgListPtr = new runningAvg(ourList.getCount());   // Create the avaraging list.
   oldObj = (ditDot*)ourList.getFirst();              // Grab a pointer to the first on the list.
   while(oldObj) {                                    // While that pointer is NOT null..
      avgListPtr->addData(oldObj->ms);                 // Add the value to the avarager.
      oldObj = (ditDot*)oldObj->getNext();            // Grab the next value on the list.
   }                                                  //
   ourList.dumpList();                                // Done with the link list, dump it all out.
   avarage = avgListPtr->getAve();                    // Calcualte the avarage.
   avarage = avarage/1000;                            // scale it.
   delete(avgListPtr);                                // Recycle the avaragin list object.
   return avarage;                                    // And now return our results.
}


void flushSerialIn(void) { 
   
   sleep(10);
   while(Serial.available()) {
      Serial.read();
      sleep(10);
   }
}


void loop(void) { 
   
   idle();
   if (Serial.available()) {
      flushSerialIn();
      switch (ourState) {
         case waiting :
            Serial.println("OK we'll start doing dits again. Lets have about a dozen using the button.");
            ourState = doingDits;
         break;
         case doingDits :
            resultDit = calcualte();
            count = 1;
            Serial.println("Good! Ok, we start doing dahs. Lets have another dozen.");
            ourState = doingDahs;
         break;
         case doingDahs :
            resultDah = calcualte();
            count = 1;
            Serial.println("Here's your results :");
            Serial.print("Dit ms : ");Serial.println(resultDit,2);
            Serial.print("Dah ms : ");Serial.println(resultDah,2);
            Serial.println("---------------");
            Serial.println("Hit return in the serial monitor to run again.");
            Serial.println();
            ourState = waiting;
         break;
      }
   }
}