=begin
/****************************************************************
**
** Implementation CannonField class, Qt tutorial 14
**
****************************************************************/
=end

include Math

class  CannonField < QWidget
attr_reader:angleChanged
attr_reader:forceChanged
attr_reader:hit
attr_reader:missed
attr_reader:canShoot

def initialize ( parent, name )
    super( parent, name )
    @hit = RSignal.new("")
    @missed = RSignal.new("")
    @angleChanged = RSignal.new("int")
    @forceChanged = RSignal.new("int")
    @canShoot = RSignal.new("bool")
    @ang = 45
    @f = 0
    @timerCount = 0
    @autoShootTimer = QTimer.new(self,"movement handler")
    connect( @autoShootTimer,QSIGNAL("timeout()"), self,"moveShot")
    @shoot_ang =0
    @shoot_f =0
    @target = QPoint.new(0,0)
    @gameEnded = false
    @barrelPressed = false
    setPalette( QPalette.new( QColor.new( 250, 250, 200) ) )
    @barrelRect = QRect.new(33, -4, 15, 8)
    @first_time = true
    newTarget()

    catchEvent
end


def setAngle( degrees )
    if ( degrees < 5 )
	degrees = 5
    elsif ( degrees > 70 )
	degrees = 70
    end
    if ( @ang == degrees )
	return
    end
    @ang = degrees
    repaint(cannonRect(),false)
    @angleChanged.sendWith( @ang )
end

def setForce( newton)
    if ( newton < 0 )
	newton = 0
    elsif ( @f == newton )
	return
    end
    @f = newton
    @forceChanged.sendWith( @f )
end

def shoot
    if ( isShooting() )
	return
    end
    @timerCount = 0
    @shoot_ang = @ang
    @shoot_f = @f
    @autoShootTimer.start( 50 )
    @canShoot.sendWith(false)
end

def newTarget
    if ( @first_time )
	@first_time = FALSE
	midnight = QTime.new( 0, 0, 0 )
	srand( midnight.secsTo(QTime::currentTime()) )
    end
    r = QRegion.new( targetRect() )
    @target = QPoint.new( 200 + rand(6400) % 190,
		     10  + rand(6400) % 255 )
    repaint( r.unite( QRegion.new(targetRect()) ) )
end

def setGameOver

    if ( @gameEnded )
	return
    end
    if ( isShooting() )
	@autoShootTimer.stop()
    end
    @gameEnded = TRUE
    repaint()
end

def restartGame

    if ( isShooting() )
	@autoShootTimer.stop()
    end
    @gameEnded = false
    repaint()
    @canShoot.sendWith( true )
end

def moveShot
    r = QRegion.new(shotRect())
    @timerCount = @timerCount + 1

    shotR = shotRect()
    if( shotR.intersects( targetRect()))
           @autoShootTimer.stop()
           @hit.send()
           @canShoot.sendWith(true)
    elsif ( shotR.x() > width() || shotR.y() > height() ||  shotR.intersects(barrierRect()) )
           @autoShootTimer.stop()
           @missed.send()
           canShoot.sendWith(true)
    else
	r = r.unite( QRegion.new( shotR ) )
    end
    repaint( r )
end


def mousePressEvent( e )

    if ( e.button() != LeftButton )
	return
    elsif ( barrelHit( e.pos() ) )
	@barrelPressed = true
    end
end


def mouseMoveEvent( e )

    if ( !@barrelPressed )
	return
    end
    pnt = e.pos()
    if ( pnt.x() <= 0 )
	pnt.setX( 1 )
    end
    if ( pnt.y() >= height() )
	pnt.setY( height() - 1 )
    end
    rad = atan2(rect().bottom().to_f - pnt.y(),  pnt.x())

    setAngle( ( rad * 180 / 3.14159265 ).round )
end


def mouseReleaseEvent( e )

    if ( e.button() == LeftButton )
	@barrelPressed = false
    end
end



def paintEvent( e )
    updateR = e.rect()
    if(@p.nil?)
	  @p = QPainter.new
	end
	@p.begin(self)

    if ( @gameEnded )
	@p.setPen( Qt::black )
	@p.setFont( QFont.new( "Courier", 48, QFont::Bold ) )
	@p.drawText( rect(), AlignCenter, "Game Over" )
    end

    if ( updateR.intersects( cannonRect() ) )
	paintCannon( @p )
    end
    if ( updateR.intersects( barrierRect() ) )
	paintBarrier( @p )
    end
    if ( @autoShootTimer.isActive() && updateR.intersects( shotRect() ) )
	paintShot( @p )
    end
    if ( !@gameEnded && updateR.intersects( targetRect()))
        paintTarget( @p )
    end
	@p.end
end

def paintShot( p )
    p.setBrush( Qt::black )
    p.setPen( Qt::NoPen )
    p.drawRect( shotRect() )
end

def paintTarget( p )
    p.setBrush( Qt::red )
    p.setPen( Qt::black )
    p.drawRect( targetRect() )
end

def paintBarrier( p )

    p.setBrush( Qt::yellow )
    p.setPen( Qt::black )
    p.drawRect( barrierRect() )
end


def paintCannon(p)
    cr = cannonRect()
    pix = QPixmap.new(cr.size())
    pix.fill(self,cr.topLeft())

    tmp = QPainter.new( pix )

    tmp.setBrush( Qt::blue )
    tmp.setPen( Qt::NoPen )

    tmp.translate( 0, pix.height() - 1 )
    tmp.drawPie( QRect.new(-35, -35, 70, 70), 0, 90*16 )
    tmp.rotate( -@ang )
    tmp.drawRect( QRect.new(33, -4, 15, 8) )
    tmp.end()

    p.drawPixmap(cr.topLeft(),pix)
end


def cannonRect
    r = QRect.new(0,0,50,50)
    r.moveBottomLeft(rect().bottomLeft())
    r
end

def shotRect
     gravity = 4

     time      = @timerCount / 4.0
     velocity  = @shoot_f
     radians   = @shoot_ang*3.14159265/180

     velx      = velocity*cos( radians )
     vely      = velocity*sin( radians )
     x0        = ( @barrelRect.right()  + 5 )*cos(radians)
     y0        = ( @barrelRect.right()  + 5 )*sin(radians)
     x         = x0 + velx*time
     y         = y0 + vely*time - 0.5*gravity*time*time

    r = QRect.new( 0, 0, 6, 6 )
    r.moveCenter( QPoint.new( x.round, height() - 1 - y.round ) )
    r
end


def barrierRect()

    return QRect.new( 145, height() - 100, 15, 100 )
end

def barrelHit( p )

    mtx = QWMatrix.new
    mtx.translate( 0, height() - 1 )
    mtx.rotate( -@ang )
    mtx = mtx.invert()
    return @barrelRect.contains( mtx.map(p) )
end


def targetRect()
    r = QRect.new( 0, 0, 20, 10 )
    r.moveCenter( QPoint.new(@target.x(),height() - 1 - @target.y()) )
    r
end

def isShooting()

    return @autoShootTimer.isActive()
end

def gameOver
    return @gameEnded
end

def sizePolicy()
    QSizePolicy.new( QSizePolicy::Expanding, QSizePolicy::Expanding )
end


end
