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

#include <algorithm>    // std::sort
#include <sstream>
#include <stdexcept>
#include <stdio.h>
#include <string.h>
#include <stdio.h>
#include <dirent.h>
#include <iomanip>
#include <iostream>
#include <fstream>
#include <fcntl.h>
#include <stdio.h>
#include <vector>
#include <math.h>
#include <ctime>
#include <stdio.h>
#include <cstdio>

#include <stdlib.h>
#include <iostream>
#include <cstdio>

#include <string.h>
#include <sys/types.h>



#include <errno.h> // Error number definitions

//#include <sys/types.h>lo
#include <sys/stat.h>


//#include <openssl/des.h>

#ifdef __linux__
	#include <unistd.h> //В C++Builder ругался что нет
	#include <sys/vfs.h> //В C++Builder ругался что нет
	#include <sys/time.h>
	#include <sys/socket.h>
	#include <netinet/in.h>
	#include <netdb.h>
#elif _WIN32
	#include <windows.h>
#else

#endif

#include "utility.h"

namespace UtilityW
{
	time_t g_file_name_cnt_time;
	int g_file_name_cnt=0;
	//Генерировать уникальное имя файла на основе времени и порядкового номера из глобавльной переменной
	std::string getNextFileName()
	{
		if(g_file_name_cnt_time != std::time(0)){
			g_file_name_cnt_time = std::time(0);
			g_file_name_cnt=0;
		}
		g_file_name_cnt++;
		std::stringstream ss;
		ss << g_file_name_cnt_time << "_" << g_file_name_cnt ;
		return ss.str();
	}

#ifdef _WIN32
	//------------------------------------------------------------------------------
	void UnixTimeToFileTime(time_t t, LPFILETIME pft)
	{
	  // Note that LONGLONG is a 64-bit value
	  LONGLONG ll;
	  ll = Int32x32To64(t, 10000000) + 116444736000000000;
	  pft->dwLowDateTime = (DWORD)ll;
	  pft->dwHighDateTime = ll >> 32;
	}
	//------------------------------------------------------------------------------
	//После преобразования времени UNIX на структуру FILETIME, другие форматы времени Win32 можно легко получить с помощью функций Win32, как FileTimeToSystemTime() и FileTimeToDosDateTime().
	void UnixTimeToSystemTime(time_t t, LPSYSTEMTIME pst)
	{
	  FILETIME ft;
	  UnixTimeToFileTime(t, &ft);
	  FileTimeToSystemTime(&ft, pst);
	}
#endif
	//------------------------------------------------------------------------------
	//Разделитель для директорий
	char separator()
	{
	#ifdef _WIN32
		return '\\';
	#else
		return '/';
	#endif
	}
	//------------------------------------------------------------------------------
	bool deleteFile(std::string fileName)
	{
		bool result=false;
#ifdef __linux__
		if(unlink(fileName.c_str())==0)
		{
			result=true;
		}
#elif _WIN32
		if(remove(fileName.c_str())==0)
		{
			result=true;
		}
#endif
		return result;
	}
	//------------------------------------------------------------------------------
	//Получить размер самого большого файла вкатологе
	long getMaxFileSize(std::string path)
	{
		long maxSize=0;
		std::list<std::string> fileList;
		UtilityW::GetFiles(fileList,path);
		std::list<std::string>::const_iterator iterator;
		for (iterator = fileList.begin(); iterator != fileList.end(); ++iterator) {
			std::string fName = *iterator;
			long fSize = UtilityW::getFileSize(fName);
			if(fSize>maxSize)
				maxSize = fSize;
		}
		return maxSize;
	}
	//------------------------------------------------------------------------------
	//Проверяем открыт ли сокет
	//timeout - Тайм аут для коннекта в секундах
	/*bool checkPort(const char *hostname,int portno,int timeout)
	{
#ifdef __linux__
		bool result=false;

	    int sockfd;
	    struct sockaddr_in serv_addr;
	    struct hostent *server;
		sockfd = socket(AF_INET, SOCK_STREAM, 0);
	    if (sockfd >= 0) {
		    server = gethostbyname(hostname);

		    if (server == NULL) {
		        fprintf(stderr,"ERROR, no such host\n");
		        //exit(0);
		    }

		    bzero((char *) &serv_addr, sizeof(serv_addr)); //TODO Устаревшая конструкция
		    serv_addr.sin_family = AF_INET;
		    bcopy((char *)server->h_addr, //TODO Разыменование нулевого указателя, проверка на ИБ
		         (char *)&serv_addr.sin_addr.s_addr,
		         server->h_length);

		    serv_addr.sin_port = htons(portno);

		    //Чтобы была возможность задать таймаут для подключения делаю неблокирующий сокет
		    int flags = fcntl(sockfd, F_GETFL, 0);
		    if(fcntl(sockfd, F_SETFL, flags | O_NONBLOCK) == -1)
		    {
		    	fprintf(stderr,"ERROR, set O_NONBLOCK!\n");
		    }

		    if (connect(sockfd,(struct sockaddr *) &serv_addr,sizeof(serv_addr)) < 0)
		    {
		    	if(errno == EINPROGRESS) //Это не ошибка, это признак того, что соединение все еще не установлено.
		    	{
		    		struct timeval  ts;
		    	    ts.tv_sec = timeout;
		    	    ts.tv_usec = 0;

					//int ret = 0;
		    		fd_set  rset, wset;
		    	    FD_ZERO(&rset);
		    	    FD_SET(sockfd, &rset);
		    	    wset = rset;    //structure assignment ok

		    	    if(select(sockfd + 1, &rset, &wset, NULL, (timeout) ? &ts : NULL) > 0)
		    	    	result=true;

		    	}else{
		    		// Произошла ошибка сразу же при соединении.
		    	}

		    } else {
		        result=true; //Соединение было установлено за время системного вызова.
		    }

		    close(sockfd);
	    }


		return result;
#elif _WIN32
		return false;
#else
		return false;
#endif
	}*/
	//------------------------------------------------------------------------------
	//Простое вычисление CRC (как для GPS)
	uint8_t CRC8(const signed char *pcBlock, unsigned char len, unsigned char crc)
	{
		for(unsigned char i=0; i < len; i++)
		crc^=pcBlock[i];
		return crc;
	}
	//---------------------------------------------------------------------------
	//Найти файлы в директории и под директории и добавить их в список
	void GetFiles(std::list<std::string>& fileList, std::string directory)
	{
		if(directory.length()>0 && directory[directory.length()-1]!=separator()) directory+=separator();
#ifdef __linux__
		DIR *dir = opendir(directory.c_str());
		if(dir)
		{
			struct dirent *ent;
			while((ent = readdir(dir)) != NULL)
			{
				if(ent->d_type==0x04)
				{
					if ((strncmp(".", ent->d_name, 1) != 0) && (strncmp("..", ent->d_name, 2) != 0))
					{
						std::string newDir = directory + ent->d_name+"/";
						GetFiles(fileList, newDir);
					}
				}
				else
				if(ent->d_type==0x08)
				{
					std::string fWName = ent->d_name;
					fWName = directory + fWName;
					fileList.push_back(fWName);
				}
			}
			closedir(dir);
		}
#elif _WIN32
		HANDLE hFind;
		WIN32_FIND_DATAA FindFileData;

		if ((hFind = FindFirstFileA((std::string(directory+"*.*")).c_str(), &FindFileData)) != INVALID_HANDLE_VALUE) {
			do {
				if (FILE_ATTRIBUTE_DIRECTORY & FindFileData.dwFileAttributes)
				{
					if ((strncmp(".", FindFileData.cFileName, 1) != 0) && (strncmp("..", FindFileData.cFileName, 2) != 0))
					{
						std::string newDir = directory + FindFileData.cFileName+"\\";
						GetFiles(fileList, newDir);
					}
				}
				else
				{
					std::string fWName = FindFileData.cFileName;
					fWName = directory + fWName;
					fileList.push_back(fWName);
				}

			} while (FindNextFileA(hFind, &FindFileData));
			FindClose(hFind);
		}
#else

#endif
	}
	//---------------------------------------------------------------------------
	//Получить список папок в директории (без подпапок)
	void GetFolders(std::list<std::string>& folderList, std::string directory)
	{
#ifdef __linux__

		if(directory.length()>0 && directory[directory.length()-1]!='/') directory+='/';
		DIR *dir = opendir(directory.c_str());
		if(dir)
		{
			struct dirent *ent;
			while((ent = readdir(dir)) != NULL)
			{
				if(ent->d_type==0x04)
				{
					if ((strncmp(".", ent->d_name, 1) != 0) && (strncmp("..", ent->d_name, 2) != 0))
					{
						std::string newDir = directory + ent->d_name+"/";
						folderList.push_back(newDir);
					}
				}
			}
			closedir(dir);
		}

#elif _WIN32
		HANDLE hFind;
		WIN32_FIND_DATAA FindFileData;

		if ((hFind = FindFirstFileA((std::string(directory+"*.*")).c_str(), &FindFileData)) != INVALID_HANDLE_VALUE) {
			do {
				if (FILE_ATTRIBUTE_DIRECTORY & FindFileData.dwFileAttributes)
				{
					if ((strncmp(".", FindFileData.cFileName, 1) != 0) && (strncmp("..", FindFileData.cFileName, 2) != 0))
					{
						std::string newDir = directory + FindFileData.cFileName+"\\";
						folderList.push_back(newDir);
					}
				}
			} while (FindNextFileA(hFind, &FindFileData));
			FindClose(hFind);
		}
#else
#endif
	}
	//---------------------------------------------------------------------------
	//Создать папку
	bool createFolder(std::string directory,int mode=0776)
	{
#ifdef __linux__
		mkdir(directory.c_str(), mode); //Если папки нет то создать её
		chmod(directory.c_str(), mode); //Бывало что при создании права не назначались
		return true;
#elif _WIN32
		CreateDirectoryA(directory.c_str(), NULL);
		return true;
#else
#endif
	}
	//---------------------------------------------------------------------------
	//Расшифровать файлик
	bool DeCrypt(std::string strKey, std::string fNameIn, std::string fNameOut)
	{
/*
		DES_cblock key;
		DES_string_to_key(strKey.c_str(), &key);

		DES_key_schedule schedule;
		DES_set_key_checked(&key, &schedule);

		const_DES_cblock input; //Блок данных DES 8 байт (или 64 бита)
		DES_cblock output; //Результирующий блок данных

		FILE *ptr;
		if((ptr = fopen(fNameIn.c_str(),"rb")) != NULL)
		{
			char prf[4];
			fgets(prf, 4, ptr); //Префикс файла
			if(strcmp("DES", prf)==0)
			{
				FILE* out = fopen(fNameOut.c_str(),"wb");
				if(out!=NULL)
				{
					unsigned int fSize;
					fread((void *)&fSize, 1, sizeof(fSize), ptr);
					//int bSize=ceil(fSize/(float)sizeof(input));
					while(!feof(ptr) && !ferror(ptr))
					{
						memset(&input, 0, sizeof(input)); //Для дебага
						ssize_t bytes_read = fread(input, 1, sizeof(input), ptr);
						if(bytes_read==sizeof(input))
						{
							DES_ecb_encrypt(&input, &output, &schedule, DES_DECRYPT); //Расшифровываем
							//Записываем в файл
							if(fSize>sizeof(output))
							{
								fwrite(&output[0],sizeof(output),1,out);
								fSize = fSize - sizeof(output);
							}else
							{
								fwrite(&output[0],fSize,1,out);
							}
						}
					}

					if(fflush(out)!=0) std::cout << "!!! fflush = "<< strerror(errno) << " !!!" << std::endl;		// Flush to OS
					if(fsync(fileno(out))!=0) std::cout << "!!! fsync = "<< strerror(errno) << " !!!" << std::endl; // Flush to disk
					if(fclose(out)!=0) std::cout << "!!! fclose = "<< strerror(errno) << " !!!" << std::endl;		// Close file
				}
			}
			fclose(ptr);
		}
*/
		return true;
	}
	//---------------------------------------------------------------------------
	//Установит знначение бита в заданную позицию
	///pos - Позиция 7..0
	unsigned char setBitVal(unsigned char bit,unsigned char pos,bool val)
	{
		unsigned char v=1;
		v=0x1<<pos;
		if(val)
		{
			bit=bit | v;
		}else
		{
			v=v ^ 0xFF;
			bit=bit & v;
		}
		return bit;
	}
	//---------------------------------------------------------------------------
	//Вернёт значение бита на заданной позиции
	///pos - Позиция 7..0
	bool getBitVal(unsigned char bit,unsigned char pos)
	{
		unsigned char v=1;
		v=v<<pos;
		return (bit & v) == v;
	}
	//---------------------------------------------------------------------------
	// get_fs_size - Определяет размер ФС.
	// @param anyfile Путь к любому файлу на этой ФС.
	// @return Размер ФС в блоках*байты.
	long getAllFSSize(std::string anyfile)
	{
	#ifdef __linux__
		struct statfs buf;
		statfs(anyfile.c_str(), &buf);
		return buf.f_blocks*buf.f_bsize;
	#elif _WIN32
		return 0; //В винде нет sys/statvfs.h
	#else
	#endif
	}
	//---------------------------------------------------------------------------
	// get_fs_free - Определяет свободное место на ФС.
	// @param anyfile Путь к любому файлу на этой ФС.
	// @return Размер ФС в блоках*байты.
	long getFreeFSSize(std::string anyfile)
	{
	#ifdef __linux__
		struct statfs buf;
		statfs(anyfile.c_str(), &buf);
		return buf.f_bfree*buf.f_bsize;
	#elif _WIN32
		return 0; //В винде нет sys/statvfs.h
	#else
	#endif
	}
	//---------------------------------------------------------------------------
	//Размер файла в байтах
	long getFileSize(std::string filename)
	{
		/*struct stat stat_buf;
		int rc = stat(filename.c_str(), &stat_buf);
		return rc == 0 ? stat_buf.st_size : -1;*/

		long size=0;
		FILE *f = fopen(filename.c_str(), "rb");
		if (f)
		{
		   fseek(f, 0, SEEK_END);
		   size = ftell(f);
		   fclose(f);
		}
		return size;
	}
	//---------------------------------------------------------------------------
	//Текущее время в миллисекундах (с учётом того что время не сохрангяется то это время со старта линукса в милисекундах)
	unsigned int getMSecTime()
	{
#ifdef __linux__
		struct timeval time_now;
		gettimeofday(&time_now, NULL);
		unsigned int curr = time_now.tv_sec * 1000;
		curr += time_now.tv_usec / 1000.0f;
		return curr;
#elif _WIN32
		std::time_t t = std::time(0);
		return t;
#else
#endif
	}

