#ifndef _QwSpriteField_Template
#define _QwSpriteField_Template   

#include "QwSpriteField.h"

template<class COORD>
QwPositionedSprite<COORD>::QwPositionedSprite(QwSpritePixmapSequence* seq) :
    myx(0),
    myy(0),
    frm(0),
    alt(0),
    images(seq)
{
    show();
    addToChunks();
}

template<class COORD>
QwPositionedSprite<COORD>::QwPositionedSprite() :
    myx(0),
    myy(0),
    frm(0),
    alt(0),
    images(0)
{
}

template<class COORD>
void QwPositionedSprite<COORD>::setSequence(QwSpritePixmapSequence* seq)
{
    bool vis=visible();
    if (vis && images) hide();
    images=seq;
    if (vis) show();
}

template<class COORD>
void QwPositionedSprite<COORD>::changeChunks()
{
    if (visible() && spritefield) {
        int chunksize=spritefield->chunkSize();
        for (int j=absY()/chunksize; j<=absY2()/chunksize; j++) {
            for (int i=absX()/chunksize; i<=absX2()/chunksize; i++) {
                spritefield->setChangedChunk(i,j);
            }
        }
    }
}

template<class COORD>
QwPositionedSprite<COORD>::~QwPositionedSprite()
{
    removeFromChunks();
}

template<class COORD>
void QwPositionedSprite<COORD>::frame(int f)
{
    moveTo(myx,myy,f);
}

template<class COORD>
void QwPositionedSprite<COORD>::x(COORD nx)
{
    moveTo(nx,myy);
}

template<class COORD>
void QwPositionedSprite<COORD>::y(COORD ny)
{
    moveTo(myx,ny);
}

template<class COORD>
void QwPositionedSprite<COORD>::moveBy(COORD dx, COORD dy)
{
    moveTo(myx+dx,myy+dy);
}

template<class COORD>
void QwPositionedSprite<COORD>::moveTo(COORD nx, COORD ny)
{
    moveTo(nx,ny,frm);
}

template<class COORD>
void QwPositionedSprite<COORD>::moveTo(COORD nx, COORD ny, int nf)
{
    if (myx!=nx || myy!=ny || frm!=nf) {
        if (nf==frm
        && (!spritefield ||
            spritefield->sameChunk(absX(),absY(),absX()-(int)myx+(int)nx,absY()-(int)myy+(int)ny)
            && spritefield->sameChunk(absX2(),absY2(),absX2()-(int)myx+(int)nx,absY2()-(int)myy+(int)ny)))
        {
            myx=nx;
            myy=ny;
            changeChunks();
        } else {
            removeFromChunks();
            myx=nx;
            myy=ny;
            frm=nf;
            addToChunks();
        }
    }
}

template<class COORD>
Pix QwPositionedSprite<COORD>::neighbourhood(int nframe) const
{ return neighbourhood(myx,myy,nframe); }

template<class COORD>
Pix QwPositionedSprite<COORD>::neighbourhood(COORD nx, COORD ny, int nframe) const
{ return QwVirtualSprite::neighbourhood((int)nx,(int)ny,image(nframe)); }

template<class COORD>
bool QwPositionedSprite<COORD>::wouldHit(QwSpriteFieldGraphic& other, COORD x, COORD y, int frame) const
{
    return QwVirtualSprite::wouldHit(other,(int)x,(int)y,image(frame));
}

template<class COORD>
int QwPositionedSprite<COORD>::rtti() const { return 2; }

template <class COORD>
QwMobilePositionedSprite<COORD>::QwMobilePositionedSprite(QwSpritePixmapSequence* s) :
    QwPositionedSprite<COORD>(s),
    bounds_action(Ignore),
    dx(0),dy(0)
{
    adoptSpritefieldBounds();
}

template <class COORD>
QwMobilePositionedSprite<COORD>::QwMobilePositionedSprite() :
    QwPositionedSprite<COORD>(),
    bounds_action(Ignore),
    dx(0),dy(0)
{
    adoptSpritefieldBounds();
}

