#ifndef EGGDUINO_H
#define EGGDUINO_H

#include <Arduino.h>
#define SUPPRESS_HPP_WARNING
#include <ServoEasing.h>
#ifdef ESP32
#include <WiFi.h>
#include <WebServer.h>
#include <SPIFFS.h>
#endif

#include <FastAccelStepper.h>
#include "SerialCommand.h"
#include "button.h"

// implemented Eggbot-Protocol-Version v13
#define initSting "EBBv13_and_above Protocol emulated by Eggduino-Firmware V1.6a"

#ifdef ESP32

// Rotational Stepper
static const int kDefaultRotDirPin = 16;
static const int kDefaultRotEnablePin = 12;
static const int kDefaultRotStepPin = 26;
#define rotMicrostep 32
static const int kDefaultRotMicrostep = rotMicrostep;

// Pen Stepper
static const int kDefaultPenStepPin = 25;
static const int kDefaultPenDirPin = 27;
static const int kDefaultPenEnablePin = 12;
#define penMicrostep 32
static const int kDefaultPenMicrostep = penMicrostep;

static const int kDefaultServoPin = 17;


#else

// Rotational Stepper
static const int kDefaultRotStepPin = 2;
static const int kDefaultRotDirPin = 5;
static const int kDefaultRotEnablePin = 8;
#define rotMicrostep 16
static const int kDefaultRotMicrostep = rotMicrostep;

// Pen Stepper
static const int kDefaultPenStepPin = 3;
static const int kDefaultPenDirPin = 6;
static const int kDefaultPenEnablePin = 8;
#define penMicrostep 16
static const int kDefaultPenMicrostep = penMicrostep;

static const int kDefaultServoPin = 4;


#endif

struct ConfigParameter {
	const char *type;
	const char *key;
	void *value;
	String description;
	int defaultValue;
	const char *defaultText;
	bool secret;
};

extern FastAccelStepperEngine g_stepEngine;
extern FastAccelStepper *g_pStepperRotate;
extern FastAccelStepper *g_pStepperPen;

extern ServoEasing penServo;
extern SerialCommand SCmd;
#ifdef ESP32
extern SerialCommand g_BLECmd;
extern SerialCommand g_WifiCmd;
#endif

extern int g_iPenUpPos;
extern int g_iPenDownPos;
extern int g_iServoRateUp;
extern int g_iServoRateDown;
extern long g_iRotStepError;
extern long g_iPenStepError;
extern int g_iPenState;
extern uint32_t g_uiNodeCount;
extern unsigned int g_uiLayer;
extern boolean g_bPrgButtonState;
extern float fROT_STEP_CORRECTION;
extern float fPEN_STEP_CORRECTION;
extern boolean g_bMotorsEnabled;
extern int g_iRotDirPin;
extern int g_iRotEnablePin;
extern int g_iRotStepPin;
extern int g_iPenStepPin;
extern int g_iPenDirPin;
extern int g_iPenEnablePin;
extern int g_iServoPin;
extern int g_iRotMicrostep;
extern int g_iPenMicrostep;
extern int g_iMaxAcclSpeed;
extern String g_sHostname;
extern String g_sWifiSsid;
extern String g_sWifiPassword;

enum ProtocolTransport {
	PROTOCOL_TRANSPORT_SERIAL = 0,
	PROTOCOL_TRANSPORT_BLE = 1,
	PROTOCOL_TRANSPORT_WIFI = 2,
};

extern ConfigParameter configParameters[];
extern const size_t configParameterCount;

void makeComInterface();
void setActiveProtocolContext(SerialCommand *parser, ProtocolTransport transport);
char *nextCommandArg();
void protocolWrite(const char *message);
void protocolWrite(const String &message);
void initHardware();
void moveOneStep();
void moveToDestination();
void sendAck();
void sendError();
void motorsOff();
void motorsOn();
void toggleMotors();
void doTogglePen();
void setprgButtonState();
bool parseSMArgs(uint16_t *duration, int *penStepsEBB, int *rotStepsEBB);
void prepareMove(uint16_t duration, int penStepsEBB, int rotStepsEBB);
void storePenUpPosInEE();
void storePenDownPosInEE();
void updateStepCorrectionFactors();
void movePenServoTo(int targetPos);

bool initConfigStore();
bool loadConfigFromFile();
bool saveConfigToFile();
String buildConfigJson();
bool applyConfigJson(const String &payload, String &errorMessage);
void startWebInterface();
void handleWebInterface();
#ifdef ESP32
void startBleInterface();
void handleBleInterface();
bool bleProtocolWrite(const char *message);
void buildDeviceName(char *nameBuffer, size_t bufferSize);
void startWifiProtocolInterface();
void handleWifiProtocolInterface();
bool wifiProtocolWrite(const char *message);
#else
inline void startBleInterface() {}
inline void handleBleInterface() {}
inline bool bleProtocolWrite(const char *message)
{
	(void)message;
	return false;
}
inline void buildDeviceName(char *nameBuffer, size_t bufferSize)
{
	(void)nameBuffer;
	(void)bufferSize;
}
inline void startWifiProtocolInterface() {}
inline void handleWifiProtocolInterface() {}
inline bool wifiProtocolWrite(const char *message)
{
	(void)message;
	return false;
}
#endif
void Log(const String &message);
void Log(const char *message);
String buildLogsJson(uint32_t sinceSeq);
void captureIncomingPrintLine(const char *line, ProtocolTransport transport);
String buildIncomingPrintLogText();
void clearIncomingPrintLog();

#endif
