package com.bitrazor.tivo.trafficcam;

import java.awt.Button;
import java.awt.Image;
import java.awt.MediaTracker;
import java.awt.Toolkit;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;

import javax.swing.ImageIcon;

import com.tivo.hme.bananas.BApplication;
import com.tivo.hme.bananas.BScreen;
import com.tivo.hme.sdk.Application;
import com.tivo.hme.sdk.Resource;
import com.tivo.hme.sdk.View;
import com.tivo.hme.sdk.util.Ticker;

/**
 * Create a screen that rotates through a number of images. Each image is a URL,
 * and is displayed for some number of seconds. Each image is faded out as the
 * new image is faded in.
 * 
 * @see Pictures,java, TiVo HME SDK v1.1 samples
 * @see http://javaalmanac.com/egs/java.net/GetImage.html?l=rel
 * 
 * @author David Staas, bitrazor.com
 */
public class ViewScreen extends BScreen implements Ticker.Client {

    private Application theApp; // A handle to the app

    private ArrayList list; // Will hold the list of URLs for images

    private int index; // Will hold the index into list

    final static int SHOW_TIME = 6000; // how long the pictures is shown

    final static int FADE_TIME = 1250; // how long to perform the fade in/out

    // the media tracker reqires a component, so we use this button
    final static Button mediaTrackerComp = new Button();

    View fg, bg; // the foreground and background pictures

    /**
     * The constructor gets the URLs for the cameras, then kicks off the Ticker
     * to periodically rotate through them.
     * 
     * @param app
     *            A handle to the application.
     */
    public ViewScreen(BApplication app) {
        super(app);

        theApp = app;
        list = new ArrayList();
        // delete Image image;
        // delete ImageResource iRes;
        index = -1;
        bg = this.getBelow(); // this.below points to the current view's
                            // background
        fg = this.getAbove(); // ... and foreground

        getCameraURLs();

        // Ticker is part of the HME utils, and allows timed actions to happen.
        Ticker.master.add(this, System.currentTimeMillis(), null);

    }

    /**
     * Populates the ArrayList list with URLs, each representing the image from
     * a road cam. This routine could be replaced to read the URLs from a config
     * file, URL, etc. for more flexibility.
     */
    public void getCameraURLs() {
        list.add("http://www.springsgov.com/trafficeng/monument.jpg");
        list.add("http://www.springsgov.com/trafficeng/Interquest.jpg");
        list.add("http://www.springsgov.com/trafficeng/Briargate.jpg");
        list.add("http://www.springsgov.com/trafficeng/woodmen.jpg");
    }

    /**
     * Wait SHOW_TIME seconds, then show the next picture. This routine must be
     * implemented for classes that implement Ticker.Client.
     */
    public long tick(long tm, Object arg1) {
        // If context is null, the app has quit.
        if (theApp.getContext() == null) {
            return -1;
        }

        // advance to the next picture and show it
        index = (index + 1) % list.size();
        showPicture((String) list.get(index));

        // Since tick is called from another thread call flush to force HME to
        // write out any pending commands.
        flush();

        // tick again to advance to the next frame
        return System.currentTimeMillis() + SHOW_TIME;

    }

    /**
     * Fade from one image to the next. getScaledImage() is called to get a
     * correctly sized image for display.
     * 
     * @param path
     *            The URL of the image to show.
     */
    void showPicture(String path) {
        // turn painting off while we twiddle things
        theApp.getRoot().setPainting(false);
        try {
            // move the current image to the background view for fading out
            bg.setResource(fg.getResource(), RSRC_IMAGE_BESTFIT);

            // get a scaled instance of the image. Width and height refer
            // to the View's width and height.
            Image img = getScaledImage(path, getWidth(), getHeight());

            // stuff the scaled image into the fg
            fg.setResource(createImage(img), RSRC_IMAGE_BESTFIT);

            // Perform the cross-fade animation
            Resource anim = getResource("*" + FADE_TIME);
            fg.setTransparency(1.0f); // start transparent, then fade IN
            fg.setTransparency(0.0f, anim);
            bg.setTransparency(0.0f); // start opaque, then fade OUT
            bg.setTransparency(1.0f, anim);
        } finally {
            theApp.getRoot().setPainting(true);
        }
    }

    /**
     * Gets an image from a URL, sized for the TiVo screen.
     */
    public static Image getScaledImage(String path, int width, int height) {
        URL url = null;
        try {
            url = new URL(path);
        } catch (MalformedURLException e1) {
            // TODO: replace this with something more graceful
            e1.printStackTrace();
        }

        // create an awt Image from a URL using this trick
        Image urlImage = Toolkit.getDefaultToolkit().createImage(url);

        // use the swing imageIcon class to synchronously load the image
        ImageIcon icon = new ImageIcon(urlImage);

        Image img = icon.getImage();
        int imgW = icon.getIconWidth();
        int imgH = icon.getIconHeight();

        //
        // figure out the scale factor and the new size
        //

        float scale = Math.min((float) width / imgW, (float) height / imgH);
        if (scale > 1.0f) {
            scale = 1.0f;
        }
        int scaleW = (int) (imgW * scale);
        int scaleH = (int) (imgH * scale);

        // Perform scaling if the image must be shrunk. We will send smaller
        // images over and let the receiver scale them up.
        if (scale < 1.0f) {
            img = img.getScaledInstance(scaleW, scaleH, Image.SCALE_FAST);
            try {
                MediaTracker mt = new MediaTracker(mediaTrackerComp);
                mt.addImage(img, 0);
                mt.waitForAll();
            } catch (InterruptedException e) {
            }
        }

        return img;
    }

    // If the left key is pressed, return to the calling screen.
    public boolean handleKeyPress(int code, long rawcode) {
        switch (code) {
        case KEY_LEFT:
            getBApp().pop();
            return true;
        }

        return super.handleKeyPress(code, rawcode);
    }

    public String toString() {
        return "View Traffic Cameras";
    }

}
