#include "multi_browser_manager.h"
#include "multi_browser_form.h"
#include "browser_box.h"
#include "dragdrop/drag_form.h"
#include "dragdrop/drag_drop.h"

namespace
{
	const int kSplitFormXOffset = 20;	//自动拆分浏览器窗口后新窗口的x偏移坐标
	const int kSplitFormYOffset = 20;	//自动拆分浏览器窗口后新窗口的y偏移坐标
	const int kDragFormXOffset = -100;	//拖拽出新浏览器窗口后的相对鼠标的x偏移坐标
	const int kDragFormYOffset = -20;	//拖拽出新浏览器窗口后的相对鼠标的y偏移坐标
}

BrowserBox* MultiBrowserManager::CreateBorwserBox(MultiBrowserForm *browser_form, const std::string &id, const std::wstring &url)
{
	BrowserBox *browser_box = NULL;
	// 如果启用了窗口合并功能,就把新浏览器盒子都集中创建到某一个浏览器窗口里
	// 否则每个浏览器盒子都创建一个浏览器窗口
	if (enable_merge_)
	{
		if (!browser_form)
		{
			browser_form = new MultiBrowserForm;
			HWND hwnd = browser_form->Create(NULL, L"MultiBrowser", UI_WNDSTYLE_FRAME, 0, false);
			if (hwnd == NULL)
			{
				browser_form = NULL;
				return NULL;
			}

			browser_form->CenterWindow();
		}

		browser_box = browser_form->CreateBox(id, url);
		if (NULL == browser_box)
			return NULL;
	}
	else
	{
		browser_form = new MultiBrowserForm;
		HWND hwnd = browser_form->Create(NULL, L"MultiBrowser", UI_WNDSTYLE_FRAME, 0, false);
		if (hwnd == NULL)
			return NULL;

		browser_box = browser_form->CreateBox(id, url);
		if (NULL == browser_box)
			return NULL;

		browser_form->CenterWindow();
	}

	box_map_[id] = browser_box;
	return browser_box;
}

MultiBrowserManager::MultiBrowserManager()
{
	enable_merge_ = true;
	use_custom_drag_image_ = true;
}

MultiBrowserManager::~MultiBrowserManager()
{

}

bool MultiBrowserManager::IsBorwserBoxActive(const std::string& id)
{
	BrowserBox *browser_box = FindBorwserBox(id);
	if (NULL != browser_box)
	{
		MultiBrowserForm *parent_form = browser_box->GetBrowserForm();
		return parent_form->IsActiveBox(browser_box);
	}

	return false;
}

BrowserBox* MultiBrowserManager::FindBorwserBox( const std::string &id )
{
	std::map<std::string, BrowserBox*>::const_iterator i = box_map_.find(id);
	if (i == box_map_.end())
		return NULL;
	else
		return i->second;
}

void MultiBrowserManager::RemoveBorwserBox( std::string id, const BrowserBox* box /*=NULL*/)
{
	auto it_box = box_map_.find(id);
	if (it_box == box_map_.end())
	{
		assert(0);
	}
	else
	{
		if (NULL == box || box == it_box->second)
		{
			box_map_.erase(it_box);
		}
		else
		{
			assert(0);
		}
	}

	if (box_map_.empty())
		nim_comp::CefManager::GetInstance()->PostQuitMessage(0);
}

