#include "desktop.h"
#include <kwm.h> 
#include <kdebug.h> 
#include <qpainter.h> 
#include <kapp.h> 
#include <stdio.h> 
#include "windowdrag.h" 

#define SCR2PAGER(x) x*width()/kapp->desktop()->width()
#define PAGER2SCR(x) x*kapp->desktop()->width()/width()

KPagerDesktop::KPagerDesktop(int desk, KWinModule *kwinmod, QWidget *parent)
  : QWidget(parent,"KPagerDesktop")
{
  deskNum=desk;
//  kdDebug() << deskNum << endl;
  kWinModule=kwinmod;
  isCurrentDesktop=false;

  setMouseTracking(TRUE);
  setAcceptDrops(TRUE);

}

KPagerDesktop::~KPagerDesktop()
{
}

void KPagerDesktop::init(void)
{
  fillWinList();
}

void KPagerDesktop::fillWinList()
{
  QValueList <WId> widlist(kWinModule->windows());
  QValueList<WId>::Iterator it;
  for( it=widlist.begin(); it!=widlist.end(); ++it)
    if (KWM::desktop(*it)==deskNum) winList.append(winData(*it,0L));
  
}


KPagerDesktop::WindowData *KPagerDesktop::winData(WId id, WindowData *wd)
{
  WindowData *w;
  if (wd) w=wd;
  else w=new WindowData;
  
  w->wid=id;
  w->rect=KWM::geometry(id);
  w->hilight=false;
  w->active=false;
  return w;
}

void KPagerDesktop::removeWin( WindowData *wd )
{
  delete wd;
  winList.remove(wd);
}

KPagerDesktop::WindowData *KPagerDesktop::findWinData(WId id)
{
  QListIterator<WindowData> it(winList);
  for( ; it.current(); ++it)
    if (it.current()->wid==id) return it.current();

  return 0L;
}

void KPagerDesktop::mouseMoveEvent(QMouseEvent *ev)
{
  WindowData *wd=windowAtPosition(ev->pos()); 
  QListIterator<WindowData> it(winList);
  for( ; it.current(); ++it) it.current()->hilight=false;
  if (wd) wd->hilight=true;

  /*
   * XXX This shouldn't update always, but just when changing
   * the highlighted window
   */
  update();
}

void KPagerDesktop::mousePressEvent(QMouseEvent *ev)
{
  if (ev->button()==LeftButton) emit deskChangeRequest(deskNum);
  else if (ev->button()==MidButton) startDrag(ev->pos());
  else if (ev->button()==RightButton) emit showPopupMenu(0,mapToGlobal(ev->pos()));
}



void KPagerDesktop::scr2Pager(QRect *r)
{
  QRect tmp(*r);
  r->setRect(deskX()+tmp.x()*deskWidth()/kapp->desktop()->width(),
            deskY()+tmp.y()*deskHeight()/kapp->desktop()->height(),
            tmp.width()*deskWidth()/kapp->desktop()->width(),
            tmp.height()*deskHeight()/kapp->desktop()->height());
}

void KPagerDesktop::pager2Scr(int *x,int *y)
{
  *x=(*x-deskX())*(kapp->desktop()->width())/deskWidth();
  *y=(*y-deskY())*(kapp->desktop()->height())/deskHeight();
}

void KPagerDesktop::scr2Pager(QPoint *)
{
}
  
void KPagerDesktop::scr2Pager(int *,int *)
{
}

KPagerDesktop::WindowData *KPagerDesktop::windowAtPosition (const QPoint &p, 
    QPoint *internalpos)
{
  QListIterator<WindowData> it(winList);
  QRect r;
  for( it.toLast() ; it.current() ; --it)
  {
    r=it.current()->rect;
    scr2Pager(&r);
    if (r.contains(p)) 
    {
      if (internalpos)
      {
	internalpos->setX(p.x()-r.x());
	internalpos->setY(p.y()-r.y());
      }
      return it.current();
    }
  }
   
  return 0L;
}

void KPagerDesktop::setCurrentDesktop(bool current)
{
  isCurrentDesktop=current;
  update();
}

void KPagerDesktop::windowChange( WId id )
{
  //kdDebug() << "KPagerDesktop::windowChange" << endl;
  WindowData *wd=findWinData(id);
  if (wd) // It's on this desktop
  {
    removeWin(wd);
    if (KWM::desktop(id)==deskNum) winList.append(winData(id));
    update();
  }
  else if (KWM::desktop(id)==deskNum)  //XXX || isSticky ??
  { // It's not on this desktop, but it's just been moved
    winList.append(winData(id));
    update(); 
  }
}

