/*
 * utility.h
 *
 *  Created on: 10 дек. 2014 г.
 *      Author: ivanov.i
 */

#ifndef UTILITY_H_
#define UTILITY_H_

#include <string>
#include <vector>
#include <list>
#ifdef __linux__
	#include <inttypes.h>
#elif _WIN32
	#include <windows.h>
	#include <stdint.h> //C++Builder
#else

#endif


namespace UtilityW
{
#ifdef _WIN32
	void UnixTimeToFileTime(time_t t, LPFILETIME pft);
	void UnixTimeToSystemTime(time_t t, LPSYSTEMTIME pst);
#endif

	//time_t g_file_name_cnt_time;
	//int g_file_name_cnt;
	std::string getNextFileName(); //Генерировать уникальное имя файла на основе времени и порядкового номера из глобавльной переменной

	char separator();
	bool checkPort(const char *hostname,int portno,int timeout); //Проверяем открыт ли сокет
	uint8_t CRC8(const signed char *pcBlock, unsigned char len, unsigned char crc);

	bool DeCrypt(std::string strKey, std::string fNameIn, std::string fNameOut);
	unsigned char setBitVal(unsigned char bit,unsigned char pos,bool val); //Установит знначение бита в заданную позицию pos - Позиция 7..0
	bool getBitVal(unsigned char bit,unsigned char pos); //Вернёт значение бита на заданной позиции, pos - Позиция 7..0

	unsigned int getMSecTime();

    std::string urlEncode(const std::string &url);
    std::string urlDecode(const std::string &encoded);

    std::string charToHex(unsigned char c);
    std::string shortToHex(unsigned short c);
    std::string uintToHex(unsigned int val,char size);

    unsigned char hexToChar(const std::string &str);
    unsigned char bitStrToChar(std::string str);
    unsigned int HexStdStrToUInt(std::string& str);
    bool hexStrToArray(const std::string &str,char* arr);
    bool arrayToHexStr(char* arr,unsigned int len,std::string &str);
    bool vectorToHexStr(std::vector < unsigned char >& arr,std::string &str);

    bool initPin(std::string pinnum); //Инициализируем ножку чтоб в неё можно записывать 0 или 1 как в файл (Документация GPIO: http://www.avrfreaks.net/wiki/index.php/Documentation:Linux/GPIO)
    bool setPinDir(std::string pinnum, bool dir); //Задать направление чтения или записи (сейчас вывод) dit=true на вывод, dit=false на ввод, pull - подтяжка к 0 или к 1 питания.
    bool setPinVal(std::string pinnum, bool val); //Задаём напряжение для ножки
    char getPinVal(std::string pinnum); //Получить значение ножки

    std::string doubleToString(double val);
    std::string intToString(signed int val);
    std::string ullintToString(unsigned long long int val);
    std::string uintToString(unsigned int val);
    std::string AfterFirst(std::string str,const char ch);
    std::string DecToBinStr(int N,int cnt=0);
    std::string DecToBinStr(unsigned int N,int cnt=0);
    std::string addZero(std::string str,int count,char ch='0');
    std::string addZero(int val,int count,char ch='0');
    std::string escape_json(const std::string& input);


    std::string AfterLast(std::string str,const unsigned char ch);
    std::string BeforeFirst(std::string str,const unsigned char ch);
    std::string BeforeLast(std::string str,char ch);
    std::string CutBeforeFirst(std::string& str,const unsigned char ch);
    std::string CutBeforeFirst(std::string& str,std::string br);
    std::string CutAfterLast(std::string& str,const unsigned char ch);
    std::string CutAfterFirst(std::string& str,std::string br);

    void Trim(std::string& s);
    void TrimLeft(std::string& s);
    void TrimRight(std::string& s);

    double StdStrToDouble(std::string& str);
    float StdStrToFloat(std::string& str);
    bool StdStrToFloat(std::string& str,float& val);

    int StdStrToInt(std::string& str);
    unsigned int StdStrToUInt(std::string& str);
    unsigned long long StdStrToULLInt(std::string& str);


