#include "NTWidget.h"
#include "NTScreen.h"
#include <typeinfo>


namespace NTCurses {

// public methods
NTWidget::NTWidget() {
	InitWidget();
}

NTWidget::NTWidget( NTWidget *parent ) {
	InitWidget();
	oParent = parent;
	oParent->AddChildWidget( this );
}

NTWidget::NTWidget( NT::NTString id ) {
	InitWidget();
	SetId( id );
}

NTWidget::NTWidget( NT::NTString id , NTWidget *parent ) {
	InitWidget();
	oParent = parent;
	oParent->AddChildWidget( this );
	SetId( id );
}


void NTWidget::InitWidget( void ) {
	bActive = false;
	bEnabled = true;
	bValid = true;
	bDirty = true;
	bLostFocusSubmit = false;

	oParent = NULL;
	oCurses = NULL;
	oChilds.clear();
	SetDirty( true );
	uX = 0;
	uY = 0;
	uWidth = 0;
	uHeight = 0;

	// debug stuff	
	sId = NT::format_string( "unknown <%08llx>" , this );
	bDebug = false;
}

NTWidget::~NTWidget() {
	while (oChilds.size()) delete oChilds.at(0);
	if (oParent) oParent->DelChildWidget( this );
}

bool NTWidget::IsCreated( void ) {
	return oCurses;
}

void NTWidget::Create( void ) {
	if (IsCreated()) return;	// already created

	if (oParent) {
		oCurses=oParent->GetCurses();
	} else {
		oCurses=new NTCurses( uX , uY , uWidth , uHeight , true );
	}
}

void NTWidget::Destroy( void ) {
	if (!IsCreated()) return;	// already destroyed

	if (oParent) {
		oCurses = NULL;
	} else {
		delete oCurses;
		oCurses = NULL;
	}
}

void NTWidget::Init( void ) {
	Create();
}

void NTWidget::InitChildWidgets( void ) {
	unsigned int len = GetNumberOfChildWidgets();
	unsigned int i;
	for (i=0;i<len;i++)
		oChilds.at(i)->Init();
}

void NTWidget::Deinit( void ) {
	Destroy();
}

void NTWidget::DeinitChildWidgets( void ) {
	unsigned int len = GetNumberOfChildWidgets();
	unsigned int i;
	for (i=0;i<len;i++)
		oChilds.at(i)->Deinit();
}

void NTWidget::Draw( void ) {

}

void NTWidget::DrawChildWidgets( void ) {
	unsigned int len = GetNumberOfChildWidgets();
	unsigned int i;
	std::vector<NTWidget *>actives;
	for (i=0;i<len;i++) {
		if (oChilds.at(i)->GetActive()) {
			actives.push_back( oChilds.at(i) );
		} else {
			oChilds.at(i)->Draw();
		}
	}
	len = actives.size();
	for (i=0;i<len;i++) actives.at(i)->Draw();
}

void NTWidget::HandleKeyEvent( int keycode) {
	// fictious
	switch (keycode) {
	case 9:
	case 10:
		if (!oParent) break;
		oParent->PushEvent( NTNextNodeControlEvent() );
		SetDirty( true );
		break;
	case KEY_BTAB:
		if (!oParent) break;
		oParent->PushEvent( NTPrevNodeControlEvent() );
		SetDirty( true );
		break;
	}
}

void NTWidget::HandleMouseEvent( int mx , int my , int mz , unsigned int bstate ) {
	// fprintf( stderr , "x:%5d y:%5d z:%5d b:%5d\n" , mx , my , mz , bstate );
}

void NTWidget::HandleGotFocusEvent( void ) {
	SetActive( true );
}

void NTWidget::HandleLostFocusEvent( void ) {
	SetActive( false );
}

bool NTWidget::BeforeLostFocus( void ) {
	return true;
}

void NTWidget::HandleEvent( NTEvent evt ) {
	switch (evt.event_type) {
	case NT_EVENT_KEYPRESS:
		HandleKeyEvent( evt.event_data.keycode );
		break;
	case NT_EVENT_MOUSE:
		HandleMouseEvent(
			evt.event_data.mouse_state.x,
			evt.event_data.mouse_state.y,
			evt.event_data.mouse_state.z,
			evt.event_data.mouse_state.buttonstate );
		break;
	default:
		break;
	}
}

void NTWidget::HandleEvents( void ) {
	while (HasEvent()) {
		NTEvent evt = PopEvent();
		HandleEvent( evt );
	}
}

void NTWidget::HandleChildEvents( void ) {
	unsigned int i,len;
	len = GetNumberOfChildWidgets();
	for (i=0;i<len;i++) {
		if (i>=GetNumberOfChildWidgets()) break;	// if somebody deletes a control from event loop
		oChilds.at(i)->HandleEvents();
	}
}

void NTWidget::EventLoop( void ) {
	HandleEvents();
}

void NTWidget::SetStringValue( NT::NTString val ) {}
NT::NTString NTWidget::GetStringValue( void ) { return ""; }
void NTWidget::SetStringParams( NT::NTString val ) {}
NT::NTString NTWidget::GetStringParams( void ) { return ""; }

void NTWidget::AddChildWidget( NTWidget *child ) {
	oChilds.push_back( child );
	SetDirty( true );
}

void NTWidget::DelChildWidget( unsigned int numofwidget ) {
	oChilds.erase( oChilds.begin() + numofwidget );
	SetDirty( true );
}

void NTWidget::SetAllChildDirty( void ) {
	unsigned int len = GetNumberOfChildWidgets();
	unsigned int i;
	for (i=0;i<len;i++)
		oChilds.at(i)->SetDirty( true );
}

void NTWidget::DelChildWidget( NTWidget *child ) {
	unsigned int numofelements = oChilds.size();
	for (unsigned int i=0;i<numofelements;i++) {
		if (oChilds[i]==child) {
			DelChildWidget( i );
			return;
		}
	}
}

unsigned int NTWidget::GetNumberOfChildWidgets( void ) {
	return oChilds.size();
}

NTWidget *NTWidget::GetParentWidget( void ) {
	return oParent;
}

int NTWidget::GetChildWidgetNumber( NTWidget *child ) {
	unsigned int numofwidgets = GetNumberOfChildWidgets();
	if (!numofwidgets) return -1;

	unsigned int i;
	for (i=0;i<numofwidgets;i++) if (oChilds.at(i)==child) return i;
	return -1;
}

NTWidget *NTWidget::GetChildWidgetFromNumber( int widgetnum ) {
	unsigned int numofwidgets = GetNumberOfChildWidgets();
	if (!numofwidgets) return NULL;
	if (widgetnum<0) return NULL;
	if ((unsigned int)widgetnum>=numofwidgets) return NULL;
	return oChilds.at(widgetnum);
}

int NTWidget::GetActiveChildWidgetNumber( void ) {
	unsigned int numofwidgets = GetNumberOfChildWidgets();
	if (!numofwidgets) return -1;

	unsigned int i;
	for (i=0;i<numofwidgets;i++) if (oChilds.at(i)->GetActive()) return i;
	return -1;
}

/*

// ezt kesobb felul kell vizsgalni, mivan akkor most handle got focussal es a barataival? :)
void NTWidget::SetActiveChild( NTWidget *child ) {
	int newpos = GetChildWidgetNumber( child );
	if (newpos<0) return;

	int actpos = GetActiveChildWidgetNumber();
	if (actpos>=0) {
		if (oChilds.at(actpos)==child) return;	// the same active
		oChilds.at(actpos)->HandleLostFocusEvent();
	}
	oChilds.at(newpos)->HandleGotFocusEvent();
}
*/

int NTWidget::GetNextEnabledChildWidgetNumber( int widgetnum ) {
	unsigned int len = GetNumberOfChildWidgets();
	widgetnum=(widgetnum+1)%len;
	while (!oChilds.at(widgetnum)->GetEnabled()) widgetnum=(widgetnum+1)%len;
	return widgetnum;
}

int NTWidget::GetPrevEnabledChildWidgetNumber( int widgetnum ) {
	unsigned int len = GetNumberOfChildWidgets();
	widgetnum=(widgetnum+len-1)%len;
	while (!oChilds.at(widgetnum)->GetEnabled()) widgetnum=(widgetnum+len-1)%len;
	return widgetnum;
}

unsigned int NTWidget::GetRelativeX() {
	if (!oParent) return 0;
	return uX + oParent->GetRelativeX();
}

unsigned int NTWidget::GetRelativeY() {
	if (!oParent) return 0;
	return uY + oParent->GetRelativeY();
}

void NTWidget::PushEvent( NTEvent evt ) {
	oEvents.push( evt );
}

void NTWidget::PushActiveChildEvent( NTEvent evt ){
	int i = GetActiveChildWidgetNumber();	
	if (i>=0) oChilds.at(i)->PushEvent( evt );
}

bool NTWidget::HasEvent( void ) {
	return !oEvents.empty();
}

NTEvent NTWidget::PopEvent( void ) {
	NTEvent retval;
	retval = oEvents.front();
	oEvents.pop();
	return retval;
}

NTCurses* NTWidget::GetCurses( void ) { return oCurses; }

void NTWidget::SetDirty( bool val ) {
	if (val==bDirty) return;
	bDirty = val;
	if (bDirty) NTGetGlobalScreen()->SetDirty();
}
bool NTWidget::GetDirty( void ) { return bDirty; }

void NTWidget::SetValid( bool val ) {
	if (val==bValid) return;
	bValid=val;
	SetDirty( true );
}

bool NTWidget::GetValid( void ) { return bValid; }

void NTWidget::SetActive( bool val ) {
	if (val==bActive) return;
	bActive=val;
	SetDirty( true );
}

void NTWidget::SetLostFocusSubmit( bool val ) {
	if (val==bLostFocusSubmit) return;
	bLostFocusSubmit=val;
	SetDirty( true );
}

bool NTWidget::GetLostFocusSubmit( void ) {
	return bLostFocusSubmit;
}

void NTWidget::SetActiveChildFromNumber( unsigned int num ) {
	if (oChilds.size()>=num) return;
	SetActiveChild( oChilds.at( num ) );
}

void NTWidget::SetActiveChild( NTWidget *child ) {
	unsigned int len = oChilds.size();
	unsigned int i;
	NTWidget *active = NULL;
	for (i=0;i<len;i++) {
		NTWidget *item = oChilds.at(i);
		if (child==item) {
			active = item;
		} else {
			item->SetActive( false );
		}
	}
	if (active) active->SetActive( true );
}

NTWidget *NTWidget::GetActiveChild( void ) {
	unsigned int len = oChilds.size();
	unsigned int i;
	for (i=0;i<len;i++) {
		NTWidget *item = oChilds.at(i);
		if (item->GetActive()) return item;
	}
	return NULL;
}

bool NTWidget::GetActive( void ) { return bActive; }

void NTWidget::SetEnabled( bool val ) {
	if (val==bEnabled) return;
	bEnabled=val;
	if (!bEnabled) bActive = false;
	SetDirty( true );
}

bool NTWidget::GetEnabled( void ) {
	return bEnabled;
}

void NTWidget::SetX( unsigned int val ) {
	if (val==uX) return;
	uX=val;
	if (IsCreated()) {
		Destroy();
		Create();
	}
	SetDirty( true );
}
unsigned int NTWidget::GetX( void ) { return uX; }

void NTWidget::SetY( unsigned int val ) {
	if (val==uY) return;
	uY=val;
	if (IsCreated()) {
		Destroy();
		Create();
	}
	SetDirty( true );
}
unsigned int NTWidget::GetY( void ) { return uY; }

void NTWidget::SetPos( unsigned int x , unsigned int y ) {
	if (x==uX && y==uY) return;
	uX = x;
	uY = y;
	if (IsCreated()) {
		Destroy();
		Create();
	}
	SetDirty( true );
}

void NTWidget::SetWidth( unsigned int val ) {
	if (val==uWidth) return;
	uWidth=val;
	if (IsCreated()) {
		Destroy();
		Create();
	}
	SetDirty( true );
}
unsigned int NTWidget::GetWidth( void ) { return uWidth; }

void NTWidget::SetHeight( unsigned int val ) {
	if (val==uHeight) return;
	uHeight=val;
	if (IsCreated()) {
		Destroy();
		Create();
	}
	SetDirty( true );
}
unsigned int NTWidget::GetHeight( void ) { return uHeight; }

void NTWidget::SetSize( unsigned int w , unsigned int h ) {
	if (w==uWidth && h==uHeight) return;
	uWidth = w;
	uHeight = h;
	if (IsCreated()) {
		Destroy();
		Create();
	}
	SetDirty( true );

}

void NTWidget::SetDebug( bool val ) {
	bDebug = val;
}

void NTWidget::SetId( NT::NTString val ) {
	sId = val;
}

}
