/*
 * Copyright (C) 2004-2012 Geometer Plus <contact@geometerplus.com>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 * 02110-1301, USA.
 */

#include <tqapplication.h>
#include <tqpixmap.h>
#include <tqimage.h>
#include <tqmenubar.h>
#include <tqaction.h>
#include <tqlayout.h>
#include <tqobjectlist.h>
#include <tqtooltip.h>

#include <ZLibrary.h>
#include <ZLPopupData.h>

#include "ZLTQtApplicationWindow.h"
#include "ZLTQtPopupMenu.h"
#include "../dialogs/ZLTQtDialogManager.h"
#include "../view/ZLTQtViewWidget.h"
#include "../util/ZLTQtKeyUtil.h"

void ZLTQtDialogManager::createApplicationWindow(ZLApplication *application) const {
	new ZLTQtApplicationWindow(application);
}

static const std::string OPTIONS = "Options";

class MyIconFactory : public TQIconFactory {

public:
	TQPixmap *createPixmap(const TQIconSet &set, TQIconSet::Size size, TQIconSet::Mode mode, TQIconSet::State state);
};

inline TQRgb grayRgb(TQRgb rgb) {
	int gray = (tqRed(rgb) + tqGreen(rgb) + tqBlue(rgb)) / 3;
	return tqRgba(gray, gray, gray, tqAlpha(rgb) / 2);
}

TQPixmap *MyIconFactory::createPixmap(const TQIconSet &set, TQIconSet::Size size, TQIconSet::Mode mode, TQIconSet::State state) {
	if (mode != TQIconSet::Disabled) {
		return 0;
	}
	TQImage image;
	image = set.pixmap(size, TQIconSet::Normal, state);
	const int numColors = image.numColors();
	if (numColors > 0) {
		for (int i = 0; i < numColors; ++i) {
			image.setColor(i, grayRgb(image.color(i)));
		}
	} else {
		const int width = image.width();
		const int height = image.height();
		for (int i = 0; i < width; ++i) {
			for (int j = 0; j < height; ++j) {
				image.setPixel(i, j, grayRgb(image.pixel(i, j)));
			}
		}
	}

	return new TQPixmap(image);
}

ZLTQtToolButton::ZLTQtToolButton(ZLTQtApplicationWindow &window, ZLToolbar::AbstractButtonItem &item) : TQToolButton(window.myToolBar), myWindow(window), myItem(item) {
	static std::string imagePrefix = ZLibrary::ApplicationImageDirectory() + ZLibrary::FileNameDelimiter;
	TQPixmap icon((imagePrefix + myItem.iconName() + ".png").c_str());
	setIconSet(TQIconSet(icon));
	TQSize size = icon.size();
	TQIconSet::setIconSize(TQIconSet::Large, size);
	TQIconSet::setIconSize(TQIconSet::Small, size);
	if (item.type() == ZLToolbar::Item::TOGGLE_BUTTON) {
		setToggleButton(true);
	} else if (item.type() == ZLToolbar::Item::MENU_BUTTON) {
		ZLToolbar::MenuButtonItem &menuButtonItem = (ZLToolbar::MenuButtonItem&)myItem;
		shared_ptr<ZLPopupData> popupData = menuButtonItem.popupData();
		myWindow.myPopupIdMap[&menuButtonItem] =
			popupData.isNull() ? (size_t)-1 : (popupData->id() - 1);
		setPopup(new ZLTQtPopupMenu(this));
    setPopupDelay(0);
	}
	TQString text = TQString::fromUtf8(myItem.tooltip().c_str());
	setTextLabel(text);
	setUsesTextLabel(false);
	TQToolTip::add(this, text);
	connect(this, TQ_SIGNAL(clicked()), this, TQ_SLOT(onActivated()));
}

void ZLTQtToolButton::onActivated() {
	myWindow.onButtonPress(myItem);
}

void ZLTQtApplicationWindow::setToggleButtonState(const ZLToolbar::ToggleButtonItem &button) {
	((TQToolButton*)myItemToWidgetMap[&button])->setOn(button.isPressed());
}

