//Cardew Internet Greeting Cards
//Copyright: Tim Joyce (tim@angles.demon.co.uk)
//13/01/97


import java.applet.*;
import HersheyFont;
import java.awt.*;
import java.awt.image.*;
import java.net.*;
import java.util.*;

public class card extends Applet implements Runnable, ImageProducer {
    URL sendURL, collectURL;
    Image dropr, dropb, open, send, close, offscreen, background, currImage, bgTile, bigImage;
    Thread loading = null;
    Thread going = null;
    HersheyFont scriptFont;
    String text, to, from, fronttext, hostName;
    boolean built = false, frontpage = false;
    int cardWidth, cardHeight, xOffset, yOffset, state;
    StringBuffer textout[] = new StringBuffer[8];
    StringBuffer toout[] = new StringBuffer[4];
    StringBuffer fromout[] = new StringBuffer[4];
    StringBuffer frontout[] = new StringBuffer[8];
    InetAddress IPAdd;
    LoadImages loader;
    int appletWidth, appletHeight;
    int imageWidth, imageHeight;
    long startTime = 0;
    Graphics ga, go;
    Cartoon cart = null;
    Image imgMemory = null;                           // memory image
    protected int dxImg;                                        // width of both images
    protected int dyImg;                                        // height of both images
    protected int frames = 5;                                   // frames in dissolve
    protected Image imgCache[] = new Image[101];                // cached dissolve images (0-100%)
    protected ColorModel RGBModel = ColorModel.getRGBdefault(); // RGB color model
    protected int percent;                                      // crossfade percentage
    protected int[] pixelsImg0;                                 // pixels from frame0
    protected int[] pixelsImg1;                                 // pixels from frame1
    protected ImageConsumer ic;                                 // image consumer
    protected int[] pixelBuffer;                                // pixel buffer
    protected int numImages;
    protected Image[] sourceImages;
    CartoonTimer timer;
    boolean playing = false;


    public void init() {
        text = getParameter("text");
        to = getParameter("to");
        from = getParameter("from");
        fronttext = getParameter("fronttext");
        String fontname = getParameter("font");
    	String at = getParameter("imageWidth");
	    imageWidth = (at != null) ? Integer.valueOf(at).intValue() : 200;
    	at = getParameter("imageHeight");
	    imageHeight = (at != null) ? Integer.valueOf(at).intValue() : 200;
        Dimension d = this.size();
        scriptFont = new HersheyFont(getCodeBase(), fontname);
        float f = (float)0.8;
        scriptFont.setHeight(f);
        scriptFont.setWidth(f);
        if (text.equals("hostName")) {
            frontpage = true;
            try {
                IPAdd = InetAddress.getLocalHost();
                hostName = IPAdd.getHostName();
            }
            catch (UnknownHostException u) {hostName = "Unknown";}
            to = "Hello "+hostName;
            from = "";
            text = "Have a look around the site, and choose a greeting card";
        }
        textout = cutString(text);
        toout = cutString(to);
        fromout = cutString(from);
        frontout = cutString(fronttext);
        try {
            sendURL = new URL(getCodeBase(),"../mid.html");
        } catch (MalformedURLException e) {}
        try {
            collectURL = new URL(getCodeBase(),"../cgi/collect.pl");
        } catch (MalformedURLException e) {}
        String imageName = getParameter("cardimage");
        state = 0;
        offscreen = this.createImage(d.width, d.height);
        go = offscreen.getGraphics();
        ga = this.getGraphics();
        loader = new LoadImages(imageName, this);
        loader.start();
    }

    public void run(){
        while (true) {
            switch (state){
              case 0:
                if (getImages()) {
                    state = 1;
                    buildImages();
                }
                break;
              case 1:
                if (built) {
                    state = 2;
                }
                break;
              case 2:
                int a = timer.getClipNum();
                if (a != 0) {
                    if (loader.clip[a-1] != null) {
                        loader.clip[a-1].play();
                    }
                }
                if (loader.birthday != null) {
                    loader.birthday.stop();
                    playing = false;
                }
                break;
              case 3:
                if (!playing) {
                    if (loader.birthday != null) {
                        loader.birthday.loop();
                        playing = true;
                    }
                }
                break;
            }
            paint(go);
            ga.drawImage(offscreen,0,0,this);
            try {going.sleep(100);}
            catch (InterruptedException e){};
        }
    }