	long getMaxFileSize(std::string path); //Получить размер самого большого файла в каталоге
	long getAllFSSize(std::string anyfile);
	long getFreeFSSize(std::string anyfile);
    long getFileSize(std::string file);
    long getFileDateModiff(std::string file);
    int readFile(std::string file, char* data, int size);
    bool dirExists(std::string path);
    bool fileExists(std::string name);
	void GetFiles(std::list<std::string>& fileList, std::string directory); //Получить список файлов в директории (в том числе и в подпапках)
	void GetFolders(std::list<std::string>& folderList, std::string directory); //Получить список папок в директории (без подпапок)
	bool createFolder(std::string directory,int mode); //Создать папку

    void delString(std::vector<std::string> *mas, int pos);
    std::string unixTimeToDate(double time);

    //bool logrotate(int cnt,int size, std::string name, std::string data); //Сохранение лог файла в 2 версии по 10 мегабайт
    bool logrotate(std::string fileName,std::string name,std::string level, std::string data,bool cout=false,int size=10); //Сохранение лог файла в 2 версии по 10 мегабайт

    void Distance(float r, float cx, float cy, float lx1, float ly1, float lx2, float ly2, bool& Coincides, float& x, float& y);

    bool parseGPRMC(std::string ans,time_t& utime,double& lon,double& lat,float& speed,float& angle); //На вход строка вида: $GPRMC,074353.0,A,4315.286297,N,07651.391112,E,0.0,255.3,191214,,,A*68
    void sleep2(int sec); //В секундах

