/***************************************************************************
 *   Copyright (C) 2006 by Alexandru Olaru                                 *
 *   qumbetlian@yahoo.com                                                  *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/

#include <fstream>
#include <errno.h>
#include "treeviewdict.hh"

TreeViewDict::MyModelColumns::MyModelColumns(){
	add(key_text);
	add(val_text);
}

TreeViewDict::MyModelColumns::~MyModelColumns(){
}

char* TreeViewDict::load_list(char* file_name, unsigned int *arg_nitems, Glib::RefPtr<Gtk::ListStore> *arg_refliststore){
	char *msg = NULL;
	std::ifstream file(file_name, std::ios::binary);
	if(!file){
		msg = (char*) malloc(sizeof(char) * (strlen(strerror(errno)) + strlen(strrchr(file_name, '/') + 1)));
		sprintf(msg, "%s %s", strerror(errno), strrchr(file_name, '/') + 1);
		return(msg);
	}
	char *bbuffer, *buffer = (char*) malloc(8);
	bbuffer = NULL;
	Gtk::TreePath rpath = Gtk::TreePath(Glib::ustring("0"));
	iter = (*arg_refliststore)->get_iter(rpath);
	while(iter) iter++;
	//***********************************************************
	// Incarcarea listelor de cuvinte
	//***********************************************************
	buffer = (char*) realloc(buffer, 65536);
	while(!file.rdstate()){
		iter = (*arg_refliststore)->append();
		file.getline(buffer, 65500, 0xAC);
		//printf("%s = ", buffer);
		(*iter)[model.key_text] = buffer;
		file.getline(buffer, 65500, 0xAC);
		//printf("%s\n", buffer);
		(*iter)[model.val_text] = buffer;
		(*arg_nitems)++;
	}
	//***********************************************************
	if(buffer) free(buffer);
	if(bbuffer) free(bbuffer);
	if(file.eof()){
		msg = (char*) malloc(3);
		strcpy(msg, "OK");
	}
	else{
		char* fmsg = "An error has ocured when read file ";
		msg = (char*) malloc((strlen(fmsg) + strlen(strrchr(file_name, '/')))*sizeof(char));
		sprintf(msg, "%s%s", fmsg, strrchr(file_name, '/') + 1);
	}
	file.close();
	return(msg);
}

Gtk::TreePath& TreeViewDict::lookup(Glib::ustring &str, unsigned int lim_up, unsigned int lim_down){
	static char path_str[6];
	static unsigned int middle;
	middle = (lim_up+lim_down)/2;
	if(middle == lim_up || middle == lim_down)
		return(establish(str, lim_up, lim_down));
	sprintf(path_str, "%d", middle);
	path = Gtk::TreePath(Glib::ustring(path_str));
	if(str <= get_key(*(treeview1->get_model()->get_iter(path))))
		return(lookup(str, lim_up, middle));
	if(str > get_key(*(treeview1->get_model()->get_iter(path))))
		return(lookup(str, middle, lim_down));
}

Gtk::TreePath& TreeViewDict::establish(Glib::ustring &str, unsigned int lim_up, unsigned int lim_down){
	char path_str[6];
	int len = str.length();
	Glib::ustring key_up, key_down;
	sprintf(path_str, "%d", lim_down);
	path = Gtk::TreePath(Glib::ustring(path_str));
	key_down = get_key(*(treeview1->get_model()->get_iter(path)));
	path.prev();
	key_up = get_key(*(treeview1->get_model()->get_iter(path)));
	for(int i = 0; i < len; i++){
		if(key_down[i] <= str[i])
			path.next();
		else
			break;
		if(key_up[i] >= str[i])
			path.prev();
		else
			break;
	}
	return(path);
}

TreeViewDict::TreeViewDict(GlademmData *gmm_data){
	treeview1 = this;
	treeview1->set_name("treeview1");
	treeview1->set_size_request(120, -1);
	treeview1->set_flags(Gtk::CAN_FOCUS | Gtk::CAN_DEFAULT);
	treeview1->set_headers_visible(false);
	treeview1->show();
	refliststore_lang1_lang2 = Gtk::ListStore::create(model);
	refliststore_lang2_lang1 = Gtk::ListStore::create(model);
	refliststore = &refliststore_lang1_lang2;
	treeview1->set_model(refliststore_lang1_lang2);
	treeview1->append_column("key text", model.key_text);
	path = Gtk::TreePath(Glib::ustring("0"));
	list.lang1_lang2_saved = true;
	list.lang2_lang1_saved = true;
	list.saved = &list.lang1_lang2_saved;
	lang1_lang2_nitems = lang2_lang1_nitems = 0;
	nitems = &lang1_lang2_nitems;
	lang1_lang2_list_name = new char[sizeof(char) * (strlen(LIST1_LIST2) + 5)];
	sprintf(lang1_lang2_list_name, "%s.dic", LIST1_LIST2);
	lang2_lang1_list_name = new char[sizeof(char) * (strlen(LIST1_LIST2) + 5)];
	sprintf(lang2_lang1_list_name, "%s.dic", LIST2_LIST1);
	list_name = lang1_lang2_list_name;
}

TreeViewDict::~TreeViewDict(){
	if(lang1_lang2_list_name) delete[] lang1_lang2_list_name;
	if(lang2_lang1_list_name) delete[] lang2_lang1_list_name;
}

void TreeViewDict::lang1_lang2_select(bool show){
	nitems = &lang1_lang2_nitems;
	refliststore = &refliststore_lang1_lang2;
	if(show) treeview1->set_model(refliststore_lang1_lang2);
	list.saved = &list.lang1_lang2_saved;
	list_name = lang1_lang2_list_name;
}

void TreeViewDict::lang2_lang1_select(bool show){
	nitems = &lang2_lang1_nitems;
	refliststore = &refliststore_lang2_lang1;
	if(show) treeview1->set_model(refliststore_lang2_lang1);
	list.saved = &list.lang2_lang1_saved;
	list_name = lang2_lang1_list_name;
}

void TreeViewDict::set_path(Gtk::TreePath l_path){
	path = l_path;
}

void TreeViewDict::on_grab_focus (){
	row_activated((*refliststore)->get_path(treeview1->get_selection()->get_selected()), *(treeview1->get_column(0)));
	Gtk::TreeView::on_grab_focus();
}

bool TreeViewDict::need_save(void){
	return(!*list.saved);
}

bool TreeViewDict::remove_word(Gtk::TreePath& l_path){
	if(iter = treeview1->get_model()->get_iter(l_path)){
		(*refliststore)->erase(iter);
		(*nitems)--;
		*list.saved = false;
		if(l_path.to_string() < path.to_string())
			path.prev();
		return(true);
	}
	return(false);
}

char* TreeViewDict::save_list(const char* path){
	char *msg = (char*) malloc(3);
	strcpy(msg, "OK");
 	if(!*list.saved){
		char fc, *file_name = new char[sizeof(char) * (strlen(path) + strlen(WORDLIST_RELATIVE_PATH) + strlen(list_name) + 2)];
		Gtk::TreePath rpath = Gtk::TreePath(Glib::ustring("0"));
		iter = (*refliststore)->get_iter(rpath);
		sprintf(file_name, "%s%s/%s", path, WORDLIST_RELATIVE_PATH, list_name);
		std::ofstream file(file_name, std::ios::binary);
		if(!file){
			msg = (char*) realloc(msg, sizeof(char) * (strlen(strerror(errno)) + strlen(list_name) + 2));
			sprintf(msg, "%s %s", strerror(errno), list_name);
			file.close();
			return(msg);
		}
		fc = 0xAC;
		char *buffer = NULL;
		unsigned long int len, _len;
		while(iter){
			len = get_key(*iter).bytes();
			_len = len + get_value(*iter).bytes() + 4;
			buffer = (char*) realloc(buffer, _len*sizeof(char));
			strcpy(buffer, get_key(*iter).c_str());
			*(buffer + len + 1) = fc;
			strcpy(buffer + len + 2, get_value(*iter).c_str());
			*(buffer + _len - 1) = fc;
			file.write(buffer, _len);
			iter++;
		}
		file.close();
		*list.saved = true;
		if(buffer) free(buffer);
	}
	return(msg);
}

char* TreeViewDict::load_lists(const char* path){
	char *msg1, *msg2, *msg = (char*) malloc(3);
	msg1 = msg2 = NULL;
	strcpy(msg, "OK");
	Gtk::TreePath rpath = Gtk::TreePath(Glib::ustring("0"));
	iter = refliststore_lang1_lang2->get_iter(rpath);
	if(!iter){
		char* file_name = new char[strlen(path) + strlen(WORDLIST_RELATIVE_PATH) + strlen(lang1_lang2_list_name) + 2];
		sprintf(file_name, "%s%s/%s", path, WORDLIST_RELATIVE_PATH, lang1_lang2_list_name);
		msg1 = load_list(file_name, &lang1_lang2_nitems, &refliststore_lang1_lang2);
	}
	iter = refliststore_lang2_lang1->get_iter(rpath);
	if(!iter){
		char* file_name = new char[strlen(path) + strlen(WORDLIST_RELATIVE_PATH) + strlen(lang2_lang1_list_name) + 2];
		sprintf(file_name, "%s%s/%s", path, WORDLIST_RELATIVE_PATH, lang2_lang1_list_name);
		msg2 = load_list(file_name, &lang2_lang1_nitems, &refliststore_lang2_lang1);
	}
	if(msg1){
		if(strcmp(msg1, "OK")){
			msg = (char*) realloc(msg, (strlen(msg1) + 1)*sizeof(char));
			strcpy(msg, msg1);
		}
		free(msg1);
	}
	if(msg2){
		if(strcmp(msg2, "OK")){
			if(strcmp(msg, "OK")){
				msg = (char*) realloc(msg, (strlen(msg) + 2)*sizeof(char));
				strcat(msg, "\n");
			}
			else
				*msg = '\0';
			msg = (char*) realloc(msg, (strlen(msg) + strlen(msg2) + 1)*sizeof(char));
			strcat(msg, msg2);
		}
		free(msg2);
	}
	return(msg);
}

unsigned int TreeViewDict::get_number_of_items(int arg){
    if(arg == 1)
        return(lang1_lang2_nitems); //for 'lang1_lang2'
    if(arg == 2)
        return(lang2_lang1_nitems); //for 'lang2_lang1'
	return(*nitems);
}

Glib::ustring TreeViewDict::get_key(Gtk::TreeModel::Row row){
	return(row[model.key_text]);
}

Glib::ustring TreeViewDict::get_value(Gtk::TreeModel::Row row){
	return(row[model.val_text]);
}

Gtk::TreePath& TreeViewDict::position_word(Glib::ustring &str){
	if(*nitems >= 2)
		return(lookup(str, 0, *nitems-1));
	else
		return(path);
}

Gtk::TreePath& TreeViewDict::add_word(Glib::ustring k, Glib::ustring v, Glib::ustring mod = Glib::ustring("get path")){
	if(*nitems > 25000)
		return(path);
	if(mod == Glib::ustring("insert")){
		if(iter = (*refliststore)->get_iter(path)){
			if(k < get_key(*iter)){
				iter = (*refliststore)->insert(iter);
				(*nitems)++;
			}
			else
				if(k > get_key(*iter)){
					iter = (*refliststore)->insert(++iter);
					(*nitems)++;
				}
			path = (*refliststore)->get_path(iter);
		}
		else{
			iter = (*refliststore)->append();
			(*nitems)++;
		}
	}
	else
		if(mod == Glib::ustring("append")){
			iter = (*refliststore)->append();
			(*nitems)++;
		}
		else
			if(mod == Glib::ustring("prepend")){
				iter = (*refliststore)->prepend();
				(*nitems)++;
			}
			else
				return(path);
	(*iter)[model.key_text] = k;
	(*iter)[model.val_text] = v;
	*list.saved = false;
	return(path);
}

bool operator > (Glib::ustring& left_str, Glib::ustring right_str){
	static unsigned int len_left_str, len_right_str, len_min;
	len_left_str = left_str.length();
	len_right_str = right_str.length();
	len_min = (len_left_str <= len_right_str) ? len_left_str:len_right_str;
	for(register unsigned int i = 0; i < len_min; i++){
		if(left_str[i] < right_str[i])
			return(false);
		if(left_str[i] > right_str[i])
			return(true);
	}
	if(len_left_str <= len_right_str)
		return(false);
	else
		return(true);
}

bool operator < (Glib::ustring& left_str, Glib::ustring right_str){
	if(left_str >= right_str)
		return(false);
	else
		return(true);
}

bool operator >= (Glib::ustring& left_str, Glib::ustring right_str){
	static unsigned int len_left_str, len_right_str, len_min;
	len_left_str = left_str.length();
	len_right_str = right_str.length();
	len_min = (len_left_str <= len_right_str) ? len_left_str:len_right_str;
	for(register unsigned int i = 0; i < len_min; i++){
		if(left_str[i] < right_str[i])
			return(false);
		if(left_str[i] > right_str[i])
			return(true);
	}
	if(len_left_str < len_right_str)
		return(false);
	else
		return(true);
}

bool operator <= (Glib::ustring& left_str, Glib::ustring right_str){
	if(left_str > right_str)
		return(false);
	else
		return(true);
}