ZLTQtApplicationWindow::ZLTQtApplicationWindow(ZLApplication *application) :
	ZLDesktopApplicationWindow(application),
	myFullScreen(false),
	myWasMaximized(false),
	myCursorIsHyperlink(false) {

	TQIconFactory::installDefaultFactory(new MyIconFactory());

	const std::string iconFileName = ZLibrary::ImageDirectory() + ZLibrary::FileNameDelimiter + ZLibrary::ApplicationName() + ".png";
	TQPixmap icon(iconFileName.c_str());
	setIcon(icon);

	setWFlags(getWFlags() | WStyle_Customize);

	myToolBar = new TQToolBar(this);
	myToolBar->setFocusPolicy(NoFocus);
	myToolBar->boxLayout()->setMargin(5);
	myToolBar->boxLayout()->setSpacing(3);
	setToolBarsMovable(false);

	resize(myWidthOption.value(), myHeightOption.value());
	move(myXOption.value(), myYOption.value());

	tqApp->setMainWidget(this);
	menuBar()->hide();
	show();
}

void ZLTQtApplicationWindow::init() {
	ZLDesktopApplicationWindow::init();
	switch (myWindowStateOption.value()) {
		case NORMAL:
			break;
		case FULLSCREEN:
			setFullscreen(true);
			break;
		case MAXIMIZED:
			showMaximized();
			break;
	}
}

void ZLTQtApplicationWindow::processAllEvents() {
	tqApp->processEvents();
}

ZLTQtApplicationWindow::~ZLTQtApplicationWindow() {
	if (isFullscreen()) {
		myWindowStateOption.setValue(FULLSCREEN);
	} else if (isMaximized()) {
		myWindowStateOption.setValue(MAXIMIZED);
	} else {
		myWindowStateOption.setValue(NORMAL);
		if (x() != -1) {
			myXOption.setValue(x());
		}
		if (y() != -1) {
			myYOption.setValue(y());
		}
		myWidthOption.setValue(width());
		myHeightOption.setValue(height());
	}
}

void ZLTQtApplicationWindow::setFullscreen(bool fullscreen) {
	if (fullscreen == myFullScreen) {
		return;
	}
	myFullScreen = fullscreen;
	if (myFullScreen) {
		myWasMaximized = isMaximized();
		if (!myWasMaximized) {
			if (x() != -1) {
				myXOption.setValue(x());
			}
			if (y() != -1) {
				myYOption.setValue(y());
			}
			myWidthOption.setValue(width());
			myHeightOption.setValue(height());
		}
		myToolBar->hide();
		showFullScreen();
	} else {
		myToolBar->show();
		showNormal();
		if (myWasMaximized) {
			showMaximized();
		} else {
			resize(myWidthOption.value(), myHeightOption.value());
			move(myXOption.value(), myYOption.value());
		}
	}
}

bool ZLTQtApplicationWindow::isFullscreen() const {
	return myFullScreen;
}

void ZLTQtApplicationWindow::keyPressEvent(TQKeyEvent *event) {
	application().doActionByKey(ZLTQtKeyUtil::keyName(event));
}

void ZLTQtApplicationWindow::wheelEvent(TQWheelEvent *event) {
	if (event->orientation() == Vertical) {
		if (event->delta() > 0) {
			application().doActionByKey(ZLApplication::MouseScrollUpKey);
		} else {
			application().doActionByKey(ZLApplication::MouseScrollDownKey);
		}
	}
}

void ZLTQtApplicationWindow::closeEvent(TQCloseEvent *event) {
	if (application().closeView()) {
		event->accept();
	} else {
		event->ignore();
	}
}

ZLTQtApplicationWindow::LineEditParameter::LineEditParameter(TQToolBar *toolbar, ZLTQtApplicationWindow &window, const ZLToolbar::ParameterItem &textFieldItem) : TQLineEdit(toolbar), myWindow(window), myActionId(textFieldItem.actionId()) {
	setAlignment(TQt::AlignHCenter);
	setFocusPolicy(ClickFocus);
	setMaxLength(textFieldItem.maxWidth());
	setMaximumWidth(textFieldItem.maxWidth() * 12 + 12);
	TQToolTip::add(this, TQString::fromUtf8(textFieldItem.tooltip().c_str()));
	myWindow.addVisualParameter(textFieldItem.parameterId(), this);
}