/*
 * --------------- paint related methods -----------------------
 */

void KPagerDesktop::paintEvent(QPaintEvent *)
{
  QPixmap pixmap(width(),height());
  QPainter p;
  p.begin(&pixmap);
  p.setFont(font());

//  kdDebug() << "paintEvent (" << deskNum << ")" << endl;
  p.fillRect(rect(), colorGroup().brush(QColorGroup::Dark));
  
  p.setPen(Qt::black);
  p.drawRect(rect());
  if (isCurrentDesktop)
     p.setPen(Qt::yellow);
  else 
     p.setPen(QColorGroup::Base);
  p.drawRect(rect());
  p.setPen(Qt::black);

  QListIterator<WindowData> it(winList);
  QPixmap *window;
  QPoint pos;
  for( ; it.current(); ++it)
  {
    window=paintWindow(it.current(),&pos);
    p.drawPixmap(pos.x(),pos.y(),*window);
    delete window;
  }
  p.end();

  p.begin(this);
  p.drawPixmap(0,0,pixmap);
  p.end();
    
}

QPixmap *KPagerDesktop::paintWindow(const WindowData *wd, QPoint *pos)
{
  QRect r(wd->rect);
  scr2Pager(&r);
  QPixmap *window=new QPixmap(r.width(),r.height());
  if (window->isNull()) return window;

  QPainter paint;
  paint.begin(window);
  paint.fillRect(0,0,r.width(),r.height(),
      colorGroup().brush(QColorGroup::Midlight));

  if (!wd->hilight)
    paint.drawRect(0,0,r.width(),r.height());
  else
  {
    paint.setPen(Qt::white);
    paint.drawRect(0,0,r.width(),r.height());
    paint.setPen(Qt::black);
  }
  paint.end();

  /**
   * Now we set pos to be the up-left corner
   */
  if (pos)
  {
    pos->setX(r.x());
    pos->setY(r.y());
  } 
  return window;
}

/*
 * --------------- Drag and Drop related methods -----------------------
 */

void KPagerDesktop::startDrag(const QPoint &p)
{
  QPoint dragpos,windowpos;
  WindowData *wd=windowAtPosition(p,&dragpos);
  QPixmap *pixmap=paintWindow(wd,&windowpos);

  int deltax=dragpos.x();
  int deltay=dragpos.y();
  windowDrag *wdrag= new windowDrag(wd->wid,deltax,deltay,deskNum,this);
  wdrag->setPixmap(*pixmap,QPoint(deltax,deltay));
  delete pixmap;
  wdrag->dragCopy();
}

void KPagerDesktop::dragEnterEvent(QDragEnterEvent *ev)
{
  if (windowDrag::canDecode( ev )) ev->accept();
}                                                                                                   

void KPagerDesktop::dragMoveEvent(QDragMoveEvent *)
{
 // TODO Moving the window while dragging would be cool, wouldn't it ?
}

void KPagerDesktop::dropEvent(QDropEvent *ev)
{
  WId w=0;
  int deltax,deltay;
  int origdesk;
  if (!windowDrag::decode(ev,w,deltax,deltay,origdesk)) return;

  int x=ev->pos().x()-deltax;
  int y=ev->pos().y()-deltay;
  /*
   * x and y now contain the position (in local coordinates) which
   * has the origin of the window
   */
  pager2Scr(&x,&y);

  kdDebug() << "moving window " << w << "d from " << origdesk << " to " << deskNum << "\n" << endl;
  if (deskNum==0)
  {
    /*
     * The next line moves the window to the active desktop. This is done
     * because in other case, kwm raises the window when it's in a semi
     * changed state and doesn't work well with kpager. Let's see how well
     * KWin behaves.
     * if (activedesktop!=KWM::desktop(w)) 
     *	KWM::moveToDesktop(w,activedesktop);
     */
    KWM::setSticky(w,true);
  }
  else
  {
    if (origdesk==0) KWM::setSticky(w,false);
    /*
     * Remember the problem with KWM when unstickyng and moving a window
     * at the same time.
     */
    KWM::moveToDesktop(w,deskNum);
  }

  QPoint p(x,y);
  KWM::move(w,p);
    
}
