#include "toplevel.h"
#include "playground.h"
#include "playcanvas.h"
#include "kmenubar.h"
#include "kpopupmenu.h"
#include "level.h"
#include "resource.h"

#include <kdebug.h>
#include <klocale.h>
#include <kmessagebox.h>
#include <kconfig.h>
#include <kiconloader.h>
#include <kstandarddirs.h>

#include <kfiledialog.h>
#include <ktempfile.h>
#include <kinputdialog.h>
#include <kio/netaccess.h>

#include <qimage.h>

#include "config.h"

#ifdef HAVE_KNEWSTUFF
#include <knewstuff/knewstuffgeneric.h>
#include <knewstuff/engine.h>
#include <knewstuff/uploaddialog.h>
#endif

#ifdef HAVE_SPEEDBAR
#include <kurlbar.h>
#endif

TopLevel::TopLevel()
	: KMainWindow()
{
	QImage tmp;
	QPixmap pix;

#ifdef HAVE_SPEEDBAR
	dialog = NULL;
#endif

	m_isfullscreen = false;
	m_delayedsharing = false;

	kapp->config()->setGroup("Preferences");

	int tilesize = kapp->config()->readNumEntry("Tilesize");
	if(tilesize) Resource::setTilesize(tilesize);
	else Resource::setTilesize(40);

	QString theme = kapp->config()->readEntry("Theme");
	if(!theme.isNull()) Resource::setTheme(theme);
	else Resource::setTheme("desert");

	playground = NULL;
	canvas = NULL;

	filemenu = new KPopupMenu(this);
	filemenu->insertItem(KGlobal::iconLoader()->loadIcon("filenew", KIcon::Small), i18n("&New"), file_new);
	filemenu->insertSeparator();
	filemenu->insertItem(KGlobal::iconLoader()->loadIcon("fileopen", KIcon::Small), i18n("&Open"), file_open);
	filemenu->insertItem(KGlobal::iconLoader()->loadIcon("filesave", KIcon::Small), i18n("&Save"), file_save);
#ifdef HAVE_KNEWSTUFF
	filemenu->insertSeparator();
	filemenu->insertItem(KGlobal::iconLoader()->loadIcon("knewstuff", KIcon::Small), i18n("&Share"), file_share);
#endif
	filemenu->insertSeparator();
	filemenu->insertItem(KGlobal::iconLoader()->loadIcon("exit", KIcon::Small), i18n("&Exit"), file_exit);

	setupMenus(false, false);

	displaymenu = new KPopupMenu(this);
	displaymenu->insertItem(KGlobal::iconLoader()->loadIcon("viewmag+", KIcon::Small), i18n("&Larger"), display_larger);
	displaymenu->insertItem(KGlobal::iconLoader()->loadIcon("viewmag-", KIcon::Small),i18n("&Smaller"), display_smaller);
	displaymenu->insertItem(KGlobal::iconLoader()->loadIcon("window_fullscreen", KIcon::Small),i18n("Show &Fullscreen"), display_fullscreen);
	displaymenu->setCheckable(true);

	elementmenu = new KPopupMenu(this);
	elementmenu->insertItem(i18n("Ground"), element_ground);
	elementmenu->insertItem(i18n("Wall"), element_wall);
	elementmenu->insertItem(i18n("Bridge"), element_bridge);
	elementmenu->insertItem(i18n("Space"), element_space);
	/*elementmenu->insertItem(i18n("Scree"), element_scree);
	elementmenu->insertItem(i18n("Bomb item"), element_bomb);
	elementmenu->insertItem(i18n("Life item"), element_live);
	elementmenu->insertItem(i18n("Power item"), element_power);
	elementmenu->insertItem(i18n("Grail item"), element_grail);
	elementmenu->insertItem(i18n("Speed item"), element_speed);
	elementmenu->insertItem(i18n("Invisible item"), element_invisible);
	elementmenu->insertItem(i18n("Flash item"), element_flash);*/
	elementmenu->setCheckable(true);

	menuBar()->insertItem(i18n("&File"), filemenu, file_menu);
	menuBar()->insertItem(i18n("&Elements"), elementmenu, element_menu);
	menuBar()->insertItem(i18n("&Display"), displaymenu, display_menu);
	menuBar()->insertItem(i18n("&Help"), helpMenu(), help_menu);

	menuBar()->setItemEnabled(display_menu, false);

	connect(filemenu, SIGNAL(activated(int)), SLOT(slotMenu(int)));
	connect(displaymenu, SIGNAL(activated(int)), SLOT(slotMenu(int)));
	connect(elementmenu, SIGNAL(activated(int)), SLOT(slotMenu(int)));

	setCaption(i18n("Kamikaze Editor"));

	m_element = Level::invalid;

	resize(400, 200);
}

