#include "stdafx.h"
#include "help.h"
#include "dataParser.h"
#include <bitset>
#include <random>
#include <experimental/filesystem>

using namespace std;

#undef min

bool help::pathExists(std::string path)
{
	std::experimental::filesystem::path p = path;
	return std::experimental::filesystem::exists(p);
}

bool help::isFolder(std::string path)
{
	std::experimental::filesystem::path p = path;
	return std::experimental::filesystem::is_directory(p);
}

bool help::isFile(std::string path)
{
	std::experimental::filesystem::path p = path;
	
	if (std::experimental::filesystem::is_directory(p))
		return false;

	return true;
}

string help::stripFileNameFromPath(std::string path)
{
	string folder = path.substr(0, path.find_last_of("\\/"));

	return folder;
}

void help::trimLeft(string &s, string const &delimiters)
{
	const size_t startpos = s.find_first_not_of(delimiters);
	if (string::npos != startpos)
	{
		//s = s.substr(startpos, s.end);
		s.erase(s.begin(), s.begin() + startpos);
	}
}

void help::trimRight(string &s, string const &delimiters)
{
	const size_t endpos = s.find_last_not_of(delimiters);
	if (string::npos != endpos)
	{
		//s = s.substr(0, endpos + 1);
		s.erase(s.begin() + endpos + 1, s.end());
	}
}

void help::trim(string &s, string const &delimiters)
{
	trimLeft(s, delimiters);
	trimRight(s, delimiters);
}

vector<string> help::split(string const& s, char const *d)
{
	vector<string> output;

	bitset<255> delims;
	while (*d)
	{
		unsigned char code = *d++;
		delims[code] = true;
	}

	string::const_iterator beg;
	bool in_token = false;
	for (string::const_iterator it = s.begin(), end = s.end(); it != end; ++it)
	{
		if (delims[*it])
		{
			if (in_token)
			{
				//output.push_back(beg, it);
				output.push_back(vector<string>::value_type(beg, it));
				in_token = false;
			}
		}
		else if (!in_token)
		{
			beg = it;
			in_token = true;
		}
	}
	if (in_token)
		output.push_back(vector<string>::value_type(beg, s.end()));

	return output;
}

void help::correctBomLine(string &s)
{
	if (s.compare(0, 3, "\xEF\xBB\xBF") == 0)  // Is the file marked as UTF-8?
	{
		s.erase(0, 3);                  // Now get rid of the BOM.
	}
	else if (s.compare(0, 2, "\xFE\xFF") == 0)  // Is the file marked as UTF-16 BE?
	{
		s.erase(0, 2);                  // Now get rid of the BOM.
	}
	else if (s.compare(0, 2, "\xFF\xFE") == 0)  // Is the file marked as UTF-16 LE
	{
		s.erase(0, 2);                  // Now get rid of the BOM.
	}
	else if (s.compare(0, 4, "\x00\x00\xFE\xFF") == 0)  // Is the file marked as UTF-32 BE?
	{
		s.erase(0, 4);                  // Now get rid of the BOM.
	}
	else if (s.compare(0, 4, "\xFF\xFE\x00\x00") == 0)  // Is the file marked as UTF-32 LE?
	{
		s.erase(0, 4);                  // Now get rid of the BOM.
	}
}

double help::random_real(int min, int max)
{
	std::random_device rd;
	std::mt19937 gen(rd());
	std::uniform_real_distribution<double> dis(min, max);

	return dis(gen);
}

int help::random_int(int min, int max)
{
	std::random_device rd;
	std::mt19937 gen(rd());
	std::uniform_int_distribution<int> dis(min, max);

	return dis(gen);
}

vtr2<double> help::random_timeSeries(int size, int dims, int min, int max)
{
	vtr2<double> ts(size);

	for (int i = 0; i < size; i++)
	{
		vtr<double> point(dims);
		for (int j = 0; j < dims; j++)
		{
			point[j] = help::random_real(min, max);
			ts[i] = (point);
		}
	}

	return ts;
}

template<class T>
vtr<T> help::vtr_init(size_t size)
{
	return vtr<T>(size);
}

template<class T>
vtr2<T> help::vtr_init(size_t size1, size_t size2)
{
	vtr2<T> tmp(size1);
	for (size_t i = 0; i < size1; i++)
		tmp[i] = vtr<T>(size2);

	return tmp;
}

template<class T>
void help::vtr_init(vtr2<T> &m, size_t size1, size_t size2, T value)
{
	m.reserve(size1);
	for (size_t i = 0; i < size1; i++)
	{
		m[i] = vtr<T>(size2);
		std::fill(m[i].begin(), m[i].end(), value);
	}

	return tmp;
}

template<class T>
vtr3<T> help::vtr_init(size_t size1, size_t size2, size_t size3)
{
	vtr3<T> tmp(size1);
	for (size_t i = 0; i < size1; i++)
		tmp[i] = help::vtr_init<T>(size2, size3);

	return tmp;
}
template vtr3<int> help::vtr_init<int>(size_t size1, size_t size2, size_t size3);
template vtr3<double> help::vtr_init<double>(size_t size1, size_t size2, size_t size3);

