// DormantNodeView.cpp
// e.moon 2jun99

#include "DormantNodeView.h"
#include "DormantNodeListItem.h"
#include "DormantNodeStatusView.h"

#include <MediaAddOn.h>
#include <MediaRoster.h>
#include <ListView.h>
#include <ListItem.h>
#include <ScrollBar.h>
#include <Font.h>

#include "array_delete.h"
#include "debug_tools.h"

// -------------------------------------------------------- //

//__BEGIN_CORTEX_NAMESPACE
//class _DormantNodeBackdropView :
//	public	BView {
//public:
//	_DormantNodeBackdropView(
//		BRect											frame) :
//		BView(frame, 0, B_FOLLOW_ALL_SIDES, B_WILL_DRAW|B_FRAME_EVENTS) {
//
//		SetViewColor(B_TRANSPARENT_COLOR);
//	}
//
//	void Draw(BRect							updateRect) {
//		PRINT(("### Draw(): %.1f x %.1f\n", Bounds().Width(), Bounds().Height()));
//		DormantNodeListItem::DrawBackground(this, Bounds());
//	}
//};
//__END_CORTEX_NAMESPACE

// -------------------------------------------------------- //

__USE_CORTEX_NAMESPACE

// -------------------------------------------------------- //
// ctor/dtor
// -------------------------------------------------------- //

DormantNodeView::~DormantNodeView() {
	clearListView();
}

DormantNodeView::DormantNodeView(
	BRect frame, const char* pName,
	uint32 resizeMode) :
	
	BView(frame, pName, resizeMode,
		B_WILL_DRAW|B_FRAME_EVENTS|B_NAVIGABLE),
	m_pListView(0),
	m_pStatusView(0),
	m_pRoster(BMediaRoster::Roster()) {

	initViews();
	scanDormantNodes();
}
		
// -------------------------------------------------------- //
// internal operations
// -------------------------------------------------------- //

// initialize all child views
void DormantNodeView::initViews() {
	BRect b = Bounds();
	b.top--;
	b.right -= B_V_SCROLL_BAR_WIDTH;
	b.bottom -= B_H_SCROLL_BAR_HEIGHT;

	m_pListView = new DormantNodeListView(
		b,
		"listView",
		B_FOLLOW_ALL_SIDES);
	
	AddChild(m_pListView);
	
	BRect scrollR = b;
	scrollR.left = scrollR.right + 1;
	scrollR.right = scrollR.left + B_V_SCROLL_BAR_WIDTH;
	BScrollBar* pScroll = new BScrollBar(
		scrollR,
		"vScroll",
		m_pListView,
		0.0, 0.0,
		B_VERTICAL);
	AddChild(pScroll);

	BRect statusR = b;
	statusR.top = statusR.bottom+1;
	statusR.bottom = statusR.top + B_H_SCROLL_BAR_HEIGHT;
	m_pStatusView = new DormantNodeStatusView(
		statusR, B_FOLLOW_LEFT_RIGHT|B_FOLLOW_BOTTOM);
	AddChild(m_pStatusView);

	// set font
	BFont font;
	m_pListView->GetFont(&font);
	font.SetSize(font.Size()+1);
	m_pListView->SetFont(&font);
	
	SetViewColor(B_TRANSPARENT_COLOR);
}

// fetch all nodes & build list view
void DormantNodeView::scanDormantNodes() {
	if(m_pListView->CountItems())
		clearListView();
	
	// init the resizable node-info buffer
	const uint32 bufferInc = 64;
	uint32 bufferSize = bufferInc;
	dormant_node_info* pInfoBuffer = new dormant_node_info[bufferSize];
	array_delete<dormant_node_info> _d(pInfoBuffer);
	
	// fill the buffer
	int32 numNodes;
	while(true) {
		numNodes = bufferSize;
		status_t err = roster()->GetDormantNodes(
			pInfoBuffer, &numNodes);
		if(err != B_OK) {
			PRINT((
				"DormantNodeView::scanDormantNodes():\n%s\n",
				strerror(err)));
			return;
		}
		
		if(numNodes < bufferSize) 
			break;
			
		// reallocate buffer & try again
		delete [] pInfoBuffer;
		bufferSize += bufferInc;
		pInfoBuffer = new dormant_node_info[bufferSize];
	}
	
	// populate the list
	for(int32 n = 0; n < numNodes; n++) {
		DormantNodeListItem* pItem = new
			DormantNodeListItem(pInfoBuffer[n]);
		//BStringItem* pItem = new BStringItem(pInfoBuffer[n].name);
		m_pListView->AddItem(pItem);
	}
}