TopLevel::~TopLevel()
{
}

void TopLevel::key(int keycode)
{
	bool moved;

	//kdDebug() << "key " << keycode << endl;
	if(!canvas) return;

	switch(keycode)
	{
		case Playground::KeyLeft:
			moved = canvas->action(PlayCanvas::moveEvent, PlayCanvas::optLeft);
			//if(moved) playground->scrollBy(-32, 0);
			break;
		case Playground::KeyRight:
			moved = canvas->action(PlayCanvas::moveEvent, PlayCanvas::optRight);
			//if(moved) playground->scrollBy(32, 0);
			break;
		case Playground::KeyUp:
			moved = canvas->action(PlayCanvas::moveEvent, PlayCanvas::optUp);
			//if(moved) playground->scrollBy(0, -32);
			break;
		case Playground::KeyDown:
			moved = canvas->action(PlayCanvas::moveEvent, PlayCanvas::optDown);
			//if(moved) playground->scrollBy(0, 32);
			break;
		case Playground::KeyZoomOut:
			scale(-5);
			break;
		case Playground::KeyZoomIn:
			scale(5);
			break;
		case Playground::KeyFullscreen:
			slotMenu(display_fullscreen);
			break;
	}
}

void TopLevel::scale(int difference)
{
	int w, h;

	if(!canvas) return;
	if(!canvas->level()) return;

	if(difference)
	{
		Resource::setTilesize(Resource::tilesize() + difference);
		canvas->setTheme(Resource::theme());
		kapp->config()->setGroup("Preferences");
		kapp->config()->writeEntry("Tilesize", Resource::tilesize());
		kapp->config()->sync();
	}

	if(!displaymenu->isItemChecked(display_fullscreen))
	{
		w = canvas->level()->width() * Resource::tilesize();
		h = canvas->level()->height() * Resource::tilesize() + menuBar()->height();
		if(int(KApplication::desktop()->width() * 0.7) < w) w = int(KApplication::desktop()->width() * 0.8);
		if(int(KApplication::desktop()->height() * 0.7) < h) h = int(KApplication::desktop()->height() * 0.7);
		setFixedSize(w, h);
	}
}

void TopLevel::newlevel(QString file)
{
	if(playground) delete playground;
	if(canvas) delete canvas;

	canvas = new PlayCanvas(this);
	canvas->enable(true);

	playground = new Playground(canvas, this);
	connect(playground, SIGNAL(key(int)), SLOT(key(int)));

	canvas->buildLevel(file);
	playground->setFocus();

	playground->show();
	setCentralWidget(playground);

	scale(0);

	m_currentlevel = file;
	m_levelmodified = false;
	setupMenus(false, true);
}

void TopLevel::createlevel()
{
	QString w, h;
	KTempFile tf;
	int i, j;

	w = KInputDialog::getText(i18n("New level"), i18n("Width:"));
	if(w.isEmpty()) return;
	h = KInputDialog::getText(i18n("New level"), i18n("Height:"));
	if(h.isEmpty()) return;

	if((!w.toInt()) || (!h.toInt()) || (w.toInt() > 100) || (h.toInt() > 100))
	{
		KMessageBox::sorry(this,
			i18n("Width and height have to be between 1 and 100"),
			i18n("New level"));
		return;
	}

	QFile *f = tf.file();

	QTextStream s(f);
	s << w << endl;
	s << h << endl;
	for(j = 0; j < h.toInt(); j++)
	{
		for(i = 0; i < w.toInt(); i++)
		{
			if(i) s << " ";
			s << "1";
		}
		s << endl;
	}

	f->close();
	kdDebug() << "tempfile: " << tf.name() << endl;
	newlevel(tf.name());
}

