package morse;

import java.util.Timer;
import java.util.TimerTask;
import javax.microedition.lcdui.Alert;
import javax.microedition.lcdui.AlertType;
import javax.microedition.lcdui.Canvas;
import javax.microedition.lcdui.ChoiceGroup;
import javax.microedition.lcdui.Command;
import javax.microedition.lcdui.CommandListener;
import javax.microedition.lcdui.Display;
import javax.microedition.lcdui.Displayable;
import javax.microedition.lcdui.Form;
import javax.microedition.lcdui.Graphics;
import javax.microedition.lcdui.TextField;
import javax.microedition.midlet.MIDlet;
import javax.microedition.midlet.MIDletStateChangeException;

/**
 *
 * @author Richard H. Tingstad
 */
public class MorseCode extends MIDlet implements CommandListener {

    private boolean[][] chars = new boolean[][]{
        {false,true},//A
        {true,false,false,false},
        {true,false,true,false},
        {true,false,false},
        {false},
        {false,false,true,false},
        {true,true,false},
        {false,false,false,false},
        {false,false},
        {false,true,true,true},
        {true,false,true},
        {false,true,false,false},//L
        {true,true},
        {true,false},
        {true,true,true},//O
        {false,true,true,false},
        {true,true,false,true},
        {false,true,false},
        {false,false,false},//S
        {true},
        {false,false,true},
        {false,false,false,true},
        {false,true,true},
        {true,false,false,true},
        {true,false,true,true},
        {true,true,false,false},//Z
        {true,true,true,true,true},//0
        {false,true,true,true,true},//1
        {false,false,true,true,true},//2
        {false,false,false,true,true},//3
        {false,false,false,false,true},//4
        {false,false,false,false,false},//5
        {true,false,false,false,false},//6
        {true,true,false,false,false},//7
        {true,true,true,false,false},//8
        {true,true,true,true,false}//9
    };

    private Form form;
    private TextField textField;
    private TextField delay;
    private ChoiceGroup choiceGroup;
    private MyCanvas myCanvas;
    private Timer timer;
    private boolean run;
    private boolean loop;
    private int timeUnit;

    protected void destroyApp(boolean unconditional) throws
            MIDletStateChangeException {
    }

    protected void pauseApp() {
    }

    protected void startApp() throws MIDletStateChangeException {
        timer = new Timer();
        form = new Form("Morse code");
        textField = new TextField("Message", "SOS", 400, TextField.ANY);
        form.append(textField);
        delay = new TextField("Time of \"dot\" (ms)", "200", 10,
                TextField.NUMERIC);
        form.append(delay);
        choiceGroup = new ChoiceGroup("", ChoiceGroup.MULTIPLE);
        choiceGroup.append("Loop", null);
        form.append(choiceGroup);
        form.addCommand(new Command("OK", Command.OK, 0));
        form.addCommand(new Command("About", Command.HELP, 1));
        form.addCommand(new Command("Exit", Command.EXIT, 2));
        form.setCommandListener(this);
        Display.getDisplay(this).setCurrent(form);
        myCanvas = new MyCanvas();
        myCanvas.addCommand(new Command("Abort", Command.CANCEL, 0));
        myCanvas.setCommandListener(this);
    }

    public void commandAction(Command command, Displayable d) {
        if (!d.equals(form)) {
            run = false;
            return;
        }
        if (command.getCommandType() == Command.EXIT) {
            notifyDestroyed();
            return;
        }
        if (command.getCommandType() != Command.OK) {
            Alert alert = new Alert("About",
                    "Richard H. Tingstad\nhttp://drop.by",
                    null, AlertType.INFO);
            Display.getDisplay(this).setCurrent(alert, form);
            return;
        }
        run = true;
        timeUnit = Integer.parseInt(delay.getString());
        loop = choiceGroup.isSelected(0);
        timer.schedule(new TimerTask() {
            public void run() {
                doStuff();
            }
        }, 0);
    }

    private void doStuff() {
        Display.getDisplay(this).setCurrent(myCanvas);
        if (!loop) {
            sendMessage();
        }
        else {
            while(run) {
                sendMessage();
                draw(false, 4 * timeUnit); //Two spaces between runs.
            }
        }
        Display.getDisplay(this).setCurrent(form);
    }

    private void sendMessage() {
        String message = textField.getString().toUpperCase();
        draw(false, 7 * timeUnit);
        for (int i = 0; i < message.length(); i++) {
            if (!run) break;
            boolean[] code = null;
            char c = message.charAt(i);
            if (message.charAt(i) == ' ') {
                draw(false, 7 * timeUnit); // 7 dots (black) between words.
                continue;
            }
            else if (c > 64 && c < 91) {
                code = chars[c - 65];
            }
            else if (c > 47 && c < 58) {
                code = chars[c - 22];//-48+26
            }
            if (code != null) {
                sendCode(code);
                draw(false, 3 * timeUnit); // 3 dots (black) between letters.
            }
            if (!run) break;
        }        
    }

    private void sendCode(boolean[] code) {
        for (int i = 0; i < code.length; i++) {
            if (!run) break;
            if (code[i]) {
                dash();
            }
            else {
                dot();
            }
            if (i < code.length - 1) {
                // 1 dot (black) between parts of same letter:
                draw(false, timeUnit);
            }
            if (!run) break;
        }
    }

    private void dash() {
        draw(true, 3 * timeUnit);
    }
    
    private void dot() {
        draw(true, timeUnit);
    }

    private void draw(final boolean white, int time) {
        myCanvas.setWhite(white);
        myCanvas.repaint();
        try {
            Thread.sleep(time);
        }
        catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

}

class MyCanvas extends Canvas {

    private boolean white;

    public void setWhite(boolean white) {
        this.white = white;
    }

    public void paint(Graphics g) {
        if (white) {
            g.setColor(255, 255, 255);
        }
        else {
            g.setColor(0, 0, 0);
        }
        g.fillRect(0, 0, this.getWidth(), this.getHeight());
    }

}