/*
 * ColorProfile.java
 *
 * Created on May 16, 2006, 5:28 PM
 *
 * To change this template, choose Tools | Template Manager
 * and open the template in the editor.
 */

package sidnet.core.interfaces;

import sidnet.colorprofiles.ColorPair;
import sidnet.core.gui.*;
import java.awt.Color;

/**
 *
 * @author Oliviu Ghica, Northwestern University
 *
 * Interface for defining the meaning and type of colors a visual node can paint itself into
 */
public abstract class ColorProfile {
    
    /** Array of colors for the interior of the node symbol */
    protected static Color[] innerColorList;
    
    /** Array of colors for the exterior of the node symbol */
    protected static Color[] outerColorList;
    
    /** Internal array for keeping track of the amount of time a particular color has been used */
    protected int[] colorCounter;
    
    /** Additional colors with special meaning */
    protected Color innerSpecialColor = null;
    protected Color outerSpecialColor = null;
    
    /** Internal array for keeping track of the amount of time a particular color is going to be used (valid) */
    protected long[] colorLifeTime;
    
    /** Event marker, indicates an indefinite duration for which the last specified color will be applied */
    public static final int FOREVER   = -1;
    
    /** Duration marker, clear the last set color */
    public static final int CLEAR     = 0;
    
    /** The tag for dead nodes */
    public static final int DEAD       = 0;
    
    /** The tag for selected nodes */
    public static final int SELECTED   = 1;
    
     /**
     * Constructor function in which you must define the assignment of colors to the array
     */
    public ColorProfile(int colorNum) {
        innerColorList = new Color[colorNum];
        outerColorList = new Color[colorNum];
        colorCounter   = new int[colorNum];
        colorLifeTime = new long[colorNum];
        
        innerColorList[DEAD]        = Color.black;         outerColorList[DEAD]     = Color.black;
        innerColorList[SELECTED]    = Color.red;           outerColorList[DEAD]     = Color.red;
    }
    
    /** 
     * Mark a given node
     * <p>
     * @param event     event marker
     * @param duration  either a marker, or an integer value. The latter indicates the amount of time, in [ms]-simulation time, the mark will last
     */
    public void mark(int event, long duration)    // [ms]
    {
        //colorCounter[event] = duration;           // duration expressed in number of cycles, not in real time measures {ex, 1, 2, 3.... FOREVER}
        if (duration != FOREVER)
            colorLifeTime[event] = System.currentTimeMillis() + duration;
        else
            colorLifeTime[event] = FOREVER;
    }
    
    /** Returns the ColorPair associated with a given instance of an implementation function */
    public ColorPair getColorSet()
    {
        Color innerCol = null;
        Color outerCol = null;
        
        for (int i = innerColorList.length-1; i >=  0; i --)
            if (colorLifeTime[i] - System.currentTimeMillis() > 0 || colorLifeTime[i] == FOREVER)
            {
                innerCol = innerColorList[i];
                outerCol = outerColorList[i];
            }
        
        if (innerCol == null)
            if (innerSpecialColor != null)
                innerCol = innerSpecialColor;
            else
                innerCol = innerColorList[innerColorList.length-1];
        if (outerCol == null)
            if (outerSpecialColor != null)
                outerCol = outerSpecialColor;
            else
                outerCol = outerColorList[innerColorList.length-1];
        
        return new ColorPair(innerCol, outerCol);
    } 
    
     /** Get remaining (simulation) time before the last paint is cleared */
    public long getTimeToColorChange()
    {
        long minTime = 0;
        for (int i = 0; i < innerColorList.length - 1; i++)
            if (minTime == 0 || minTime < Math.max(colorLifeTime[i]-System.currentTimeMillis(), 0))
                minTime = Math.max(colorLifeTime[i]-System.currentTimeMillis(), 0);
        return minTime;
    }
}
