#include	"StdAfx.h"

#include	"ScrollbarWidget.h"
#include	"SlotConnectable.h"
#include	"WebApp.h"
#include	"DC.h"

#include	"../Bfx.Abstract.Engine/Import.Begin.h"
#include		"../Bfx.Abstract.Model.PrintEngine/Utilities/ImageFileUtilities.h"
#include		"../Bfx.Abstract.Interpreter/IsInFunction.h"
#include	"../Bfx.Abstract.Engine/Import.End.h"

#include	<Wt/WApplication>
#include	<Wt/WPainter>

#include	<boost/assign/std/vector.hpp> 

using namespace std;
using namespace boost;
using namespace boost::assign;
using namespace BitFactory;
using namespace BitFactory::UI::Web;
using namespace BitFactory::UI::Architecture;

Pixel::Scalar BitFactory::UI::Web::Scrollbar()
{
	return Pixel::Scalar( 22 );
}

class ScrollbarWidget::Impl
	: public SlotConnectable
{
	Wt::JSlot myScrollJS;
	Wt::JSignal< int > myScrolled;
	int myScrolledOffset;
	String myOrientation;
	Wt::WContainerWidget* myC;
	ScrollbarWidget* mySelf;
public:
	Impl( const ScrollbarWidget* self )
		: mySelf( const_cast< ScrollbarWidget* >( self ) )
		, myScrolled( this, "scrolled" )
		, myScrolledOffset( 0 )
	{
		myScrolled.connect( SLOT( this, Impl::Scrolled ) );
	}
	void Init( const String& orientation, const std::vector< Wt::WWidget* >& toScroll )
	{
		myOrientation = orientation;
		mySelf->addWidget( myC = new Wt::WContainerWidget );
		String js = "function(obj, event) {";
		foreach_auto( w, toScroll )
			js += "$('#" + w->id() + "').scroll" + myOrientation + "(obj.scroll" + myOrientation + ");";
		js += myScrolled.createCall( "obj.scroll" + myOrientation ) + ";";
		js += "}";
		myScrollJS.setJavaScript( js );
		mySelf->scrolled().connect( myScrollJS );
	}
	void ResizeImpl( const Pixel::Size& viewed, const Pixel::Size& all )
	{
		mySelf->resize( viewed.Width().Get(), viewed.Height().Get() );
		myC->resize( all.Width().Get(), all.Height().Get() );
	}
	void Scrolled( int offset )
	{
		myScrolledOffset = offset;
	}
	int Offset()
	{
		return myScrolledOffset;
	}
	void ScrollTo( int pos )
	{
		GetWebApp()->doJavaScript( mySelf->jsRef() + ".scroll" + myOrientation + " += " + to_string( pos ) );
	}
};
X_PIMPL_IMPLEMENTATION( ScrollbarWidget )

ScrollbarWidget::ScrollbarWidget( const String& orientation, const std::vector< Wt::WWidget* >& toScroll, Wt::WContainerWidget* p )
	: Wt::WContainerWidget( p )
{
	GetPimpl()->Init( orientation, toScroll );
}
Pixel::Scalar ScrollbarWidget::GetScrollOffset() const
{
	return Pixel::Scalar( GetPimpl()->Offset() );
}
void ScrollbarWidget::ResizeImpl( const Pixel::Size& viewed, const Pixel::Size& all )
{
	GetPimpl()->ResizeImpl( viewed, all );
}
void ScrollbarWidget::ScrollTo( const Pixel::Scalar& position )
{
	GetPimpl()->ScrollTo( position.Get() );
}
HScrollbarWidget::HScrollbarWidget( const std::vector< Wt::WWidget* >& toScroll, Wt::WContainerWidget* p )
	: ScrollbarWidget( "Left", toScroll, p )
{
	foreach_auto( w, toScroll )
		GetWidgetParent< AbsolutePositionContainerBase >( w )->SetHorizontalScrollbar( this );
	setOverflow( Wt::WContainerWidget::OverflowScroll, Wt::Horizontal );
	setOverflow( Wt::WContainerWidget::OverflowHidden, Wt::Vertical );
}
void HScrollbarWidget::Resize( const Pixel::Scalar& viewed, const Pixel::Scalar& all )
{
	ResizeImpl( Pixel::Size( viewed, Scrollbar() ), Pixel::Size( all, 1 ) );
}

VScrollbarWidget::VScrollbarWidget( const std::vector< Wt::WWidget* >& toScroll, Wt::WContainerWidget* p )
	: ScrollbarWidget( "Top", toScroll, p )
{
	foreach_auto( w, toScroll )
	{
		GetWidgetParent< AbsolutePositionContainerBase >( w )->SetVerticalScrollbar( this );
		if( auto interact = dynamic_cast< Wt::WInteractWidget* >( w ) )
			interact->mouseWheel().connect( [&]( const Wt::WMouseEvent& e )
			{
				ScrollTo( Pixel::Scalar( -10 * e.wheelDelta() ) );
			});
	}
	setOverflow( Wt::WContainerWidget::OverflowHidden, Wt::Horizontal );
	setOverflow( Wt::WContainerWidget::OverflowScroll, Wt::Vertical );
}
void VScrollbarWidget::Resize( const Pixel::Scalar& viewed, const Pixel::Scalar& all )
{
	ResizeImpl( Pixel::Size( Scrollbar(), viewed ), Pixel::Size( 1, all ) );
}
