/*	Led.java
 *	Animated bended led sign applet
 * 	(c) fabrice armisen 06/1996(kakou@geocitie.com)
 *
 *
 *	Be warning, this source code is provided only for an educational purpose.  
 *	It is copyrighted Fabrice Armisen 1996 and can't be inclued in any commercial 
 *	product without my authorization.
 *
 *	If you modify this code to use it in a non commercial purpose please put this
 *	copyright text with your product. Thank you.
 *
 */

/*
 *	Last modified : 
 *	02/12/97 : add stop and start methods
 *
 */

import java.awt.*;
import java.awt.image.*;
import java.applet.Applet;




public class Led extends Applet implements Runnable
{
    private static final int RED = 1;
    private static final int GREEN = 2;
    private static final int BLUE = 3;
    private volatile boolean sem;
    private Image ledImgs[];
    private int ledTab[];
    private int ledNb;
    private Image offScreen;
    private Image backImg;
    private Dimension dimInLed;
    private Dimension realDimInLed;
    private Color backColor;
    private Thread ledAnimator;
    private Color bgColor;
    private int TextColor;
    private String defText;
    private String text;
    private LightPoint morphTab[];
    private boolean imageLoaded;

    public String getAppletInfo()
    {
        return "(c) Kakou 97 - kakou@geocities.com";
    }

    public void init()
    {
        int radius;
        double vDistortion;
        int offX;
        int offY;

        showStatus("(c) Kakou 97 - kakou@geocities.com");

        text = getParameter("message");
        if (text == null)
            text = new String(defText);

        String imageName = getParameter("back_image");

        String colorStr = getParameter("back_color");
        if (colorStr == null)
            backColor = Color.black;
        else
            backColor = new Color(Integer.parseInt(colorStr));

        String radiusStr = getParameter("radius");
        if (colorStr == null)
            radius = size().width / 2;
        else
            radius = Integer.parseInt(radiusStr);

        String vDistortionStr = getParameter("vDistortion");
        if (vDistortionStr == null)
            vDistortion = 1.0;
        else
            vDistortion = Double.valueOf(vDistortionStr).doubleValue();

        String offXStr = getParameter("offX");
        if (offXStr == null)
            offX = 0;
        else
            offX = Integer.parseInt(offXStr);

        String offYStr = getParameter("offY");
        if (offYStr == null)
            offY = 0;
        else
            offY = Integer.parseInt(offYStr);

        dimInLed = new Dimension(50, 7);
        realDimInLed = new Dimension(dimInLed.width + 5, dimInLed.height);
        ledNb = realDimInLed.width * realDimInLed.height;
        ledTab = new int[ledNb];

        showStatus("Building distortion tab");
        morphTab = buildMorph(radius, vDistortion,new Point(offX, offY));
        showStatus("Building images");
        ledImgs = new Image[4];
        setBackground(bgColor);
        offScreen = createImage(size().width, size().height);

        buildImgs();
        if (imageName != null)
        {
            showStatus("Loading background");
            backImg = getImage(getDocumentBase(), imageName);
            prepareImage(backImg, this);
        }
        else
            showStatus("(c) Kakou 97 - kakou@geocities.com");

        TextColor = 1;
        ledAnimator = new Thread(this);
        ledAnimator.start();
    }

    private LightPoint[] buildMorph(int radius, double vDistortion, Point ledOffset)
    {
        LightPoint lightTab[] = new LightPoint[dimInLed.width * dimInLed.height];
        int i = 0;
        for (int y = 0; y < dimInLed.height; y++)
        {
            for (int x = 0; x < dimInLed.width; x++)
            {
                double alpha = Math.PI + (double)x * Math.PI / dimInLed.width;
                double rayon = (double)radius - (double)(dimInLed.height - y) * 4.0;
                double rx = (double)ledOffset.x + rayon * Math.cos(alpha) + radius - 4.0;
                double ry = (double)ledOffset.y - rayon * Math.sin(alpha) * vDistortion;
                lightTab[i++] = new LightPoint((int)rx, (int)ry);
            }
        }
        return lightTab;
    }

    private final void buildImgs()
    {
        Color ledColors[] = new Color[8];
        ledColors[0] = bgColor;
        ledColors[1] = bgColor;
        ledColors[2] = Color.red;
        ledColors[3] = new Color(128, 0, 0);
        ledColors[4] = Color.green;
        ledColors[5] = new Color(0, 128, 0);
        ledColors[6] = Color.blue;
        ledColors[7] = new Color(0, 0, 128);
        int bC = bgColor.getRGB();
        for (int i = 0; i < 4; i++)
        {
            int hC = ledColors[i * 2].getRGB();
            int lC = ledColors[i * 2 + 1].getRGB();
            int pixels[] = new int[16];
            pixels[0] = bC;
            pixels[1] = lC;
            pixels[2] = lC;
            pixels[3] = bC;
            pixels[4] = lC;
            pixels[5] = hC;
            pixels[6] = hC;
            pixels[7] = lC;
            pixels[8] = lC;
            pixels[9] = hC;
            pixels[10] = hC;
            pixels[11] = lC;
            pixels[12] = bC;
            pixels[13] = lC;
            pixels[14] = lC;
            pixels[15] = bC;
            ledImgs[i] = createImage(new MemoryImageSource(4, 4, ColorModel.getRGBdefault(), pixels, 0, 4));
        }
        int pixels[] = new int[size().width * size().height];
        for (int i = 0; i < size().width * size().height; i++)
            pixels[i] = bC;
    }

