#pragma once
//#ifdef AccelStepper_h
#include <Automaton.h>
#include "AccelStepper.h"

class Atm_AccelStepper: public Machine {

 public:
  enum { DISABLE, ENABLED, RUNNING, STOP, HOMING_LOW, HOMING_HIGH, LIMIT_LOW, LIMIT_HIGH }; // STATES
  enum { EVT_DISABLE, EVT_ENABLE, EVT_ENABLED_TIMEOUT, EVT_MOVE, EVT_STOP,
          EVT_EMERGENCY_STOP, EVT_ON_LIMIT_LOW, EVT_ON_LIMIT_HIGH, EVT_ON_TARGET,
          EVT_HOMING_LOW, EVT_HOMING_HIGH, ELSE }; // EVENTS
  Atm_AccelStepper( void ) : Machine() {};
  Atm_AccelStepper& begin( int step_pin, int dir_pin );
  Atm_AccelStepper& trace( Stream & stream );
  Atm_AccelStepper& trigger( int event );
  int state( void );
  Atm_AccelStepper& onChangeposition( Machine& machine, int event = 0 );
  Atm_AccelStepper& onChangeposition( atm_cb_push_t callback, int idx = 0 );
  Atm_AccelStepper& onChangestate( Machine& machine, int event = 0 );
  Atm_AccelStepper& onChangestate( atm_cb_push_t callback, int idx = 0 );
  Atm_AccelStepper& onOnlimithigh( Machine& machine, int event = 0 );
  Atm_AccelStepper& onOnlimithigh( atm_cb_push_t callback, int idx = 0 );
  Atm_AccelStepper& onOnlimitlow( Machine& machine, int event = 0 );
  Atm_AccelStepper& onOnlimitlow( atm_cb_push_t callback, int idx = 0 );
  Atm_AccelStepper& onOntarget( Machine& machine, int event = 0 );
  Atm_AccelStepper& onOntarget( atm_cb_push_t callback, int idx = 0 );
  Atm_AccelStepper& onStop( Machine& machine, int event = 0 );
  Atm_AccelStepper& onStop( atm_cb_push_t callback, int idx = 0 );
  Atm_AccelStepper& onOnhominglow( Machine& machine, int event = 0 );
  Atm_AccelStepper& onOnhominglow( atm_cb_push_t callback, int idx = 0 );
  Atm_AccelStepper& onOnhominghigh( Machine& machine, int event = 0 );
  Atm_AccelStepper& onOnhominghigh( atm_cb_push_t callback, int idx = 0 );
  Atm_AccelStepper& disable( void );
  Atm_AccelStepper& enable( void );
  //Atm_AccelStepper& move( void );
  Atm_AccelStepper& stop( void );
  Atm_AccelStepper& emergency_stop( void );
  Atm_AccelStepper& on_limit_low( void );
  Atm_AccelStepper& on_limit_high( void );
  Atm_AccelStepper& on_target( void );

  AccelStepper *stepper;

  long int _maxStep = 0; //0 is undefined, can be set using setMaxstep or homingHigh
  long int homing_speed = 1000;
  bool homingLow_done = 0 ;
  bool homingHigh_done = 0 ;
  long int max_speed = 1000;
  long int acceleration = 100;
  Atm_AccelStepper& setMaxStep( long int maxStep );
  Atm_AccelStepper& setMaxSpeed( long int maxSpeed );
  Atm_AccelStepper& setHomingSpeed( long int homingSpeed);
  Atm_AccelStepper& setAcceleration( long int acc);
  Atm_AccelStepper& setPosition( long int position);
  long int getPosition();
  long int distanceToGo();
  bool isRunning();
  float getSpeed();

  Atm_AccelStepper& move(long int stepRel);
  Atm_AccelStepper& moveTo(long int stepAbs);
  Atm_AccelStepper& movePercent(float percent);
  Atm_AccelStepper& moveToPercent(float percent);
  Atm_AccelStepper& rotate(long int speed );
  Atm_AccelStepper& homing( bool direction );
  int runMode = 0; // 0 uses run() for positioning, 1 uses runSpeed() for constant speed
  Atm_AccelStepper& position_refresh( long int refresh_ms = 1000);

  // Atm_AccelStepper& rotationReversed(bool reversed);

