package com.lushprojects.circuitjs1.client;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Vector;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.TextArea;
public class CustomLogicModel implements Editable {
static int FLAG_SCHMITT = 1;
static HashMap<String, CustomLogicModel> modelMap;
int flags;
String name;
String[] inputs;
String[] outputs;
String infoText;
String rules;
Vector<String> rulesLeft, rulesRight;
boolean dumped;
static CustomLogicModel getModelWithName(String name) {
if (modelMap == null)
modelMap = new HashMap<String,CustomLogicModel>();
CustomLogicModel lm = modelMap.get(name);
if (lm != null)
return lm;
lm = new CustomLogicModel();
lm.name = name;
lm.infoText = (name.equals("default")) ? "custom logic" : name;
modelMap.put(name, lm);
return lm;
}
static CustomLogicModel getModelWithNameOrCopy(String name, CustomLogicModel oldmodel) {
if (modelMap == null)
modelMap = new HashMap<String,CustomLogicModel>();
CustomLogicModel lm = modelMap.get(name);
if (lm != null)
return lm;
lm = new CustomLogicModel(oldmodel);
lm.name = name;
lm.infoText = name;
modelMap.put(name, lm);
return lm;
}
static void clearDumpedFlags() {
if (modelMap == null)
return;
Iterator it = modelMap.entrySet().iterator();
while (it.hasNext()) {
Map.Entry<String,CustomLogicModel> pair = (Map.Entry)it.next();
pair.getValue().dumped = false;
}
}
CustomLogicModel() {
inputs = listToArray("A,B");
outputs = listToArray("C,D");
rulesLeft = new Vector<String>();
rulesRight = new Vector<String>();
rules = "";
}
CustomLogicModel(CustomLogicModel copy) {
flags = copy.flags;
inputs = copy.inputs;
outputs = copy.outputs;
infoText = copy.infoText;
rules = copy.rules;
rulesLeft = copy.rulesLeft;
rulesRight = copy.rulesRight;
}
CustomLogicModel(StringTokenizer st) {
name = unescape(st.nextToken());
flags = new Integer(st.nextToken()).intValue();
inputs = listToArray(unescape(st.nextToken()));
outputs = listToArray(unescape(st.nextToken()));
infoText = unescape(st.nextToken());
rules = unescape(st.nextToken());
parseRules();
modelMap.put(name, this);
}
String arrayToList(String arr[]) {
if (arr == null)
return "";
if (arr.length == 0)
return "";
String x = arr[0];
int i;
for (i = 1; i < arr.length; i++)
x += "," + arr[i];
return x;
}
String [] listToArray(String arr) {
return arr.split(",");
}
public EditInfo getEditInfo(int n) {
if (n == 0) {
EditInfo ei = new EditInfo("Inputs", 0, -1, -1);
ei.text = arrayToList(inputs);
return ei;
}
if (n == 1) {
EditInfo ei = new EditInfo("Outputs", 0, -1, -1);
ei.text = arrayToList(outputs);
return ei;
}
if (n == 2) {
EditInfo ei = new EditInfo("Info Text", 0, -1, -1);
ei.text = infoText;
return ei;
}
if (n == 3) {
EditInfo ei = new EditInfo("<a href=\"customlogic.html\" target=\"_blank\">Definition</a>", 0, -1, -1);
ei.textArea = new TextArea();
ei.textArea.setVisibleLines(5);
ei.textArea.setText(rules);
return ei;
}
/*
* not implemented
if (n == 4) {
EditInfo ei = new EditInfo("", 0, -1, -1);
ei.checkbox = new Checkbox("Schmitt", (flags & FLAG_SCHMITT) != 0);
return ei;
}
*/
return null;
}
public void setEditValue(int n, EditInfo ei) {
if (n == 0)
inputs = listToArray(ei.textf.getText());
if (n == 1)
outputs = listToArray(ei.textf.getText());
if (n == 2)
infoText = ei.textf.getText();
if (n == 3) {
rules = ei.textArea.getText();
parseRules();
}
if (n == 4) {
if (ei.checkbox.getState())
flags |= FLAG_SCHMITT;
else
flags &= ~FLAG_SCHMITT;
}
CirSim.theSim.updateModels();
}
void parseRules() {
String lines[] = rules.split("\n");
int i;
rulesLeft = new Vector<String>();
rulesRight = new Vector<String>();
for (i = 0; i != lines.length; i++) {
String s = lines[i].toLowerCase();
if (s.length() == 0 || s.startsWith("#"))
continue;
String s0[] = s.replaceAll(" ", "").split("=");
if (s0.length != 2) {
Window.alert("Error on line " + (i+1) + " of model description");
return;
}
if (s0[0].length() < inputs.length) {
Window.alert("Model must have >= " + (inputs.length) + " digits on left side");
return;
}
if (s0[0].length() > inputs.length + outputs.length) {
Window.alert("Model must have <= " + (inputs.length+outputs.length) + " digits on left side");
return;
}
if (s0[1].length() != outputs.length) {
Window.alert("Model must have " + (outputs.length) + " digits on right side");
return;
}
String rl = s0[0];
boolean used[] = new boolean[26];
int j;
String newRl = "";
for (j = 0; j != rl.length(); j++) {
char x = rl.charAt(j);
if (x == '?' || x == '+' || x == '-' || x == '0' || x == '1') {
newRl += x;
continue;
}
if (x < 'a' || x > 'z') {
Window.alert("Error on line " + (i+1) + " of model description");
return;
}
// if a letter appears twice, capitalize it the 2nd time so we can compare
if (used[x-'a']) {
newRl += (char)(x + 'A' - 'a');
continue;
}
used[x-'a'] = true;
newRl += x;
}
rulesLeft.add(newRl);
rulesRight.add(s0[1]);
}
}
String dump() {
dumped = true;
if (rules.length() > 0 && !rules.endsWith("\n"))
rules += "\n";
return "! " + escape(name) + " " + flags + " " + escape(arrayToList(inputs)) + " " +
escape(arrayToList(outputs)) + " " + escape(infoText) + " " + escape(rules);
}
static String escape(String s) {
if (s.length() == 0)
return "\\0";
return s.replace("\\", "\\\\").replace("\n", "\\n").replace(" ", "\\s").replace("+", "\\p").
replace("=", "\\q").replace("#", "\\h").replace("&", "\\a");
}
static String unescape(String s) {
if (s.equals("\\0"))
return "";
int i;
for (i = 0; i < s.length(); i++) {
if (s.charAt(i) == '\\') {
char c = s.charAt(i+1);
if (c == 'n')
s = s.substring(0, i) + "\n" + s.substring(i+2);
else if (c == 's')
s = s.substring(0, i) + " " + s.substring(i+2);
else if (c == 'p')
s = s.substring(0, i) + "+" + s.substring(i+2);
else if (c == 'q')
s = s.substring(0, i) + "=" + s.substring(i+2);
else if (c == 'h')
s = s.substring(0, i) + "#" + s.substring(i+2);
else if (c == 'a')
s = s.substring(0, i) + "&" + s.substring(i+2);
else
s = s.substring(0, i) + s.substring(i+1);
}
}
return s;
}
}