/*
 * (C) Antonio Larrosa Jimenez <larrosa@kde.org> KDE artistic license.
 * (C) Daniel M. Duley (mosfet@kde.org) KDE artistic license.
 */
#include <qpainter.h>
#include <qdrawutil.h>
#include <qtooltip.h>
#include <qpopupmenu.h>
#include <qcursor.h>

#include <kconfig.h>
#include <kwin.h>
#include <kwinmodule.h>
#include <kapp.h>
#include <kglobal.h>
#include <klocale.h>
#include <kprocess.h>
#include <dcopclient.h>
#include <kwinmodule.h>
#include <klibloader.h>
#include <kaction.h>
#include <kdebug.h>
#include "pixmap/desktoppixmap.h"
#include "icon/desktopicon.h"

#include "pagerapplet.h"
#include "pagerapplet.moc"

KWinModule *kwin_module;

extern "C"
{
  InternalApplet* init(QWidget *parent, KWinModule *module)
  {
    kwin_module = module;
	KGlobal::locale()->insertCatalogue("kpagerapplet");
    return new KPager(parent, "kpagerapplet");
  }
}

KPager::KPager(QWidget *parent, const char *name)
  : InternalApplet(parent, name)
{
  curDesk = KWin::currentDesktop();
  mainlayout = 0;
  layout = 0;
  viewMode=DesktopPlain;
  allocateDesktops();

  /*
  * TODO Someone should test the signal windowChange, 
  * as it doesn't seem to be emitted
  * (David): wrong, I get lots of debug output showing it does...
  */
  connect(kwin_module, SIGNAL(windowChange(WId)), SLOT(test(WId))); 
  
  connect(kwin_module, SIGNAL(desktopChange(int)), SLOT(slotSetDesktop(int)));
  connect(kwin_module, SIGNAL(desktopNumberChange(int)),
          SLOT(slotSetDesktopCount(int)));

  KConfig *config = KGlobal::config();
  config->setGroup("kpager");
  QFont defFont("Helvetica", 10, QFont::Bold);
  defFont = config->readFontEntry("Font", &defFont);
  setFontPropagation(AllChildren);
  setFont(defFont);
  setActions(About | Help | Preferences);
}

void KPager::about()
{
  // TODO
}

void KPager::help()
{
  //kapp->invokeHelp();
}

void KPager::preferences()
{
  // TODO : Implement a real preferences dialog.
  showPopupMenu(0, QCursor::pos());
}

int KPager::isDesktopMode() const
{
 return (viewMode>1);
}

void KPager::slotSetDesktop(int desktop)
{
  if(KWin::numberOfDesktops() > static_cast<int>(dskList.count()))
    slotSetDesktopCount(desktop);
  if (dskList[curDesk-1]->inherits("QButton")) 
    	((QButton *)dskList[curDesk-1])->setDown(false);
  else
  if (dskList[curDesk-1]->inherits("KPagerDesktop")) 
    	((KPagerDesktop *)dskList[curDesk-1])->setCurrentDesktop(false);
  
  curDesk = desktop;
  if (dskList[curDesk-1]->inherits("QButton")) 
	((QButton *)dskList[curDesk-1])->setDown(true);
  else
  if (dskList[curDesk-1]->inherits("KPagerDesktop")) 
    	((KPagerDesktop *)dskList[curDesk-1])->setCurrentDesktop(true);
}

void KPager::slotButtonClicked(int desk)
{
//  if(desk != curDesk) // clicked the current desktop
//    btnList[curDesk-1]->setDown(true);
//  else
    KWin::setCurrentDesktop( desk );
}

int KPager::widthForHeight(int h)
{
  int deskNum = KWin::numberOfDesktops();
  int deskHalf = deskNum/2;

  if(h <= 32)
    return deskNum*(h) + 10;
  else
    return deskHalf*((h)/2) + 10;
}

int KPager::heightForWidth(int w)
{
  int deskNum = KWin::numberOfDesktops();
  int deskHalf = deskNum/2;

  if(w <= 32)
    return deskNum*(w) + 10;
  else
    return deskHalf*((w)/2) + 10;
}