template<class T>
vtr3<T> help::vtr_initPartial(size_t size1, size_t size2)
{
	vtr3<T> tmp(size1);
	for (size_t i = 0; i < size1; i++)
		tmp[i] = vtr2<T>(size2);

	return tmp;
}
template vtr3<double> help::vtr_initPartial<double>(size_t size1, size_t size2);

template <typename T>
T help::vtr_findMax(vtr2<T> const &input)
{
	double max = constant::MIN_double;

	for (auto &&i : input)
		for (auto &&j : i)
			if (j > max)
				max = j;

	return max;
}
template double help::vtr_findMax<double>(vtr2<double> const &input);

template <typename T>
T help::vtr_findMax(vtr3<T> const &input)
{
	double max = constant::min_double;

	for (auto &i : input) {
		auto tmp = vtr_findMax(i);

		if (tmp > max)
			max = tmp;
	}

	return max;
}

template <typename T>
T help::vtr_findMin(vtr2<T> const &input)
{
	double min = constant::MAX_double;

	for (auto &&i : input)
		for (auto &&j : i)
			if (j < min)
				min = j;

	return min;
}
template double help::vtr_findMin<double>(vtr2<double> const &input);

//void help::interpolate2(vtr3<double> &input)
//void help::interpolate(vtr3<double> &input)

void help::normalizeMany(vtr3<double> &input)
{
	for (size_t i = 0; i < input.size(); i++) //dims
	{
		normalize(input[i]);
	}
}

void help::normalize(vtr2<double> &input)
{
	for (size_t i = 0; i < input[0].size(); i++) //dims
	{
		double mean = 0;
		for (size_t j = 0; j < input.size(); j++) //lenght of sequence
		{
			mean += input[j][i];
		}
		mean = mean / (double)input.size();
		//mean = abs(mean);
				
		for (size_t j = 0; j < input.size(); j++) //lenght of sequence
		{
			input[j][i] = input[j][i] / mean;
		}
	}
}

void help::normalizeZeroOne(vtr3<double> &input, double max)
{
	for (size_t i = 0; i < input.size(); i++)
	{
		for (size_t j = 0; j < input[i].size(); j++)
		{
			for (size_t k = 0; k < input[i][j].size(); k++)
			{
				input[i][j][k] /= max;
			}
		}
	}
}

vtr2<double> help::normalize(vtr2<double> const &input, double coef)
{
	vtr2<double> output(input.size());

	for (size_t i = 0; i < input.size(); i++) //dims
	{
		vtr<double> el(input[i].size());
		for (size_t j = 0; j < input[i].size(); j++) //lenght of sequence
		{
			el[j] = input[i][j] * coef;
		}
		output[i] = el;
	}

	return output;
}

vtr3<double> help::separateSequence(vtr3<double> const &input, int size)
{
	vtr3<double> output;

	for (int i = 0; i < size; i++)
	{
		auto tmp = separateSequenceOne(input[i]);
		output.insert(output.end(), tmp.begin(), tmp.end());
	}

	return output;
}

vtr3<double> help::separateSequenceOne(vtr2<double> const &input)
{
	vtr3<double> output;

	const size_t dims = input[0].size();

	for (size_t i = 0; i < dims; i++)
	{
		vtr2<double> sequence;
		sequence.reserve(input.size());
		for (size_t j = 0; j < input.size(); j++)
		{
			vector<double> el(1);
			el[0] = input[j][i];
			sequence.push_back(el);
		}
		output.push_back(sequence);
	}

	return output;
}

//void help::reduce(vtr3<double> &input, size_t skip)
//void help::paa(vtr3<double> &input, size_t ratio)
//void help::sax(vtr3<double> &input, size_t numClasses)
//void help::smooth(vtr3<double> &input, size_t width)


vtr2<double> help::convert_arrd(double* const &series, size_t len)
{
	vtr2<double> out(len);
	for (size_t i = 0; i < len; i++)
	{
		vtr<double> point(1);
		point[0] = series[i];

		out[i] = point;
	}

	return out;
}

vtr2<double> help::convert_arr2d(double* const &series, size_t len, size_t dims)
{
	vtr2<double> out(len);
	for (size_t i = 0; i < len; i++)
	{
		vtr<double> point(&series[0] + (i * dims), &series[0] + ((i + 1) * dims));
		//cout << point.size() << endl;
		out[i] = point;
	}

	return out;
}

vtr2<double> help::convert_arr3d(double* const &input, size_t len, size_t dims)
{
	vtr2<double> out(len);
	for (size_t i = 0; i < len; i++)
	{
		//int size = (sizeof(input[i]) / sizeof(double)) / dims;
		//auto tseries = convert_arr2d(input[i], size);
	}

	return out;
}