/*
Copyright (C) 2005 David Green <green@couchpotato.net>
All Rights Reserved.

This file is part of Aelfengard.

Aelfengard is proprietary software. You may not redistribute it without
prior written permission from the copyright holder.
*/

package common.gameevent;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.LinkedHashMap;

import javax.swing.Timer;

import common.PubGroupMember;
import common.ui.GameClient;

public class GroupGameEvent extends GameEvent {

    // was having incompatible version error
    private static final long serialVersionUID = 0L;
    
    private static final LinkedHashMap<Integer,PubGroupMember> arrowMap = new LinkedHashMap<Integer,PubGroupMember>();
    private static final Timer timer = new Timer(50, new ActionListener() {
        public void actionPerformed(ActionEvent e) {
            PubGroupMember[] players = new PubGroupMember[arrowMap.size()];
            if (players.length == 0) {
                timer.stop();
                return;
            }
            arrowMap.values().toArray(players);
            long now = System.currentTimeMillis();
            for (int i = 0; i < players.length; i++) {
                // update arrow directions
                if (players[i].removeTime <= now) {
                    players[i].lastArrowDirection = players[i].direction;
                    arrowMap.remove(players[i].id);
                }
                else {
                    double amtDone = now - players[i].lastArrowUpdate;
                    double amtTotal = players[i].removeTime - players[i].lastArrowUpdate;
                    double pctDone = amtDone / amtTotal;
                    double diff;
                    boolean doneWithFirst = false;
                    while (true) {
                        diff = players[i].direction - players[i].lastArrowDirection;
                        if (diff > Math.PI && !doneWithFirst) {
                            players[i].lastArrowDirection += 2 * Math.PI;
                            continue;
                        }
                        doneWithFirst = true; // to ensure no infinite loops from rounding probs
                        if (diff < - Math.PI) {
                            players[i].lastArrowDirection -= 2 * Math.PI;
                            continue;
                        }
                        break;
                    }
                    diff *= pctDone;
                    players[i].lastArrowDirection += diff;
                }
            }
            GameClient.getGroupList().modify(players);
        }
    });
    
    public static enum EventType {
        ADD, MODIFY, REMOVE, CLEAR;
    }
    
    private final EventType type;
    private final PubGroupMember[] players;
    
    public GroupGameEvent(EventType type, PubGroupMember... players) {
        this.type = type;
        this.players = players;
    }
    
    public void run() {
        switch (type) {
            case ADD: {
                for (int i = 0; i < players.length; i++) {
                    players[i].lastArrowDirection = players[i].direction;
                    arrowMap.remove(players[i].id); // in case it's in there?
                }
                GameClient.getGroupList().add(players);
                break;
            }
            case MODIFY: {
                long now = System.currentTimeMillis();
                for (int i = 0; i < players.length; i++) {
                    if (players[i].withYou) {
                        arrowMap.remove(players[i].id); // no need to draw arrow anymore
                    }
                    else {
                        players[i].removeTime = now + 2000;
                        PubGroupMember oldPlayer = arrowMap.get(players[i].id);
                        if (oldPlayer == null) {
                            oldPlayer = GameClient.getGroupList().get(players[i]);
                        }
                        if (oldPlayer != null && !oldPlayer.withYou) {
                            // New remove time is average of old and new remove times
                            players[i].lastArrowDirection = oldPlayer.lastArrowDirection;
                            players[i].lastArrowUpdate = now;
                            arrowMap.put(players[i].id, players[i]);
                            if (!timer.isRunning()) {
                                timer.start();
                            }
                        }
                        else {
                            players[i].lastArrowDirection = players[i].direction;
                        }
                    }
                }
                GameClient.getGroupList().modify(players);
                break;
            }
            case REMOVE: {
                for (int i = 0; i < players.length; i++) {
                    arrowMap.remove(players[i].id);
                }
                GameClient.getGroupList().remove(players); break;
            }
            case CLEAR: {
                arrowMap.clear();
                for (int i = 0; i < players.length; i++) {
                    players[i].lastArrowDirection = players[i].direction;
                }
                GameClient.getGroupList().clear(players); break;
            }
        }
    }

}