void MultiBrowserManager::SetEnableMerge(bool enable)
{
	if (enable_merge_ == enable)
		return;

	enable_merge_ = enable;

	if (enable_merge_)
	{
		// 如果当前只有一个浏览器窗口或者浏览器盒子,就不需要进行合并操作
		if (box_map_.size() <= 1)
			return;

		// 选择第一个浏览器盒子所属的窗口作为合并窗口
		MultiBrowserForm *merge_form = box_map_.begin()->second->GetBrowserForm();

		// 遍历所有浏览器盒子,脱离原浏览器窗口,再附加到合并窗口里
		for (auto it_box : box_map_)
		{
			ASSERT(NULL != it_box.second);
			MultiBrowserForm *parent_form = it_box.second->GetBrowserForm();
			if (merge_form != parent_form)
			{
				if (parent_form->DetachBox(it_box.second))
				{
					merge_form->AttachBox(it_box.second);
				}
			}
		}
	}
	else
	{
		// 如果当前只有一个浏览器盒子,就不需要进行拆分操作
		if (box_map_.size() <= 1)
			return;

		// 给新拆分的窗口设置坐标
		bool first_sort = true;
		ui::UiRect rect_old_form;
		MultiBrowserForm *sort_form = NULL;

		// 遍历所有浏览器盒子,脱离原浏览器窗口,创建新的浏览器窗口并附加浏览器盒子
		for (auto it_box : box_map_)
		{
			ASSERT(NULL != it_box.second);
			MultiBrowserForm *parent_form = it_box.second->GetBrowserForm();
			if (1 == parent_form->GetBoxCount())
			{
				sort_form = parent_form;
			}
			else if (parent_form->DetachBox(it_box.second))
			{
				MultiBrowserForm *browser_form = new MultiBrowserForm;
				HWND hwnd = browser_form->Create(NULL, L"MultiBrowser", UI_WNDSTYLE_FRAME, 0, false);
				if (hwnd == NULL)
				{
					ASSERT(0);
					continue;
				}

				if (!browser_form->AttachBox(it_box.second))
				{
					ASSERT(0);
					continue;
				}

				sort_form = browser_form;
			}

			if (NULL != sort_form)
			{
				if (first_sort)
				{
					first_sort = false;
					sort_form->CenterWindow();
					rect_old_form = sort_form->GetPos(true);
				}
				else
				{
					rect_old_form.left += kSplitFormXOffset;
					rect_old_form.top += kSplitFormXOffset;
					sort_form->SetPos(rect_old_form, true, SWP_NOSIZE, NULL, true);
				}
			}
		}
	}
}

bool MultiBrowserManager::IsEnableMerge() const
{
	return enable_merge_;
}

void MultiBrowserManager::SetUseCustomDragImage(bool use)
{
	use_custom_drag_image_ = use;
}

bool MultiBrowserManager::IsUseCustomDragImage() const
{
	return use_custom_drag_image_;
}

bool MultiBrowserManager::IsDragingBorwserBox() const
{
	return enable_merge_ && NULL != draging_box_;
}

void MultiBrowserManager::SetDropForm(MultiBrowserForm *browser_form)
{
	if (NULL == browser_form)
		return;

	drop_browser_form_ = browser_form;
}

bool MultiBrowserManager::DoDragBorwserBox(BrowserBox *browser_box, HBITMAP bitmap, POINT pt_offset)
{
	if (!enable_merge_)
		return false;

	SdkDropSource* drop_src = new SdkDropSource;
	if (drop_src == NULL)
		return false;

	SdkDataObject* data_object = CreateDragDataObject(bitmap, pt_offset);
	if (data_object == NULL)
		return false;

	// 无论什么时候都让拖拽时光标显示为箭头
	drop_src->SetFeedbackCursor(::LoadCursor(NULL, MAKEINTRESOURCE(IDC_ARROW)));

	OnBeforeDragBorwserBox(browser_box, bitmap, pt_offset);

	// 此函数会阻塞直到拖拽完成
	DWORD dwEffect;
	HRESULT hr = ::DoDragDrop(data_object, drop_src, DROPEFFECT_COPY | DROPEFFECT_MOVE, &dwEffect);

	OnAfterDragBorwserBox();

	// 销毁位图
	DeleteObject(bitmap);
	drop_src->Release();
	data_object->Release();
	return true;
}

SdkDataObject* MultiBrowserManager::CreateDragDataObject(HBITMAP bitmap, POINT pt_offset)
{
	SdkDataObject* data_object = new SdkDataObject;
	if (data_object == NULL)
		return NULL;

	if (use_custom_drag_image_)
	{
		FORMATETC fmtetc = { 0 };
		fmtetc.dwAspect = DVASPECT_CONTENT;
		fmtetc.lindex = -1;
		fmtetc.cfFormat = CF_HDROP;
		fmtetc.tymed = TYMED_NULL;

		STGMEDIUM medium = { 0 };
		medium.tymed = TYMED_NULL;
		data_object->SetData(&fmtetc, &medium, FALSE);
	}
	else
	{
		FORMATETC fmtetc = { 0 };
		fmtetc.dwAspect = DVASPECT_CONTENT;
		fmtetc.lindex = -1;
		fmtetc.cfFormat = CF_BITMAP;
		fmtetc.tymed = TYMED_GDI;

		STGMEDIUM medium = { 0 };
		medium.tymed = TYMED_GDI;
		HBITMAP hBitmap = (HBITMAP)OleDuplicateData(bitmap, fmtetc.cfFormat, NULL);
		medium.hBitmap = hBitmap;
		data_object->SetData(&fmtetc, &medium, FALSE);

		BITMAP bitmap_info;
		GetObject(hBitmap, sizeof(BITMAP), &bitmap_info);
		SIZE bitmap_size = { bitmap_info.bmWidth, bitmap_info.bmHeight };
		SdkDragSourceHelper dragSrcHelper;
		dragSrcHelper.InitializeFromBitmap(hBitmap, pt_offset, bitmap_size, data_object, RGB(255, 0, 255));
	}

	return data_object;
}

