#include "CFireFlierClientApp.hh"
#include "CDlgUSpaceRules.hh"
#include "fireflierIO.h"
#include <glibmm/arrayhandle.h>
#include <algorithm>
#if FF_DEBUG
#include <iostream>
#endif
using namespace std;


// definition of static member
const CDlgUSpaceRules::CUSpaceRulesColumnRecord CDlgUSpaceRules::m_colRecord;


CDlgUSpaceRules::CDlgUSpaceRules()
	: Gtk::Window()
	, m_butDel(Gtk::Stock::DELETE)
{
	initGUI();

	ffIO.networkThread.signal_USpaceRules_avail().connect(m_signalUSpaceRulesAvail.slot(true));
	ffIO.networkThread.signal_Authentication().connect(m_signalAuthentication.slot());
	ffIO.networkThread.signal_error().connect(m_signalNetworkThreadError.slot());

	m_signalUSpaceRulesAvail.connect(SigC::slot(*this, &CDlgUSpaceRules::on_USpaceRules_avail));
	m_signalAuthentication.connect(SigC::slot(*this, &CDlgUSpaceRules::on_Authentication));
	m_signalNetworkThreadError.connect(SigC::slot(*this, &CDlgUSpaceRules::on_networkthread_error));
}


CDlgUSpaceRules::~CDlgUSpaceRules()
{
#ifdef WITHGCONF
	if (m_gconfUI[strGConfUIUSpaceRulesDlg_remember].get_bool())
	{
		if (is_visible())
			save_pos_and_size();
		m_gconfUI.write();
	}
#endif
}

void CDlgUSpaceRules::initGUI()
{
	m_tvUSpaceRules.modify_font(Pango::FontDescription("Courier 10 Pitch"));
	Gtk::VBox* vboxWhole = manage(new Gtk::VBox);
	Gtk::HBox* hboxDlgAction = manage(new Gtk::HBox(true, 5));
	hboxDlgAction->set_border_width(5);

	Gtk::ScrolledWindow* scrwnd = manage(new Gtk::ScrolledWindow);
	scrwnd->set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
	scrwnd->add(m_tvUSpaceRules);
	
	Gtk::Button* butCancel = manage(new Gtk::Button(Gtk::Stock::CLOSE));
	m_butDel.set_sensitive(false);
	hboxDlgAction->pack_start(m_butDel, Gtk::PACK_EXPAND_WIDGET, 2);
	hboxDlgAction->pack_start(*butCancel, Gtk::PACK_EXPAND_WIDGET, 2);
	vboxWhole->pack_start(*scrwnd, Gtk::PACK_EXPAND_WIDGET, 0);
	vboxWhole->pack_start(*hboxDlgAction, Gtk::PACK_SHRINK, 0);

	add(*vboxWhole);
	set_modal(false);
	set_title(strAppTitle+"::Userspace Rules");
	
	m_pListUSpaceRules = Gtk::ListStore::create(m_colRecord);
	m_tvUSpaceRules.set_model(m_pListUSpaceRules);
	m_tvUSpaceRules.append_column("Userspace Rules", m_colRecord.m_colUSpaceRule);
	m_pListSel = m_tvUSpaceRules.get_selection();
	m_pListSel->set_mode(Gtk::SELECTION_MULTIPLE);
	m_pListSel->signal_changed().connect(SigC::slot(*this, &CDlgUSpaceRules::on_selection_changed));

	show_all_children();

	m_butDel.signal_clicked().connect(SigC::slot(*this, &CDlgUSpaceRules::on_butDel_clicked));
#ifdef WITHGCONF
	m_gconfUI.add_dir(gb_pGConfClient, strGConfUIUSpaceRulesDlg, SigC::slot(*this, &CDlgUSpaceRules::on_value_changed));
	on_value_changed("", Gnome::Conf::Value());
	signal_delete_event().connect(SigC::slot(*this, &CDlgUSpaceRules::on_delete));
	butCancel->signal_clicked().connect(SigC::slot(*this, &CDlgUSpaceRules::on_butCancel_clicked));
#else
	m_tvUSpaceRules.modify_font(Pango::FontDescription("Courier 10 Pitch"));
	resize(600, 400);
	butCancel->signal_clicked().connect(SigC::slot(*this, &CDlgUSpaceRules::hide));
#endif
}


#ifdef WITHGCONF
bool CDlgUSpaceRules::on_delete(GdkEventAny*)
{
	save_pos_and_size();
	return false;
}

