/*
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.ui;

import java.util.ArrayList;
import java.util.HashMap;

import javax.swing.table.AbstractTableModel;

import common.PubEntity;
import common.gameevent.StatGameEvent.StatType;

/**
 * Table model representing the room list or the group list.
 * 
 * @author David Green <green@couchpotato.net>
 *
 * @param <E> the type of pubentity that this model will contain
 */
public class EntityTableModel<E extends PubEntity> extends AbstractTableModel {

    private static final long serialVersionUID = 4048796753803491120L;
    
    // stores the actual entities in order
    private final ArrayList<E> list = new ArrayList<E>();
    
    // map of id -> entity
    private final HashMap<Integer,E> map = new HashMap<Integer,E>();
    
    // the table model's name (displayed in column header)
    private final String name;
    
    /**
     * Creates a new entity table model.
     * @param name the table model's name (displayed in column header)
     */
    public EntityTableModel(String name) {
        this.name = name;
    }
    
    public int getRowCount() {
        return list.size();
    }

    public int getColumnCount() {
        return 1; // everything goes in 1 column
    }

    @Override
    public String getColumnName(int columnIndex) {
        return name; // acts as a 'title' for the list
    }

    public Object getValueAt(int rowIndex, int columnIndex) {
        return list.get(rowIndex);
    }

    /**
     * Clears the list, replacing it with the specified entities.
     * @param entities the new entities in the list
     */
    public void clear(E... entities) {
        list.clear();
        map.clear();
        fireTableDataChanged();
        add(entities);
    }

    /**
     * Adds the specified entities to the list.
     * @param entities the entities to add
     */
    public void add(E... entities) {
        if (entities.length == 0) {
            return;
        }
        int size = list.size();
        for (int i = 0; i < entities.length; i++) {
            if (entities[i] != null) {
                list.add(entities[i]);
                map.put(entities[i].id, entities[i]);
            }
        }
        int newSize = list.size();
        if (newSize != size) {
            fireTableRowsInserted(size, newSize - 1);
        }
    }

    /**
     * Removes the specfied entities from the list.
     * @param entities the entities to remove
     */
    public void remove(E... entities) {
        for (int i = 0; i < entities.length; i++) {
            int idx = list.indexOf(entities[i]);
            if (idx < 0) {
                continue;
            }
            list.remove(idx);
            map.remove(entities[i].id);
            fireTableRowsDeleted(idx, idx);
        }
    }

    /**
     * Modifies the specified entities in the list.
     * @param entities the entities to modify
     */
    public void modify(E... entities) {
        for (int i = 0; i < entities.length; i++) {
            int idx = list.indexOf(entities[i]);
            list.set(idx, entities[i]);
            map.put(entities[i].id, entities[i]);
            fireTableRowsUpdated(idx, idx);
        }
    }
    
    /**
     * Looks up the specified entity in the list, and returns it if it exists.
     * @param entity the entity to look up
     * @return the entity from the list, or null if not found
     */
    public E get(E entity) {
        int idx = list.indexOf(entity);
        return idx < 0 ? null : list.get(idx);
    }
    
    /**
     * Performs a health update for the specified entity. 
     * @param id the entity to update
     * @param hp the new health for that entity
     */
    public void health(int id, int hp) {
        E entity = map.get(id);
        entity.hp = hp;
        int idx = list.indexOf(entity);
        fireTableRowsUpdated(idx, idx);
    }

    /**
     * Causes an update to the specified stat in the list.
     * Works by just delegating the update to the table model.
     * @param id the entity id to update
     * @param statType the type of stat to update
     * @param current the new value of the stat
     * @param max the new max value of the stat
     */
    public void statUpdate(int id, StatType statType, int current, int max) {
        switch (statType) {
            case HEALTH: {
                health(id, current < 0 ? -1 : ((current * 10000) / max));
                break;
            }
            default: throw new RuntimeException("Unrecognized stat type: " + statType);
        }
    }

}