#ifndef _GPIO_H_
#define _GPIO_H_

#include <unistd.h>
#include <stdint.h>
#include <memory>
#include <ostream>
#include <iostream>
#include "../../config.h"

class Gpio 
{
	public: 
		enum pinMode
		{
			undefined,
			input, 
			output, 
			analog, 
			alternate
		};
		
		enum pinState
		{
			floating, 
			pushPull, 
			openDrain 
		};
		
		enum pinPullUpDown
		{
			none,
			pullUp,
			pullDown
		};

		enum pinSpeed
		{
			slow, 
			normal, 
			fast, 
			veryFast
		};
		
		enum pinInterrupt
		{
			disabled,
			enabled 
		};
	
		enum pinFunction
		{
			passive,
			gpio,
			i2c,
			spi,
			pwm,
			pcm,
			uart,
			eeprom,
			clk
		};

		struct pinDefinition
		{
			uint8_t no;
			pinMode mode; 
			pinState state;
			pinPullUpDown pud;
			pinSpeed speed;
			pinInterrupt interrupt; 
			pinFunction function;
		};

		enum errors
		{
			notValidMode,
			notValidOut,
			pinOutOfRange,
			pinNotDeclared, 
			pinNotReachable, 
			pinNoPullUpDown, 
			pinNotAnalog, 
			pinNotDigital, 
			pinTooFast, 
			pinBocked, 
			pinAlreadyUsed,
			pinNotGpio
		};

		Gpio(); 
		~Gpio(); 

		void setFunction(uint8_t gpioNo, Gpio::pinFunction function); 
		void setMode(uint8_t gpioNo, pinMode mode); 
		void setOutputState(uint8_t gpioNo, pinState state); 
		void setPullUpDonw(uint8_t gpioNo, pinPullUpDown resistance); 
		void setSpeed(uint8_t gpioNo, pinSpeed speed); 
		void config(uint8_t gpioNo, pinFunction function, pinMode mode, pinState state, pinPullUpDown resistance, pinSpeed speed); 
		
		uint8_t readPin(uint8_t gpioNo);
		void writePin(uint8_t gpioNo, uint8_t value);

		uint16_t readRange(uint8_t start, uint8_t stop); 
		void writeRange(uint8_t start, uint8_t stop, uint16_t value); 
	
		void pinInitiate(uint8_t gpioNo);
		void pinUninitiate(uint8_t gpioNo);
		
		void checkCurrentPins();
		void pinList();
		void pinPrintInfo(uint8_t gpioNo);

	private:
		void throwError(uint16_t line, errors errNo); 	
		class gpioImpl; 
		std::unique_ptr<gpioImpl> gpioPimpl; 
};

#endif //  _GPIO_H_
