/***************************** LICENSE START ***********************************

 Copyright 2012 ECMWF and INPE. This software is distributed under the terms
 of the Apache License version 2.0. In applying this license, ECMWF does not
 waive the privileges and immunities granted to it by virtue of its status as
 an Intergovernmental Organization or submit itself to any jurisdiction.

 ***************************** LICENSE END *************************************/

#ifndef SyncFolders_H
#include "SyncFolders.h"
#endif

#ifndef MetviewUI_H
#include "MetviewUI.h"
#endif

#ifndef FolderViewer_H
#include "FolderViewer.h"
#endif

#ifndef XMText_H
#include "XMText.h"
#endif

#include <Xm/ToggleB.h>

const double maxFrequency     = 60*60*24; // One day
const double startFrequency   = 5;        // 5 sec.
const double defaultFrequency = 5; //2*60*60;  // 2 hour


static set<SyncFolders*> syncs;

class SyncViewer : public FolderViewer {
	Widget menu() { return 0; }
	bool  dropCopy() { return false; }
	bool  accept(IconObject* o);

	set<string> names_;

public:

	SyncViewer(SyncFolders&,Widget,Folder*);
	void names(const set<string>&);
};

SyncViewer::SyncViewer(SyncFolders&,Widget drag,Folder* f):
	FolderViewer(f)
{
	FolderViewer::install(drag);
}

bool SyncViewer::accept(IconObject* o)
{
	return names_.find(o->name()) != names_.end();
}

void SyncViewer::names(const set<string>& s)
{
	names_ = s;
	redraw();
}

SyncFolders::SyncFolders(Folder* user,Folder* system):
	user_(user),
	system_(system),
	Timeout(startFrequency),
	what_was_added_(0),
	what_was_removed_(0),
	changed_yours_(0),
	changed_system_(0)
{
	syncs.insert(this);
//	enable();
}

SyncFolders::~SyncFolders()
{

	syncs.erase(this);
	
	delete what_was_added_;
	delete what_was_removed_;
	delete changed_yours_;
	delete changed_system_;
}

void SyncFolders::add(Folder* user,Folder* system)
{
	if(user && system) {

		for(set<SyncFolders*>::iterator j = syncs.begin(); j != syncs.end(); ++j)
		{
			SyncFolders* s = *j;
			if(s->user_ == user && s->system_ == system)
			{
				s->frequency(startFrequency);
				return;
			}
		}
		new SyncFolders(user,system);
	}
}

void SyncFolders::sync(Folder* user,Folder* system)
{
//	mode_t previous_mask;
//	previous_mask = umask (S_IWUSR);
	user->copyContent(system);
//	umask (previous_mask);
}

void SyncFolders::make()
{
	if(xd_rootwidget()) return;

	create(XtDisplay(MetviewUI::root()),"Metview",0,0);
	XtRealizeWidget(xd_rootwidget());
	string name = user_->fullName();
	XtVaSetValues(xd_rootwidget(),XmNtitle,name.c_str(),0);

	what_was_added_   = new SyncViewer(*this,added_,system_);
	what_was_removed_ = new SyncViewer(*this,gone_,user_);
	changed_yours_    = new SyncViewer(*this,changed_u_,user_);
	changed_system_   = new SyncViewer(*this,changed_s_,system_);

	XMText text(text_);
	char buffer[10240];
	sprintf(buffer,"The folder \"%s\" is synchronized with the folder \"%s\". "
		"The latter has been modified, and you can decide to apply the relevant changes.",
		user_->fullName().c_str(),system_->fullName().c_str());

	text.set(buffer);
//	XtVaSetValues(text_,XmNrows, 6,0);

}

void SyncFolders::show()
{
	make();
	XMapRaised(XtDisplay(xd_rootwidget()),XtWindow(xd_rootwidget()));
}

void SyncFolders::hide()
{
	make();
	XUnmapWindow(XtDisplay(xd_rootwidget()),XtWindow(xd_rootwidget()));
}


static bool changed(IconObject* u,IconObject* s)
{
	if(s->path().lastModified() > u->path().lastModified())
		if(s->sameAs(u))
		{
			u->touch();
			return false;
		}
		else
			return true;
	return false;
}

void SyncFolders::run()
{

	Path u = user_->path();
	Path s = system_->path();

	set<string> user_files   = u.files();
	set<string> system_files = s.files();

	set<string> added = system_files;
	set<string> gone  = user_files;

	set<string> modified;

	for(set<string>::iterator j = user_files.begin(); j != user_files.end(); ++j)
		added.erase(*j);

	for(set<string>::iterator j = system_files.begin(); j != system_files.end(); ++j)
		gone.erase(*j);

	for(set<string>::iterator j = system_files.begin(); j != system_files.end(); ++j)
		if(user_files.find(*j) != user_files.end())
		{
			IconObject* uo = user_->find(*j);
			IconObject* so = system_->find(*j);

			if(uo && so && changed(uo,so))
				modified.insert(*j);
		}

	if(added.size() || gone.size() || modified.size())
	{
		make();

		if(added.size())   XtManageChild(added_form_);     else XtUnmanageChild(added_form_);
		if(gone.size())     XtManageChild(gone_form_);     else XtUnmanageChild(gone_form_);
		if(modified.size()) XtManageChild(changed_form_);  else XtUnmanageChild(changed_form_);


		what_was_added_->names(added);
		what_was_removed_->names(gone);
		changed_yours_->names(modified);
		changed_system_->names(modified);

		adjust();
		disable();
		show();
	}

	frequency(defaultFrequency);

}

void SyncFolders::closeCB(Widget, XtPointer)
{
	hide();
	enable();
	frequency(maxFrequency);
}

void SyncFolders::syncCB(Widget, XtPointer)
{
	hide();
	enable();
	//frequency(maxFrequency);
}

void SyncFolders::adjust()
{
	return;
	make();

	// Added

	if(XmToggleButtonGetState(add_all_)) 
		what_was_added_->selectAll();

	if(XmToggleButtonGetState(add_none_))
		what_was_added_->selectNone();

	// Gone

	if(XmToggleButtonGetState(remove_all_))
		what_was_removed_->selectAll();

	if(XmToggleButtonGetState(keep_all_))
		what_was_removed_->selectNone();
		

	// Changed

	if(XmToggleButtonGetState(preserve_all_))
	{
		changed_yours_->selectAll();
		changed_system_->selectNone();
	}

	if(XmToggleButtonGetState(overwrite_all_))
	{
		changed_yours_->selectNone();
		changed_system_->selectAll();
	}

//	if(XmToggleButtonGetState(preserve_selected_))
//	if(XmToggleButtonGetState(overwrite_all_))

}

void SyncFolders::entryCB(Widget, XtPointer)
{
	adjust();
}

void SyncFolders::selectCB(Widget, XtPointer)
{
	cout << "SyncFolders::selectCB " << endl;
}


#if 0
add_all_
add_selected_
add_none_

preserve_all_
preserve_selected_
overwrite_all_
overwrite_selected_

remove_all_
remove_selected_
keep_all_
#endif
