package com.srbenoit.filter;

import java.awt.image.BufferedImage;
import com.srbenoit.filter.items.ByteArrayPipeItem;
import com.srbenoit.filter.items.ImageArrayPipeItem;
import com.srbenoit.filter.items.PointSetArrayPipeItem;
import com.srbenoit.filter.items.StringPipeItem;
import com.srbenoit.filter.items.TimeSeriesPipeItem;
import com.srbenoit.filter.items.TrajectoryListPipeItem;
import com.srbenoit.util.ResourceLoader;

/**
 * A specification for an output generated by a filter.
 */
public class FilterOutput {

    /** the data type of the output */
    public final Class<? extends AbstractPipeItem> type;

    /** a description of the output */
    public final String description;

    /** the default key of the pipe item the filter will add to the pipe */
    public final String defaultKey;

    /** the actual key of the pipe item the filter will add to the pipe */
    private String actualKey;

    /** the icon that represents the output */
    private final BufferedImage icon;

    /**
     * Constructs a new <code>FilterOutput</code>.
     *
     * @param  clazz   the data type of the output
     * @param  desc    a description of the output
     * @param  defKey  the default key of the pipe item the filter will add to the pipe
     */
    public FilterOutput(final Class<? extends AbstractPipeItem> clazz, final String desc,
        final String defKey) {

        BufferedImage img;

        if (clazz == null) {
            throw new IllegalArgumentException("output data type cannot be null");
        }

        if (desc == null) {
            throw new IllegalArgumentException("output data description cannot be null");
        }

        if (defKey == null) {
            throw new IllegalArgumentException("output default key cannot be null");
        }

        this.type = clazz;
        this.description = desc;
        this.defaultKey = defKey;
        this.actualKey = defKey;

        if (clazz.equals(ByteArrayPipeItem.class)) {
            img = ResourceLoader.loadImage(FilterOutput.class, "icons/binary.png");
        } else if (clazz.equals(ImageArrayPipeItem.class)) {
            img = ResourceLoader.loadImage(FilterOutput.class, "icons/images.png");
        } else if (clazz.equals(PointSetArrayPipeItem.class)) {
            img = ResourceLoader.loadImage(FilterOutput.class, "icons/point_set.png");
        } else if (clazz.equals(StringPipeItem.class)) {
            img = ResourceLoader.loadImage(FilterOutput.class, "icons/text.png");
        } else if (clazz.equals(TimeSeriesPipeItem.class)) {
            img = ResourceLoader.loadImage(FilterOutput.class, "icons/time_series.png");
        } else if (clazz.equals(TrajectoryListPipeItem.class)) {
            img = ResourceLoader.loadImage(FilterOutput.class, "icons/trajectories.png");
        } else {
            img = null;
        }

        if (img == null) {
            this.icon = new BufferedImage(24, 16, BufferedImage.TYPE_INT_RGB);
        } else {
            this.icon = img;
        }
    }

    /**
     * Sets the key of the pipe item from which the input will be taken.
     *
     * @param  key  the key
     */
    public void setKey(final String key) {

        this.actualKey = key;
    }

    /**
     * Gets the key of the pipe item from which the input will be taken.
     *
     * @return  the key
     */
    public String getKey() {

        return this.actualKey;
    }

    /**
     * Tests whether another object is equal to this <code>FilterOutput</code>. In order to be
     * considered equal, the object must be a <code>FilterOutput</code> and must have the same
     * values for all fields.
     *
     * @param   obj  the object to test
     * @return  <code>true</code> if the object is equal to this <code>FilterOutput</code>; <code>
     *          false</code> otherwise
     */
    @Override public boolean equals(final Object obj) {

        FilterOutput other;
        boolean equal;

        if (obj instanceof FilterOutput) {
            other = (FilterOutput) obj;
            equal = other.type.equals(this.type) && other.description.equals(this.description)
                && other.defaultKey.equals(this.defaultKey)
                && ((this.actualKey == null) ? (other.getKey() == null)
                                             : this.actualKey.equals(other.getKey()));
        } else {
            equal = false;
        }

        return equal;
    }

    /*
     * Gets the hash code for the object.
     *
     * @return the hash code
     */
    @Override public int hashCode() {

        return this.type.hashCode() + description.hashCode() + defaultKey.hashCode()
            + ((this.actualKey == null) ? 0 : this.actualKey.hashCode());
    }

    /**
     * Gets a 24x16 icon representing the filter output data type
     *
     * @return  the icon
     */
    public BufferedImage getIcon() {

        return this.icon;
    }
}