    public void paint(Graphics g){
        switch (state){
          case 0:
            drawLoading(g);
            break;
          case 1:
            drawLoading(g);
            break;
          case 2:
            drawClosed(g);
            break;
          case 3:
            drawOpen(g);
            break;
        }
    }

    public void drawLoading(Graphics g) {
        g.setColor(new Color(248,253,187));
        g.fillRect(0,0,528,278);
        g.setColor(Color.black);
        scriptFont.drawString("Welcome to Cardew",150,160,g);
        scriptFont.drawString("Loading",150,200,g);
        if (startTime == 0) {
            startTime = new Date().getTime();
        }
        long nowTime = new Date().getTime();
        int i = 0;
        for (long a=startTime; a<nowTime; a+=1000) {
            i++;
            scriptFont.drawString(".",230+i*5,200,g);
        }
    }

    public void drawClosed(Graphics g) {
        if (background == null) {
            Dimension d = this.size();
            background = this.createImage(d.width, d.height);
            Graphics gb = background.getGraphics();
            drawBackground(gb);
        }
        g.drawImage(background,0,0,this);
        g.drawImage(imgCache[timer.getCurrentImage()],xOffset,yOffset,this);
        for (int i=0; i<8; i++) {
            if (frontout[i] != null) {
                String draw = frontout[i].toString();
                scriptFont.drawString(draw,320,125+i*30,g);
            }
        }
        g.drawImage(open,455,215,this);
    }

    public void drawBackground(Graphics g) {
        xOffset = (250 - imageWidth)/2;
        yOffset = (250 - imageHeight)/2;
        g.setColor(Color.black);
        for (int i=0; i<10; i++) {
            for (int j=0; j<5; j++) {
                g.drawImage(bgTile,i*50,j*50,this);
            }
        }
        g.drawLine(250,0,250,250);
        g.drawImage(dropr,500,0,this);
        g.drawImage(dropb,0,250,this);
    }

    public void drawOpen(Graphics g) {
        g.drawImage(background,0,0,this);
        for (int i=0; i<4; i++) {
            if (toout[i] != null) {
                String draw = toout[i].toString();
                scriptFont.drawString(draw,10,30+i*30,g);
            }
        }
        for (int i=0; i<4; i++) {
            if (fromout[i] != null) {
                String draw = fromout[i].toString();
                scriptFont.drawString(draw,10,150+i*30,g);
            }
        }
        for (int i=0; i<8; i++) {
            if (textout[i] != null) {
                String draw = textout[i].toString();
                scriptFont.drawString(draw,260,30+i*30,g);
            }
        }
        if (frontpage) {
            g.drawImage(send,265,170,this);
        }
        g.drawImage(close,455,215,this);
    }


    public boolean mouseUp(Event evt, int x, int y)  {
        if (frontpage) {
            if ((x>265)&&(y>170)&&(x<310)&&(y<244)) {
                getAppletContext().showDocument(sendURL);
                stop();
            }
        }
        if (frontpage) {
            if ((x>310)&&(y>170)&&(x<365)&&(y<244)) {
                getAppletContext().showDocument(collectURL);
                stop();
            }
        }
        if ((x>455)&&(y>215)) {
            if (state == 2) {
                state = 3;
            } else {
                if (state == 3) {
                    state = 2;
                }
            }
        }
        return true;
    }

    public boolean getImages() {
        if (loader.Complete()) {
            bigImage = loader.getPic(0);
            bgTile = loader.getPic(1);
            open = loader.getPic(2);
            close = loader.getPic(3);
            send = loader.getPic(4);
            dropr = loader.getPic(5);
            dropb = loader.getPic(6);
            return true;
        } else {
            return false;
        }
    }