  Atm_AccelStepper& setEnablePin( int enablePin );
  Atm_AccelStepper& pinReversed( bool directionInvert=false,  bool stepInvert=false, bool enableInvert=false );
  bool enabled ;



  //limits public methods and variables
  Atm_AccelStepper& limitLow_set(int mode = 0, int pin = -1, int reversed=0);
  Atm_AccelStepper& limitLow_isHard(bool hardlimit = 1);
  Atm_AccelStepper& limitLow_setThresholds (int threshold_low=510, int threshold_high = 1024);
  Atm_AccelStepper& limitHigh_set(int mode = 0, int pin = -1, int reversed=0);
  Atm_AccelStepper& limitHigh_isHard(bool hardlimit = 1);
  Atm_AccelStepper& limitHigh_setThresholds (int threshold_low=510, int threshold_high = 1024);
  bool limitLow_State_raw;
  bool limitLow_State = 0;
  bool limitHigh_State = 0;
  bool limitHigh_State_raw;
  bool limitLow_State_prev;
  bool limitHigh_State_prev;
  const static int limit_buf_size = 20 ;
  bool limitLow_state_buf [limit_buf_size] ;
  int limitLow_state_total = 0 ;
  int limitLow_buf_head ;
  int limitLow_avg(bool limitState);
  bool limitHigh_state_buf [limit_buf_size] ;
  int limitHigh_state_total = 0 ;
  int limitHigh_buf_head ;
  int limitHigh_avg(bool limitState);
  bool changed = 0 ; //temp container to test if some value changed

 private:
  // ACTIONS
  enum { ENT_DISABLED, ENT_ENABLED,ENT_RUNNING, LP_RUNNING, ENT_STOP, LP_STOP,
          ENT_HOMING_LOW, LP_HOMING_LOW, EXT_HOMING_LOW,
          ENT_HOMING_HIGH, LP_HOMING_HIGH, EXT_HOMING_HIGH,
          ENT_LIMIT_LOW, LP_LIMIT_LOW, ENT_LIMIT_HIGH, LP_LIMIT_HIGH };
  // CONNECTORS
  enum { ON_CHANGEPOSITION, ON_CHANGESTATE, ON_ONLIMITHIGH,
          ON_ONLIMITLOW, ON_ONTARGET, ON_STOP, ON_ONHOMINGLOW, ON_ONHOMINGHIGH, CONN_MAX };
  atm_connector connectors[CONN_MAX];
  int event( int id );
  void action( int id );



  //positionning private variables
  long int _currentStep = 0;
  long int _targetStep = 0;

  long int _currentSpeed;
  atm_timer_millis position_timer ;
  int POSITION_SEND_TIMER = 50 ;
  void stepper_update(void);

  // bool _rotationReversed = 0 ;

  //enable private variables
  int _enablePin = -1;
  bool _enableReversed = 0 ;
  //enable timeout not implemented yet
  // atm_timer_millis idle_timer ;
  // int IDLE_TIMEOUT_DURATION = 500000 ;

  //Limits private variables
  int _limitLow_Pin;
  int _limitLow_Mode = 0; //0 no limit, 1 digital, 2 analog with thresholds
  bool _limitLow_Reversed ; //invert logic of limit switches
  int _limitLow_Thresholds[2] ; //analog value  range for two analog limits
  bool _limitLow_Hard = 0;
  int _limitHigh_Pin;
  int _limitHigh_Mode=0; //0 no limit, 1 digital, 2 analog with thresholds
  bool _limitHigh_Reversed ; //invert logic of limit switches
  int _limitHigh_Thresholds[2] ; //analog value  range for two analog limits
  bool _limitHigh_Hard = 0 ;
  // int _isHoming = 0 ;
  atm_timer_millis limits_timer ;
  int LIMIT_UPDATE_RATE = 5 ;
  // void updateLimitSwitch();

};

//#endif

