/** 
 * Called when the mouse was moved during a drag and drop operation
 *
 * @param DragDropEvent    The event that describes this drag drop operation.
 */
void FDockingDragOperation::OnDragged( const FDragDropEvent& DragDropEvent )
{
	const bool bPreviewingTarget = HoveredDockTarget.TargetNode.IsValid();
	if ( !bPreviewingTarget )
	{
		// The tab is being dragged. Move the the decorator window to match the cursor position.
		FVector2D TargetPosition = DragDropEvent.GetScreenSpacePosition() - GetDecoratorOffsetFromCursor();
		CursorDecoratorWindow->UpdateMorphTargetShape( FSlateRect(TargetPosition.X, TargetPosition.Y, TargetPosition.X + LastContentSize.X, TargetPosition.Y + LastContentSize.Y) );	
		CursorDecoratorWindow->MoveWindowTo( TargetPosition );
	}
}
/**
 * Invoked when the drag and drop operation has ended.
 * 
 * @param bDropWasHandled   true when the drop was handled by some widget; false otherwise
 */
void FDockingDragOperation::OnDrop( bool bDropWasHandled, const FPointerEvent& MouseEvent )
{
	check(CursorDecoratorWindow.IsValid());

	const FVector2D WindowSize = CursorDecoratorWindow->GetSizeInScreen();
	// Destroy the CursorDecoratorWindow by calling the base class implementation because we are relocating the content into a more permanent home.
	FDragDropOperation::OnDrop(bDropWasHandled, MouseEvent);

	TabBeingDragged->SetDraggedOverDockArea( NULL );

	if (!bDropWasHandled)
	{
		// If we dropped the tab into an existing DockNode then it would have handled the DropEvent.
		// We are here because that didn't happen, so make a new window with a new DockNode and drop the tab into that.

		const FVector2D PositionToDrop = MouseEvent.GetScreenSpacePosition() - GetDecoratorOffsetFromCursor();

		TSharedRef<FTabManager> MyTabManager = TabBeingDragged->GetTabManager();
		
		TSharedPtr<SWindow> NewWindowParent = MyTabManager->GetPrivateApi().GetParentWindow();

		
		TSharedRef<SWindow> NewWindow = SNew(SWindow)
			.Title( FGlobalTabmanager::Get()->GetApplicationTitle() )
			.AutoCenter(EAutoCenter::None)
			.ScreenPosition( PositionToDrop )
			// Make room for the title bar; otherwise windows will get progressive smaller whenver you float them.
			.ClientSize( SWindow::ComputeWindowSizeForContent( WindowSize ) )
			.CreateTitleBar(false);

		TSharedPtr<SDockingTabStack> NewDockNode;

		if ( TabBeingDragged->GetTabRole() == ETabRole::NomadTab )
		{
			TabBeingDragged->SetTabManager(FGlobalTabmanager::Get());
		}

		// Create a new dockarea
		TSharedRef<SDockingArea> NewDockArea = 
			SNew(SDockingArea, TabBeingDragged->GetTabManager(), FTabManager::NewPrimaryArea())
			. ParentWindow( NewWindow )
			. InitialContent
			(
				SAssignNew(NewDockNode, SDockingTabStack, FTabManager::NewStack())
			);

		if (TabBeingDragged->GetTabRole() == ETabRole::MajorTab || TabBeingDragged->GetTabRole() == ETabRole::NomadTab)
		{
			TSharedPtr<SWindow> RootWindow = FGlobalTabmanager::Get()->GetRootWindow();
			if ( RootWindow.IsValid() )
			{
				// We have a root window, so all MajorTabs are nested under it.
				FSlateApplication::Get().AddWindowAsNativeChild( NewWindow, RootWindow.ToSharedRef() )->SetContent(NewDockArea);
			}
			else
			{
				// App tabs get put in top-level windows. They show up on the taskbar.
				FSlateApplication::Get().AddWindow( NewWindow )->SetContent(NewDockArea);
			}
		}
		else
		{
			// Other tab types are placed in child windows. Their life is controlled by the top-level windows.
			// They do not show up on the taskbar.

			if ( NewWindowParent.IsValid() )
			{
				FSlateApplication::Get().AddWindowAsNativeChild( NewWindow, NewWindowParent.ToSharedRef() )->SetContent(NewDockArea);
			}
			else
			{
				FSlateApplication::Get().AddWindow( NewWindow )->SetContent(NewDockArea);
			}
		}

		// Do this after the window parenting so that the window title is set correctly
		NewDockNode->OpenTab(TabBeingDragged.ToSharedRef());

		// Let every widget under this tab manager know that this tab has found a new home.
		TabOwnerAreaOfOrigin->GetTabManager()->GetPrivateApi().OnTabRelocated( TabBeingDragged.ToSharedRef(), NewWindow );
	}
	else
	{
		// The event was handled, so we HAVE to have some window that we dropped onto.
		TSharedRef<SWindow> WindowDroppedInto = MouseEvent.GetWindow();

		// Let every widget under this tab manager know that this tab has found a new home.
		TSharedPtr<SWindow> NewWindow = ( TabOwnerAreaOfOrigin->GetParentWindow() == WindowDroppedInto )
			// Tab dropped into same window as before, meaning there is no NewWindow.
			? TSharedPtr<SWindow>()
			// Tab was dropped into a different window, so the tab manager needs to know in order to re-parent child windows.
			: WindowDroppedInto;

		TabOwnerAreaOfOrigin->GetTabManager()->GetPrivateApi().OnTabRelocated( TabBeingDragged.ToSharedRef(), WindowDroppedInto );
	}
}