// ------------------------------------------------------------------------
/*
	author: Marcos Boyington
   
	Copyright (C) Electronic Arts LA 2004.  All rights reserved.	
*/
// ------------------------------------------------------------------------

/*! \file */

#ifndef REVEAL_TEXT_WINDOW_H
#define REVEAL_TEXT_WINDOW_H

#include <stddef.h>
#include "reveal/callback/callback_1.h"
#include "reveal/impl/window.h"
#include "reveal/impl/gui_metrics.h"
#include "reveal/type_traits/type_traits.h"
#include "reveal/impl/util.h"

namespace Reveal {

	namespace Impl {
// ------------------------------------------------------------------------------
/*!
	\brief Prevents TextWindow from being inlined all over the place
	
	If using a text window, be sure to set GuiMetrics::TEXT_HEIGHT and GuiMetrics::CHAR_WIDTH appropriately
*/
// ------------------------------------------------------------------------------
class TextWindowBase : public Impl::Window
{
public:
	enum { LINE_LEN = 64 };

	void Clear ();

protected:
	TextWindowBase( const char* name, Impl::Tree& tree, size_t numLines );

	void CalcMaxDisplayable ();

	void AddLine( const char* line, char buffer[][LINE_LEN] );

	//Override of Window::DoRender
    virtual void DoRender( const Renderer& renderer, const GuiColors& guiColors ) const {};

	//Local function called by template class that actually does the rendering
	void DoRender( const Renderer& renderer, const GuiColors& guiColors, char buffer[][LINE_LEN] ) const;

	virtual Impl::Widget* DoHandle( const InputState& inputState );

	void ClampDisplayStart (int adjust = 0) const;

	TextWindowBase( const TextWindowBase& ); // Not implemented, non-copyable;
	TextWindowBase& operator = ( const TextWindowBase& ); // Not implemented, non-assignable;

	virtual size_t  DoToString( const char* path, char* buffer, size_t size ) const;

	// Attributes;
	//DisplayStart can be adjusted on render
	mutable size_t mDisplayStart;

	size_t mBufferPos, mMaxNumLines, mMaxNumChars, mNumLines;
	bool mbCircled;
};

	} //End Impl namespace
// ------------------------------------------------------------------------------
/*!
	\brief Allows for a simple window which has multiple lines of [scrollable] text
	
	If using a text window, be sure to set GuiMetrics::TEXT_HEIGHT and GuiMetrics::CHAR_WIDTH appropriately
*/
// ------------------------------------------------------------------------------
template < size_t NUM_LINES = 32 >
class TextWindow : public Impl::TextWindowBase
{
	public:
	typedef Callback::Callback1< void, TextWindow<NUM_LINES>& > RefreshCallback;

	TextWindow( const char* name, Impl::Tree& tree, const RefreshCallback& refreshCallback = RefreshCallback() )
		: Impl::TextWindowBase( name, tree, NUM_LINES )
		, mRefreshCallback(refreshCallback)
	{
		for ( size_t i = 0; i < NUM_LINES; i++ ) mBuffer[ i ][ 0 ] = '\0';
	}

	void AddLine( const char* line )
	{	TextWindowBase::AddLine(line, mBuffer);		}

private:

	virtual void DoRender( const Renderer& renderer, const GuiColors& guiColors ) const
	{	TextWindowBase::DoRender( renderer, guiColors, mBuffer );	}

	virtual Impl::Widget* DoHandle (const InputState &inputState)
	{
		if ( mRefreshCallback.Valid() )
		{
			mRefreshCallback(*this);
		}

		return TextWindowBase::DoHandle( inputState );
	}

	TextWindow( const TextWindow& ); // Not implemented, non-copyable;
	TextWindow& operator = ( const TextWindow& ); // Not implemented, non-assignable;

	// Attributes;

	//We temporarily change the buffer, but undo the change (thus mutable)
	mutable char  mBuffer[NUM_LINES][LINE_LEN];

	RefreshCallback mRefreshCallback;
};

} // Namespace Reveal;

#endif