void KPager::resizeEvent(QResizeEvent*)
{
  delete mainlayout;

  int deskNum = KWin::numberOfDesktops();
  int deskHalf = deskNum/2;
  bool horiz = orientation() == Horizontal;
  bool small = (horiz && height() <=32) || (!horiz && width() <=32);

  QWidget *dsk;

  if(horiz)
    {
      mainlayout = new QHBoxLayout(this, 0);

      if (small)
        layout = new QGridLayout(1, deskNum, 0);
      else
        layout = new QGridLayout(2, deskHalf, 0);
    }
  else
    {
      mainlayout = new QVBoxLayout(this, 0);

      if (small)
        layout = new QGridLayout(deskNum, 1, 0);
      else
        layout = new QGridLayout(deskHalf, 2, 0);
    }
  if (isDesktopMode()) layout->setSpacing(1);
  
  mainlayout->addLayout(layout, 1);
  
  int c = 0, i=0;

  if (small)
    {
      while(c <  deskNum){
        dsk = dskList[c];
        if(horiz)
          layout->addWidget(dsk, 0, c);
        else
          layout->addWidget(dsk, c, 0);
        ++c;
      }
    }
  else
    {
      while(c <  deskHalf){
        dsk = dskList[i];
        if(horiz)
          layout->addWidget(dsk, 0, c);
        else
          layout->addWidget(dsk, c, 0);
        ++i;
        dsk = dskList[i];
        if(horiz)
          layout->addWidget(dsk, 1, c);
        else
          layout->addWidget(dsk, c, 1);
        ++c, ++i;
      }
    }
  mainlayout->activate();
  layout->activate();
  updateGeometry();

  if(KWin::numberOfDesktops() > 1){
    if(!isVisible())
      show();
  }
  else
    hide();
}

QWidget *KPager::desktopFactory(int desktopNumber)
{
  QWidget *r=0L;
  switch (viewMode)
  {
    case (ButtonNumber):
    case (ButtonName):
      { 
	KMiniPagerButton *btn;
	btn = new KMiniPagerButton(desktopNumber, this);
	btn->setDown(desktopNumber == KWin::currentDesktop());
	// fix this once kwin supports names
	//QToolTip::add(btn, i18n("Desktop: ") + KWin::desktopName(desktopNumber));
	QToolTip::add(btn, i18n("Desktop: ") + QString::number(desktopNumber));

	r=btn;
      } break;
    case (DesktopPlain):
    case (DesktopSimple):
      /*
       * The difference between Plain and Simple is that Simple does set the
       * background to be the same than the real one
       */
      {
	KPagerDesktop *dsk=new KPagerDesktop(desktopNumber,kwin_module,this);
	dsk->init();
	r=dsk;
      } break;
    case (DesktopIcon):
      {
	KLibLoader::self()->library("libkpagericon");
	KPagerDesktopIcon *dsk=new KPagerDesktopIcon(desktopNumber,
	    					kwin_module,this);

	dsk->init();
	r=dsk;
      } break;
    case (DesktopPixmap):
      {
	KLibLoader::self()->library("libkpagerpixmap");
	KPagerDesktopPixmap *dsk=new KPagerDesktopPixmap(desktopNumber,
	    					kwin_module,this);

	dsk->init();
	r=dsk;
      } break;
  } 
  

  if (isDesktopMode())
  {
     connect(kwin_module, SIGNAL(windowChange(WId)), r, SLOT(windowChange(WId)));
     kdDebug() << "windowChange signal connected" << endl;;
  }

  return r;
}

void KPager::allocateDesktops()
{
  int i;
  int deskNum = KWin::numberOfDesktops();
  QWidget *dsk;
  for(i=1; i <= deskNum; ++i)
  {
    dsk = desktopFactory(i);
    dsk->show();
    dskList.append(dsk);
    connect(dsk, SIGNAL(deskChangeRequest(int)), SLOT(slotButtonClicked(int)));
    connect(dsk, SIGNAL(showPopupMenu(WId,QPoint)),
	SLOT(showPopupMenu(WId,QPoint)));  
  }
}

void KPager::slotSetDesktopCount(int)
{
  QValueList<QWidget*>::Iterator it;
  for(it=dskList.begin(); it != dskList.end(); ++it)
    delete (KMiniPagerButton *)(*it);
    
  dskList.clear();
  allocateDesktops();
  curDesk = KWin::currentDesktop();
  resizeEvent(0); // TODO Fix these tries to get the layout working
  updateLayout();
}

void KPager::showPopupMenu(WId /*wid*/, QPoint pos)
{
  QPopupMenu *moptions=new QPopupMenu(this);
  KSelectAction *views=new KSelectAction(i18n("View Mode"),0,this);
  QStringList strlist;
  strlist.append(i18n("Desktop Number"));
  strlist.append(i18n("Desktop Name"));
  strlist.append(i18n("Plain View"));
  strlist.append(i18n("Simple View"));
  strlist.append(i18n("Icon View"));
  strlist.append(i18n("Pixmap View"));
  views->setItems(strlist);
  connect(views, SIGNAL(activated(int)), this, SLOT(setViewMode(int)));
  
  views->plug(moptions);
  
  moptions->exec(pos);  
}

void KPager::setViewMode(int i)
{
  viewMode=(ViewMode) i;
  slotSetDesktopCount(0);
}

void KPager::test(WId)
{
  //kdDebug() << "here, KPager::test, windowChanged" << endl;
}

