#include "StdAfx.h"
#include "eventlist.h"

EventList::EventList(void)
{
	NeedRefresh = 0;
	NeedEditRefresh = 0;
}

EventList::~EventList(void)
{
}

int EventList::Create(HWND parent)
{
	Load("eventwindow");
	titlebar.title = env.GetWideString("eventwindow","title",L"TelescopingList");
	titlebar.Load("eventwindow::titlebar");
	expand.Load("eventwindow::expand");
	edit.Load("eventwindow::edit");
	
	list.Load("eventwindow::list");
	list.scrollbar.Load("eventwindow::scrollbar");
	
	editinglist.Load("eventwindow::editinglist");
	editinglist.scrollbar.Load("eventwindow::scrollbar");

	// load the item appearances for the active event list (Private versions)
	ActivePrivate.Load("eventwindow::styles::activeprivate");
	PendingPrivate.Load("eventwindow::styles::pendingprivate");
	// load the item appearnaces for the editing list
	CheckedPrivate.Load("eventwindow::editstyles::checkedprivate");
	UncheckedPrivate.Load("eventwindow::editstyles::uncheckedprivate");

	// load the item appearances for the active event list (Public versions)
	ActivePublic.Load("eventwindow::styles::activepublic");
	PendingPublic.Load("eventwindow::styles::pendingpublic");
	// load the item appearnaces for the editing list
	CheckedPublic.Load("eventwindow::editstyles::checkedpublic");
	UncheckedPublic.Load("eventwindow::editstyles::uncheckedpublic");

	moveable = 0;
	ShowInTaskBar = 0;
	TelescopingList::Create(parent);

	EmptyStyle.Load("eventwindow::styles::empty");
	EditEmptyStyle.Load("eventwindow::editstyles::empty");
	list.ShowEmptyItem(EmptyStyle.description.data(),EmptyStyle);
	editinglist.ShowEmptyItem(EditEmptyStyle.description.data(),EditEmptyStyle);


	SetTimer(hWnd,0,5000,0);

	// finally request notifications for changes
	AddCustomNotification(bcEvent);

	return 1;
}

void EventList::DeepRefresh(int memoize)
{
	if(memoize && editing){
		NeedRefresh = 1;
		return;
	} else
		NeedRefresh = 0;

	Vector<int> SubscribedEventIds;

#ifdef SUPERUSER
	db.GetAllEvents(SubscribedEventIds);
#else
	db.GetSubscribedEvents(theApp.user.UserId,SubscribedEventIds);
#endif

	{
		int i;
		// first remove events that are no longer subscribed to
		Vector<int> current;
		list.GetKeys(current);
		for(i=0;i<current.length;i++){
			if(SubscribedEventIds.find(current[i])==-1){ // not subscribed to anymore, remove it
				ListItem * item = list.GetItemByKey(current[i]);
				if(item){
					Event * event = (Event *)item->userdata;
					Delete(event);
				}
			}
		}

		// now take care of the events that are still subscribed
		for(i=0;i<SubscribedEventIds.length;i++){
			ListItem * item = list.GetItemByKey(SubscribedEventIds[i]);
			if(item){ // already in the list
				Event * event = (Event *)item->userdata;
				event->DeepRefresh(SubscribedEventIds[i]);
			} else { // not in the list yet, so add it
				Event * event = new Event();
				event->DeepRefresh(SubscribedEventIds[i]);
				Add(event);
			}
		}
	}

	nActiveEvents = 0;
	std::list<ListItem*>::iterator i;
	for(i=list.items.begin();i!=list.items.end();i++){
		ListItem * item = *i;
		Event * event = (Event*)item->userdata;
		if(event->active)
			nActiveEvents++;
	}

	TCHAR buffer[100];
	_stprintf(buffer,L"%d/%d",nActiveEvents,list.items.size());
	expand.text = buffer;
	expand.Redraw();
}

void EventList::Add(Event * event)
{
	ListItem * item = list.CreateItem(event->record.EventName,event->record.EventId);
	event->item = item;
	event->editing = 0;
	event->ShallowRefresh();
	item->userdata = event;
	item->usertype = bcEvent;
	list.AddItem(item);
}