void MultiBrowserManager::OnBeforeDragBorwserBox(BrowserBox *browser_box, HBITMAP bitmap, POINT pt_offset)
{
	// 获取当前被拖拽的浏览器盒子所属的浏览器窗口
	draging_box_ = browser_box;
	MultiBrowserForm *drag_browser_form = draging_box_->GetBrowserForm();
	ASSERT(NULL != drag_browser_form);

	// 获取被拖拽浏览器窗口中浏览器盒子的数量
	int box_count = drag_browser_form->GetBoxCount();
	ASSERT(box_count > 0);
	drop_browser_form_ = NULL;

	drag_browser_form->OnBeforeDragBoxCallback(nbase::UTF8ToUTF16(draging_box_->GetId()));

	if (use_custom_drag_image_)
		DragForm::CreateCustomDragImage(bitmap, pt_offset);
}

void MultiBrowserManager::OnAfterDragBorwserBox()
{
	if (use_custom_drag_image_)
		DragForm::CloseCustomDragImage();

	if (NULL == draging_box_)
		return;

	// 获取当前被拖拽的浏览器盒子所属的浏览器窗口
	MultiBrowserForm *drag_browser_form = draging_box_->GetBrowserForm();
	ASSERT(NULL != drag_browser_form);

	// 获取被拖拽浏览器窗口中浏览器盒子的数量
	int box_count = drag_browser_form->GetBoxCount();
	ASSERT(box_count > 0);

	// 如果被拖拽的浏览器盒子放入到一个浏览器窗口里
	if (NULL != drop_browser_form_)
	{
		if (drag_browser_form == drop_browser_form_)
		{
			drag_browser_form->OnAfterDragBoxCallback(false);
		}
		else
		{
			drag_browser_form->OnAfterDragBoxCallback(true);
			if (drag_browser_form->DetachBox(draging_box_))
			{
				drop_browser_form_->AttachBox(draging_box_);
			}
		}

		// 如果被拖拽的浏览器窗口包含多个浏览器盒子,就投递一个WM_LBUTTONUP消息给窗口
		// (因为窗口被拖拽时触发了ButtonDown和ButtonMove消息,但是最终的ButtonUp消息会被忽略,这里补上)
		// 如果只有一个浏览器盒子,则浏览器盒子脱离浏览器窗口时,浏览器窗口就会关闭,不需要投递
		if (box_count > 1)
			drag_browser_form->PostMessage(WM_LBUTTONUP, 0, 0);
	}
	// 如果没有被拖拽到另一个浏览器窗口里
	else
	{
		// 如果被拖拽的浏览器窗口里只有一个浏览器盒子,则拖拽失败
		if (1 == box_count)
		{
			drag_browser_form->OnAfterDragBoxCallback(false);
		}
		// 如果有多个浏览器盒子, 就把浏览器盒子脱离原浏览器窗口,附加到新的浏览器窗口,拖拽成功
		else
		{
			drag_browser_form->OnAfterDragBoxCallback(true);

			if (drag_browser_form->DetachBox(draging_box_))
			{
				MultiBrowserForm *browser_form = new MultiBrowserForm;
				HWND hwnd = browser_form->Create(NULL, L"MultiBrowser", UI_WNDSTYLE_FRAME, 0, false);
				if (hwnd != NULL)
				{
					if (browser_form->AttachBox(draging_box_))
					{
						// 这里设置新浏览器窗口的位置,设置到偏移鼠标坐标100,20的位置
						POINT pt_mouse;
						::GetCursorPos(&pt_mouse);
						ui::UiRect rect(pt_mouse.x + kDragFormXOffset, pt_mouse.y + kDragFormYOffset, 0, 0);
						browser_form->SetPos(rect, false, SWP_NOSIZE);
					}
				}
			}
		}

		// 如果没有被拖拽到另一个浏览器窗口里,这时不会有浏览器窗口被关闭,所以直接投递ButtonUp消息
		drag_browser_form->PostMessage(WM_LBUTTONUP, 0, 0);
	}

	draging_box_ = NULL;
	drop_browser_form_ = NULL;
}