void TopLevel::savelevel(QString fn)
{
	int i, j;

	QFile f(fn);
	f.open(IO_WriteOnly);
	QTextStream s(&f);
	s << canvas->level()->width() << endl;
	s << canvas->level()->height() << endl;
	for(j = 0; j < canvas->level()->height(); j++)
	{
		for(i = 0; i < canvas->level()->width(); i++)
		{
			if(i) s << " ";
			s << canvas->level()->tile(i, j);
		}
		s << endl;
	}

	f.close();
	kdDebug() << "saved as: " << f.name() << endl;

	m_currentlevel = fn;
	m_levelmodified = false;
	setupMenus(false, true);
}

void TopLevel::sharelevel()
{
#ifdef HAVE_KNEWSTUFF
	int w, h;

	if((m_levelmodified) && (!m_delayedsharing))
	{
		int ret = KMessageBox::questionYesNo(this,
			i18n("The level has been modified, should it be saved first?"),
			i18n("Share level"));
		if(ret == KMessageBox::Yes)
		{
			m_delayedsharing = true;
			slotMenu(file_save);
			return;
		}
	}
	m_delayedsharing = false;

	KTempFile tf2(QString::null, ".png");
	QPixmap pix = canvas->backgroundPixmap();
	QImage im = pix.convertToImage();
	if(im.width() > im.height())
	{
		w = 64;
		h = 64 * im.height() / im.width();
	}
	else
	{
		h = 64;
		w = 64 * im.width() / im.height();
	}
	im = im.smoothScale(w, h);
	pix.convertFromImage(im);
	pix.save(tf2.name(), "PNG");

	KNewStuffGeneric *ns = new KNewStuffGeneric("kamikaze/level", this);
	ns->upload(m_currentlevel, tf2.name());
#endif
}

#ifdef HAVE_SPEEDBAR
void TopLevel::setupDialog(bool savemode, bool usermode)
{
	KURLBar *bar;
	QString globaldir, localdir, initdir;

	globaldir = locate("data", "kamikaze/levels/");
	localdir = locateLocal("data", "kamikaze/", true);
	if(usermode) initdir = localdir;
	else initdir = globaldir;

	dialog = new KFileDialog(initdir, i18n("*|Kamikaze Levels"), this, "kamikaze", true);
	bar = dialog->speedBar();
	if(bar)
	{
		bar->clear();
		bar->insertItem(KURL(globaldir), i18n("Installed"), true, "kamikaze");
		bar->insertItem(KURL(localdir), i18n("Own levels"), true, "kamikaze");
	}

	if(savemode)
	{
		dialog->setOperationMode(KFileDialog::Saving);
	}
}
#endif