void EventList::Delete(Event * event)
{
	list.DeleteItem(event->item);
	delete event;
}

void EventList::EditAdd(Event * event)
{
	ListItem * item = editinglist.CreateItem(event->record.EventName,event->record.EventId);
	event->item = item;
	event->editing = 1;
	event->ShallowRefresh();
	item->userdata = event;
	item->usertype = bcEvent;
	editinglist.AddItem(item);
}

void EventList::EditDelete(Event * event)
{
	editinglist.DeleteItem(event->item);
	delete event;
}


void EventList::OnListSelect(HWND h, HWND hItem)
{
	ListItem * item = (ListItem*)GetWindowLongPtr(hItem,GWL_USERDATA);
	if(list.hWnd==h){
		// Show the view or edit event windows depending on ownership
		Event * event = (Event *)item->userdata;
		if(event){
#ifdef SUPERUSER
			theApp.EditEvent(event->record.EventId);
#else
			if(event->record.OwnerId==theApp.user.UserId){
				theApp.EditEvent(event->record.EventId);
			} else {
				theApp.ViewEvent(event->record.EventId);
			}
#endif
		}
	} else if(editinglist.hWnd==h){
#ifdef SUPERUSER

#else
		Event * event = (Event *)item->userdata;
		if(event){
			if(event->checked){
				db.UnsubscribeFromEvent(theApp.user.UserId,event->record.EventId);
				rpc.ServerNotifyImmediate(bcEvent,event->record.EventId,bcUnsubscribe,theApp.user.UserId);
				event->checked = 0;
				event->ShallowRefresh();
				DeepRefresh();
			} else {
				COleDateTime now = COleDateTime::GetCurrentTime();
				db.SubscribeToEvent(theApp.user.UserId,event->record.EventId,event->record.StartTime,event->record.EndTime,1);
				rpc.ServerNotifyImmediate(bcEvent,event->record.EventId,bcSubscribe,theApp.user.UserId);
				event->checked = 1;
				event->ShallowRefresh();
				DeepRefresh();
			}
		}
#endif
	}
}

void EventList::OnListDblSelect(HWND h, HWND hItem)
{
	ListItem * item = (ListItem*)GetWindowLongPtr(hItem,GWL_USERDATA);
	if(list.hWnd==h){

	} else if(editinglist.hWnd==h){

	}
}

void EventList::OnPopupStart(WPARAM wParam, LPARAM lParam)
{
	HWND hSourceList = (HWND)lParam;
	if(hSourceList==list.hWnd || hSourceList==editinglist.hWnd){
		ListItem * item = (ListItem *)wParam;
		Event * event = (Event *)item->userdata;
		if(event){
			event->ShallowRefresh();
			RECT rect;
			GetWindowRect(item->hWnd,&rect);
			event->popup.SetLocation(theApp.sidebar.location.X+location.X+list.location.X-event->popup.size.Width,theApp.sidebar.location.Y+rect.top);
			event->popup.SetActivator(item->hWnd);
			event->popup.Show();
		}
	}
}

void EventList::OnPopupEnd(WPARAM wParam, LPARAM lParam)
{
	HWND hSourceList = (HWND)lParam;
	if(hSourceList==list.hWnd || hSourceList==editinglist.hWnd){
		ListItem * item = (ListItem *)wParam;
		Event * event = (Event *)item->userdata;
		if(event){
			if(event->popup.titlebar.MouseOutside)
				event->popup.Hide();
			else
				event->popup.StartTimer();
		}
	} 
}


void EventList::OnTimer()
{
	lipos i;
	for(i=list.items.begin();i!=list.items.end();i++){
		ListItem * item =  *i;
		if(item){
			Event * event = (Event*)item->userdata;
			event->ShallowRefresh(); // only refresh time-sensitive components
		}		
	}
}

void EventList::OnButton(HWND h)
{
	if(h==edit.hWnd && editing==0){ // about to show the editing list
		if(NeedEditRefresh)
			DeepRefreshEdit(0);
	}
	if(h==edit.hWnd && editing==1){
		if(NeedRefresh)
			DeepRefresh(0);
	}

	TelescopingList::OnButton(h);
}

