<commit_before>#include "ImportExport.h"
#include "FileFormat.h"
#include "Converter.h"
#include "Endian.h"
#include "Internationalisation.h"
#include "StringUtils.h"
#include "HtmlUtils.h"
#include "GlobalStateStruct.h"
#include "DynvHelpers.h"
#include "version/Version.h"
#include <glib.h>
#include <fstream>
#include <string>
#include <iostream>
#include <sstream>
#include <boost/math/special_functions/round.hpp>
#include <boost/filesystem.hpp>
#include <boost/algorithm/string.hpp>
using namespace std;

static bool getOrderedColors(ColorList *color_list, vector<ColorObject*> &ordered)
{
	color_list_get_positions(color_list);
	size_t max_index = 0;
	bool index_set = false;
	for (auto color: color_list->colors){
		if (color->position_set){
			if (!index_set){
				max_index = color->position;
				index_set = true;
			}else if (color->position > max_index){
				max_index = color->position;
			}
		}
	}
	if (!index_set){
		return false;
	}else{
		ordered.resize(max_index + 1);
		for (auto color: color_list->colors){
			if (color->position_set){
				ordered[color->position] = color;
			}
		}
		return true;
	}
}
ImportExport::ImportExport(ColorList *color_list, const char* filename, GlobalState *gs):
	m_color_list(color_list),
	m_converter(nullptr),
	m_converters(nullptr),
	m_filename(filename),
	m_item_size(ItemSize::medium),
	m_background(Background::none),
	m_gs(gs),
	m_include_color_names(true)
{
}
void ImportExport::setConverter(Converter *converter)
{
	m_converter = converter;
}
void ImportExport::setConverters(Converters *converters)
{
	m_converters = converters;
}
void ImportExport::setItemSize(ItemSize item_size)
{
	m_item_size = item_size;
}
void ImportExport::setItemSize(const char *item_size)
{
	string v(item_size);
	if (v == "small")
		m_item_size = ItemSize::small;
	else if (v == "medium")
		m_item_size = ItemSize::medium;
	else if (v == "big")
		m_item_size = ItemSize::big;
	else if (v == "controllable")
		m_item_size = ItemSize::controllable;
	else
		m_item_size = ItemSize::medium;
}
void ImportExport::setBackground(Background background)
{
	m_background = background;
}
void ImportExport::setBackground(const char *background)
{
	string v(background);
	if (v == "none")
		m_background = Background::none;
	else if (v == "white")
		m_background = Background::white;
	else if (v == "gray")
		m_background = Background::gray;
	else if (v == "black")
		m_background = Background::black;
	else if (v == "first_color")
		m_background = Background::first_color;
	else if (v == "last_color")
		m_background = Background::last_color;
	else if (v == "controllable")
		m_background = Background::controllable;
	else
		m_background = Background::none;
}
void ImportExport::setIncludeColorNames(bool include_color_names)
{
	m_include_color_names = include_color_names;
}
static void gplColor(ColorObject* color_object, ostream &stream)
{
	using boost::math::iround;
	Color color;
	color_object_get_color(color_object, &color);
	const char* name = color_object_get_name(color_object);
	stream
		<< iround(color.rgb.red * 255) << "\t"
		<< iround(color.rgb.green * 255) << "\t"
		<< iround(color.rgb.blue * 255) << "\t" << name << endl;
}
bool ImportExport::exportGPL()
{
	ofstream f(m_filename, ios::out | ios::trunc);
	if (f.is_open()){
		boost::filesystem::path path(m_filename);
		f << "GIMP Palette" << endl;
		f << "Name: " << path.filename().string() << endl;
		f << "Columns: 1" << endl;
		f << "#" << endl;
		vector<ColorObject*> ordered;
		getOrderedColors(m_color_list, ordered);
		for (auto color: ordered){
			gplColor(color, f);
			if (!f.good()){
				f.close();
				return false;
			}
		}
		f.close();
		return true;
	}
	return false;
}
bool ImportExport::importGPL()
{
	ifstream f(m_filename, ios::in);
	if (!f.is_open()){
		return false;
	}
	string line;
	getline(f, line);
	if (f.good() && line != "GIMP Palette"){
		f.close();
		return false;
	}
	do{
		getline(f, line);
	}while (f.good() && ((line.size() < 1) || (((line[0] > '9') || (line[0] < '0')) && line[0] != ' ')));
	int r, g, b;
	Color c;
	ColorObject* color_object;
	string strip_chars = " \t";
	for(;;){
		if (!f.good()) break;
		stripLeadingTrailingChars(line, strip_chars);
		if (line.length() > 0 && line[0] == '#'){ // skip comment lines
			getline(f, line);
			continue;
		}
		stringstream ss(line);
		ss >> r >> g >> b;
		getline(ss, line);
		if (!f.good()) line = "";
		c.rgb.red = r / 255.0;
		c.rgb.green = g / 255.0;
		c.rgb.blue = b / 255.0;
		color_object = color_list_new_color_object(m_color_list, &c);
		color_object_set_name(color_object, line.c_str());
		color_list_add_color_object(m_color_list, color_object, true);
		color_object_release(color_object);
		getline(f, line);
	}
	if (!f.eof()) {
		f.close();
		return false;
	}
	f.close();
	return true;
}
bool ImportExport::importGPA()
{
	return palette_file_load(m_filename, m_color_list);
}
bool ImportExport::exportGPA()
{
	return palette_file_save(m_filename, m_color_list);
}
bool ImportExport::exportTXT()
{
	ofstream f(m_filename, ios::out | ios::trunc);
	if (f.is_open()){
		vector<ColorObject*> ordered;
		getOrderedColors(m_color_list, ordered);
		ConverterSerializePosition position;
		position.index = 0;
		position.count = ordered.size();
		position.first = true;
		position.last = position.count <= 1;
		for (auto color: ordered){
			string line;
			converters_color_serialize(m_converter, color, position, line);
			f << line << endl;
			position.index++;
			if (position.index + 1 == position.count){
				position.last = true;
			}
			if (position.first)
				position.first = false;
			if (!f.good()){
				f.close();
				return false;
			}
		}
		f.close();
		return true;
	}
	return false;
}
bool ImportExport::importTXT()
{
	ifstream f(m_filename, ios::in);
	if (!f.is_open()){
		return false;
	}
	uint32_t table_size;
	Converter *converter = nullptr;
	Converter **converter_table = converters_get_all_type(m_converters, CONVERTERS_ARRAY_TYPE_PASTE, &table_size);
	ColorObject* color_object;
	Color dummy_color;
	typedef multimap<float, ColorObject*, greater<float>> ValidConverters;
	ValidConverters valid_converters;
	string line;
	string strip_chars = " \t";
	for(;;){
		getline(f, line);
		stripLeadingTrailingChars(line, strip_chars);
		if (!line.empty()){
			for (size_t i = 0; i != table_size; ++i){
				converter = converter_table[i];
				if (!converter->deserialize_available) continue;
				color_object = color_list_new_color_object(m_color_list, &dummy_color);
				float quality;
				if (converters_color_deserialize(m_converters, converter->function_name, line.c_str(), color_object, &quality) == 0){
					if (quality > 0){
						valid_converters.insert(make_pair(quality, color_object));
					}else{
						color_object_release(color_object);
					}
				}else{
					color_object_release(color_object);
				}
			}
			bool first = true;
			for (auto result: valid_converters){
				if (first){
					first = false;
					color_list_add_color_object(m_color_list, result.second, true);
				}
				color_object_release(result.second);
			}
			valid_converters.clear();
		}
		if (!f.good()) {
			if (f.eof()) break;
			f.close();
			return false;
		}
	}
	f.close();
	return true;
}
static void cssColor(ColorObject* color_object, ostream &stream)
{
	Color color, hsl;
	color_object_get_color(color_object, &color);
	const char* name = color_object_get_name(color_object);
	color_rgb_to_hsl(&color, &hsl);
	stream << " * " << name
		<< ": " << HtmlHEX{&color}
		<< ", " << HtmlRGB{&color}
		<< ", " << HtmlHSL{&color}
		<< endl;
}
bool ImportExport::exportCSS()
{
	ofstream f(m_filename, ios::out | ios::trunc);
	if (f.is_open()){
		f << "/**" << endl << " * Generated by Gpick " << gpick_build_version << endl;
		vector<ColorObject*> ordered;
		getOrderedColors(m_color_list, ordered);
		for (auto color: ordered){
			cssColor(color, f);
			if (!f.good()){
				f.close();
				return false;
			}
		}
		f << " */" << endl;
		if (!f.good()){
			f.close();
			return false;
		}
		f.close();
		return true;
	}
	return false;
}
static void htmlColor(ColorObject* color_object, bool include_color_name, ostream &stream)
{
	Color color, text_color;
	color_object_get_color(color_object, &color);
	color_get_contrasting(&color, &text_color);
	stream << "<div style=\"background-color:" << HtmlRGB{&color} << "; color:" << HtmlRGB{&text_color} << "\">";
	if (include_color_name){
		string name = color_object_get_name(color_object);
		escapeHtmlInplace(name);
		if (!name.empty())
			stream << name << ":<br/>";
	}
	stream << HtmlHEX{&color} << "</div>";
}
static string getHtmlColor(ColorObject* color_object)
{
	Color color;
	color_object_get_color(color_object, &color);
	stringstream ss;
	ss << HtmlRGB{&color};
	return ss.str();
}
bool ImportExport::exportHTML()
{
	ofstream f(m_filename, ios::out | ios::trunc);
	if (f.is_open()){
		boost::filesystem::path path(m_filename);
		vector<ColorObject*> ordered;
		getOrderedColors(m_color_list, ordered);
		int item_size = 64;
		switch (m_item_size){
			case ItemSize::small:
				item_size = 32;
				break;
			case ItemSize::medium:
				item_size = 64;
				break;
			case ItemSize::big:
				item_size = 96;
				break;
			case ItemSize::controllable:
				break;
		}
		string background = "";
		switch (m_background){
			case Background::none:
				break;
			case Background::white:
				background = "background-color:white;";
				break;
			case Background::gray:
				background = "background-color:gray;";
				break;
			case Background::black:
				background = "background-color:black;";
				break;
			case Background::first_color:
				if (!ordered.empty())
					background = "background-color:" + getHtmlColor(ordered.front()) + ";";
				break;
			case Background::last_color:
				if (!ordered.empty())
					background = "background-color:" + getHtmlColor(ordered.back()) + ";";
				break;
			case Background::controllable:
				break;
		}
		f << "<!DOCTYPE html><html lang=\"en\"><head><meta charset=\"utf-8\"><title>"
			<< path.filename().string() << "</title>" << endl
			<< "<style>" << endl
			<< "div#colors div{float: left; width: " << item_size << "px; height: " << item_size << "px; margin: 2px; text-align: center; font-size: 12px; font-family: Arial, Helvetica, sans-serif}" << endl
			<< "html{" << background << "}" << endl
			<< "input{margin-left: 1em;}" << endl
			<< "</style>"
			<< "</head>" << endl
			<< "<body>" << endl;
		if (m_item_size == ItemSize::controllable || m_background == Background::controllable){
			f << "<form>" << endl;
			if (m_item_size == ItemSize::controllable){
				f << "<div>" << _("Item size") << ":<input type=\"range\" id=\"item_size\" min=\"16\" max=\"128\" value=\"64\" oninput=\"var elements = document.querySelectorAll('div#colors div'); for (var i = 0; i < elements.length; i++){ elements[i].style.width = this.value + 'px'; elements[i].style.height = this.value + 'px'; }\" />" << "</div>" << endl;
			}
			if (m_background == Background::controllable){
				f << "<div>" << _("Background color") << ":<input type=\"color\" id=\"background\" oninput=\"document.body.style.backgroundColor = this.value;\" />" << "</div>" << endl;
			}
			f << "</form>" << endl;
		}
		f << "<div id=\"colors\">" << endl;
		string hex_case = dynv_get_string_wd(m_gs->params, "gpick.options.hex_case", "upper");
		if (hex_case == "upper"){
			f << uppercase;
		}else{
			f << nouppercase;
		}
		for (auto color: ordered){
			htmlColor(color, m_include_color_names, f);
			if (!f.good()){
				f.close();
				return false;
			}
		}
		f << "</div>" << endl;
		f << "</body></html>" << endl;
		if (!f.good()){
			f.close();
			return false;
		}
		f.close();
		return true;
	}
	return false;
}