    public StringBuffer[] cutString(String text) {
        StringBuffer text1 = new StringBuffer(text);
        text1.append(" ");
        int length = text1.length();
        if (length > 300) {
            length = 300;
        }
        StringBuffer textout[] = new StringBuffer[20];
        int outcount = 0;
        for (int i=0; i<length; i++) {
            StringBuffer textout1 = new StringBuffer();
            int j = i+20;
            if (j > length-1){
                j = length-1;
            }
            int l=0;
            for (int k=j; k>i; k--){
                if (text1.charAt(k) == " ".toCharArray()[0]) {
                    l = k;
                    k = 0;
                }
            }
            boolean space = true;
            if (l==0) {
                l = i+20;
                space = false;
            }
            if (l > length){
                l = length;
            }
            for (int m=i; m<l; m++) {
                textout1.append(text1.charAt(m));
            }
            i = l;
            if (!space) {i--;}
            textout[outcount] = textout1;
            outcount++;
        }
        return textout;
    }

    public void buildImages() {

        frames = (bigImage.getWidth(null)/imageWidth);
        dxImg = imageWidth;
        dyImg = imageHeight;
        sourceImages = new Image[frames*2];
        for (int i=0; i<frames; i++){
            for (int j=0; j<2; j++){
                int k = i*2+j;
                sourceImages[k] = this.createImage(imageWidth, imageHeight);
                Graphics g = sourceImages[k].getGraphics();
                g.drawImage(bigImage,-i*imageWidth,0,null);
            }
        }
        for (int i=0; i<frames; i++){
            Graphics g = sourceImages[(i*2)+1].getGraphics();
            g.drawImage(bigImage,-i*imageWidth,-imageHeight,this);
        }
        numImages = 0;
        for (int i=0; i<(frames*2)-1; i++){
            fadeimages(sourceImages[i], sourceImages[i+1]);
        }
        fadeimages(sourceImages[(frames*2)-1], sourceImages[0]);
        timer = new CartoonTimer(numImages, 5);
        timer.start();
        built = true;
    }

    public void addConsumer(ImageConsumer ic)
    {
        this.ic = ic;
    }
    public boolean isConsumer(ImageConsumer ic)
    {
        return this.ic == ic;
    }

    public void removeConsumer(ImageConsumer ic)
    {
        if (ic == this.ic)
        {
            this.ic = null;
        }
    }

    public void requestTopDownLeftRightResend(ImageConsumer ic)
    {
    }

    public void startProduction(ImageConsumer ic)
    {
        // Inform the consumer about what we're going to send.
        ic.setDimensions(dxImg, dyImg);
        ic.setColorModel(RGBModel);
        ic.setHints(ImageConsumer.TOPDOWNLEFTRIGHT | ImageConsumer.COMPLETESCANLINES |
                    ImageConsumer.SINGLEPASS | ImageConsumer.SINGLEFRAME);

        // Fill in the pixel buffer based on the two images
        int count = dxImg * dyImg;
        int inverse = 100 - percent;
        for (int i = 0; i < count; i++)
        {
            // Get RGB value from image 1
            int rgb1 = pixelsImg0[i];
            int r1 = (rgb1 >> 16) & 0xff;
            int g1 = (rgb1 >> 8) & 0xff;
            int b1 = rgb1 & 0xff;

            // Get RGB value from image 2
            int rgb2 = pixelsImg1[i];
            int r2 = (rgb2 >> 16) & 0xff;
            int g2 = (rgb2 >> 8) & 0xff;
            int b2 = rgb2 & 0xff;

            // Average the RGB values using percent to weight them
            int r = ((r1 * percent / 100) + (r2 * inverse / 100));
            int g = ((g1 * percent / 100) + (g2 * inverse / 100));
            int b = ((b1 * percent / 100) + (b2 * inverse / 100));

            // Store resulting pixel in the pixel buffer
            pixelBuffer[i] = 0xff000000 | (r << 16) | (g << 8) | b;
        }

        // Give the pixels in the buffer to the image consumer in one big bunch
        ic.setPixels(0, 0, dxImg, dyImg, RGBModel, pixelBuffer, 0, dxImg);

        // Tell the consumer we're done
        ic.imageComplete(ImageConsumer.STATICIMAGEDONE);
    }

    int[] grabPixels(Image img) throws InterruptedException
    {
        int[] pixelsImg = new int[dxImg * dyImg];
        PixelGrabber pg = new PixelGrabber(img, 0, 0, dxImg, dyImg, pixelsImg, 0, dxImg);
        pg.grabPixels();
        return pixelsImg;
    }


