/////////////////////////////////////////////////////////////////////////////
// Name:        No names yet.
// Purpose:     Contrib. demo
// Author:      Aleksandras Gluchovas
// Modified by:
// Created:     3/01/99
// RCS-ID:      $Id: XLayoutUtility.cpp,v 1.3 2001/01/29 13:21:00 georgetasker Exp $
// Copyright:   (c) No Magic, Inc.
// Licence:   	wxWindows license
/////////////////////////////////////////////////////////////////////////////
 
#ifdef __GNUG__
#pragma implementation "objstore.h"
// #pragma interface
#endif

// For compilers that support precompilation, includes "wx.h".
#include "wx/wxprec.h"

#ifdef __BORLANDC__
#pragma hdrstop
#endif

#ifndef WX_PRECOMP
#include "wx/wx.h"
#endif

#include "XLayoutUtility.h"

/***** Implementation for class XLayoutUtility *****/

XLayoutUtility::XLayoutUtility()

	: mpScene( NULL )
{}

void XLayoutUtility::SetScene( XCollection* pScene )
{
	mpScene = pScene;
}

void XLayoutUtility::AlignItems( int alignment )
{
	XObjListT items = mpScene->GetSelection();

	XRect focus = GetFocusedItem().GetBounds();

	StartBatch();

    size_t i;
	for( i = 0; i != items.Count(); ++i )
	{
		items[i]->NotifyWillChange();

		XRect r = items[i]->GetBounds();

		switch( alignment )
		{
			case wxTop    : { r.y = focus.y; break; }
			case wxBottom : { r.y = focus.y + focus.height - r.height; break; }
			case wxLeft   : { r.x = focus.x; break; }
			case wxRight  : { r.x = focus.x + focus.width - r.width; break; }
			default: break;
		}

		items[i]->SetBounds( r );

		items[i]->GetEditor().NotifyObjectChanged();
	}

	mpScene->GetEditor().NotifyObjectChanged();

	FinishBatch();

	mpScene->SetSelection( items );
}

void XLayoutUtility::MakeSameSize( bool width, bool height, bool both )
{
	XObjListT items = mpScene->GetSelection();

	XRect focus = GetFocusedItem().GetBounds();

	StartBatch();

    size_t i;
	for( i = 0; i != items.Count(); ++i )
	{
		items[i]->NotifyWillChange();

		XRect r = items[i]->GetBounds();

		if ( width || both )
		
			r.width = focus.width;

		if ( height || both )
		
			r.height = focus.height;

		items[i]->SetBounds( r );

		items[i]->GetEditor().NotifyObjectChanged();
	}

	mpScene->GetEditor().NotifyObjectChanged();

	FinishBatch();

	mpScene->SetSelection( items );
}

void XLayoutUtility::Center( bool vertically )
{
	XObjListT items = mpScene->GetSelection();

	StartBatch();

	XRect page;
	GetPageBounds( page );

    size_t i;
	for( i = 0; i != items.Count(); ++i )
	{
		items[i]->NotifyWillChange();

		XRect r = items[i]->GetBounds();

		if ( vertically == FALSE )
		
			r.x = page.x + ( page.width  - r.width )  / 2;
		else
			r.y = page.y + ( page.height - r.height ) / 2;

		items[i]->SetBounds( r );

		items[i]->GetEditor().NotifyObjectChanged();
	}

	mpScene->GetEditor().NotifyObjectChanged();

	FinishBatch();

	mpScene->SetSelection( items );
}

void XLayoutUtility::Flip( bool vertically )
{
	XRect page;
	GetPageBounds( page );

	XObjListT items = mpScene->GetSelection();

	StartBatch();

	int xc = page.x + page.width / 2;
	int yc = page.y + page.height / 2;

    size_t i;
	for( i = 0; i != items.Count(); ++i )
	{
		items[i]->NotifyWillChange();

		XRect r = items[i]->GetBounds();

		if ( vertically == TRUE )
		{
			if ( r.y < yc )
			
				r.y = yc + ( yc - r.y ) - r.height;
			else
				r.y = yc - ( r.y + r.height - yc );
		}
		else
		{
			if ( r.x < xc )
			
				r.x = xc + ( xc - r.x ) - r.width;
			else
				r.x = xc - ( r.x + r.width - xc );
		}

		items[i]->SetBounds( r );

		items[i]->GetEditor().NotifyObjectChanged();
	}

	mpScene->GetEditor().NotifyObjectChanged();

	FinishBatch();

	mpScene->SetSelection( items );
}

