#include "StdAfx.h"
#include "locationlist.h"

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

LocationList::~LocationList(void)
{
}

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

	// load the item appearances for the active location list
	Active.Load("locationwindow::styles::active");
	Nobody.Load("locationwindow::styles::nobody");
	Eventful.Load("locationwindow::styles::event");
	Unknown.Load("locationwindow::styles::unknown");
	UserOccupied.Load("locationwindow::styles::UserOccupied");
	// load the item appearnaces for the editing list
	Checked.Load("locationwindow::editstyles::checked");
	Unchecked.Load("locationwindow::editstyles::unchecked");

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

	EmptyStyle.Load("locationwindow::styles::empty");
	EditEmptyStyle.Load("locationwindow::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(bcLocation);
	AddCustomNotification(bcUser);

	return 1;
}

void LocationList::UpdateActiveCount()
{
	nActiveLocations = 0;
	std::list<ListItem*>::iterator i;
	for(i=list.items.begin();i!=list.items.end();i++){
		ListItem * item = *i;
		Location * location = (Location*)item->userdata;
		if(location->IsActive())
			nActiveLocations++;
	}

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

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

	Vector<int> locationIds;
#ifdef SUPERUSER
	db.GetAllLocations(locationIds);
#else
	db.GetSubscribedLocations(theApp.user.UserId,locationIds);
#endif

	{
		int i;

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

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

	UpdateActiveCount();
}

void LocationList::Add(Location * location)
{
	ListItem * item = list.CreateItem(location->record.LocationName,location->record.LocationId);
	location->item = item;
	location->editing = 0;
	location->ShallowRefresh();
	item->userdata = location;
	item->usertype = bcLocation;
	list.AddItem(item);
}

void LocationList::Delete(Location * location)
{
	list.DeleteItem(location->item);
	delete location;
}

void LocationList::EditAdd(Location * location)
{
	ListItem * item = editinglist.CreateItem(location->record.LocationName,location->record.LocationId);
	location->item = item;
	location->editing = 1;
	location->ShallowRefresh();
	item->userdata = location;
	item->usertype = bcLocation;
	editinglist.AddItem(item);
}

void LocationList::EditDelete(Location * location)
{
	editinglist.DeleteItem(location->item);
	delete location;
}


void LocationList::OnListSelect(HWND h, HWND hItem)
{
	ListItem * item = (ListItem*)GetWindowLongPtr(hItem,GWL_USERDATA);
	if(list.hWnd==h){
		// open up the map window and center the map on this location
		Location * location = (Location*)item->userdata;
		if(location){
			theApp.mapwindow.Show();
			BringWindowToTop(theApp.mapwindow.hWnd);
			theApp.mapwindow.ShowLocation(location->record.LocationId);
			theApp.mapwindow.GlideToLocation(location->record.LocationId);
		}
	} else if(editinglist.hWnd==h){
#ifdef SUPERUSER

#else
		Location * location = (Location *)item->userdata;
		if(location){
			if(location->checked){
				db.UnsubscribeFromLocation(theApp.user.UserId,location->record.LocationId);
				location->checked = 0;
			} else {
				db.SubscribeToLocation(theApp.user.UserId,location->record.LocationId);
				location->checked = 1;
			}
			location->ShallowRefresh();
			DeepRefresh();
		}
#endif
	}
}

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

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

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

void LocationList::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 LocationList::ClearList()
{
	lipos i;
	for(i=list.items.begin();i!=list.items.end();i++){
		ListItem * item = *i;
		Location * location = (Location*)item->userdata;
		delete location;
	}
	list.DeleteAllItems();
}

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

	Vector<int> subscribed;
	db.GetSubscribedLocations(theApp.user.UserId,subscribed);
	Vector<int> locationIds;
	db.GetVisibleLocations(locationIds);
	int i;
	// first remove locations that are no longer subscribed to
	Vector<int> current;
	editinglist.GetKeys(current);
	for(i=0;i<current.length;i++){
		if(locationIds.find(current[i])==-1){ // not subscribable to anymore, remove it
			ListItem * item = editinglist.GetItemByKey(current[i]);
			if(item){
				Location * location = (Location *)item->userdata;
				EditDelete(location);
			}
		}
	}

	for(i=0;i<locationIds.length;i++){
		ListItem * item = editinglist.GetItemByKey(locationIds[i]);
		if(item){ // already in the list
			Location * location = (Location *)item->userdata;
			// determine if this location is in the subscribed location list (w/o a db lookup)
			if(subscribed.find(locationIds[i])==-1)
				location->checked = 0;
			else
				location->checked = 1;
			location->DeepRefresh(locationIds[i]);
		} else { // not in the list yet, so add it
			Location * location = new Location();
			location->haspopup = 0;
			// determine if this location is in the subscribed location list (w/o a db lookup)
			if(subscribed.find(locationIds[i])==-1)
				location->checked = 0;
			else
				location->checked = 1;
			location->DeepRefresh(locationIds[i]);
			EditAdd(location);
		}
	}

	UpdateActiveCount();
}

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

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

	if(hList==editinglist.hWnd && item){
		Location * location = (Location *)item->userdata;
		if(location){
			db.UnsubscribeFromLocation(theApp.user.UserId,location->record.LocationId);
			location->checked = 0;
			DeepRefresh();
		}
	}
}

void LocationList::OnCustomNotify(int id, Notification& n)
{
	ListItem * item;
	Location * location;

	switch(id){
	case bcLocation:

		switch(n.reason){
		case bcAdd:
			DeepRefresh();
			DeepRefreshEdit();
			break;
		default:
			item = list.GetItemByKey(n.param[0]);
			if(item){
				location = (Location*)item->userdata;
				if(location){
					// this notification applies to a location in the list
					switch(n.reason){
					case bcRemove:
						DeepRefresh();
						DeepRefreshEdit();
						break;
					default: // the location will handle the rest
						location->OnCustomNotify(id,n);
						UpdateActiveCount();
					}
		
				}
			}
			break;
		}

		break;
	case bcUser: // all of these will be taken care of by MapLocation
		switch(n.reason){
		case bcMove:
		case bcLogOff:
		case bcLogOn:
			UpdateActiveCount();
			break;
		}
		break;
	}
}

void LocationList::ShallowRefreshItem(int locationId)
{
	ListItem * item = list.GetItemByKey(locationId);
	if(item){
		Location * location = (Location*)item->userdata;
		if(location){
			location->ShallowRefresh();
			UpdateActiveCount();
		}
	}

}