void ZLTQtApplicationWindow::LineEditParameter::keyReleaseEvent(TQKeyEvent *event) {
	event->accept();
	if (event->key() == TQt::Key_Enter || event->key() == TQt::Key_Return) {
		myWindow.application().doAction(myActionId);
		myWindow.setFocusToMainWidget();
	} else if (event->key() == TQt::Key_Escape) {
		restoreOldValue();
		myWindow.setFocusToMainWidget();
	}
}

std::string ZLTQtApplicationWindow::LineEditParameter::internalValue() const {
	return (const char*)text().utf8();
}

void ZLTQtApplicationWindow::LineEditParameter::internalSetValue(const std::string &value) {
	setText(TQString::fromUtf8(value.c_str()));
}

void ZLTQtApplicationWindow::addToolbarItem(ZLToolbar::ItemPtr item) {
	switch (item->type()) {
		case ZLToolbar::Item::TEXT_FIELD:
			myItemToWidgetMap[&*item] = new LineEditParameter(myToolBar, *this, (ZLToolbar::ParameterItem&)*item);
			break;
		case ZLToolbar::Item::PLAIN_BUTTON:
		case ZLToolbar::Item::MENU_BUTTON:
		case ZLToolbar::Item::TOGGLE_BUTTON:
			myItemToWidgetMap[&*item] = new ZLTQtToolButton(*this, (ZLToolbar::AbstractButtonItem&)*item);
			break;
		case ZLToolbar::Item::SEPARATOR:
			myToolBar->addSeparator();
			myItemToWidgetMap[&*item] = (TQWidget*)myToolBar->children()->getLast();
			break;
	}
}

void ZLTQtApplicationWindow::setToolbarItemState(ZLToolbar::ItemPtr item, bool visible, bool enabled) {
	TQWidget *widget = myItemToWidgetMap[&*item];
	if (widget == 0) {
		return;
	}
	widget->setEnabled(enabled);
	widget->setShown(visible);

	switch (item->type()) {
		default:
			break;
		case ZLToolbar::Item::MENU_BUTTON:
		{
			ZLToolbar::MenuButtonItem &menuButtonItem = (ZLToolbar::MenuButtonItem&)*item;
			shared_ptr<ZLPopupData> data = menuButtonItem.popupData();
			if (!data.isNull() && (data->id() != myPopupIdMap[&menuButtonItem])) {
				myPopupIdMap[&menuButtonItem] = data->id();
				((ZLTQtPopupMenu*)((TQToolButton*)widget)->popup())->reset(data);
			}
			break;
		}
	}
}

ZLTQtViewWidgetPositionInfo::ZLTQtViewWidgetPositionInfo(const ZLTQtApplicationWindow &window) : myWindow(window) {
}

int ZLTQtViewWidgetPositionInfo::x() const {
	return 0;
}

int ZLTQtViewWidgetPositionInfo::y() const {
	return ((myWindow.myToolBar != 0) && myWindow.myToolBar->isVisible()) ?
		myWindow.myToolBar->height() : 0;
}

int ZLTQtViewWidgetPositionInfo::width() const {
	return myWindow.width();
}

int ZLTQtViewWidgetPositionInfo::height() const {
	return myWindow.height() - y();
}

ZLViewWidget *ZLTQtApplicationWindow::createViewWidget() {
	ZLTQtViewWidgetPositionInfo positionInfo(*this);
	ZLTQtViewWidget *viewWidget = new ZLTQtViewWidget(this, &application(), positionInfo);
	setCentralWidget(viewWidget->widget());
	viewWidget->widget()->show();
	return viewWidget;
}

void ZLTQtApplicationWindow::close() {
	TQMainWindow::close();
}

void ZLTQtApplicationWindow::grabAllKeys(bool) {
}

void ZLTQtApplicationWindow::setCaption(const std::string &caption) {
	TQMainWindow::setCaption(TQString::fromUtf8(caption.c_str()));
}

void ZLTQtApplicationWindow::setHyperlinkCursor(bool hyperlink) {
	if (hyperlink == myCursorIsHyperlink) {
		return;
	}
	myCursorIsHyperlink = hyperlink;
	if (hyperlink) {
		myStoredCursor = cursor();
		setCursor(TQt::pointingHandCursor);
	} else if (&myStoredCursor != &TQt::waitCursor) {
		setCursor(myStoredCursor);
	}
}

void ZLTQtApplicationWindow::setFocusToMainWidget() {
	centralWidget()->setFocus();
}

#include "ZLTQtApplicationWindow.moc"
