// ============================================================================
// 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;

import java.awt.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

/**
 *  Count out shoots.
 */
public class BulletCounter
        implements FrameListener
{
  /** The ships shoots as they are running. */
  private Map<Integer, Integer> shipBullets = new HashMap<Integer, Integer>();
  /** The ufo bullets as they are running. */
  private Map<Integer, Integer> ufoBullets  = new HashMap<Integer, Integer>();
  /** The position of the ship in the previous frame. */
  private Point shipPos;
  /** The direction of the ship in the previous frame. */
  private FrameInfo.Direction shipDirection;
  /** The position of the ufo in the previous frame. */
  private Point ufoPos;
  /** Bullets which don't live in the next frame */
  private int vanishingShipBullets;

  /**
   * Called each time a frame is received.
   * <p/>
   * <b>ATTENTION:</b> this is called from the communication thread!
   * Implementing classes must be aware of this and take care by synchronization or similar!
   *
   * @param frame the received frame
   */
  public void frameReceived(FrameInfo frame)
  {
    vanishingShipBullets = 0;
    Integer frameNr = frame.getIndex();
    for (Bullet bullet: frame.getBullets()) {
      Integer id = bullet.getIdentity();
      if (shipBullets.containsKey(id)) {
        shipBullets.put(id, frameNr);
        if (bullet.getLifetime() == Bullet.MAX_LIFETIME-1) {
          // todo: get exact lifetime
          ++vanishingShipBullets;
        }
        else {
          for (Asteroid ast: frame.getAsteroids()) {
            if (bullet.isHitting(ast, 0)) {
              ++vanishingShipBullets;
              break;
            }
          }
        }
      }
      else if (ufoBullets.containsKey(id)) {
        ufoBullets.put(id, frameNr);
      }
      else {
        // new bullet
        if (shipPos != null && Tools.getLength(bullet.getDelta(shipPos)) < Tools.getLength(shipDirection.getDisplacement()) + 3) {
          shipBullets.put(id, frameNr);
        }
        else if (ufoPos != null) {
          ufoBullets.put(id, frameNr);
        }
        else {
          //System.err.println("Warning: neither ship nor ufo bullet: "+bullet);
        }
      }
    }
    for (Integer id: new ArrayList<Integer>(shipBullets.keySet())) {
      if (shipBullets.get(id) != frameNr) { // deliberately using == instead of equals()
        shipBullets.remove(id);
      }
    }
    for (Integer id: new ArrayList<Integer>(ufoBullets.keySet())) {
      if (ufoBullets.get(id) != frameNr) { // deliberately using == instead of equals()
        ufoBullets.remove(id);
      }
    }
    SpaceShip ship = frame.getSpaceShip();
    if (ship != null) {
      shipPos = ship.getLocation();
    }
    else {
      shipPos = null;
    }
    Ufo ufo = frame.getUfo();
    if (ufo != null) {
      ufoPos = ufo.getLocation();
    }
    else {
      ufoPos = null;
    }
    shipDirection = frame.getNextShootingDirection();
  }

  public int getShipBulletCount()
  {
    return shipBullets.size();
  }

  public int getNextShipBulletCount()
  {
    return getShipBulletCount() - vanishingShipBullets;
  }

  /**
   *  Is a given bullet a ship bullet?
   *  @param bullet bullet
   *  @return is it a ship bullet?
   */
  public boolean isShipBullet(Bullet bullet)
  {
    return shipBullets.get(bullet.getIdentity()) != null;
  }

}