void EventList::ClearList()
{
	lipos i;
	for(i=list.items.begin();i!=list.items.end();i++){
		ListItem * item = *i;
		Event * event = (Event*)item->userdata;
		delete event;
	}
	list.DeleteAllItems();
}

void EventList::DeepRefreshEdit(int memoize)
{
	if(memoize && !editing){
		NeedEditRefresh = 1;
		return;
	} else
		NeedEditRefresh = 0;

	Vector<int> subscribed;
	db.GetSubscribedEvents(theApp.user.UserId,subscribed);
	Vector<int> eventIds;

#ifdef SUPERUSER
	db.GetAllEvents(eventIds);
#else
	db.GetSubscribableEvents(theApp.user.UserId,eventIds);
#endif

	int i;
	// first remove events that are no longer subscribable
	Vector<int> current;
	editinglist.GetKeys(current);
	for(i=0;i<current.length;i++){
		if(eventIds.find(current[i])==-1){ // not subscribable to anymore, remove it
			ListItem * item = editinglist.GetItemByKey(current[i]);
			if(item){
                Event * event = (Event *)item->userdata;
				EditDelete(event);
			}
		}
	}

	// now take care of the ones that are
	for(i=0;i<eventIds.length;i++){
		ListItem * item = editinglist.GetItemByKey(eventIds[i]);
		if(item){ // already in the list
			Event * event = (Event *)item->userdata;
			if(subscribed.find(eventIds[i])==-1)
				event->checked = 0;
			else
				event->checked = 1;
			event->DeepRefresh(eventIds[i]);
		} else { // not in the list yet, so add it
			Event * event = new Event();
			if(subscribed.find(eventIds[i])==-1)
				event->checked = 0;
			else
				event->checked = 1;
			event->DeepRefresh(eventIds[i]);
			EditAdd(event);
		}
	}
}

void EventList::ClearEditList()
{
	lipos i;
	for(i=editinglist.items.begin();i!=editinglist.items.end();i++){
		ListItem * item = *i;
		Event * event = (Event*)item->userdata;
		delete event;
	}
	editinglist.DeleteAllItems();
}

void EventList::OnListDeleteItem(WPARAM wParam, LPARAM lParam)
{
	HWND hList = (HWND)wParam;
	ListItem * item = (ListItem *)lParam;

	if(hList==editinglist.hWnd && item){
		Event * event = (Event *)item->userdata;
		if(event){
			rpc.BeginTransaction();
			db.UnsubscribeFromEvent(theApp.user.UserId,event->record.EventId);
			rpc.ServerNotify(bcEvent,event->record.EventId,bcUnsubscribe,theApp.user.UserId);
			rpc.ServerNotify(bcEvent,event->record.EventId,bcModified,theApp.user.UserId);
			EditDelete(event);
			DeepRefresh();
			rpc.EndTransaction();
		}
	}
}

void EventList::OnCustomNotify(int id, Notification& n)
{
	ListItem * item;
	Event * event;

	switch(id){
	case bcEvent:
		switch(n.reason){
		case bcAdd:
		case bcRemove:
		case bcSubscribe:
		case bcUnsubscribe:
		case bcModified:
			DeepRefresh();
			DeepRefreshEdit();
			break;
		default:
			item = list.GetItemByKey(n.param[0]);
			if(item){
				event = (Event*)item->userdata;
				if(event){
					// this notification applies to an event in the list
					event->OnCustomNotify(id,n);
				}
			}
			item = editinglist.GetItemByKey(n.param[0]);
			if(item){
				event = (Event*)item->userdata;
				if(event){
					// this notification applies to an event in the editing list
					event->OnCustomNotify(id,n);
				}
			}
			break;
		}

		break;
	}
}

int EventList::Exists(int id)
{
	Vector<int> current;
	list.GetKeys(current);
	return (current.find(id)!=-1);
}

int EventList::EditExists(int id)
{
	Vector<int> current;
	editinglist.GetKeys(current);
	return (current.find(id)!=-1);
}