    public void update(Graphics gc)
    {
        int i;
        sem = true;
        int toNextLine = realDimInLed.width - dimInLed.width;

        Graphics offScreenGC = offScreen.getGraphics();
        if (!imageLoaded)
        {
            offScreenGC.setColor(backColor);
            offScreenGC.fillRect(0, 0, size().width, size().height);
        }
        else
            offScreenGC.drawImage(backImg, 0, 0, null);
        int il = i = 0;
        for (int y = 0; y < dimInLed.height; y++)
        {
            for (int x = 0; x < dimInLed.width; x++)
            {
                int ind = ledTab[i];
                if (ind != 0)
                    offScreenGC.drawImage(ledImgs[ind], morphTab[il].x, morphTab[il].y, null);
                i++;
                il++;
            }
            i += toNextLine;
        }
        paint(gc);
        sem = false;
    }

    public void paint(Graphics gc)
    {
        gc.drawImage(offScreen, 0, 0, null);
    }

 	public void stop()
	{
		if (ledAnimator != null)
			ledAnimator.suspend();
	}
		
	public void start()
	{
		if (ledAnimator != null)
			ledAnimator.resume();
	}

    public void run()
    {
        for (int i = 0; i < ledNb; i++)
            ledTab[i] = 0;
        repaint();
        int pos = 0;
        int scrollTimer = 0;
        while (true)
        {
            if (scrollTimer == 0)
            {
                drawLetter(Letter.fromChar(text.charAt(pos)), dimInLed.width, 0, TextColor);
                pos = (pos + 1) % text.length();
                if (pos == 0)
                    TextColor = TextColor % 3 + 1;
            }
            scrollTimer = (scrollTimer + 1) % 5;
            scrollLeft(1);
            repaint();
            do
            {
                try
                {
                    Thread.sleep(10, 0);
                }
                catch (InterruptedException e)
                {
                }
            }
            while (sem);
        }
    }

    private final void drawLetter(int l[], int x, int y, int col)
    {
        int j;
        int pp = x + realDimInLed.width * y;
        int pl = 0;
        try
        {
            for (j = 0; j < 7; j++)
            {
                for (int i = 0; i < 5; i++)
                {
                    if (l[pl] != 0)
                        ledTab[pp] = col;
                    else
                        ledTab[pp] = 0;
                    pp++;
                    pl++;
                }
                pp += realDimInLed.width - 5;
            }
        }
        catch (ArrayIndexOutOfBoundsException e)
        {
        }
        return;
    }

    public boolean imageUpdate(Image img, int infoflags, int x, int y, int w, int h)
    {
        if ((infoflags & 32) == 0)
            return true;
        imageLoaded = true;
        showStatus("(c) Kakou 97 - kakou@geocities.com");
        repaint();
        return false;
    }

    private final void scrollLeft(int ds)
    {
        int i = 0;
        for (int y = 0; y < realDimInLed.height; y++)
        {
            for (int x = 0; x < realDimInLed.width - ds; x++)
            {
                ledTab[i] = ledTab[i + ds];
                i++;
            }
            for (int ii = i; ii < i + ds; ii++)
                ledTab[ii] = 0;
            i += ds;
        }
    }

    public Led()
    {
        sem = false;
        bgColor = Color.black;
        defText = "(C) KAKOU - KAKOU@GEOCITIES.COM ";
        imageLoaded = false;
    }
}

class Letter
{
    public static final int A[] = { 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 1, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0 };
    public static final int B[] = { 1, 1, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 1, 0, 0 };
    public static final int C[] = { 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0 };
    public static final int D[] = { 1, 1, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 1, 0, 0 };
    public static final int E[] = { 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0 };
    public static final int F[] = { 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0 };
    public static final int G[] = { 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0 };
    public static final int H[] = { 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 1, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0 };
    public static final int I[] = { 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0 };
    public static final int J[] = { 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0 };
    public static final int K[] = { 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0 };
    public static final int L[] = { 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0 };
    public static final int M[] = { 1, 0, 0, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0 };
    public static final int N[] = { 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0 };
    public static final int O[] = { 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0 };
    public static final int P[] = { 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0 };
    public static final int Q[] = { 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0 };
    public static final int R[] = { 1, 1, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0 };
    public static final int S[] = { 0, 1, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0 };
    public static final int T[] = { 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0 };
    public static final int U[] = { 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0 };
    public static final int V[] = { 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0 };
    public static final int W[] = { 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0 };
    public static final int X[] = { 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0 };
    public static final int Y[] = { 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0 };
    public static final int Z[] = { 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0 };
    public static final int SPACE[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
    public static final int COLON[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0 };
    public static final int MINUS[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
    public static final int AT[] = { 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0 };
    public static final int DEFAULT[] = { 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0 };
    public static final int POINT[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 };

    private Letter()
    {
    }

    public static int[] fromChar(int lettre)
    {
        switch (lettre)
        {
        case 65:
            return A;

        case 66:
            return B;

        case 67:
            return C;

        case 68:
            return D;

        case 69:
            return E;

        case 70:
            return F;

        case 71:
            return G;

        case 72:
            return H;

        case 73:
            return I;

        case 74:
            return J;

        case 75:
            return K;

        case 76:
            return L;

        case 77:
            return M;

        case 78:
            return N;

        case 79:
            return O;

        case 80:
            return P;

        case 81:
            return Q;

        case 82:
            return R;

        case 83:
            return S;

        case 84:
            return T;

        case 85:
            return U;

        case 86:
            return V;

        case 87:
            return W;

        case 88:
            return X;

        case 89:
            return Y;

        case 90:
            return Z;

        case 64:
            return AT;

        case 58:
            return COLON;

        case 45:
            return MINUS;

        case 46:
            return POINT;

        case 32:
            return SPACE;

        default:
            return DEFAULT;
        }
    }

    static
    {
    }
}

class LightPoint
{
    int x;
    int y;

    public LightPoint(int x, int y)
    {
        this.x = x;
        this.y = y;
    }
}