    bool deleteFile(std::string fileName); //Удалить файл
    bool deleteOldFiles(std::string path,int days); //Удалить файлы старше заданного количества дней
    bool deleteOldFile(std::string path); //Удалить 1 последний файл
}
//------------------------------------------------------------------------------
//Расширяемый массив элементов, может выступать в качестве родителя те. удалять элементы при уничтожении списка или при удалении элемента из списка
template <class T> class TSimpleList
{
private:
	T* f_NULL; //При выходе за пределы массива выдаётся этот элемент
	T* List; //массив элементов
	unsigned int f_size; //размер массива (без учёта занятых позиций)
	unsigned int f_count; //количество элементов
	unsigned int f_step; //шаг увеличения массива
public:
	bool f_owner; //являеться ли владельцем элементов данный списк (нужно ли удалять элементы списка)

	explicit TSimpleList(unsigned int step=10,bool owner=false)
	{
		if(step==0)step=1;
		f_step=step;
		List=new T[f_step];
		f_size=f_step;
		f_count=0;
		f_owner=owner;
		f_NULL=NULL;
	};
	~TSimpleList()
	{
		if(f_owner)
			for(unsigned int i=0;i<f_count;i++)
				delete List[i];
		delete[] List;
	};
	unsigned int count()
	{
		return f_count;
	};
	unsigned int size() //количество элементов
	{
		return f_count;
	};
	//Добавить элемент в конец массива
	T add(T item)
	{
		if(f_count<f_size)
		{
			List[f_count]=item;
			f_count++;
		}else
		{
			T* buf=new T[f_size+=f_step];
			for(unsigned int i=0;i<=f_count;i++) buf[i]=List[i];
			T* buf0=List;
			List=buf;
			delete[] buf0;
			List[f_count++]=item;
		}
		return item;
	};
	void push_back(T item) {add(item);};

	void insert(T item, unsigned int pos) //pos - 0..N
	{
		if(pos>=f_count)
		{
			if(pos<f_size){List[pos]=item; f_count=pos+1;} //в пустую область
			else //в не выделенную область
			{
				T* buf=new T[pos+1];
				for(unsigned int i=0;i<=f_count;i++) buf[i]=List[i];
				T* buf0=List;
				List=buf;
				delete[] buf0;
				List[pos]=item;
				f_count=pos+1;
			}
		}else//сдвинуть имеющиеся
		{
			add(List[f_count-1]);
			for(unsigned int i=f_count-2;i>pos;i--)
				List[i]=List[i-1];
			List[pos]=item;
		}
	};
	void del(T item) //удаляем элемент и сдвигаем все элементы на 1 в лево
	{
		unsigned int cnt=0;
		bool b=false;
		for(unsigned int i=0;i<f_count;i++)
		{
			//if(List[i]==item){cnt--; b=true;}
			if(List[i]==item){b=true; continue;}
			List[cnt]=List[i];
			cnt++;
		}
		if(b)
		{
			f_count--;
			if(f_owner)delete item;
		}
	};
	bool del(unsigned int pos) //удаляем элемент и сдвигаем все элементы на 1 в лево
	{
		if(pos>=f_count)return false;
		f_count--;
		if(f_owner) delete List[pos];
		for(unsigned int i=pos;i<f_count;i++) List[i]=List[i+1];
		return true;
	};
	T& get(unsigned int i)
	{	if(i>=f_count) {return (T&)f_NULL;}
		return List[i];
	};
	T& operator[](unsigned int i)
	{	if(i>=f_count) {return (T&)f_NULL;}
		return List[i];
	};
	bool Pos(T item,unsigned int &pos) //Узнать позицию элемента в массиве
	{
		for(unsigned int i=0;i<f_count;i++)
			if(List[i]==item) { pos=i; return true; }
		return false;
	};
	//Очистить массив с уменьшением размерности до одного шага увеличения массива
	void clear()
	{
		unsigned int cnt=f_count;
		f_count=0;
		if(f_owner) for(unsigned int i=0;i<cnt;i++)	delete List[i];
		T* tmp=List;
		f_size=f_step;
		List=new T[f_step];
		delete[] tmp;
	};
};
//------------------------------------------------------------------------------
//простой список не являющийся владельцем своих элементов (можно задавать реальные обьекты а не ссылки)
template <class T> class TSimpleList2
{
private:
	T* List; //массив элементов
	unsigned int f_size;//размер массива
	unsigned int f_count;//количество элементов
	unsigned int f_step;//шаг увеличения массива
public:
	explicit TSimpleList2() //Для использования конструктора по умолчанию
	{
		f_step=10;
		List=new T[f_step];
		f_size=f_step;
		f_count=0;
	};

	TSimpleList2(unsigned int step)
	{
		if(step==0)step=1;
		f_step=step;
		List=new T[f_step];
		f_size=f_step;
		f_count=0;
	};

	~TSimpleList2()
	{
		delete[] List;
	};
	unsigned int count() //количество элементов
	{
		return f_count;
	};
	unsigned int size() //количество элементов
	{
		return f_count;
	};

	//Добавить элемент в конец массива
	void add(T item)
	{
		if(f_count<f_size)
		{
			List[f_count]=item;
			f_count++;
		}
		else
		{
			T* buf=new T[f_size+=f_step];
			for(unsigned int i=0;i<=f_count;i++) buf[i]=List[i];
			T* buf0=List;
			List=buf;
			delete[] buf0;
			List[f_count]=item;
			f_count++;
		}
	};

	void push_back(T item){add(item);};

	void del(T item) //удаляем элемент и сдвигаем все элементы на 1 в лево
	{
		unsigned int cnt=0;
		bool b=false;
		for(unsigned int i=0;i<f_count;i++)
		{
			//if(List[i]==item){cnt--; b=true;}
			if(List[i]==item){b=true; continue;}
			List[cnt]=List[i];
			cnt++;
		}
		if(b)
		{
			f_count--;
		}
	};
	bool del(unsigned int pos) //удаляем элемент и сдвигаем все элементы на 1 в лево
	{
		if(pos>=f_count)return false;
		f_count--;
		for(unsigned int i=pos;i<f_count;i++) List[i]=List[i+1];
		return true;
	};
	bool pop_front(){ return del(0); };

	T& front(){return List[0];};
	T& get(unsigned int i){return List[i];};
	T& operator[](unsigned int i){return List[i];};
	bool Position(T item, unsigned int &pos) //Найти позицию элемента в списке перебором
	{
		for(unsigned int i=0;i<f_count;i++)
			if(List[i]==item) { pos=i; return true; }
		return false;
	};

	void clear()
	{
		unsigned int cnt=f_count;
		f_count=0;
		T* tmp=List;
		f_size=f_step;
		List=new T[f_step];
		delete[] tmp;
	};
};
//------------------------------------------------------------------------------

#endif /* UTILITY_H_ */