bool ImportExport::exportType(FileType type)
{
	switch (type){
		case FileType::gpa:
			return exportGPA();
		case FileType::gpl:
			return exportGPL();
		case FileType::ase:<commit_msg>Add automatic copy on click for color codes in exported HTML files.<commit_after>#include "ImportExport.h"
#include "FileFormat.h"
#include "Converter.h"
#include "Endian.h"
#include "Internationalisation.h"
#include "StringUtils.h"
#include "HtmlUtils.h"
#include "GlobalStateStruct.h"
#include "DynvHelpers.h"
#include "version/Version.h"
#include <glib.h>
#include <fstream>
#include <string>
#include <iostream>
#include <sstream>
#include <boost/math/special_functions/round.hpp>
#include <boost/filesystem.hpp>
#include <boost/algorithm/string.hpp>
using namespace std;

static bool getOrderedColors(ColorList *color_list, vector<ColorObject*> &ordered)
{
	color_list_get_positions(color_list);
	size_t max_index = 0;
	bool index_set = false;
	for (auto color: color_list->colors){
		if (color->position_set){
			if (!index_set){
				max_index = color->position;
				index_set = true;
			}else if (color->position > max_index){
				max_index = color->position;
			}
		}
	}
	if (!index_set){
		return false;
	}else{
		ordered.resize(max_index + 1);
		for (auto color: color_list->colors){
			if (color->position_set){
				ordered[color->position] = color;
			}
		}
		return true;
	}
}
ImportExport::ImportExport(ColorList *color_list, const char* filename, GlobalState *gs):
	m_color_list(color_list),
	m_converter(nullptr),
	m_converters(nullptr),
	m_filename(filename),
	m_item_size(ItemSize::medium),
	m_background(Background::none),
	m_gs(gs),
	m_include_color_names(true)
{
}
void ImportExport::setConverter(Converter *converter)
{
	m_converter = converter;
}
void ImportExport::setConverters(Converters *converters)
{
	m_converters = converters;
}
void ImportExport::setItemSize(ItemSize item_size)
{
	m_item_size = item_size;
}
void ImportExport::setItemSize(const char *item_size)
{
	string v(item_size);
	if (v == "small")
		m_item_size = ItemSize::small;
	else if (v == "medium")
		m_item_size = ItemSize::medium;
	else if (v == "big")
		m_item_size = ItemSize::big;
	else if (v == "controllable")
		m_item_size = ItemSize::controllable;
	else
		m_item_size = ItemSize::medium;
}
void ImportExport::setBackground(Background background)
{
	m_background = background;
}
void ImportExport::setBackground(const char *background)
{
	string v(background);
	if (v == "none")
		m_background = Background::none;
	else if (v == "white")
		m_background = Background::white;
	else if (v == "gray")
		m_background = Background::gray;
	else if (v == "black")
		m_background = Background::black;
	else if (v == "first_color")
		m_background = Background::first_color;
	else if (v == "last_color")
		m_background = Background::last_color;
	else if (v == "controllable")
		m_background = Background::controllable;
	else
		m_background = Background::none;
}
void ImportExport::setIncludeColorNames(bool include_color_names)
{
	m_include_color_names = include_color_names;
}
static void gplColor(ColorObject* color_object, ostream &stream)
{
	using boost::math::iround;
	Color color;
	color_object_get_color(color_object, &color);
	const char* name = color_object_get_name(color_object);
	stream
		<< iround(color.rgb.red * 255) << "\t"
		<< iround(color.rgb.green * 255) << "\t"
		<< iround(color.rgb.blue * 255) << "\t" << name << endl;
}
bool ImportExport::exportGPL()
{
	ofstream f(m_filename, ios::out | ios::trunc);
	if (f.is_open()){
		boost::filesystem::path path(m_filename);
		f << "GIMP Palette" << endl;
		f << "Name: " << path.filename().string() << endl;
		f << "Columns: 1" << endl;
		f << "#" << endl;
		vector<ColorObject*> ordered;
		getOrderedColors(m_color_list, ordered);
		for (auto color: ordered){
			gplColor(color, f);
			if (!f.good()){
				f.close();
				return false;
			}
		}
		f.close();
		return true;
	}
	return false;
}
bool ImportExport::importGPL()
{
	ifstream f(m_filename, ios::in);
	if (!f.is_open()){
		return false;
	}
	string line;
	getline(f, line);
	if (f.good() && line != "GIMP Palette"){
		f.close();
		return false;
	}
	do{
		getline(f, line);
	}while (f.good() && ((line.size() < 1) || (((line[0] > '9') || (line[0] < '0')) && line[0] != ' ')));
	int r, g, b;
	Color c;
	ColorObject* color_object;
	string strip_chars = " \t";
	for(;;){
		if (!f.good()) break;
		stripLeadingTrailingChars(line, strip_chars);
		if (line.length() > 0 && line[0] == '#'){ // skip comment lines
			getline(f, line);
			continue;
		}
		stringstream ss(line);
		ss >> r >> g >> b;
		getline(ss, line);
		if (!f.good()) line = "";
		c.rgb.red = r / 255.0;
		c.rgb.green = g / 255.0;
		c.rgb.blue = b / 255.0;
		color_object = color_list_new_color_object(m_color_list, &c);
		color_object_set_name(color_object, line.c_str());
		color_list_add_color_object(m_color_list, color_object, true);
		color_object_release(color_object);
		getline(f, line);
	}
	if (!f.eof()) {
		f.close();
		return false;
	}
	f.close();
	return true;
}
bool ImportExport::importGPA()
{
	return palette_file_load(m_filename, m_color_list);
}
bool ImportExport::exportGPA()
{
	return palette_file_save(m_filename, m_color_list);
}
bool ImportExport::exportTXT()
{
	ofstream f(m_filename, ios::out | ios::trunc);
	if (f.is_open()){
		vector<ColorObject*> ordered;
		getOrderedColors(m_color_list, ordered);
		ConverterSerializePosition position;
		position.index = 0;
		position.count = ordered.size();
		position.first = true;
		position.last = position.count <= 1;
		for (auto color: ordered){
			string line;
			converters_color_serialize(m_converter, color, position, line);
			f << line << endl;
			position.index++;
			if (position.index + 1 == position.count){
				position.last = true;
			}
			if (position.first)
				position.first = false;
			if (!f.good()){
				f.close();
				return false;
			}
		}
		f.close();
		return true;
	}
	return false;
}
bool ImportExport::importTXT()
{
	ifstream f(m_filename, ios::in);
	if (!f.is_open()){
		return false;
	}
	uint32_t table_size;
	Converter *converter = nullptr;
	Converter **converter_table = converters_get_all_type(m_converters, CONVERTERS_ARRAY_TYPE_PASTE, &table_size);
	ColorObject* color_object;
	Color dummy_color;
	typedef multimap<float, ColorObject*, greater<float>> ValidConverters;
	ValidConverters valid_converters;
	string line;
	string strip_chars = " \t";
	for(;;){
		getline(f, line);
		stripLeadingTrailingChars(line, strip_chars);
		if (!line.empty()){
			for (size_t i = 0; i != table_size; ++i){
				converter = converter_table[i];
				if (!converter->deserialize_available) continue;
				color_object = color_list_new_color_object(m_color_list, &dummy_color);
				float quality;
				if (converters_color_deserialize(m_converters, converter->function_name, line.c_str(), color_object, &quality) == 0){
					if (quality > 0){
						valid_converters.insert(make_pair(quality, color_object));
					}else{
						color_object_release(color_object);
					}
				}else{
					color_object_release(color_object);
				}
			}
			bool first = true;
			for (auto result: valid_converters){
				if (first){
					first = false;
					color_list_add_color_object(m_color_list, result.second, true);
				}
				color_object_release(result.second);
			}
			valid_converters.clear();
		}
		if (!f.good()) {
			if (f.eof()) break;
			f.close();
			return false;
		}
	}
	f.close();
	return true;
}
static void cssColor(ColorObject* color_object, ostream &stream)
{
	Color color, hsl;
	color_object_get_color(color_object, &color);
	const char* name = color_object_get_name(color_object);
	color_rgb_to_hsl(&color, &hsl);
	stream << " * " << name
		<< ": " << HtmlHEX{&color}
		<< ", " << HtmlRGB{&color}
		<< ", " << HtmlHSL{&color}
		<< endl;
}
bool ImportExport::exportCSS()
{
	ofstream f(m_filename, ios::out | ios::trunc);
	if (f.is_open()){
		f << "/**" << endl << " * Generated by Gpick " << gpick_build_version << endl;
		vector<ColorObject*> ordered;
		getOrderedColors(m_color_list, ordered);
		for (auto color: ordered){
			cssColor(color, f);
			if (!f.good()){
				f.close();
				return false;
			}
		}
		f << " */" << endl;
		if (!f.good()){
			f.close();
			return false;
		}
		f.close();
		return true;
	}
	return false;
}
static void htmlColor(ColorObject* color_object, bool include_color_name, ostream &stream)
{
	Color color, text_color;
	color_object_get_color(color_object, &color);
	color_get_contrasting(&color, &text_color);
	stream << "<div style=\"background-color:" << HtmlRGB{&color} << "; color:" << HtmlRGB{&text_color} << "\">";
	if (include_color_name){
		string name = color_object_get_name(color_object);
		escapeHtmlInplace(name);
		if (!name.empty())
			stream << name << ":<br/>";
	}
	stream << "<span>" << HtmlHEX{&color} << "</span>" << "</div>";
}
static string getHtmlColor(ColorObject* color_object)
{
	Color color;
	color_object_get_color(color_object, &color);
	stringstream ss;
	ss << HtmlRGB{&color};
	return ss.str();
}
bool ImportExport::exportHTML()
{
	ofstream f(m_filename, ios::out | ios::trunc);
	if (f.is_open()){
		boost::filesystem::path path(m_filename);
		vector<ColorObject*> ordered;
		getOrderedColors(m_color_list, ordered);
		int item_size = 64;
		switch (m_item_size){
			case ItemSize::small:
				item_size = 32;
				break;
			case ItemSize::medium:
				item_size = 64;
				break;
			case ItemSize::big:
				item_size = 96;
				break;
			case ItemSize::controllable:
				break;
		}
		string background = "";
		switch (m_background){
			case Background::none:
				break;
			case Background::white:
				background = "background-color:white;";
				break;
			case Background::gray:
				background = "background-color:gray;";
				break;
			case Background::black:
				background = "background-color:black;";
				break;
			case Background::first_color:
				if (!ordered.empty())
					background = "background-color:" + getHtmlColor(ordered.front()) + ";";
				break;
			case Background::last_color:
				if (!ordered.empty())
					background = "background-color:" + getHtmlColor(ordered.back()) + ";";
				break;
			case Background::controllable:
				break;
		}
		f << "<!DOCTYPE html><html lang=\"en\"><head><meta charset=\"utf-8\"><title>"
			<< path.filename().string() << "</title>" << endl
			<< "<style>" << endl
			<< "div#colors div{float: left; width: " << item_size << "px; height: " << item_size << "px; margin: 2px; text-align: center; font-size: 12px; font-family: Arial, Helvetica, sans-serif}" << endl
			<< "div#colors div span{font-weight: bold; cursor: pointer}" << endl
			<< "div#colors div span:hover{text-decoration: underline}" << endl
			<< "html{" << background << "}" << endl
			<< "input{margin-left: 1em;}" << endl
			<< "</style>"
			<< "</head>" << endl
			<< "<body>" << endl;
		if (m_item_size == ItemSize::controllable || m_background == Background::controllable){
			f << "<form>" << endl;
			if (m_item_size == ItemSize::controllable){
				f << "<div>" << _("Item size") << ":<input type=\"range\" id=\"item_size\" min=\"16\" max=\"128\" value=\"64\" oninput=\"var elements = document.querySelectorAll('div#colors div'); for (var i = 0; i < elements.length; i++){ elements[i].style.width = this.value + 'px'; elements[i].style.height = this.value + 'px'; }\" />" << "</div>" << endl;
			}
			if (m_background == Background::controllable){
				f << "<div>" << _("Background color") << ":<input type=\"color\" id=\"background\" oninput=\"document.body.style.backgroundColor = this.value;\" />" << "</div>" << endl;
			}
			f << "</form>" << endl;
		}
		f << "<div id=\"colors\">" << endl;
		string hex_case = dynv_get_string_wd(m_gs->params, "gpick.options.hex_case", "upper");
		if (hex_case == "upper"){
			f << uppercase;
		}else{
			f << nouppercase;
		}
		for (auto color: ordered){
			htmlColor(color, m_include_color_names, f);
			if (!f.good()){
				f.close();
				return false;
			}
		}
		f << "</div>" << endl;
		f << "<script>" << endl
			<< "function selectText(element){ if (document.selection){ var range = document.body.createTextRange(); range.moveToElementText(element); range.select(); }else if (window.getSelection){ var range = document.createRange(); range.selectNode(element); window.getSelection().addRange(range); } }" << endl
			<< "document.getElementById('colors').addEventListener('click', function(event){ if (event.target.tagName.toLowerCase() == 'span'){ event.preventDefault(); selectText(event.target); document.execCommand('copy'); }});" << endl
			<< "</script>";
		f << "</body></html>" << endl;
		if (!f.good()){
			f.close();
			return false;
		}
		f.close();
		return true;
	}
	return false;
}

bool ImportExport::exportType(FileType type)
{
	switch (type){
		case FileType::gpa:
			return exportGPA();
		case FileType::gpl:
			return exportGPL();
		case FileType::ase:
{'fraction_non_alphanumeric': 0.17151720478386873, 'fraction_numerical': 0.004979795093677293, 'mean_word_length': 4.403617115130128, 'pattern_counts': {'":': 8, '<': 481, '<?xml version=': 0, '>': 129, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7624281', 'n_tokens_mistral': 9747, 'n_tokens_neox': 8730, 'n_words': 1853}