    public void fadeimages(Image a, Image b)
    {
        // set up variables for our class local ImageProducer
        try {
            pixelsImg0 = grabPixels(a);
            pixelsImg1 = grabPixels(b);
        }
        catch (InterruptedException e){};

        pixelBuffer = new int[dxImg * dyImg];
        // loop through frames
        for (int frame = 5; frame > 0; frame--){

            // compute percentage of crossfade based on frames
            percent = frame * 100 / 5;

            // if the image isn't in the cache, we need to make it
            // produce crossfade image
            Image imgNew = createImage(this);
            prepareImage(imgNew, null);
            imgCache[numImages] = imgNew;
            numImages++;
        }
    }


    public void start() {
        if (going == null){
            going = new Thread(this);
     	    going.start();
        }
    }

    public void stop() {
	    if (going != null) {
	        going.stop();
	        going = null;
        }
    }

}


class CartoonTimer extends Thread {
    protected Thread thread = null;                             // thread for animating fade
    protected int numImages, currentImage, clipNum;
    protected int frames;

    public CartoonTimer(int numImages, int frames){
        this.numImages = numImages;
        this.frames = frames;
    }

    public void run(){

        while (true){
            for (int i=0; i<numImages; i++) {
                setCurrentImage(i);
                setClipNum(0);
                int sleep;
                if (i%frames == 0) {
                    if ((i/frames)%2 == 1) {
                        setClipNum(i/(frames*2)+1);
                    }
                    sleep = 3000;
                } else {
                    sleep = 100;
                }
                try {thread.sleep(sleep);}
                catch (InterruptedException e){};
            }
        }
    }

    public synchronized void setCurrentImage(int currentImage){
        this.currentImage = currentImage;
    }

    public synchronized int getCurrentImage(){
        return currentImage;
    }

    public synchronized void setClipNum(int c){
        this.clipNum = c;
    }

    public synchronized int getClipNum(){
        int a = clipNum;
        clipNum = 0;
        return a;
    }

}



class LoadImages extends Thread {

    MediaTracker tracker;
    Image image[] = new Image[8];
    String imageName;
    boolean complete = false;
    Applet App;
    AudioClip clip[] = new AudioClip[3];
    AudioClip birthday;

    public void run() {
        tracker = new MediaTracker(App);
        String imageURL = new String(App.getCodeBase()+imageName);
        image[0] = App.getImage(App.getDocumentBase(), imageURL);
        imageURL = new String(App.getCodeBase()+"back.gif");
        image[1] = App.getImage(App.getDocumentBase(), imageURL);
        imageURL = new String(App.getCodeBase()+"open.gif");
        image[2] = App.getImage(App.getDocumentBase(), imageURL);
        imageURL = new String(App.getCodeBase()+"close.gif");
        image[3] = App.getImage(App.getDocumentBase(), imageURL);
        imageURL = new String(App.getCodeBase()+"send.gif");
        image[4] = App.getImage(App.getDocumentBase(), imageURL);
        imageURL = new String(App.getCodeBase()+"drop1.gif");
        image[5] = App.getImage(App.getDocumentBase(), imageURL);
        imageURL = new String(App.getCodeBase()+"drop2.gif");
        image[6] = App.getImage(App.getDocumentBase(), imageURL);
        for (int i=0; i<7; i++){
            tracker.addImage(image[i],i);
        }
        try {tracker.waitForAll();
        } catch (InterruptedException e) {}
        complete = true;
  	    clip[0] = App.getAudioClip(App.getCodeBase(), "frame0.au");
  	    clip[1] = App.getAudioClip(App.getCodeBase(), "frame1.au");
  	    clip[2] = App.getAudioClip(App.getCodeBase(), "frame2.au");
  	    birthday = App.getAudioClip(App.getCodeBase(), "birth.au");
    }

    public LoadImages(String imageName, Applet a) {
        this.imageName = imageName;
        App = a;
    }

    public boolean Complete() {
        return complete;
    }


    public Image getPic(int imagenum) {
        return image[imagenum];
    }

}