	//Ротация логов при записи создаёт новый файл но не больше заданого числа лог файлов
	//Ищем файлы с максимальным индексом и проверяем его размер если он больше заданого то создаём новый иначе дописываем
/*	bool logrotate(unsigned int cnt,signed int size, std::string name, std::string data)
	{
		//Формируем список файлов
		std::vector<std::string> vFNames;
		DIR *dir = opendir("/mnt/sd/");
		if(dir)
		{
			struct dirent *ent;
			while((ent = readdir(dir)) != NULL)
			{
				if(std::string(ent->d_name).find(name)!=std::string::npos && std::string(ent->d_name).find(".txt")!=std::string::npos)
				{
					vFNames.push_back(ent->d_name);
				}
			}
			closedir(dir);
		}
		std::sort(vFNames.begin(), vFNames.end());

		std::string fName;
		if(vFNames.size()>0)
		{
			if(getFileSize(vFNames.at(0))>size)
			{
				std::string sNum = BeforeFirst(AfterLast(vFNames.at(0),'_'),'.');
				sNum = intToString(StdStrToInt(sNum)+1);
				for(unsigned int i=0;i<6-sNum.length();i++) sNum="0"+sNum;
				fName = name+"_"+sNum+".txt";
			}else
			{
				fName = vFNames.at(0);
			}
			if(vFNames.size()>cnt)
				deleteFile(vFNames.at(vFNames.size()-1).c_str()); //Если привысили количество файлов удаляем самый старый
		}else
		{
			 fName = "/mnt/sd/" + name + "_000000.txt";
		}

		std::ofstream myfile (fName.c_str(),std::fstream::app | std::fstream::out);
		if (myfile.is_open())
		{
			myfile << data << "\n";
			myfile.close();

			return true;
		}
		return false;
	}
*/
	//---------------------------------------------------------------------------
	//Сохранение лог файла по 10 мегабайт (в 2 файлика)
	//size - мегабайт на 1 файл
	/*bool logrotate(std::string fileName, std::string data,bool cout,int size)
	{
		bool result=false;

		long fileSize = getFileSize(fileName);
		//Переименовываем файл если он привысил размер
		if(fileSize>1024*1024*size)
		{
			remove(std::string(fileName + ".1").c_str()); //Пытаюсь удалить старый файл
			rename(fileName.c_str(),std::string(fileName+".1").c_str());
		}

		//Записываем лог
		std::ofstream myfile(fileName.c_str(),std::fstream::app | std::fstream::out);
		if (myfile.is_open())
		{
			timeval curTime;
			gettimeofday(&curTime, NULL);
			int milli = curTime.tv_usec / 1000;
			//std::time_t utime = std::time(0); так как не мог выбрать миллисекунды
			std::time_t utime = curTime.tv_sec;

			//Время в заданом формате
			char buffer[80]; memset(buffer,0,sizeof(buffer));
			//std::strftime(buffer,sizeof(buffer),"%Y.%m.%d %H:%M:%S",std::localtime(&utime));
			std::strftime(buffer,sizeof(buffer),"%Y.%m.%d %H:%M:%S",std::localtime(&utime));
			std::string time=buffer;
			time+=":"+intToString(milli); //Добавляю миллисекунды

			if(cout)
				std::cout << "[" << time << "] " << data << std::endl; //Повтор лога в консоль

			myfile << "[" << time << "] " << data << std::endl;
			myfile.flush();
			myfile.close();
			result=true;
		}else
		{
			std::cerr << "Logrotate error: " << strerror(errno) << " fileName: " << fileName << std::endl;
		}
		return result;
	}*/
	//---------------------------------------------------------------------------
	std::string escape_json(const std::string& input) {
	    std::ostringstream oss;
	    for (char c : input) {
	        switch (c) {
	            case '"':  oss << "\\\""; break;
	            case '\\': oss << "\\\\"; break;
	            case '\b': oss << "\\b";  break;
	            case '\f': oss << "\\f";  break;
	            case '\n': oss << "\\n";  break;
	            case '\r': oss << "\\r";  break;
	            case '\t': oss << "\\t";  break;
	            default:
	                if (static_cast<unsigned char>(c) < 0x20 || c == 0x7F) {
	                    oss << "\\u" << std::hex << std::setw(4) << std::setfill('0') << static_cast<int>(c);
	                } else {
	                    oss << c;
	                }
	                break;
	        }
	    }
	    return oss.str();
	}
	//---------------------------------------------------------------------------
	//Сохранение лог файла по 10 мегабайт (в 2 файлика) Функция отрабатывает за 4 миллисекунды
	bool logrotate(std::string fileName, std::string thread, std::string level, std::string data, bool cout, int size)
	{
		long fileSize = getFileSize(fileName);
		//Переименовываем файл если он привысил размер
		if(fileSize>1024*1024* size)
		{
			remove(std::string(fileName + ".1").c_str()); //Пытаюсь удалить старый файл
			rename(fileName.c_str(),std::string(fileName+".1").c_str());
		}

		//Записываем лог
		std::ofstream myfile(fileName.c_str(), std::ofstream::binary | std::fstream::app);
		if (myfile.is_open())
		{
			std::stringstream str(std::stringstream::out | std::stringstream::binary);
#if defined(_WIN32) || defined(_WINDOWS) || defined(_BORLAND)
			SYSTEMTIME st;
			GetLocalTime(&st);
			char buffer[256];
			memset(buffer, 0, sizeof(buffer));
			sprintf(buffer,
				"%d-%02d-%02d %02d:%02d:%02d.%03d",
				st.wYear,
				st.wMonth,
				st.wDay,
				st.wHour,
				st.wMinute,
				st.wSecond,
				st.wMilliseconds);
			str << "[" << buffer << "] " << data << std::endl;
#else
			timeval curTime;
			gettimeofday(&curTime, NULL);
			int milli = curTime.tv_usec / 1000;
			std::time_t utime = curTime.tv_sec;
			char buffer[80]; memset(buffer, 0, sizeof(buffer));
			std::strftime(buffer, sizeof(buffer), "%Y-%m-%dT%H:%M:%S", std::localtime(&utime));
			str << "{\"timestamp\":\"" << buffer << "." << std::setw(3) << std::setfill('0') << milli << "Z\", \"thread\":\"" <<thread<<"\", \"level\":\""<<level<<"\", \"message\":\"" << escape_json(data)<<"\"}" << std::endl;
#endif
			if (cout)
				std::cout << "[" << buffer << "] " << data << std::endl; //Повтор лога в консоль

			myfile.write(str.str().c_str(), str.str().length());
			myfile.flush();
			myfile.close();
			return true;
		}else
		{
			std::cerr << "Error: " << strerror(errno) << " " << fileName << std::endl;
		}
		return true;
	}
	//---------------------------------------------------------------------------
	std::string charToHex(unsigned char c)
	{
		short i = c;
		std::stringstream s;
		s << std::setw(2) << std::setfill('0') << std::hex << i;
		std::string result=s.str();
		return result;
	}
	//---------------------------------------------------------------------------
	std::string shortToHex(unsigned short c)
	{
		std::stringstream s;
		s << std::setw(4) << std::setfill('0') << std::hex << c;
		return s.str();
	}
	//---------------------------------------------------------------------------
	std::string uintToHex(unsigned int val,char size){
		std::stringstream s;
		s << std::setw(size) << std::setfill('0') << std::hex << val;
		return s.str();
	}
	//---------------------------------------------------------------------------
	unsigned char hexToChar(const std::string &str) {
		short c = 0;

		if(!str.empty()) {
			std::istringstream in(str);

			in >> std::hex >> c;

			//if(in.fail()) {
			//	throw std::runtime_error("stream decode failure");
			//}
		}
		return static_cast<unsigned char>(c);
	}
	//---------------------------------------------------------------------------
	//Преобразовать строку битов в char
	unsigned char bitStrToChar(std::string str)
	{
		unsigned char result=0;
		int s=str.size();
		for(int i=0;i<std::min(8,s);i++)
		{
			result=setBitVal(0,7-i,result);
		}
		return result;
	}
	//---------------------------------------------------------------------------
	bool hexStrToArray(const std::string &str,char* arr)
	{
		short c;
		if(str.size()==0 || (str.size() % 2) > 0) return false;
		for(size_t i=0;i<str.size()/2;i++)
		{
			std::istringstream in(str.substr(i*2,2));
			in >> std::hex >> c;
			if(in.fail()) return false;
			arr[i] = c;
		}
		return true;
	}
	//---------------------------------------------------------------------------
	bool arrayToHexStr(char* arr,unsigned int len,std::string &str)
	{
		for(unsigned int i=0;i<len;i++)
		{
			str+=charToHex(arr[i]);
		}
		return true;
	}
	//---------------------------------------------------------------------------
	bool vectorToHexStr(std::vector < unsigned char >& arr,std::string &str)
	{
		for (unsigned int i = 0; i < arr.size(); i++)
		{
			str+=charToHex(arr[i]);
		}
		return true;
	}
	//---------------------------------------------------------------------------
	//Инициализируем ножку чтоб в неё можно записывать 0 или 1 как в файл
	//Документация GPIO: http://www.avrfreaks.net/wiki/index.php/Documentation:Linux/GPIO
	/*bool initPin(std::string pinnum)
	{
		bool result=true;

		std::string path = "/sys/class/gpio/gpio"; //Чтобы не переинициализировать проверяем существование директории
		path += pinnum;
		DIR* dir = opendir(path.c_str());
		if (dir)
		{
			closedir(dir);
		}else
		{
			FILE *fp;
			char set_value[4] = {0,0,0,0};
			if ((fp = fopen("/sys/class/gpio/export", "ab")) != NULL)
			{
				rewind(fp); //К началу файла
				strcpy(set_value,pinnum.c_str());
				fwrite(&set_value, sizeof(char), strlen(set_value), fp);
				fclose(fp);
			}else
				result=false;
		}
		return result;
	}*/
	//---------------------------------------------------------------------------
	//Задать направление чтения или записи (сейчас вывод) (A=0,B=32,C=64,D=96,E=128)
	//dit=true на запись, dit=false на чтение, pull - подтяжка к 0 или к 1 питания.
	/*bool setPinDir(std::string pinnum,bool dir=true)
	{
		bool result=true;
		FILE *fp;
		std::string fName = "/sys/class/gpio/gpio";
		fName += pinnum;
		fName += "/direction";  //Почемуто глючит когда плюсую в 1 строку (ответ от AT команд: повторы)

		char set_value[5] = {0,0,0,0,0};

		//проверяем нужно ли менять направление если нет ничего не делаем
		if((fp = fopen(fName.c_str(), "r")) != NULL)
		{
			fread(set_value, 3, 1, fp);
			fclose(fp);
		}

		if((dir && !(set_value[0]=='o' && set_value[1]=='u' && set_value[2]=='t')) || (!dir && !(set_value[0]=='i' && set_value[1]=='n')))
		{
			if ((fp = fopen(fName.c_str(), "rb+")) != NULL)
			{
				rewind(fp);
				memset (set_value, 0, 5);
				if(dir)
				{
					strcpy(set_value,"out");
					fwrite(&set_value, sizeof(char), strlen(set_value), fp);
				}else
				{
					strcpy(set_value,"in");
					fwrite(&set_value, sizeof(char), strlen(set_value), fp);
					memset (set_value, 0, 5);
				}
				fclose(fp);
			} else
				result=false;
		}
		return result;
	}*/
	//---------------------------------------------------------------------------
	//Задаём напряжение для ножки (A=0,B=32,C=64,D=96,E=128)
	bool setPinVal(std::string pinnum, bool val)
	{
		bool result=true;
		FILE *fp;
		std::string fName = "/sys/class/gpio/gpio";
		fName += pinnum;
		fName += "/value";
		unsigned char ch;
		if(val) ch='1'; else ch='0';
		if ((fp = fopen(fName.c_str(), "wb+")) != NULL)
		{
			rewind(fp); //К началу файла
			if(fwrite(&ch, sizeof(char), 1, fp)!=1) result=false;
			fclose(fp);
		}else
			result=false;
		return result;
	}
	//---------------------------------------------------------------------------
	//Получит напряжение ножки (A=0,B=32,C=64,D=96,E=128)
	char getPinVal(std::string pinnum)
	{
		FILE *fp;
		std::string fName= "/sys/class/gpio/gpio";
		fName += pinnum;
		fName += "/value";
		char ch=-1;

		fp = fopen(fName.c_str(), "r");
		if (fp != NULL)
		{
			//rewind(fp); //К началу файла
			if(fread (&ch, sizeof(char), 1, fp)!=1)
			{
				ch=-1; //Ошибка
			}
			fclose(fp);
		}else
			ch=-1;

		if(ch=='0') return 0;
		else if(ch=='1') return 1;
		else return -1; //Ошибка
	}
	//---------------------------------------------------------------------------
	std::string doubleToString(double val)
	{
		std::ostringstream strs;
		strs << val;
		return strs.str();
	}
	//---------------------------------------------------------------------------
	std::string intToString(int val)
	{
		std::stringstream ss;
		ss << val;
		return ss.str();
	}
	//---------------------------------------------------------------------------
	std::string uintToString(unsigned int val)
	{
		std::stringstream ss;
		ss << val;
		return ss.str();
	}
	//---------------------------------------------------------------------------
	std::string ullintToString(unsigned long long int val)
	{
		std::stringstream ss;
		ss << val;
		return ss.str();
	}
	//---------------------------------------------------------------------------
	std::string DecToBinStr(unsigned int N,int cnt){
		std::string S="";
		if(N!=0)
		{
			for(unsigned long i=1;i<sizeof(N)*8;i++)
			{
				if((N & 1) == 1) S="1"+S; else S="0"+S;
				N=N >> 1;
			}
			S=S.substr(S.find("1"),S.size());
		}
		cnt-=S.size();
		if(cnt>0){
			for(int i=0;i<cnt;i++)
				S="0"+S;
		}
		return S;
	}
	//---------------------------------------------------------------------------
	std::string addZero(std::string str,int count,char ch){
		int val=std::min(count,(int)str.length());
		return std::string(count - val, ch) + str;
	}
	//---------------------------------------------------------------------------
	std::string addZero(int val,int count,char ch){
		return addZero(intToString(val),count,ch);
	}
	//---------------------------------------------------------------------------
	std::string DecToBinStr(int N,int cnt)
	{
		std::string S="";
		if(N!=0)
		{
			for(unsigned long i=1;i<sizeof(N)*8;i++)
			{
				if((N & 1) == 1) S="1"+S; else S="0"+S;
				N=N >> 1;
			}
			S=S.substr(S.find("1"),S.size());
		}
		cnt-=S.size();
		if(cnt>0){
			for(int i=0;i<cnt;i++)
				S="0"+S;
		}
		return S;
	}
	//---------------------------------------------------------------------------
	std::string AfterFirst(std::string str,const char ch)
	{
		unsigned int pos=str.find(ch);
		std::string result="";
		result.append(str,pos+1,str.size());
		return result;
	}

