#ifndef __BLOP_BLOPUTILS_H__
#define __BLOP_BLOPUTILS_H__
#include "array.h"
#include "frame.h"
#include "pad.h"
#include "var.h"
#include "length.h"
#include "function.h"
#include "constants.h"
#include "text.h"
#include <algorithm>
namespace blop
{
bool isfinite(double v);
bool isnan(double v);
bool isinf(double v);
bool isnormal(double v);
// --------------------------------------------------------------------------------
std::istream *openin(const var &filename);
std::ostream *openout(const var &filename);
// --------------------------------------------------------------------------------
length axislength(axis *a, double from, double to=unset);
length x1len(double a,double b=unset);
length x2len(double a,double b=unset);
length y1len(double a,double b=unset);
length y2len(double a,double b=unset);
// return the length along the x1/x2/y1/y2 axes:
// - from the origin to 'a', if 'b'==unset,
// - from 'a' to 'b', if 'b' is not unset
// --------------------------------------------------------------------------------
// Print the current canvas to a terminal
void print(terminal *term);
// ---------- system --------------------------------------------------------------
// Like the usual 'system(const char *cmd)' function of C,
// but for 'var' argument
int system(const var &);
// Run a command in the background, return it's process-id. This process-id is also
// automatically registered, and will be waited for before quitting the program.
int system_bg(const var &cmd);
// ---------- shell ---------------------------------------------------------------
// The same as the 'system' function, but the same shell process
// is used for all subsequent calls. For example a 'cd /tmp' command
// processed by this function will have an effect for all later calls
// of this function. These two commands list the /tmp directory:
// shell("cd /tmp");
// shell("ls");
void shell(const var &command);
// ---------- readcmd -------------------------------------------------------------
// Read the output of the provided command (which is executed
// in /bin/sh). The first character MAY be a '<', in which
// case it is removed from it (this is introduced in order to
// match the 'plot' command, where the initial '<' in the filename
// to be plotted indicates that it is to be treated as a pipe)
// If 'rc' is provided, the return code of the command
// is returned in this variable
var readcmd(const var &cmd,int *rc = 0);
int readcmd(const var &cmd, array &out, const var &separator = "\n", int *rc = 0);
int readcmd(const var &cmd, std::vector<std::string> &out, const var &separator = "\n", int *rc = 0);
// ---------- readfile ------------------------------------------------------------
// Reads and returns the content of the provided file. The second version reads
// the file, and splits its contents (by default at newlines) into the array 'out',
// and returns the number of entries in out
var readfile(const var &filename);
int readfile(const var &filename, array &out, const var &separator = "\n");
// ---------- draw the content of a file ------------------------------------------
text &fdraw_file_content(const var &filename);
text &pdraw_file_content(const var &filename);
text &cdraw_file_content(const var &filename);
// Create a sequence of numbers
array sequence(var start, var stop, var step=1);
// ---------- split and join ------------------------------------------------------
// Splits the string 's' into the vector 'out', and returns the number of entries
array split(const var &s, const var &separator = " \t\n");
int split(const string &s,const string &separator, std::vector<std::string> &out);
var join(const array &a, const var &separator = array::outfs());
var join(const std::vector<double> &a, const var &separator = array::outfs());
var join(const std::vector<std::string> &a, const var &separator = array::outfs());
// ---------- split a data line (interpret quoation marks, etc) -------------------
void split_quoted(std::string line, std::vector<blop::var> &fields);
// ---------- getfield -----------------------------------------------------------
// Split the provided string 's' at characters specified by 'separator', and return
// the 'i'th element
var getfield(const var &s, unsigned int i, const var &separator = " \t\n");
// ---------- getline ------------------------------------------------------------
// Read a line from the input stream and return it in 'v' (the first version)
// or immediately split it as well (at whitespaces) into the array 'a'
// line_separator specifies the character to be interpreted as end-of-line (only
// the first character of this string is used)
// field_separator contains the characters at which the line will be split
// (it will be the second argument to the 'split' function described above)
istream &getline(istream &, var &v, const var &line_separator = "\n");
istream &getline(istream &, array &a, const var &line_separator = "\n", const var &field_separator = "\t ");
istream &getline(istream &, std::vector<std::string> &a, const std::string &line_separator = "\n", const std::string &field_separator = "\t ");
// ---------- tolatex ------------------------------------------------------------
// Transform a string (possibly containing _, $, and other latex-special chars)
// to latex, where these characters are escaped
var tolatex(const var &);
// ---------- parallel_sort -------------------------------------------------------
// Sort two arrays based on the values of the first array. The elements of the second
// array will correspond to the same elements of the first array.
template <class A, class B>
class LessThanPairFirst
{
public:
// compare by the 'first' element of a pair (if they are equal,
// compare by the 'second' element of the pair)
bool operator()(const std::pair<A,B> &a, const std::pair<A,B> &b)
{
if(a.first<b.first) return true;
if(a.first<=b.first && a.second<b.second) return true;
return false;
}
};
template <class Container1, class Container2>
void parallel_sort(Container1 &v1,Container2 &v2)
{
std::vector<std::pair<typename Container1::value_type,typename Container2::value_type> > a;
const unsigned int n = std::min(v1.size(),v2.size());
for(unsigned int i=0; i<n; ++i)
{
a.push_back(std::pair<typename Container1::value_type,typename Container2::value_type>(v1[i],v2[i]));
}
sort(a.begin(), a.end(), LessThanPairFirst<typename Container1::value_type, typename Container2::value_type>());
for(unsigned int i=0; i<n; ++i)
{
v1[i] = a[i].first;
v2[i] = a[i].second;
}
}
void parallel_sort(std::vector<double> &x, std::vector<double> &y);
void parallel_sort(std::vector<blop::var> &x, std::vector<blop::var> &y);
void parallel_sort(array &x, array &y);
// A utility class to in-line initialize a std::vector. Usage:
// vector<int> i = initvector(1)(2)(3)(4)(5);
// vector<double> d = initvector(1.1)(2.2)(3.3);
// vector<double> d2 = initvector<double>(1)(2)(3);
template <typename T> class vector_initializer
{
private:
std::vector<T> vector_;
public:
vector_initializer(const T &t) { vector_.push_back(t); }
vector_initializer<T> &operator()(const T &t) { vector_.push_back(t); return *this; }
operator std::vector<T>() const { return vector_; }
};
template <typename T> vector_initializer<T> initvector(const T &t) { return vector_initializer<T>(t); }
}
#endif