//////////////////////////////////////////////////////////////////////////
//
// This file is part of the BWEM Library.
// BWEM is free software, licensed under the MIT/X11 License. 
// A copy of the license is provided with the library in the LICENSE file.
// Copyright (c) 2015, 2017, Igor Dimitrijevic
//
//////////////////////////////////////////////////////////////////////////

#pragma once

#include <math.h>

#include <string>
#include <vector>
#include <algorithm>
#include <cstdint>
#include <limits>
#include <fstream>
#include <sstream>

#include "defs.h"

namespace BWEM {

namespace utils {

//extern std::ofstream Log;

template <class T> void unused(const T &) {}

inline int queenWiseNorm(int dx, int dy)
{
	return ::std::max(abs(dx), abs(dy));
}


inline int squaredNorm(int dx, int dy)
{
	return dx*dx + dy*dy;
}


inline double norm(int dx, int dy)
{
	return sqrt(squaredNorm(dx, dy));
}


inline int scalar_product(int ax, int ay, int bx, int by)
{
	return ax*bx + ay*by;
}


// Returns whether the line segments [a, b] and [c, d] intersect.
bool intersect(int ax, int ay, int bx, int by, int cx, int cy, int dx, int dy);


template<class T>
std::string my_to_string(const T & value)
{
    std::ostringstream oss;
    std::string res;
    oss << value;
    res = oss.str();
    return res;
}


template<class T>
T string_to_value(const std::string & s)
{
	std::istringstream iss(s);
	T res;
	iss >> res;
	return res;
}


template<typename T>
bool from_string(const std::string & s, T & dest)
{
	std::istringstream iss(s);
	return !(iss >> dest).fail();
}


bool canWrite(const ::std::string & fileName);

// http://stackoverflow.com/questions/17224256/function-checking-if-an-integer-type-can-fit-a-value-of-possibly-different-inte
template <typename T, typename U>
bool CanTypeFitValue(const U value) {
    const intmax_t botT = intmax_t(std::numeric_limits<T>::min() );
    const intmax_t botU = intmax_t(std::numeric_limits<U>::min() );
    const uintmax_t topT = uintmax_t(std::numeric_limits<T>::max() );
    const uintmax_t topU = uintmax_t(std::numeric_limits<U>::max() );
    return !( (botT > botU && value < static_cast<U> (botT)) || (topT < topU && value > static_cast<U> (topT)) );        
}


// http://stackoverflow.com/questions/6942273/get-random-element-from-container-c-stl
template <typename I>
I random_element(I begin, I end)
{
    const auto n = std::distance(begin, end);
    const auto divisor = (RAND_MAX + 1) / n;

	typename std::remove_const<decltype(n)>::type k;
    do { k = std::rand() / divisor; } while (k >= n);

    std::advance(begin, k);
	return begin;
}


template<class T>
inline const typename T::value_type & random_element(const T & Container)
{
    const auto n = Container.size();
    const auto divisor = (RAND_MAX + 1) / n;

	typename std::remove_const<decltype(n)>::type k;
    do { k = std::rand() / divisor; } while (k >= n);

	return Container[k];
}


template<class T>
inline typename T::value_type & random_element(T & Container)
{
	return const_cast<typename T::value_type &>(random_element(static_cast<const T &>(Container)));
}


template<class T>
inline void really_remove(T & Container, const typename T::value_type & Element)
{
    Container.erase(remove(Container.begin(), Container.end(), Element), Container.end());
}


template<class T, class Pred>
inline void really_remove_if(T & Container, Pred pred)
{
    Container.erase(remove_if(Container.begin(), Container.end(), pred), Container.end());
}


template<class T, class E>
inline bool contains(const T & Container, const E & Element)
{
    return find(Container.begin(), Container.end(), Element) != Container.end();
}




template<class T>
inline void fast_erase(std::vector<T> & Vector, int i)
{
	bwem_assert((0 <= i) && (i < (int)Vector.size()));

	std::swap(Vector[i], Vector.back());
	Vector.pop_back();
}


struct compare2nd
{
    template <typename T>
    bool operator()(const T & a, const T & b)
    {
        return a.second < b.second;
    }
};


//////////////////////////////////////////////////////////////////////////////////////////////
//                                                                                          //
//                                  class Markable
//                                                                                          //
//////////////////////////////////////////////////////////////////////////////////////////////
//
//  Provides efficient marking ability.
//
//  Usage: class MyNode : (public) Markable<MyNode, unsigned> {...};
//
//  Note: This implementation uses a static member.
//

template<class Derived, class Mark>
class Markable
{
public:
    typedef Mark mark_t;

                            Markable() : m_lastMark(0) {}

    bool                    Marked() const      { return m_lastMark == m_currentMark; }
    void                    SetMarked() const   { m_lastMark = m_currentMark; }
    void                    SetUnmarked() const { m_lastMark = m_currentMark-1; }
    static void             UnmarkAll()         { ++m_currentMark; }

private:
    mutable mark_t          m_lastMark;
    static mark_t           m_currentMark;
};


template<class Derived, class Mark>
Mark Markable<Derived, Mark>::m_currentMark = 0;




//////////////////////////////////////////////////////////////////////////////////////////////
//                                                                                          //
//                                  class UserData
//                                                                                          //
//////////////////////////////////////////////////////////////////////////////////////////////
//
//  Provides free-to-use, intrusive data for several types of the BWEM library
//	Despite their names and their types, they can be used for any purpose.
//

class UserData
{
public:
	// Free use.
	int					Data() const					{ return m_data; }
	void				SetData(int data) const			{ m_data = data; }

	// Free use.
	void *				Ptr() const						{ return m_ptr; }
	void				SetPtr(void * p) const			{ m_ptr = p; }

	// Free use.
	void *				Ext() const						{ return m_ext; }
	void				SetExt(void * p) const			{ m_ext = p; }

protected:
						UserData() = default;
						UserData(const UserData &) = default;

private:
	mutable void *		m_ptr = nullptr;
	mutable void *		m_ext = nullptr;
	mutable int			m_data = 0;
};

}} // namespace BWEM::utils