template <class COORD>
void QwMobilePositionedSprite<COORD>::adoptSpritefieldBounds()
{
    if (spritefield) {
        bounds(0,0,spritefield->width()-1,spritefield->height()-1);
    } else {
        // Simple default so programmer can see the problem
        bounds(0,0,50,50);
    }
}

template <class COORD>
void QwMobilePositionedSprite<COORD>::bounds(COORD l, COORD t, COORD r, COORD b)
{
    b_left=l;
    b_top=t;
    b_right=r;
    b_bottom=b;
}

template <class COORD>
void QwMobilePositionedSprite<COORD>::setBoundsAction(int a)
{
    bounds_action=a;
}

template <class COORD>
bool QwMobilePositionedSprite<COORD>::outOfBounds()
{
    return (exact_x()<b_left) || (exact_x()>b_right)
        || (exact_y()<b_top) || (exact_y()>b_bottom);
}

template <class COORD>
COORD QwMobilePositionedSprite<COORD>::mod(COORD a,COORD m)
{
   return a-((int)(a/m))*a;
}

template <class COORD>
void QwMobilePositionedSprite<COORD>::moveTo(COORD x, COORD y, int frame)
{
   if (x<b_left) {
      switch (bounds_action) { 
         case Ignore: break;
         case Stop: 
            x=b_left; break;
         case Wrap:
            x=b_right-mod(b_left-x,b_right-b_left);
            break;
         case Bounce:
            x=b_left+mod(b_left-x,b_right-b_left);
            dx=-dx;
      }
   } else if (x>b_right) {
      switch (bounds_action) { 
         case Ignore: break;
         case Stop: 
            x=b_right; break;
         case Wrap:
            x=b_left+mod(x-b_right,b_right-b_left);
            break;
         case Bounce:
            x=b_right-mod(x-b_right,b_right-b_left);
            dx=-dx;
      }
   }

   if (y<b_top) {
      switch (bounds_action) { 
         case Ignore: break;
         case Stop: 
            y=b_top; break;
         case Wrap:
            y=b_bottom-mod(b_top-y,b_bottom-b_top);
            break;
         case Bounce: 
            y=b_top+mod(b_top-y,b_bottom-b_top);
            dy=-dy;
      }
   } else if (y>b_bottom) {
      switch (bounds_action) { 
         case Ignore: break;
         case Stop: 
            y=b_bottom; break;
         case Wrap:
            y=b_top+mod(y-b_bottom,b_bottom-b_top);
            break;
         case Bounce:
            y=b_bottom-mod(y-b_bottom,b_bottom-b_top);
            dy=-dy;
      }
   }

    QwPositionedSprite<COORD>::moveTo(x,y,frame);
}

template <class COORD>
void QwMobilePositionedSprite<COORD>::forward(COORD multiplier)
{
    QwPositionedSprite<COORD>::moveTo(exact_x()+multiplier*dx, exact_y()+multiplier*dy);
}

template <class COORD>
Pix QwMobilePositionedSprite<COORD>::forwardHits(COORD multiplier, int frme) const
{
    int ix = int(exact_x()+multiplier*dx);
    int iy = int(exact_y()+multiplier*dy);
    if (ix == x() && iy == y())
	return 0;
    return QwPositionedSprite<COORD>::neighbourhood((COORD)ix, (COORD)iy, frme);
}

template <class COORD>
Pix QwMobilePositionedSprite<COORD>::forwardHits(COORD multiplier) const
{
    int ix = int(exact_x()+multiplier*dx);
    int iy = int(exact_y()+multiplier*dy);
    if (ix == x() && iy == y())
	return 0;
    return QwPositionedSprite<COORD>::neighbourhood(ix, iy);
}

template <class COORD>
void QwMobilePositionedSprite<COORD>::forward(COORD multiplier, int frme)
{
    moveTo(exact_x()+multiplier*dx, exact_y()+multiplier*dy, frme);
}

#endif
