#include "stdafx.h"
#include "EditEventWindow.h"

#define STATUS(x) status.SetText(env.GetWideString("EditEventWindow::status",x,_T(x)))

EditEventWindow::EditEventWindow()
{

}

EditEventWindow::~EditEventWindow()
{

}

int EditEventWindow::Create(HWND parent)
{
	Load("EditEventWindow");
	Category.Load("EditEventWindow::Category");
	Description.Load("EditEventWindow::Description");
	EndDate.Load("EditEventWindow::EndDate");
	EndTime.Load("EditEventWindow::EndTime");
	EventName.Load("EditEventWindow::EventName");
	Location.Load("EditEventWindow::Location");
	OtherLocation.Load("EditEventWindow::OtherLocation");
	Private.Load("EditEventWindow::Private");
	CanViews.Load("EditEventWindow::CanViews");
	StartDate.Load("EditEventWindow::StartDate");
	StartTime.Load("EditEventWindow::StartTime");
	Eternal.Load("EditEventWindow::Eternal");
	Keywords.Load("EditEventWindow::Keywords");
	Group.Load("EditEventWindow::Group");
	update.Load("EditEventWindow::update");
	cancel.Load("EditEventWindow::cancel");
	eventdelete.Load("EditEventWindow::delete");

#ifdef ENABLEEVENTTRACKTIME
	TrackingEternal.Load("EditEventWindow::TrackingEternal");
	TrackingStartDate.Load("EditEventWindow::TrackingStartDate");
	TrackingStartTime.Load("EditEventWindow::TrackingStartTime");
	TrackingEndDate.Load("EditEventWindow::TrackingEndDate");
	TrackingEndTime.Load("EditEventWindow::TrackingEndTime");	
#endif 

	status.Load("EditEventWindow::status");

	Category.scrollbar.Load("EditEventWindow::ScrollBar");
	Location.scrollbar.Load("EditEventWindow::ScrollBar");
	Group.scrollbar.Load("EditEventWindow::ScrollBar");

	CategoryStyle.Load("EditEventWindow::Category::ItemStyle");
	LocationStyle.Load("EditEventWindow::Location::ItemStyle");
	GroupStyle.Load("EditEventWindow::Group::ItemStyle");

	StaticWindow::Create(parent);

	EndDate.Create(hWnd);
	EndTime.Create(hWnd);
	StartDate.Create(hWnd);
	StartTime.Create(hWnd);

	Eternal.Create(hWnd);
	Description.Create(hWnd,ES_MULTILINE);
	Category.Create(hWnd);
	Group.Create(hWnd);
	EventName.Create(hWnd);
	Location.Create(hWnd);
	OtherLocation.Create(hWnd);
	Private.Create(hWnd);
	CanViews.Create(hWnd);
	Keywords.Create(hWnd);
	
#ifdef ENABLEEVENTTRACKTIME
	TrackingEternal.Create(hWnd);

	TrackingEndDate.Create(hWnd);
	TrackingEndTime.Create(hWnd);
	TrackingStartDate.Create(hWnd);
	TrackingStartTime.Create(hWnd);
#endif

	update.Create(hWnd);
	cancel.Create(hWnd);
	eventdelete.Create(hWnd);

	status.Create(hWnd,ES_LEFT|ES_READONLY);
	status.Disable();

	// set up tab
	TabOrder tab;
	tab.Add(EventName);
	tab.Add(Keywords);
	tab.Add(StartDate);
	tab.Add(StartTime);
	tab.Add(EndDate);
	tab.Add(EndTime);
	tab.Add(Eternal);
	tab.Add(Description);
	tab.Add(Category);
	tab.Add(Group);
	tab.Add(Location);
	tab.Add(Private);
	tab.Add(CanViews);
#ifdef ENABLEEVENTTRACKTIME
	tab.Add(TrackingEternal);
	tab.Add(TrackingStartDate);
	tab.Add(TrackingStartTime);
	tab.Add(TrackingEndDate);
	tab.Add(TrackingEndTime);
#endif
	tab.Add(OtherLocation);
	tab.Commit();


	STATUS("DefaultStatus");

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

	return 1;
}