	//---------------------------------------------------------------------------
	std::string BeforeFirst(std::string str,const unsigned char ch)
	{
		unsigned int pos=str.find(ch);
		std::string result="";
		result.append(str,0,pos);
		return result;
	}
	//---------------------------------------------------------------------------
	///Получить строку до указанного символа если символа нет то вернет всю строку.
	std::string BeforeLast(std::string str,char ch)
	{
		int pos=0;
		for(unsigned int i=0;i<str.length();i++)
		{
			if(str[i]==ch) pos=i;
		}
		if(pos==0) pos=str.length();

		std::string result="";
		result.append(str,0,pos);
		return result;
	}
	//---------------------------------------------------------------------------
	//Отрезать от строки до указанного символа если не найден символ отрезается вся строка
	std::string CutBeforeFirst(std::string& str,const unsigned char ch)
	{
		int pos=str.find(ch);
		std::string result="";
		if(pos==-1)
		{
			result.append(str);
			str.erase();
		}else
		{
			result.append(str,0,pos);
			str.erase(0,pos+1);
		}
		return result;
	}
	//---------------------------------------------------------------------------
	std::string CutBeforeFirst(std::string& str,std::string br)
	{
		int pos=str.find(br);
		std::string result="";
		if(pos==-1)
		{
			result.append(str);
			str.erase();
		}else
		{
			result.append(str,0,pos);
			str.erase(0,pos+br.length());
		}
		return result;
	}
	//---------------------------------------------------------------------------
	//Если не найдёт нужный символ то вернёт всю строку
	std::string CutAfterLast(std::string& str,const unsigned char ch)
	{
		std::string result="";
		size_t pos=str.find_last_of(ch);
		if(pos!=std::string::npos)
		{
			result.append(str,pos+1,str.length()-pos-1);
			str.erase(pos);
		}else
		{
			result.append(str);
			str.erase();
		}
		return result;
	}
	//---------------------------------------------------------------------------
	std::string CutAfterFirst(std::string& str,std::string br)
	{
		size_t pos=str.find(br);
		std::string result="";
		if(pos==std::string::npos)
		{
			result.append(str);
			str.erase();
		}else
		{
			result.append(str,pos + br.size(),str.length() - pos - br.size());
			str.erase(pos);
		}
		return result;
	}
	//---------------------------------------------------------------------------
	//Всё после заданного разделителя, если разделитель не найден то сначала строки
	std::string AfterLast(std::string str,const unsigned char ch)
	{
		int pos=str.find_last_of(ch)+1;
		if(pos>=0)
		{
			int len=str.length()-pos;
			return str.substr(pos,len);
		}else
		{
			return str;
		}
	}
	//---------------------------------------------------------------------------
	template<typename T>
	T fromString(const std::string& s)
	{
		std::istringstream iss(s);
		T res;
		iss >> res;
		return res;
	}
	//---------------------------------------------------------------------------
	double StdStrToDouble(std::string& str)
	{
		if(str=="") return 0;
		return fromString<double>(str);
	}
	//---------------------------------------------------------------------------
	float StdStrToFloat(std::string& str)
	{
		if(str=="") return 0;
		return fromString<float>(str);
	}
	//---------------------------------------------------------------------------
	//Безопасное преобразование в float
	bool StdStrToFloat(std::string& str,float& val)
	{
		if(str=="") { val = 0; return false; }
		try
		{
			val = fromString<float>(str);
			return true;
		}catch(...)
		{
			val=0;
			return false;
		}
	}
	//---------------------------------------------------------------------------
	int StdStrToInt(std::string& str)
	{
		if(str=="") return 0;
		return fromString<int>(str);
	}
	//---------------------------------------------------------------------------
	unsigned int StdStrToUInt(std::string& str)
	{
		std::string tmp="";
		for(int i=0;i<(int)str.length();i++)
			if(str[i]=='0' || str[i]=='1' || str[i]=='2' || str[i]=='3' || str[i]=='4' || str[i]=='5' || str[i]=='6' || str[i]=='7' || str[i]=='8' || str[i]=='9') tmp+=str[i];

		if(tmp=="") return 0;
		return fromString<unsigned int>(tmp);
	}
	//---------------------------------------------------------------------------
	unsigned long long StdStrToULLInt(std::string& str){
		std::string tmp="";
		for(int i=0;i<(int)str.length();i++)
			if(str[i]=='0' || str[i]=='1' || str[i]=='2' || str[i]=='3' || str[i]=='4' || str[i]=='5' || str[i]=='6' || str[i]=='7' || str[i]=='8' || str[i]=='9') tmp+=str[i];

		if(tmp=="") return 0;
		return fromString<unsigned long long>(tmp);
	}
	//---------------------------------------------------------------------------
	unsigned int HexStdStrToUInt(std::string& str)
	{
		unsigned int x;
		std::stringstream ss;
		ss << std::hex << str;
		ss >> x;
		return x;
	}
	//---------------------------------------------------------------------------
	//Получить дату последнего изменения файла
	long getFileDateModiff(std::string file)
	{
	#ifdef __linux__
		struct stat fStat;
		int rc = stat(file.c_str(), &fStat);
		if(rc==0)
		{
			return fStat.st_mtim.tv_sec;
		}
		return 0;
	#elif _WIN32
		return 0;
	#else
	#endif
	}
	//------------------------------------------------------------------------------
	//удалить старые файлы которые были созданы больше заданного количества дней
	bool deleteOldFiles(std::string path,int days)
	{
		bool result=true;
		std::list<std::string> fileList;
		UtilityW::GetFiles(fileList,path);
		std::list<std::string>::const_iterator iterator;
		for (iterator = fileList.begin(); iterator != fileList.end(); ++iterator) {
			std::string fName = *iterator;
			long timeS = getFileDateModiff(fName);
			int tNow=std::time(NULL);
			int tDiff = tNow-timeS;
			if(tDiff > days*24*60*60) {
				if(!deleteFile(fName)) {
					result=result & false;
				}
			}
		}
		return result;
	}
	//------------------------------------------------------------------------------
	//Удалить самый старый файл в директории
	bool deleteOldFile(std::string path)
	{
		bool result=true;
		long timeOld = std::time(NULL);
		std::string fNameOld = "";
		std::list<std::string> fileList;
		UtilityW::GetFiles(fileList,path);
		std::list<std::string>::const_iterator iterator;
		for (iterator = fileList.begin(); iterator != fileList.end(); ++iterator) {
			std::string fName = *iterator;
			long timeS = getFileDateModiff(fName);
			if(timeOld>timeS){
				timeOld=timeS;
				fNameOld=fName;
			}
		}
		if(fNameOld.length()>0){
			if(!deleteFile(fNameOld)) {
				result=false;
			}
		}
		return result;
	}
	//---------------------------------------------------------------------------
	//Прочитать файл в память (закоментил, проверка на ИБ)
	// data - куда будем писать, разанее нужно создать
	/*int readFile(std::string file, char* data, int size)
	{
		ssize_t bytes_read = 0;
		FILE *ptr;
		if((ptr = fopen(file.c_str(),"rb")) != NULL)
		{
			while(!feof(ptr) && !ferror(ptr))
			{
				ssize_t read = fread(data, 1, size, ptr);
				data = data + read;
				bytes_read+=read;
			}
			fclose(ptr);
		}
		return bytes_read;
	}*/
	//---------------------------------------------------------------------------
	bool dirExists(std::string path)
	{
		struct stat info;

		if(stat( path.c_str(), &info ) != 0)
			return 0;
		else if(info.st_mode & S_IFDIR)
			return 1;
		else
			return 0;
	}
	//---------------------------------------------------------------------------
	bool fileExists(std::string name)
	{
	    if (FILE *file = fopen(name.c_str(), "r")) {
	        fclose(file);
	        return true;
	    } else {
	        return false;
	    }
	}
	//---------------------------------------------------------------------------
	void delString(std::vector<std::string> *mas, int pos)
	{
		int size = (int)mas->size();
		if(pos<size)
			mas->erase(mas->begin()+pos);
	}
	//---------------------------------------------------------------------------
	//time - время в секундах с милисекундами в дробной
	std::string unixTimeToDate(double time)
	{
#ifdef __linux__
		struct tm * dt;
		char b[20];
		memset(b,0,20);

		time_t tmp1=floor(time);
		unsigned short tmp2 = (time - tmp1) * 1000;

		dt = localtime(&tmp1);
		strftime(b, sizeof(b), "%Y.%m.%d %H:%M:%S", dt);

		std::string result=b;
		if(tmp2!=0)
		{
			result += '.';
			result += intToString(tmp2);
		}
		return result;
#elif _WIN32
		return "";
#else
#endif
	}
	//---------------------------------------------------------------------------
	//В секундах
	void sleep2(int sec)
	{
#ifdef __linux__
		sleep(sec);
#elif _WIN32
		Sleep(sec*1000);
#else
#endif
	}
	//---------------------------------------------------------------------------
	void TrimLeft(std::string& str)
	{
		size_t startpos = str.find_first_not_of(" \t\f\n\r");
		if(startpos != std::string::npos)
		{
			str = str.substr( startpos );
		}else
		{
			str.clear(); //Вся строка из спец символов
		}
	}
	//---------------------------------------------------------------------------
	void TrimRight(std::string& str)
	{
		 std::string::size_type endpos = str.find_last_not_of(" \t\f\n\r");
		if( endpos != std::string::npos )
		{
			str = str.substr( 0, endpos+1 );
		}else
		{
			str.clear(); //Вся строка из спец символов
		}
	}
	//---------------------------------------------------------------------------
	void Trim(std::string& s)
	{
		TrimLeft(s);
		TrimRight(s);
	}
	//------------------------------------------------------------------------------
	//Для определения проходит ли линия в нутри заданого радиуса
	//r - радиус
	//cx,cy - центр радиуса
	//lx1, ly1 - начало линии
	//lx2, ly2 - конец линии
	//Coincides - Проходит или нет
	//x, y - Ближайшая точка на линии к центру радиуса
	void Distance(float r, float cx, float cy, float lx1, float ly1, float lx2, float ly2, bool& Coincides, float& x, float& y)
	{
		double ang, angcos, angsin;
		double ncx, ncy, nlx2, nr;

		x = 0.0; y = 0.0;

		cx = cx - lx1;
		cy = cy - ly1;
		lx2 = lx2 - lx1;
		ly2 = ly2 - ly1;
		ang = atan(ly2 / lx2);
		if (lx2<0) ang = ang + M_PI;
		if ((lx2>0) && (ly2<0)) ang = ang + (2 * M_PI);
		angcos = cos(ang);
		angsin = sin(ang);
		ncx = cx*angcos + cy*angsin;
		ncy = cy*angcos - (cx*angsin);
		nlx2 = lx2*angcos + ly2*angsin;
		nr = fabs(ncy);
		Coincides = false;
		if (nr<r)
		{
			Coincides = true;
			if (ncx<0)
			{
				if (ncx<-r)
				{
					Coincides = false;
					return;
				}
				nr = sqrt(ncx*ncx + ncy*ncy);
				if (nr<r)
				{
					x = lx1;
					y = ly1;
					return;
				}
				Coincides = false;
				return;
			}
			else
				if (ncx>nlx2)
				{
					if (ncx>nlx2 + r)
					{
						Coincides = false;
						return;
					}
					nr = sqrt((ncx - nlx2)*(ncx - nlx2) + ncy*ncy);
					if (nr<r)
					{
						x = lx2 + lx1;
						y = ly2 + ly1;
						return;
					}
					Coincides = false;
					return;
				}
				else
				{
					angcos = cos(2 * M_PI - ang);
					angsin = sin(2 * M_PI - ang);
					x = (float)(ncx*angcos + lx1);
					y = (float)(-(ncx*angsin) + ly1);
					return;
				}
		}
	}

