// ============================================================================
// File:               $File$
//
// Project:            
//
// Purpose:            
//
// Author:             Rammi
//
// Copyright Notice:   (c) 2008  Rammi (rammi@caff.de)
//                     This code is in the public domain.
//                     Use at own risk.
//                     No guarantees given.
//
// Latest change:      $Date$
//
// History:	       $Log$
//=============================================================================
package de.caff.asteroid.rammi;

import de.caff.asteroid.*;
import de.caff.util.Tools;

/**
 */
class DefaultScorer
        implements Scorer
{
  static final int    DANGER_FRAMES = 138;
  static final int    DANGER_SCORE  = 174;
  static final double NEARNESS_BASE = 762;
  static final double ROTATION_BASE = 2;
  private static final int REACH_SQUARED = (int)Tools.square(Bullet.MIN_LIFETIME * Bullet.BULLET_SPEED);

  private double dangerFrames;
  private double dangerScore;
  private double nearnessBase;
  private double rotationBase;

  public DefaultScorer(double dangerFrames, double dangerScore, double nearnessBase, double rotationBase)
  {
    this.dangerFrames = dangerFrames;
    this.dangerScore  = dangerScore * dangerFrames * dangerFrames;
    this.nearnessBase = nearnessBase * nearnessBase;
    this.rotationBase = rotationBase;
  }

  public DefaultScorer()
  {
    this(DANGER_FRAMES, DANGER_SCORE, NEARNESS_BASE, ROTATION_BASE);
  }

  public double getUfoScore(SpaceShip ship, AbstractBasicAsteroidPlayer.RotateAndWait raw, Ufo ufo, int shots,
                            int numTargets)
  {
    double score = 0;
    double deltaSquared = getDeltaSquared(ship, ufo);
    if (deltaSquared < REACH_SQUARED) {
      score += ufo.getScore();
      score += getDangerScore(ship, ufo);
      score += getNearnessScore(deltaSquared);
      score += getRotationScore(ship, raw, ufo, numTargets);
    }
    return score;
  }

  public double getAsteroidScore(SpaceShip ship, AbstractBasicAsteroidPlayer.RotateAndWait raw, Asteroid ast, int shots,
                                 int numTargets)
  {
    double score = 0;
    double deltaSquared = getDeltaSquared(ship, ast);
    if (deltaSquared < REACH_SQUARED) {
      score += getDangerScore(ship, ast);
      score += getNearnessScore(deltaSquared);
      score += getRotationScore(ship, raw, ast, numTargets);
      if (false) {
        switch (ast.getScore()) {
        case Asteroid.SCORE_LARGE_ASTEROID:
          score += shots;
          break;
        case Asteroid.SCORE_MIDDLE_ASTEROID:
          score += Math.min(shots, 3);
          break;
        case Asteroid.SCORE_SMALL_ASTEROID:
          if (shots <= 2) {
            score += 4;
          }
          break;
        }
      }
    }
    return score;
  }

  private static double getDeltaSquared(SpaceShip ship, MovingGameObject object)
  {
    double deltaX = GameObject.normalizeDeltaX(object.getCorrectedX() - ship.getCorrectedX());
    double deltaY = GameObject.normalizeDeltaY(object.getCorrectedY() - ship.getCorrectedY());
    return deltaX*deltaX + deltaY*deltaY;
  }

  private double getDangerScore(SpaceShip ship, MovingGameObject object)
  {
    int frames = AsteroidPlayer.getFramesUntilCollision(ship, object, (int)dangerFrames);
    if (frames > 0  &&  frames < dangerFrames) {
      return dangerScore/(frames * frames);
    }
    return 0.0;
  }

  private double getNearnessScore(double deltaSquared)
  {
    return nearnessBase / deltaSquared;
  }

  private double getRotationScore(SpaceShip ship, AbstractBasicAsteroidPlayer.RotateAndWait raw, MovingGameObject object, int numTargets)
  {
    if (rotationBase != 0  &&  raw != null  /*&&  numTargets <= 4*/) {
      /*
      Point2D shootDir = AbstractBasicAsteroidPlayer.getShootDirection(ship, object);
      if (shootDir != null) {
        double shootAngle = Math.atan2(shootDir.getY(), shootDir.getX());
        Point2D shipDir = direction.getBulletVelocity();
        double shipAngle = Math.atan2(shipDir.getY(), shipDir.getX());
        double deltaAngle = Math.abs(shootAngle - shipAngle);
        if (deltaAngle > Math.PI) {
          deltaAngle = Math.PI - deltaAngle;
        }
        int steps = (int)(deltaAngle/AbstractBasicAsteroidPlayer.ROT_ANGLE);
        return rotationBase/(steps + 1)/numTargets;
      } */
      return rotationBase/(Math.abs(raw.getHitFrames())+1);
    }
    return 0.0;
  }
}
