//  Lattice Boltzmann Method Analysis Tool
//  https://mmg-gitlab.fjfi.cvut.cz/gitlab/lbm/lbmat

#pragma once

#include <stdio.h>
#include <stdarg.h>
#include <unistd.h>
#include <iostream>
#include <sstream>
#include <fstream>
#include <chrono>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/file.h>
#include <ginac/ginac.h>
#include <malloc.h> // malloc_trim

const int MQ=27;	// maximal Q
const int MDIM=3; 	// maximal DIM

using namespace std;
using namespace GiNaC;

using vct=std::vector<ex>;
using vcti=std::vector<int>;

// for indexing in PDE_STRUCT3
using indx=long int; // 2D position in the array ind x ind
using vctidx=std::vector<indx>;

using hashmap=std::unordered_map< indx, ex >;

enum { NSE, ADE };

struct BASE
{
	bool factor_coefs = true;
	bool plot_memory_usage = true;
	long peak_memory = 0;

	char target_dir[1024];
	void log(const char* fmt, ... );

	// time counter
	time_t time_start=0;

	bool file_exists(const std::string &s);
	bool mark_exists(const char* fmt, ... );
	bool mark(const char* fmt, ... );
	void create_mark(const char* fmt, ... );
	void timestamp(char *str, time_t reference);
	std::string ReplaceString(std::string subject, const std::string& search, const std::string& replace);
	bool sign(ex nr);

	string factorize_latex(ex co);
	void factorize_latex(ostringstream &sout1, ostringstream &sout2, ex co, int &counter, const char *id);
	void factorize_latex_simple(ostringstream &sout1, ex co);
	// dev
	string factorize_latex_v1(ex co);

	lst subs_vels; // for factorize_latex

	void replace_coefs_expression_recursive(ex& expr, int &sym_index, vct &bas2, lst  &sym_subs, const char* prefix, int level, ex &new_expr, ex term);

	// general tools
	// replace all coeffs in expr by symbolic polynomial based on bas2
	// debug / TODO: for now, assuming quadratic polynomials only?
	void replace_coefs_expression(ex& expr, int &sym_index, vct &bas2, lst  &sym_subs, const char* prefix);
	void dump_lst(const char *dir_name, const char *subdir_name, const char*filename_prefix, int counter, lst& list, bool erase);
	void dump_lst(const char *dir_name, const char*filename_prefix, int counter, lst& list, bool erase);
	ex load_ex(const std::string &filename, parser &reader);

	// J. Klinkovsky: https://mmg-gitlab.fjfi.cvut.cz/gitlab/tnl/tnl-benchmark-mesh/-/blob/master/MemoryInfo.h
	inline long parseLine(char* line)
	{
	    // This assumes that a digit will be found and the line ends in " kB".
	    int i = strlen(line);
	    const char* p = line;
	    while (*p <'0' || *p > '9') p++;
	    line[i-3] = '\0';
	    return atol(p);
	}

	// J. Klinkovsky: https://mmg-gitlab.fjfi.cvut.cz/gitlab/tnl/tnl-benchmark-mesh/-/blob/master/MemoryInfo.h
	inline long getSelfPhysicalMemory()
	{
	    // explicitly release unused memory
	    malloc_trim(0);
	
	    FILE* file = fopen("/proc/self/status", "r");
	    long result = -1;
	    char line[128];

	    while (fgets(line, 128, file) != NULL){
	        if (strncmp(line, "VmRSS:", 6) == 0){
	            // convert from kB to B
	            result = parseLine(line) * 1024;
	            break;
	        }
	   }
 	   fclose(file);
	    return result;
	}
	
	bool isnegative(ex& e)
	{
	        ostringstream s1, s2;
	        s1<<e;
	        s2<<(-e);
	        // longer string has a negative sign inside
	        return (s1.str().length() > s2.str().length()) ? true : false;
	}
};

struct FUN
{
        vct mu;
        ex rho;
        ex vel[3];
};

#include "base.hpp"