// remove and deallocate each item in the list view
void DormantNodeView::clearListView() {	
	for(int32 last = m_pListView->CountItems()-1;
		last >= 0; last--) {
		BListItem* pItem = m_pListView->RemoveItem(last);
		delete pItem;
	}
}

// -------------------------------------------------------- //
// BHandler impl
// -------------------------------------------------------- //

void DormantNodeView::MessageReceived(BMessage* pMsg) {
	switch(pMsg->what) {
		default:
			_inherited::MessageReceived(pMsg);
	}
}

// -------------------------------------------------------- //
// BView impl
// -------------------------------------------------------- //
/*
void DormantNodeView::FrameResized(float width, float height) {
	BRect b = Bounds();
	float oldWidth = b.Width();
	float oldHeight = b.Height();
	_inherited::FrameResized(width, height);
	
	//updateScrollBar();
	if(width > oldWidth)
		Invalidate(BRect(oldWidth, b.top, width, b.bottom));
	if(height > oldHeight)
		Invalidate(BRect(b.left, oldHeight, b.right, height));
}
*/


// -------------------------------------------------------- //


// -------------------------------------------------------- //
// DormantNodeListView
// -------------------------------------------------------- //

DormantNodeListView::~DormantNodeListView() {}
DormantNodeListView::DormantNodeListView(
	BRect frame, const char* pName, uint32 resizeMode) :

	BListView(frame, pName, B_SINGLE_SELECTION_LIST, resizeMode),
	m_dragActive(false),
	m_dragInProgress(false) {}

void DormantNodeListView::Draw(BRect updateRect) {

	// draw items
	_inherited::Draw(updateRect);

	// draw background
	BRect bgRect = Bounds();
	if(CountItems()) {
		bgRect.top = ItemFrame(CountItems()-1).bottom + 1;
	}
	
	if(updateRect.Intersects(bgRect))
		DormantNodeListItem::DrawBackground(this, bgRect);
}

void DormantNodeListView::MouseDown(BPoint point) {
	// select
	Select(IndexOf(point));

	uint32 buttons;
	GetMouse(&point, &buttons, true);
	if(buttons & B_PRIMARY_MOUSE_BUTTON)
		m_dragActive = true;
	
	// 
	//_inherited::MouseDown(point);
}

void DormantNodeListView::MouseMoved(
	BPoint point,
	uint32 transit,
	const BMessage* pDragMsg) {
	
//	_inherited::MouseMoved(point, transit, pDragMsg);

	if(!m_dragActive || m_dragInProgress)
		return;

	uint32 index = IndexOf(point);
	DormantNodeListItem* pItem =
		dynamic_cast<DormantNodeListItem*>(ItemAt(index));
	if(!pItem || !pItem->IsSelected())
		return;
		
	// start dragging
	m_dragInProgress = true;

	BMessage dragMsg(DormantNodeView::M_INSTANTIATE_NODE);
	dragMsg.AddData(
		"dormantNodeInfo",
		B_RAW_TYPE,
		(const void*)&pItem->info(),
		sizeof(pItem->info()));
	DragMessage(&dragMsg, ItemFrame(index));
	
	SetMouseEventMask(
		B_POINTER_EVENTS,
		B_LOCK_WINDOW_FOCUS);
}

void DormantNodeListView::MouseUp(BPoint point) {
//	_inherited::MouseUp(point);

	// mark mouse as released (no longer drag-capable)
	uint32 buttons;
	GetMouse(&point, &buttons, true);
	if(!(buttons & B_PRIMARY_MOUSE_BUTTON)) {
		m_dragActive = false;	
		m_dragInProgress = false;
	}
}

// END -- DormantNodeView.cpp --