	bool parseGPRMC(std::string ans,time_t& utime,double& lon,double& lat,float& speed,float& angle)
	{
#ifdef __linux__
		bool result=false;
		std::string time; //Время «hh» — часы, «mm» — минуты, «ss.sss» — секунды. Длина дробной части секунд варьируется.
		std::string date; //Дата «ddmmyy» ведущие нули обязательны

		UtilityW::Trim(ans);
		if(ans!="")
		{
			if(ans.find("$GPRMC")==0) //Recommended minimum specific GPS/Transit data см. https://ru.wikipedia.org/wiki/NMEA_0183 (Берётся с UBLOX 6)
			{
				//Пример пакета: $GPRMC,074353.0,A,4315.286297,N,07651.391112,E,0.0,255.3,191214,,,A*68
				try
				{
					std::string stmp1="",stmp2=""; //Временные строки
					//Подсчитываем контрольную сумму
					unsigned char csum=0;
					for(int i=1;i<(int)ans.length();i++)
					{	if(ans[i]=='*') break;
						csum  = csum ^ ans[i];
					}
					stmp1=UtilityW::AfterLast(ans,'*');
					if(csum==UtilityW::HexStdStrToUInt(stmp1)) //Проверяем контрольную сумму
					{
						UtilityW::CutBeforeFirst(ans,','); //Удаляем $GPRMC,
						std::string time = UtilityW::CutBeforeFirst(ans,','); //Время фиксации местоположения по Всемирному координированному времени UTC: «hh» — часы, «mm» — минуты, «ss.sss» — секунды. Длина дробной части секунд варьируется. Лидирующие нули не опускаются.
						if(UtilityW::CutBeforeFirst(ans,',')=="A") //Если данные достоверны
						{
							stmp2 = UtilityW::CutBeforeFirst(ans,','); //«GGMM.MM» — широта. 2 цифры градусов(«GG»), 2 цифры целых минут, точка и дробная часть минут переменной длины. Лидирующие нули не опускаются.
							if(stmp2.length()>0)
							{
								stmp1=stmp2.substr(0,2); stmp2=stmp2.substr(2);
								lat = UtilityW::StdStrToDouble(stmp1);
								lat += UtilityW::StdStrToDouble(stmp2) / 60.0f;
							}else
								lat = 0;

							if(UtilityW::CutBeforeFirst(ans,',')=="S") lat=-lat; //«P» — «N» для северной или «S» для южной широты.

							stmp2 = UtilityW::CutBeforeFirst(ans,','); //«gggmm.mm» — долгота. 3 цифры градусов(«ggg»), 2 цифры целых минут, точка и дробная часть минут переменной длины. Лидирующие нули не опускаются.
							if(stmp2.length()>0)
							{
								stmp1=stmp2.substr(0,3); stmp2=stmp2.substr(3);
								lon = UtilityW::StdStrToDouble(stmp1);
								lon += UtilityW::StdStrToDouble(stmp2) / 60.0f;
							}else
								lon = 0;

							if(UtilityW::CutBeforeFirst(ans,',')=="W") lon=-lon; //«J» — «E» для восточной или «W» для западной долготы.

							stmp1 = UtilityW::CutBeforeFirst(ans,','); // горизонтальная составляющая скорости относительно земли в узлах.
							speed = UtilityW::StdStrToFloat(stmp1);
							stmp1 = UtilityW::CutBeforeFirst(ans,','); //путевой угол (направление скорости) в градусах.
							angle = UtilityW::StdStrToFloat(stmp1);
							std::string date = UtilityW::CutBeforeFirst(ans,','); //«ddmmyy» — дата: день месяца, месяц, последние 2 цифры года (ведущие нули обязательны).

							//Преобразую время в UnixTime
							utime = 0;
							if(date!="" && time!="")
							{
								time=UtilityW::BeforeFirst(time,'.');
								std::string date_time = date + " " + time; //Формат: «ddmmyy hhmmss»
								struct tm tmd;
								memset(&tmd, 0, sizeof(struct tm));
								if(strptime(date_time.c_str(), "%d%m%y %H%M%S", &tmd))
								{
									utime = mktime(&tmd);
								}
							}
							result=true;
						}
					}
				}catch(...)
				{}
			}
		}
		return result;
#elif _WIN32
		return false;
#else
#endif
	}

}