void TopLevel::slotMenu(int id)
{
	int w, h;
	QString f;

	switch(id)
	{
		case file_new:
			createlevel();
			break;
		case file_save:
#ifdef HAVE_SPEEDBAR
			setupDialog(true, true);
			connect(dialog, SIGNAL(okClicked()), SLOT(slotSaveLevel()));
			dialog->show();
#else
			f = KFileDialog::getOpenFileName();
			if(f.isEmpty()) return;
			savelevel(f);
			if(m_delayedsharing) sharelevel();
#endif
			break;
		case file_open:
#ifdef HAVE_SPEEDBAR
			setupDialog(false, false);
			connect(dialog, SIGNAL(okClicked()), SLOT(slotOpenLevel()));
			dialog->show();
#else
			f = KFileDialog::getOpenFileName();
			if(!f.isEmpty()) newlevel(f);
#endif
			break;
		case file_share:
#ifdef HAVE_SPEEDBAR
			sharelevel();
#else
			sharelevel();
#endif
			break;
		case file_exit:
			close();
			break;
		case display_larger:
			scale(5);
			break;
		case display_smaller:
			scale(-5);
			break;
		case display_fullscreen:
			if(!canvas) return;
			if(!displaymenu->isItemChecked(display_fullscreen))
			{
				m_geometry = frameGeometry();
				m_tilesize = Resource::tilesize();
				m_isfullscreen = true;

				displaymenu->setItemChecked(display_fullscreen, true);
				w = kapp->desktop()->width() / (canvas->level()->width() + 1);
				h = kapp->desktop()->height() / (canvas->level()->height() + 1);
				Resource::setTilesize((w < h ? w : h));
				if(canvas->enabled()) canvas->setTheme(Resource::theme());
				setFixedSize(kapp->desktop()->width(), kapp->desktop()->height());
				showFullScreen();

				kapp->config()->setGroup("Preferences");
				kapp->config()->writeEntry("Fullscreen", 1);
				kapp->config()->sync();
			}
			else
			{
				m_isfullscreen = false;

				displaymenu->setItemChecked(display_fullscreen, false);
				Resource::setTilesize(m_tilesize);
				if(canvas->enabled()) canvas->setTheme(Resource::theme());
				scale(0);
				move(m_geometry.x(), m_geometry.y());
				showNormal();

				kapp->config()->setGroup("Preferences");
				kapp->config()->writeEntry("Fullscreen", 0);
				kapp->config()->sync();
			}
			break;


		case element_ground:
			m_element = Level::ground;
			break;
		case element_wall:
			m_element = Level::wall;
			break;
		case element_bridge:
			m_element = Level::bridge;
			break;
		case element_space:
			m_element = Level::space;
			break;
		case element_scree:
			m_element = Level::itemScree;
			break;
		case element_bomb:
			m_element = Level::itemBomb;
			break;
		case element_live:
			m_element = Level::itemLive;
			break;
		case element_power:
			m_element = Level::itemPower;
			break;
		case element_grail:
			m_element = Level::itemGrail;
			break;
		case element_speed:
			m_element = Level::itemSpeed;
			break;
		case element_invisible:
			m_element = Level::itemInvisible;
			break;
		case element_flash:
			m_element = Level::itemFlash;
			break;
	}
}

void TopLevel::setTheme(QString theme)
{
	if(canvas) canvas->setTheme(theme);
}

void TopLevel::mousePressEvent(QMouseEvent *e)
{
	if(!canvas) return;

	int x = e->x() / Resource::tilesize();
	int y = e->y() / Resource::tilesize();

	kdDebug() << "click: " << x << ", " << y << endl;

	canvas->level()->setTile(x, y - 1, m_element);
	canvas->setTheme(Resource::theme());

	m_levelmodified = true;
	setupMenus(true, true);
}

void TopLevel::keyPressEvent(QKeyEvent *e)
{
	switch(e->key())
	{
		case Qt::Key_Down:
			key(Playground::KeyDown);
			break;
		case Qt::Key_Up:
			key(Playground::KeyUp);
			break;
		case Qt::Key_Left:
			key(Playground::KeyLeft);
			break;
		case Qt::Key_Right:
			key(Playground::KeyRight);
			break;
		case Qt::Key_Minus:
			key(Playground::KeyZoomOut);
			break;
		case Qt::Key_Plus:
			key(Playground::KeyZoomIn);
			break;
		case Qt::Key_F:
			key(Playground::KeyFullscreen);
			break;
	}
}

#ifdef HAVE_SPEEDBAR

void TopLevel::slotOpenLevel()
{
	QString f = dialog->selectedFile();
	delete dialog;
	if(!f.isEmpty()) newlevel(f);
}

void TopLevel::slotSaveLevel()
{
	QString f = dialog->selectedFile();
	delete dialog;
	if(!f.isEmpty())
	{
		savelevel(f);
		if(m_delayedsharing) sharelevel();
	}
}

#endif

void TopLevel::setupMenus(bool save_enabled, bool share_enabled)
{
	filemenu->setItemEnabled(file_save, save_enabled);
#ifdef HAVE_KNEWSTUFF
	filemenu->setItemEnabled(file_share, share_enabled);
#endif
}