void EditEventWindow::DeepRefresh(int eventId)
{
	// load locations and categories
	int i;
	Vector<int> locationIds, groupIds, categoryIds;
	ListItem * item;

	// and put them into the lists
	db.GetAllEventCategories(categoryIds);
	Category.DeleteAllItems();
	for(i=0;i<categoryIds.length;i++){
		EventCategoryRecord record;
		db.GetCachedEventCategory(categoryIds[i],record);
		item = Category.CreateItem(record.Category,record.CategoryId);
		item->Set(CategoryStyle);
		Category.AddItem(item);
	}
	
	db.GetVisibleLocations(locationIds);
	Location.DeleteAllItems();
	item = Location.CreateItem(L"Other...",OtherLocationId);
	item->Set(LocationStyle);
	Location.AddItem(item);
	for(i=0;i<locationIds.length;i++){
		LocationRecord record;
		db.GetCachedLocation(locationIds[i],record);
		item = Location.CreateItem(record.LocationName,record.LocationId);
		item->Set(LocationStyle);
		Location.AddItem(item);
	}
	item = Location.CreateItem(L"No Location",NullLocationId);
	item->Set(LocationStyle);
	Location.AddItem(item);

	db.GetSubscribedGroups(theApp.user.UserId,groupIds);
	Group.DeleteAllItems();
	item = Group.CreateItem(L"No Group",NullGroupId);
	item->Set(GroupStyle);
	Group.AddItem(item);
	for(i=0;i<groupIds.length;i++){
		GroupRecord record;
		db.GetCachedGroup(groupIds[i],record);
		item = Group.CreateItem(record.GroupName,record.GroupId);
		item->Set(GroupStyle);
		Group.AddItem(item);
	}

	record.EventId = eventId;

	if(eventId==NullEventId){
		// Initialize all the fields to default values
		EventName.SetText(L"");
		Description.SetText(L"");
		Keywords.SetText(L"");
		Private.SetValue(0);
		StartDate.SetValue(COleDateTime::GetCurrentTime());
		EndDate.SetValue(COleDateTime::GetCurrentTime());
		COleDateTime deftime1, deftime2;
		deftime1.SetTime(8,0,0);
		deftime2.SetTime(8,30,0);
		StartTime.SetValue(deftime1);
		EndTime.SetValue(deftime2);
		Eternal.SetValue(0);
		Location.SetSelection(NullLocationId);
		OtherLocation.SetText(L"");
		Category.SetSelection(NullCategoryId);
		Group.SetSelection(NullGroupId);

#ifdef ENABLEEVENTTRACKTIME
		TrackingStartDate.SetValue(COleDateTime::GetCurrentTime());
		TrackingEndDate.SetValue(COleDateTime::GetCurrentTime());
		TrackingStartTime.SetValue(COleDateTime::GetCurrentTime());
		TrackingEndTime.SetValue(COleDateTime::GetCurrentTime());
		TrackingEternal.SetValue(0);
#endif

		STATUS("UnknownEvent");
	} else {
		// Fill the fields with current values
		db.GetCachedEvent(eventId,record);

		EventName.SetText(record.EventName);
		Description.SetText(record.Description);
		Keywords.SetText(record.Keywords);
		Private.SetValue(record.Private);
		StartDate.SetValue(COleDateTime(record.StartTime));
		EndDate.SetValue(COleDateTime(record.EndTime));
		StartTime.SetValue(COleDateTime(record.StartTime));
		EndTime.SetValue(COleDateTime(record.EndTime));
		Eternal.SetValue(record.Eternal);
		Location.SetSelection(record.LocationId);
		OtherLocation.SetText(record.OtherLocation);
		Category.SetSelection(record.CategoryId);
		Group.SetSelection(record.GroupId);

		if(Private.checked){
			CanViews.Show();
			BringWindowToTop(CanViews.hWnd);
		} else {
			CanViews.Hide();
		}

		Vector<int> members;
		db.GetEventCanViews(record.EventId,members);
		CanViews.SetText(L"");
		std::wstring member;
		for(int i=0;i<members.length;i++){
			db.GetCachedUsername(members[i],member);
			CanViews.AppendText(member.data());
			CanViews.AppendText(L" ");
		}

		if(Eternal.checked){
			StartTime.Hide();
			StartDate.Hide();
			EndTime.Hide();
			EndDate.Hide();
		} else {
			StartTime.Show();
			StartDate.Show();
			EndTime.Show();
			EndDate.Show();
		}

		EventSubscriptionRecord esr;
		db.GetEventSubscription(theApp.user.UserId,record.EventId,esr);

#ifdef ENABLEEVENTTRACKTIME
		TrackingStartDate.SetValue(COleDateTime(esr.TrackingStart));
		TrackingEndDate.SetValue(COleDateTime(esr.TrackingEnd));
		TrackingStartTime.SetValue(COleDateTime(esr.TrackingStart));
		TrackingEndTime.SetValue(COleDateTime(esr.TrackingEnd));
		TrackingEternal.SetValue(esr.Eternal);

		if(TrackingEternal.checked){
			TrackingStartTime.Hide();
			TrackingStartDate.Hide();
			TrackingEndTime.Hide();
			TrackingEndDate.Hide();
		} else {
			TrackingStartTime.Show();
			TrackingStartDate.Show();
			TrackingEndTime.Show();
			TrackingEndDate.Show();
		}		
#endif

		STATUS("DefaultStatus");

	}

}