void CDlgUSpaceRules::on_butCancel_clicked()
{
	save_pos_and_size();
	hide();
}

void CDlgUSpaceRules::save_pos_and_size()
{
	int nX, nY;
	get_position(nX, nY);
	m_gconfUI[strGConfUIUSpaceRulesDlg_posX].set(nX);
	m_gconfUI[strGConfUIUSpaceRulesDlg_posY].set(nY);
	m_gconfUI[strGConfUIUSpaceRulesDlg_sizeX].set(get_width());
	m_gconfUI[strGConfUIUSpaceRulesDlg_sizeY].set(get_height());
}

void CDlgUSpaceRules::on_value_changed(const ustring& strKey, const Gnome::Conf::Value& value)
{
	bool bFFConcerned = (strKey.find(strGConfUIUSpaceRulesDlg) != ustring::npos);
#if FF_DEBUG
	cerr << "CDlgUSpaceRules::on_value_changed(): strKey=" << strKey << endl;
	cerr << "CDlgUSpaceRules::on_value_changed()::bFFConcerned=" << bFFConcerned << endl;
#endif
	if (bFFConcerned && strKey.length())
		m_gconfUI[strKey] = value;
	if (bFFConcerned || !strKey.length())
	{
#if FF_DEBUG
		cerr << "CDlgUSpaceRules::on_value_changed(): moving window" << endl;
#endif
		move(m_gconfUI[strGConfUIUSpaceRulesDlg_posX].get_int(), m_gconfUI[strGConfUIUSpaceRulesDlg_posY].get_int());
		resize(m_gconfUI[strGConfUIUSpaceRulesDlg_sizeX].get_int(), m_gconfUI[strGConfUIUSpaceRulesDlg_sizeY].get_int());
		Pango::FontDescription font(m_gconfUI[strGConfUIUSpaceRulesDlg_font].get_string());
		m_tvUSpaceRules.modify_font(font);
	}
}
#endif // WITHGCONF

void CDlgUSpaceRules::on_USpaceRules_avail(const char* szMsg, int nLen)
{
#if FF_DEBUG
	cerr << "CDlgUSpaceRules::on_USpaceRules_avail" << endl;
#endif
	m_pListUSpaceRules->clear();
	const char* itLineBegin = szMsg;
	const char* itLineEnd = NULL;
	const char* itEnd = itLineBegin+nLen+1;
	for (; (itLineEnd = find(itLineBegin, itEnd, '\n')) != itEnd; itLineBegin = itLineEnd+1)
		m_pListUSpaceRules->append()->set_value(m_colRecord.m_colUSpaceRule, ustring(itLineBegin, itLineEnd));
	
}


void CDlgUSpaceRules::deleteRule(const Gtk::TreePath& path, int* nCount)
{
	Glib::ArrayHandle <int>::const_iterator pathIt = path.get_indices().begin();
#if FF_DEBUG
	cout << "deleting userspace rule nr: " << (*pathIt)-*nCount << endl;
#endif
	try
	{
		// server sends us the new rules, therefore deleting a treerow is not needed
		ffIO << CCO_USpaceRuleDelete((*pathIt)-*nCount);
		++*nCount;
	}
	catch (...)
	{
	}
}


void CDlgUSpaceRules::on_butDel_clicked()
{
	lock();
	int nCount = 0;
	m_pListSel->selected_foreach(SigC::bind(SigC::slot(&CDlgUSpaceRules::deleteRule), &nCount));
	unlock();
}


void CDlgUSpaceRules::on_selection_changed()
{
	lock();
	bool bAnySelected = false;
	m_pListSel->selected_foreach(SigC::bind(SigC::slot(isAnySelected), &bAnySelected));
	// disable delete button if no node is selected
	m_butDel.set_sensitive(bAnySelected);
	unlock();
}

void CDlgUSpaceRules::isAnySelected(const Gtk::TreePath& path, bool* bWasHere)
{
	*bWasHere = true;
}


void CDlgUSpaceRules::on_Authentication(int nAuthenticated)
{
	lock();
	if (nAuthenticated == 1)
		m_butDel.set_sensitive();
	unlock();
}


void CDlgUSpaceRules::on_networkthread_error(CffIO::pCffIOError pErr, bool bDisconnected)
{
	lock();
	if (bDisconnected)
		m_butDel.set_sensitive(false);
	unlock();
}
