import javax.microedition.midlet.MIDlet;
import javax.microedition.lcdui.*;
import javax.microedition.rms.*;

public class Paranoia extends MIDlet 
                        implements CommandListener, ItemStateListener {
        private RecordStore rs=null;

        private String pin, fp, seed, pass, seq;

        private Display dpy;
        private Form frmPin, frmSettings, frmGenerate;

        private TextField txtGetPin;
        private TextField txtSetPin, txtSetFP, txtSetSeed, txtSetPass,
                        txtSetSeq;
        private TextField txtSeq;
        private StringItem strFP, strSeed, strOTP;

        private Command cmdLoadSettings = new Command("OK", Command.OK, 1);
        private Command cmdSaveSettings = new Command("Save", Command.OK, 1);
        private Command cmdGenerate = new Command("Generate", Command.OK, 1);
        private Command cmdDelete = new Command("Delete Settings",
                                                        Command.OK, 2);
        private Command cmdExit = new Command("Exit", Command.CANCEL, 1);

        public Paranoia() {
                dpy = Display.getDisplay(this);
                buildUI();
        }

        private void buildUI() {
                frmPin = new Form("Paranoia");
                txtGetPin = new TextField("Pin", "", 6, TextField.NUMERIC);
                frmPin.append(txtGetPin);
                frmPin.addCommand(cmdDelete);
                //frmPin.addCommand(cmdLoadSettings);
                frmPin.addCommand(cmdExit);
                frmPin.setCommandListener(this);
                frmPin.setItemStateListener(this);

                frmSettings = new Form("Paranoia");
                txtSetPin = new TextField("Pin", "", 6, TextField.NUMERIC);
                frmSettings.append(txtSetPin);
                txtSetFP = new TextField("Fingerprint", "", 48, TextField.ANY
                        | TextField.NON_PREDICTIVE | TextField.SENSITIVE  );
                frmSettings.append(txtSetFP);
                txtSetSeed = new TextField("Seed", "", 10, TextField.ANY
                        | TextField.NON_PREDICTIVE | TextField.SENSITIVE  );
                frmSettings.append(txtSetSeed);
                txtSetPass = new TextField("Passphrase", "", 20, TextField.ANY
                        | TextField.NON_PREDICTIVE | TextField.SENSITIVE  );
                frmSettings.append(txtSetPass);
                txtSetSeq = new TextField("Sequence Number", "", 3, 
                                TextField.NUMERIC);
                frmSettings.append(txtSetSeq);
                frmSettings.addCommand(cmdSaveSettings);
                frmSettings.addCommand(cmdExit);
                frmSettings.setCommandListener(this);

                frmGenerate = new Form("Paranoia");
                strFP = new StringItem("Fingerprint", "");
                frmGenerate.append(strFP);
                strSeed = new StringItem("Seed", "");
                frmGenerate.append(strSeed);
                txtSeq = new TextField("Seq", "", 3, 
                                TextField.NUMERIC);
                frmGenerate.append(txtSeq);
                strOTP = new StringItem("OTP", "");
                frmGenerate.append(strOTP);
                frmGenerate.addCommand(cmdExit);
                frmGenerate.setCommandListener(this);
                frmGenerate.setItemStateListener(this);
        }

        public void destroyApp(boolean what) {
        }

        public void pauseApp() {
                destroyApp(false);
        }

        public void startApp() {
                dpy.setCurrent(frmPin);
        }

        public void commandAction(Command c, Displayable d) {
                if(c == cmdExit) {
                        destroyApp(false);
                        notifyDestroyed();
                }
                if(c == cmdLoadSettings) {
                        if(loadSettings()) {
                                if(pin.equals(txtGetPin.getString())) {
                                        generate();
                                        dpy.setCurrent(frmGenerate);
                                } else {
                                        Alert alert = new Alert ("Paranoia");
                                        alert.setString("Invalid Pin");
                                        alert.setTimeout(3000);
                                        alert.setType(AlertType.ERROR);
                                        dpy.setCurrent (alert);
                                }
                        } else {
                                txtSetPin.setString(txtGetPin.getString());
                                dpy.setCurrent(frmSettings);
                        }
                }
                if(c == cmdSaveSettings) {
                        saveSettings();
                        generate();
                        dpy.setCurrent(frmGenerate);
                }
                if(c == cmdDelete) {
                        deleteSettings();
                        destroyApp(false);
                        notifyDestroyed();
                }
        }

        public void itemStateChanged (Item item) {
                if(item == txtSeq 
                && txtSeq.size() > 0
                && Integer.parseInt(txtSeq.getString()) >= 100) {
                        generate();         
                }
                if(item == txtGetPin && txtGetPin.size() >= 4) {
                        if(loadSettings()) {
                                if(pin.equals(txtGetPin.getString())) {
                                        generate();
                                        dpy.setCurrent(frmGenerate);
                                } else {
                                        Alert alert = new Alert ("Paranoia");
                                        alert.setString("Invalid Pin");
                                        alert.setTimeout(3000);
                                        alert.setType(AlertType.ERROR);
                                        dpy.setCurrent (alert);
                                }
                        } else {
                                txtSetPin.setString(txtGetPin.getString());
                                dpy.setCurrent(frmSettings);
                        }
                }
        }

        private void generate(){
                saveSeq();
                new ComputeThread(Integer.parseInt(seq),
                                seed, pass, this).start();
        }

        public synchronized void setOTP(String s) {
                strOTP.setText(s);
        }

        private boolean loadSettings() {
                try {
                        rs = RecordStore.openRecordStore("Paranoia",false);
                } catch( RecordStoreNotFoundException e ) {
                        return false;
                } catch( RecordStoreException e ) {
                        System.out.println(e);
                        return false;
                }

                try {
                        System.out.println("records=" + rs.getNumRecords());
                        if (rs.getNumRecords() != 5) {
                                rs.closeRecordStore();
                                return false;
                        }
                } catch( RecordStoreException e ) {
                        System.out.println(e);
                        return false;
                }

                try {
                        RecordEnumeration re = rs.enumerateRecords(null, null,
                                        false);
                        while (re.hasNextElement()) {
                                String record = new String(re.nextRecord());
                                System.out.println(record);
                                if(record.startsWith("pin=")) {
                                        pin = record.substring(
                                                "pin=".length(),
                                                record.length());
                                }
                                if(record.startsWith("fp=")) {
                                        fp = record.substring(
                                                "fp=".length(),
                                                record.length());
                                }
                                if(record.startsWith("seed=")) {
                                        seed = record.substring(
                                                "seed=".length(),
                                                record.length());
                                }
                                if(record.startsWith("pass=")) {
                                        pass = record.substring(
                                                "pass=".length(),
                                                record.length());
                                }
                                if(record.startsWith("seq=")) {
                                        seq = record.substring(
                                                "seq=".length(),
                                                record.length());
                                }
                        }

                        if(             pin.length() == 0 || 
                                        fp.length() == 0 ||
                                        seed.length() == 0 ||
                                        pass.length() == 0 ||
                                        seq.length() == 0
                                        ) {
                                rs.closeRecordStore();
                                return false;
                        }
                } catch( RecordStoreException e ) {
                        System.out.println(e);
                        return false;
                } finally {
                        try {
                                rs.closeRecordStore();
                        } catch ( RecordStoreException e ) {
                                System.out.println(e);
                        }
                }

                strFP.setText(fp);
                strSeed.setText(seed);
                txtSeq.setString(seq);
                return true;
        }

        private boolean saveSettings() {
                pin = txtSetPin.getString();
                fp = txtSetFP.getString();
                seed = txtSetSeed.getString();
                pass = txtSetPass.getString();
                seq = txtSetSeq.getString();

                deleteSettings();
                try {
                        rs = RecordStore.openRecordStore("Paranoia",true);

                        byte bytesPin[] = ("pin="  + pin ).getBytes();
                        byte bytesFP[]  = ("fp="   + fp  ).getBytes();
                        byte bytesSeed[]= ("seed=" + seed).getBytes();
                        byte bytesPass[]= ("pass=" + pass).getBytes();
                        byte bytesSeq[] = ("seq="  + seq ).getBytes();

                        rs.addRecord(bytesPin, 0,bytesPin.length);
                        rs.addRecord(bytesFP,  0,bytesFP.length);
                        rs.addRecord(bytesSeed,0,bytesSeed.length);
                        rs.addRecord(bytesPass,0,bytesPass.length);
                        rs.addRecord(bytesSeq, 0,bytesSeq.length);

                        rs.closeRecordStore();
                } catch( RecordStoreException e ){
                        System.out.println(e);
                        return false;
                }

                strFP.setText(fp);
                strSeed.setText(seed);
                txtSeq.setString(seq);
                return true;
        }

        private void saveSeq() {
                seq = txtSeq.getString();
                String newseq = new Integer(Integer.parseInt(seq)+1).toString();

                try {
                        rs = RecordStore.openRecordStore("Paranoia",false);
                } catch( RecordStoreNotFoundException e ) {
                } catch( RecordStoreException e ) {
                        System.out.println(e);
                }

                try {
                        System.out.println("records=" + rs.getNumRecords());
                        RecordEnumeration re = rs.enumerateRecords(null, null,
                                        false);
                        while (re.hasNextElement()) {
                                int i = re.nextRecordId();
                                String record = new String(rs.getRecord(i));
                                System.out.println(record);
                                if(record.startsWith("seq=")) {
                                        byte bytesSeq[]=
                                                ("seq=" + newseq).getBytes();
                                        rs.deleteRecord(i);
                                        rs.addRecord(bytesSeq, 0,
                                                bytesSeq.length);
                                }
                        }
                } catch( RecordStoreException e ) {
                        System.out.println(e);
                } finally {
                        try {
                                rs.closeRecordStore();
                        } catch ( RecordStoreException e ) {
                                System.out.println(e);
                        }
                }
        }

        private void deleteSettings() {
                try {
                        RecordStore.deleteRecordStore("Paranoia");
                } catch( RecordStoreNotFoundException Ignore ) {
                } catch( RecordStoreException e ){
                        System.out.println(e);
                }
        }
}