void EditEventWindow::OnButton(HWND h)
{
	if(h==Private.hWnd){
		if(Private.checked){
			CanViews.Show();
			BringWindowToTop(CanViews.hWnd);
		} else
			CanViews.Hide();
	} else if(h==update.hWnd){

		rpc.BeginTransaction();

		if(record.EventId==NullEventId){
			Hide();
			rpc.EndTransaction();
			return;
		}

		DATE now = COleDateTime::GetCurrentTime();

		// construct the event record
		record.EventName = EventName.Data();
		if(record.EventName.length()==0){
			STATUS("NeedEventName");
			rpc.EndTransaction();
			return;
		}
		record.Description = Description.Data();

		COleDateTime dt0,dt1;
		dt1.SetDateTime(EndDate.date.GetYear(),EndDate.date.GetMonth(),EndDate.date.GetDay(),
			EndTime.time.GetHour(),EndTime.time.GetMinute(),0);
		dt0.SetDateTime(StartDate.date.GetYear(),StartDate.date.GetMonth(),StartDate.date.GetDay(),
			StartTime.time.GetHour(),StartTime.time.GetMinute(),0);

		record.Eternal = Eternal.checked;

		// validate the time interval
		if(dt0>dt1){
			if(record.Eternal){
				// just alter it ourselves
				record.StartTime = dt1;
				record.EndTime = dt0;
			} else { // we have to complain
				STATUS("InvalidTimeInterval");
				rpc.EndTransaction();
				return;
			}
		} else {
			record.StartTime = dt0;
			record.EndTime = dt1;	
		}

		if(Category.selectedItem){
			record.CategoryId = Category.selectedItem->key;
		} else {
			record.CategoryId = NullCategoryId;
		}
		if(Location.selectedItem){
			record.LocationId = Location.selectedItem->key;
		} else {
			record.LocationId = NullLocationId;
		}

		if(record.LocationId==OtherLocationId)
			record.OtherLocation = OtherLocation.Data();

		if(Group.selectedItem){
			record.GroupId = Group.selectedItem->key;
		} else {
			record.GroupId = NullGroupId;
		}
		record.OwnerId = theApp.user.UserId;
		record.Private = Private.checked;
		record.Keywords = Keywords.Data();

		int tmpId;
		db.GetEventId(record.EventName,tmpId);

		// now ask the db layer toupdate it
		if(tmpId!=record.EventId && tmpId!=NullEventId){
			STATUS("EventNameExists");
			rpc.EndTransaction();
			return;
		}
		STATUS("UpdatingEvent");
		DoEvents();

		db.UpdateEvent(record);

		if(record.EventId==NullEventId){
			STATUS("CreateFailed");
			rpc.EndTransaction();
			return;
		}

		STATUS("AssigningPermissions");
		DoEvents();

#ifdef ENABLEEVENTTRACKTIME
		COleDateTime TrackingStart;
		TrackingStart.SetDateTime(TrackingStartDate.date.GetYear(),
			TrackingStartDate.date.GetMonth(),
			TrackingStartDate.date.GetDay(),
			TrackingStartTime.time.GetHour(),
			TrackingStartTime.time.GetMinute(),0);
		COleDateTime TrackingEnd;
		TrackingEnd.SetDateTime(TrackingEndDate.date.GetYear(),
			TrackingEndDate.date.GetMonth(),
			TrackingEndDate.date.GetDay(),
			TrackingEndTime.time.GetHour(),
			TrackingEndTime.time.GetMinute(),0);

		db.SubscribeToEvent(theApp.user.UserId,
			record.EventId,
			TrackingStart.m_dt,TrackingEnd.m_dt,TrackingEternal.checked);
#else
		db.SubscribeToEvent(theApp.user.UserId,
			record.EventId,record.StartTime,record.EndTime,1);
#endif

		rpc.ServerNotify(bcEvent,record.EventId,bcSubscribe,theApp.user.UserId);

		Vector<int> CanViewIds1;
		if(record.GroupId!=NullGroupId){
			// permit the group members to view
			db.GetGroupMembers(record.GroupId,CanViewIds1);
		}

		Vector<int> CanViewIds2;
		if(record.Private){
			
			// parse users and permit them to view
			std::wstring members = CanViews.Data();
			std::wstring member;
			int i,j = 0,len = members.length()+1;
			TCHAR * buffer = new TCHAR[len];
			_tcscpy(buffer,CanViews.Data());
			
			int n = 0;

			// first count
			for(i=0;i<len;i++){
				if(buffer[i]==L' ' || buffer[i]==L',' || buffer[i]==L'\0'){
					buffer[i] = L'\0';
					member = &(buffer[j]);
					j = i+1;

					if(member!=L""){
						print(L"Permitting %s to view the %s event.\n",member.data(),(TCHAR*)record.EventName);
						n++;
					} else {
						print(L"No such user: %s\n",member.data());
					}
				}
			}
			CanViewIds2.allocate(n);
			n = 0; j = 0;
			for(i=0;i<len;i++){
				if(buffer[i]==L' ' || buffer[i]==L',' || buffer[i]==L'\0'){
					buffer[i] = L'\0';
					member = &(buffer[j]);
					j = i+1;

					if(member!=L""){
						print(L"Permitting %s to view the %s event.\n",member.data(),(TCHAR*)record.EventName);
						db.GetUserId(member.data(),CanViewIds2[n]);
						n++;
					} else {
						print(L"No such user: %s\n",member.data());
					}
				}
			}
		}

		// concatenate the two lists of users into one
		int i;
		Vector<int> CanViewIds;
		CanViewIds.allocate(CanViewIds1.length+CanViewIds2.length);
		for(i=0;i<CanViewIds1.length;i++) CanViewIds[i] = CanViewIds1[i];
		for(i=0;i<CanViewIds2.length;i++) CanViewIds[i+CanViewIds1.length] = CanViewIds2[i];


		// remove permissions from the old users that are not on the list anymore
		Vector<int> OldCanViewIds;
		db.GetEventCanViews(record.EventId,OldCanViewIds);
		for(i=0;i<OldCanViewIds.length;i++){
			if(CanViewIds.find(OldCanViewIds[i])==-1){
				db.DeleteEventPermission(OldCanViewIds[i],record.EventId);
				rpc.ServerNotify(bcEvent,record.EventId,bcPermission,OldCanViewIds[i]);
			}
		}

		// now permit the new users to view this event
		for(i=0;i<CanViewIds.length;i++){
			if(CanViewIds[i]!=NullUserId){
				if(OldCanViewIds.find(CanViewIds[i])==-1){
					db.SetEventPermission(CanViewIds[i],record.EventId,0,1);
					// don't need to notify them because they will receive the bcModified notification
				}
			} 
		}

		// Update the event list
		theApp.eventlist.DeepRefresh();
		theApp.eventlist.DeepRefreshEdit();

		// hide the window since we are done with it
		Hide();
		rpc.ServerNotify(bcEvent,record.EventId,bcModified,theApp.user.UserId);

		STATUS("DefaultStatus");

		rpc.EndTransaction();

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

		rpc.BeginTransaction();
		// remove the event
		db.DeleteEvent(record.EventId);
		rpc.ServerNotify(bcEvent,record.EventId,bcRemove,theApp.user.UserId);
		// Update the event list
		ListItem * item = theApp.eventlist.list.GetItemByKey(record.EventId);
		if(item){
			Event * event = (Event *)item->userdata;
			theApp.eventlist.Delete(event);
		}
		item = theApp.eventlist.editinglist.GetItemByKey(record.EventId);
		if(item){
			Event * event = (Event *)item->userdata;
			theApp.eventlist.EditDelete(event);
		}
	
		Hide();
		STATUS("DefaultStatus");
		rpc.EndTransaction();
	} else if(h==cancel.hWnd){
		Hide();
		STATUS("DefaultStatus");
	} 
#ifdef ENABLEEVENTTRACKTIME
	else if(h==TrackingEternal.hWnd){
		if(TrackingEternal.checked){
			TrackingStartTime.Hide();
			TrackingStartDate.Hide();
			TrackingEndTime.Hide();
			TrackingEndDate.Hide();
		} else {
			TrackingStartTime.Show();
			TrackingStartDate.Show();
			TrackingEndTime.Show();
			TrackingEndDate.Show();
		}
	} 
#endif
	else if(h==Eternal.hWnd){
		if(Eternal.checked){
			StartTime.Hide();
			StartDate.Hide();
			EndTime.Hide();
			EndDate.Hide();
		} else {
			StartTime.Show();
			StartDate.Show();
			EndTime.Show();
			EndDate.Show();
		}
	}
}

void EditEventWindow::OnCustomNotify(int id, Notification& n)
{
	if(!hidden && record.EventId!=NullEventId && id==bcEvent && n.param[0]==record.EventId){
		DeepRefresh(record.EventId);
	}
}

void EditEventWindow::OnNotify(int idCtrl, NMHDR * pnmh)
{
	FORWARD_WM_NOTIFY(StartDate.hWnd,idCtrl,pnmh,SendMessage);
	FORWARD_WM_NOTIFY(EndDate.hWnd,idCtrl,pnmh,SendMessage);
#ifdef ENABLEEVENTTRACKTIME
	FORWARD_WM_NOTIFY(TrackingStartDate.hWnd,idCtrl,pnmh,SendMessage);
	FORWARD_WM_NOTIFY(TrackingEndDate.hWnd,idCtrl,pnmh,SendMessage);
#endif
}