/*
Automaton::ATML::begin - Automaton Markup Language

<?xml version="1.0" encoding="UTF-8"?>
<machines>
  <machine name="Atm_AccelStepper">
    <states>
      <DISABLED index="0" on_enter="ENT_DISABLED">
        <EVT_ENABLE>ENABLED</EVT_ENABLE>
      </DISABLED>
      <ENABLED index="1" on_enter="ENT_ENABLED">
        <EVT_DISABLE>DISABLED</EVT_DISABLE>
        <EVT_ENABLED_TIMEOUT>DISABLED</EVT_ENABLED_TIMEOUT>
        <EVT_STOP>STOP</EVT_STOP>
        <EVT_EMERGENCY_STOP>STOP</EVT_EMERGENCY_STOP>
      </ENABLED>
      <RUNNING index="2" on_loop="LP_RUNNING">
        <EVT_DISABLE>DISABLED</EVT_DISABLE>
        <EVT_STOP>STOP</EVT_STOP>
        <EVT_EMERGENCY_STOP>STOP</EVT_EMERGENCY_STOP>
        <EVT_ON_LIMIT_LOW>LIMIT_LOW</EVT_ON_LIMIT_LOW>
        <EVT_ON_LIMIT_HIGH>LIMIT_HIGH</EVT_ON_LIMIT_HIGH>
        <EVT_ON_TARGET>ENABLED</EVT_ON_TARGET>
      </RUNNING>
      <STOP index="3">
        <EVT_DISABLE>DISABLED</EVT_DISABLE>
        <EVT_STOP>STOP</EVT_STOP>
        <EVT_EMERGENCY_STOP>STOP</EVT_EMERGENCY_STOP>
      </STOP>
      <HOMING_LOW index="4" on_enter="ENT_HOMING_LOW" on_exit="EXT_HOMING_LOW">
        <EVT_DISABLE>DISABLED</EVT_DISABLE>
        <EVT_STOP>STOP</EVT_STOP>
        <EVT_EMERGENCY_STOP>STOP</EVT_EMERGENCY_STOP>
        <EVT_ON_LIMIT_LOW>ENABLED</EVT_ON_LIMIT_LOW>
      </HOMING_LOW>
      <HOMING_HIGH index="5" on_enter="ENT_HOMING_HIGH" on_exit="EXT_HOMING_HIGH">
        <EVT_DISABLE>DISABLED</EVT_DISABLE>
        <EVT_STOP>STOP</EVT_STOP>
        <EVT_EMERGENCY_STOP>STOP</EVT_EMERGENCY_STOP>
        <EVT_ON_LIMIT_HIGH>ENABLED</EVT_ON_LIMIT_HIGH>
      </HOMING_HIGH>
      <LIMIT_LOW index="6" on_enter="ENT_LIMIT_LOW">
        <EVT_STOP>STOP</EVT_STOP>
        <EVT_EMERGENCY_STOP>STOP</EVT_EMERGENCY_STOP>
        <EVT_ON_LIMIT_LOW>LIMIT_LOW</EVT_ON_LIMIT_LOW>
      </LIMIT_LOW>
      <LIMIT_HIGH index="7" on_enter="ENT_LIMIT_HIGH">
        <EVT_STOP>STOP</EVT_STOP>
        <EVT_EMERGENCY_STOP>STOP</EVT_EMERGENCY_STOP>
        <EVT_ON_LIMIT_HIGH>LIMIT_HIGH</EVT_ON_LIMIT_HIGH>
      </LIMIT_HIGH>
    </states>
    <events>
      <EVT_DISABLE index="0" access="MIXED"/>
      <EVT_ENABLE index="1" access="MIXED"/>
      <EVT_ENABLED_TIMEOUT index="2" access="PRIVATE"/>
      <EVT_STOP index="3" access="MIXED"/>
      <EVT_EMERGENCY_STOP index="4" access="MIXED"/>
      <EVT_ON_LIMIT_LOW index="5" access="MIXED"/>
      <EVT_ON_LIMIT_HIGH index="6" access="MIXED"/>
      <EVT_ON_TARGET index="7" access="MIXED"/>
    </events>
    <connectors>
      <CHANGEPOSITION autostore="0" broadcast="0" dir="PUSH" slots="1"/>
      <CHANGESTATE autostore="0" broadcast="0" dir="PUSH" slots="1"/>
      <ONLIMITHIGH autostore="0" broadcast="0" dir="PUSH" slots="1"/>
      <ONLIMITLOW autostore="0" broadcast="0" dir="PUSH" slots="1"/>
      <ONTARGET autostore="0" broadcast="0" dir="PUSH" slots="1"/>
      <STOP autostore="0" broadcast="0" dir="PUSH" slots="1"/>
    </connectors>
    <methods>
    </methods>
  </machine>
</machines>

Automaton::ATML::end
*/