// ============================================================================
// File:               $File$
//
// Project:            
//
// Purpose:            
//
// Author:             Rammi
//
// Copyright Notice:   (c) 2008  Rammi (rammi@caff.de)
//
// Latest change:      $Date$
//
// History:	       $Log$
//=============================================================================
package de.caff.asteroid.rammi;

import de.caff.asteroid.*;
import de.caff.asteroid.analysis.DumpFile;
import de.caff.asteroid.analysis.FrameKeyInfo;
import de.caff.util.Tools;

import java.awt.*;
import java.awt.geom.Point2D;
import java.util.LinkedList;
import java.util.List;
import java.util.Locale;

/**
 */
public class Extract
  implements GameData
{
  private static final Point SHIP_POS = new Point(524, 524);
  private static class BulletLane
  {
    private final Point startDir;
    private Bullet lastFramesBullet;
    private Point firstDelta;
    private Point velocity;

    private BulletLane(Point startDir, Bullet bullet)
    {
      this.startDir = new Point(startDir);
      firstDelta = GameObject.getTorusDelta(bullet.getLocation(), SHIP_POS);
      lastFramesBullet = bullet;
      velocity = new Point();
    }

    public boolean addBullet(Bullet bullet)
    {
      lastFramesBullet = bullet;
      velocity.x += bullet.getVelocityX();
      velocity.y += bullet.getVelocityY();
      return bullet.getLifetime() == 8;
    }

    public Bullet getLastFramesBullet()
    {
      return lastFramesBullet;
    }

    public Point2D getVelocity()
    {
      return new Point2D.Double(velocity.getX()/8, velocity.getY()/8);
    }

    public Point getStartDir()
    {
      return startDir;
    }

    public Point getFirstDelta()
    {
      return firstDelta;
    }

    public boolean equals(Object o)
    {
      if (this == o) {
        return true;
      }
      if (o == null || getClass() != o.getClass()) {
        return false;
      }

      BulletLane that = (BulletLane)o;

      if (!firstDelta.equals(that.firstDelta)) {
        return false;
      }
      if (!startDir.equals(that.startDir)) {
        return false;
      }
      if (!velocity.equals(that.velocity)) {
        return false;
      }

      return true;
    }

    public int hashCode()
    {
      int result;
      result = startDir.hashCode();
      result = 31 * result + firstDelta.hashCode();
      result = 31 * result + velocity.hashCode();
      return result;
    }
  }


  public static void main(String[] args)
  {
    //readFile(args[0]);
    Locale.setDefault(Locale.US);
    BulletLane[] lanes = new BulletLane[256];
    for (int k = -256;  k <= 256;  ++k) {
      BulletLane result = readFile(String.format("dir-dump/dir.%d.dump", k));
      if (result == null) {
        System.err.println(String.format("%-3d: no result!", k));
      }
      else {
        int index = k;
        while (index < 0) {
          index += 256;
        }
        index = index % 256;
        if (lanes[index] == null) {
          lanes[index] = result;
        }
        else {
          if (!lanes[index].equals(result)) {
            System.err.println(String.format("%-3d: Mismatch!", k));
          }
        }
      }
    }
    for (BulletLane l: lanes) {
      System.out.println(String.format("new Direction(%d, %d, %1.3f, %1.3f, %d, %d),",
                                       l.getStartDir().x, l.getStartDir().y,
                                       l.getVelocity().getX(), l.getVelocity().getY(),
                                       l.getFirstDelta().x, l.getFirstDelta().y));
    }
  }

  private static BulletLane readFile(String filename)
  {
    try {
      DumpFile file = new DumpFile(filename);
      file.runPreparerDirectly(new SimpleVelocityPreparer());
      List<BulletLane> flying = new LinkedList<BulletLane>();
      Point startDir = null;
      BulletLane result = null;
      int count = 0;
      for (FrameKeyInfo info: file.getInfos()) {
        FrameInfo frameInfo = info.getFrameInfo();
        for (Bullet bullet: frameInfo.getBullets()) {
          if (bullet.getLifetime() <= 0  &&  startDir != null  &&
                  Tools.getDistance(bullet.getLocation(), SHIP_POS) < 25) {
            flying.add(new BulletLane(startDir, bullet));
            startDir = null;
          }
          else if (bullet.getLifetime() <= 8) {
            boolean found = false;
            for (BulletLane bl: flying) {
              if (bl.getLastFramesBullet().getLifetime() == bullet.getLifetime() - 1  &&
                      Tools.getLength(GameObject.getTorusDelta(bl.getLastFramesBullet().getLocation(),
                                                               bullet.getLocation())) <= 10) {
                Bullet last = bl.getLastFramesBullet();
                if (last.getLifetime() > 0  &&
                    Tools.getLength(GameObject.getTorusDelta(last.getNextLocation(),
                                                             bullet.getLocation())) > 4) {
                  continue;
                }
                if (bl.addBullet(bullet)) {
                  double angle = 180/Math.PI*Math.atan2(bl.getVelocity().getY(), bl.getVelocity().getX());
                  if (angle < 0) {
                    angle += 360;
                  }
                  /*
                  System.out.println(String.format("%3d: %3.1f, frame=%d, Start: %s, Velocity: %s, First: %s",
                                                   count++,
                                                   angle,
                                                   frameInfo.getCounter(),
                                                   bl.getStartDir(),
                                                   bl.getVelocity(),
                                                   bl.getFirstDelta()));
                  */
                  flying.remove(bl);
                  result = bl;
                }
                found = true;
                break;
              }
            }
            if (!found) {
              System.out.println("Not found: "+bullet+" in frame "+frameInfo.getIndex());
            }
          }
        }
        List<FrameKeyInfo.ButtonInfo> buttonList = info.getButtons();
        if (!buttonList.isEmpty()  &&
             (buttonList.get(0).getButtons().getKeys() & BUTTON_FIRE) != 0) {
          SpaceShip ship = frameInfo.getSpaceShip();
          if (ship != null) {
            if (startDir != null) {
              System.out.println("*** STARTDIR in frame "+frameInfo.getIndex());
            }
            startDir = ship.getDirection();
          }
        }
      }
      return result;
    } catch (Throwable e) {
      e.printStackTrace();
    }
    return null;
  }
}