void XLayoutUtility::Arrange( bool right )
{
	XRect page;
	GetPageBounds( page );

	XObjListT items = mpScene->GetSelection();

	StartBatch();

	PosT space = 0;

	PosT gap    = 10;
	PosT margin = 20;

    size_t i;
	for( i = 0; i != items.Count(); ++i )
	{
		XRect r = items[i]->GetBounds();

		if ( right )
		
			space += r.height;
		else
			space += r.width;
	}
	
	PosT from = 0;

	PosT total = space + gap * ( items.Count() - 1 );

	if ( right )

		from = ( total <= page.height ) 
			   ? page.y + ( page.height - total ) /2
			   : page.y;
	else
		from = ( total <= page.width ) 
			   ? page.x + ( page.width - total ) /2
			   : page.x;

	for( i = 0; i != items.Count(); ++i )
	{
		items[i]->NotifyWillChange();

		XRect r = items[i]->GetBounds();

		if ( right )
		{
			if ( from + r.height > page.y + page.height )

				from = page.y + page.height - r.height;

			r.y = from;

			r.x = page.x + page.width  - r.width - margin;

			from += r.height + gap;
		}
		else
		{
			if ( from + r.width > page.x + page.width )

				from = page.x + page.width - r.width;

			r.x = from;

			from += r.width + gap;

			r.y = page.y + page.height - r.height - margin;
		}

		items[i]->SetBounds( r );

		items[i]->GetEditor().NotifyObjectChanged();
	}

	mpScene->GetEditor().NotifyObjectChanged();

	FinishBatch();

	mpScene->SetSelection( items );
}

void XLayoutUtility::SendItemsBack()
{
	XCollection& scene = GetScene();

	XObjListT lst = scene.GetSelection();

	StartBatch();

    size_t i;
	for( i = 0; i != lst.Count(); ++i )
	{	
		XObject* pObj = lst[i];

		scene.Detach( pObj );

		// FIXME:: older stuff...
		// insert after the dialog-frame view

		scene.GetContents().Insert( pObj, 2 );
	}

	FinishBatch();

	mpScene->SetSelection( lst );

	mpScene->RefreshNow();
}

void XLayoutUtility::SelectAllItems()
{
	XObjListT& sel = mpScene->GetSelection();

	if ( !sel.Count() ) 

		DoSelectAll( NULL );
	else
	{
		if ( sel[0]->GetSurroundingObject() == NULL )

			DoSelectAll( NULL );
		else
			DoSelectAll( sel[0]->GetSurroundingObject() );
	}

	/*
	XObjListT& lst = mpScene->GetContents();
	XObjListT sel;

    size_t i;
	for( i = 0; i != lst.Count(); ++i )
	{
		if ( strcmp( lst[i]->GetTypeName() , "XResourceView" ) == 0 )
		{
			XResourceView* pView = (XResourceView*)lst[i];

			if ( !pView->IsRootView() ) 

				sel.push_back( pView );
		}
	}

	mpScene->SetSelection( sel );

	if ( mpScene->HasEditor() ) mpScene->GetEditor().NotifyObjectChanged();
	*/
}

bool XLayoutUtility::CanLayout()
{
	return mpScene->HasSelection();
}

bool XLayoutUtility::CanAlign()
{
	return ( mpScene->HasMultipleSelection() );
}

XCollection& XLayoutUtility::GetScene()
{
	return *mpScene;
}

XObject& XLayoutUtility::GetFocusedItem()
{
	return *mpScene->GetFocus();
}

void XLayoutUtility::StartBatch()
{
	mpScene->StartBatch();
}

void XLayoutUtility::FinishBatch()
{
	mpScene->FinishBatch();
}

void XLayoutUtility::GetPageBounds( XRect& bounds )
{
	XObjListT& sel = mpScene->GetSelection();

	if ( !sel.Count() ) return;

	XObject* pSurObj = sel[0]->GetSurroundingObject();

	if ( !pSurObj ) return;

	bounds = pSurObj->GetLimitingBounds();
}

/*** protected methods ***/

void XLayoutUtility::DoSelectAll( XObject* pSurObj )
{
	XObjListT& lst = mpScene->GetContents();
	XObjListT sel;


	if ( pSurObj == NULL && HasNestedObjects() )
	
		pSurObj = GetRootObject();

    size_t i;
	for( i = 0; i != lst.Count(); ++i )
	{
		XObject* pObj = lst[i];

		if ( !mpScene->IsBackgroundObj( *pObj ) &&
			 pObj->GetSurroundingObject() == pSurObj )

			 sel.Add( pObj );
	}

	mpScene->SetSelection( sel, FALSE );

	mpScene->GetEditor().NotifyObjectChanged();

	if ( sel.Count() )

		mpScene->SetFocus( sel[0] );

	mpScene->RefreshNow();
}

bool XLayoutUtility::HasNestedObjects()
{
	XObjListT& lst = mpScene->GetContents();

    size_t i;
	for( i = 0; i != lst.Count(); ++i )
	
		if ( lst[i]->GetSurroundingObject() )

			return TRUE;

	return FALSE;
}

XObject* XLayoutUtility::GetRootObject()
{
	XObjListT& lst = mpScene->GetContents();

    size_t i;
	for( i = 0; i != lst.Count(); ++i )
	{
		XObject* pObj = lst[i];

		if ( !mpScene->IsBackgroundObj( *pObj ) &&
			 pObj->GetSurroundingObject() == NULL )

			 return pObj;
	}

//glt - There should be a return value here!!!
	return NULL;
}