package lu.tudor.santec.gecamed.core.gui.widgets.animatedicon;

/*******************************************************************************
 * This file is part of GECAMed.
 * 
 * GECAMed is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License (L-GPL) as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * GECAMed is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public License (L-GPL)
 * along with GECAMed.  If not, see <http://www.gnu.org/licenses/>.
 * 
 * GECAMed is Copyrighted by the Centre de Recherche Public Henri Tudor (http://www.tudor.lu)
 * (c) CRP Henri Tudor, Luxembourg, 2008
 *******************************************************************************/

import java.awt.Component;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.lang.ref.WeakReference;

import javax.swing.Timer;

/** Provide animation of auto-generated animations.  Makes use of the repaint
 * tracking structure established by {@link AnimatedIcon}. 
 */
public abstract class AbstractAnimatedIcon extends AnimatedIcon {
    private static final int DEFAULT_INTERVAL = 1000/24;

    private Timer timer;
    private int repaintInterval;
    private int frame;
    private int frameCount;
    
    protected AbstractAnimatedIcon() {
        this(0);
    }
    
    protected AbstractAnimatedIcon(int frameCount) {
        this(frameCount, DEFAULT_INTERVAL);
    }
    
    protected AbstractAnimatedIcon(int frameCount, int interval) {
        this.frameCount = frameCount;
        setFrameInterval(interval);
    }
    
    /** Ensure the timer stops running, so it, too can be GC'd. */
    protected void finalize() {
        timer.stop();
    }
    
    /** Setting a frame interval of zero stops automatic animation. */
    public void setFrameInterval(int interval) {
        repaintInterval = interval;
        if (interval != 0) {
            if (timer == null) {
                timer = new Timer(interval, new AnimationUpdater(this));
                timer.setRepeats(true);
            }
            else {
                timer.setDelay(interval);
            }
        }
        else if (timer != null) {
            timer.stop();
            timer = null;
        }
    }

    public int getFrameInterval() {
        return repaintInterval;
    }
    
    /** Returns the total number of frames. */
    public int getFrameCount() {
        return frameCount;
    }
    
    /** Advance to the next animation frame. */
    public void nextFrame() {
        setFrame(getFrame() + 1);
    }
    
    /** Set the current animation frame number. */
    public void setFrame(int f) {
        this.frame = f;
        if (frameCount != 0)
            frame = frame % frameCount;
        repaint();
    }
    
    /** Returns the current animation frame number. */
    public int getFrame() {
        return frame;
    }

    /** Implement this method to paint the icon. */
    protected abstract void paintFrame(Component c, Graphics g, int x, int y);

    public abstract int getIconWidth();
    public abstract int getIconHeight();
    
    protected synchronized void registerRepaintArea(Component c, int x, int y, int w, int h) {
        if (timer != null && !timer.isRunning()) {
            timer.start();
        }
        super.registerRepaintArea(c, x, y, w, h);
    }
    
    private static class AnimationUpdater implements ActionListener {
        private WeakReference ref;
        public AnimationUpdater(AbstractAnimatedIcon icon) {
            this.ref = new WeakReference(icon);
        }
        public void actionPerformed(ActionEvent e) {
            AbstractAnimatedIcon icon = (AbstractAnimatedIcon)ref.get();
            if (icon != null) {
                icon.nextFrame();
            }
        }
    }
}
