/**
 * 
 */
package ui.view;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;

import javax.swing.JPanel;
import javax.swing.Timer;

import classes.HolonBody;
import classes.SubNet;
import ui.controller.Control;
import ui.model.Model;

/**
 * This class shows the holon view
 * 
 * @author Gruppe14
 *
 */
public class HolonCanvas extends JPanel implements ActionListener {
	private static final long serialVersionUID = 1L;
	// edge Object Start Point
	private Model model;
	private final Control controller;
	Graphics2D g2; // For Painting
	private int N;
	private ArrayList<HolonBody> bodies;
	private Timer timer = new Timer(33, this);
	private Dimension center;
	private ArrayList<SubNet> subnets;
	private int rx, ry;

	/**
	 * Constructor.
	 * 
	 * @param mod
	 *            the Model
	 * @param control
	 *            the Controller
	 */
	public HolonCanvas(Model mod, Control control) {
		this.controller = control;
		this.model = mod;
		subnets = controller.getSimManager().getSubNets();
		N = subnets.size();
		bodies = new ArrayList<>();
		calcCenter();
		timer.start();
	}

	public void paintComponent(Graphics g) {
		super.paintComponent(g);
		if (!controller.getSimManager().getSubNets().equals(subnets)) {
			subnets = controller.getSimManager().getSubNets();
			N = subnets.size();
			N += 1;
			bodies = new ArrayList<>();
			startthebodies(N);
		}
		for (int i = 0; i < N; i++) {
			g.setColor(bodies.get(i).color);
			if (i != 0) {
				g.fillOval(bodies.get(i).rx, bodies.get(i).ry, subnets.get(i - 1).getObjects().size() * 8,
						subnets.get(i - 1).getObjects().size() * 8);
			} else
				g.fillOval(bodies.get(0).rx, bodies.get(0).ry, 0, 0);
		}
		addforces(N);
	}

	// Initialize N bodies with random positions
	public void startthebodies(int N) {
		double solarmass = 1.98892e30;
		calcCenter();
		// the central mass
		bodies.add(0, new HolonBody(center.width, center.height, 0, 0, 1e6 * solarmass, new Color(0, 0, 0)));
		for (int i = 0; i < N - 1; i++) {
			int px = (int) (Math.random() * this.getWidth());
			int py = (int) (Math.random() * this.getHeight());

			double mass = (subnets.get(i).getObjects().size()) / 10 * solarmass * 10 + 1e20;
			Color color = model.getSubNetColors().get(i);
			bodies.add(new HolonBody(px, py, 0, 0, mass, color));
		}
	}

	// reset the forces, then add all the new forces
	public void addforces(int N) {
		for (int i = 0; i < N; i++) {
			bodies.get(i).resetForce();

			for (int j = 0; j < N; j++) {
				if (i != j)
					bodies.get(i).addForce(bodies.get(j));
			}
		}
		// loop again and update the bodies using timestep dt
		for (int i = 1; i < N; i++) {
			rx = bodies.get(i).rx;
			ry = bodies.get(i).ry;
			bodies.get(i).update(1e-9);
			if (checkCollison(i)) {
				bodies.get(i).rx = rx;
				bodies.get(i).ry = ry;
				bodies.get(i).vx = 0;
				bodies.get(i).vy = 0;
			}
		}
	}

	// check if body would collide with any other body
	private boolean checkCollison(int i) {
		boolean collision = false;
		int r1 = (subnets.get(i - 1).getObjects().size() * 8) / 2;
		int r2 = 1;
		for (int j = 0; j < N; j++) {
			if (j != i) {
				int dist = (int) (Math.pow(rx - bodies.get(j).rx, 2) + Math.pow(ry - bodies.get(j).ry, 2));
				if (j != 0)
					r2 = (subnets.get(j - 1).getObjects().size() * 8) / 2;

				if (Math.pow(r2 - r1, 2) <= dist && dist <= Math.pow(r2 + r1, 2)) {
					collision = true;
				}
			}
		}
		return collision;
	}

	@Override
	public void actionPerformed(ActionEvent arg0) {
		repaint();
	}

	// calculate center of canvas for center gravity
	public void calcCenter() {
		center = this.getSize();
		center.height /= 2;
		center.width /= 2;
	}

}
