ShipDescription: add support for conditional sections
[fleet.git] / src / edu / berkeley / fleet / two / ShipDescription.java
1 package edu.berkeley.fleet.two;
2 import edu.berkeley.fleet.api.*;
3 import java.io.*;
4 import java.util.*;
5
6 /** NOT YET FINALIZED: A description (specification) of a ship */
7 public class ShipDescription implements Iterable<DockDescription> {
8
9     private Fleet fleet;
10     private String name;
11     private LinkedHashMap<String,DockDescription> docks         = new LinkedHashMap<String,DockDescription>();
12     private LinkedHashMap<String,DockDescription> ports = new LinkedHashMap<String,DockDescription>();
13     private HashMap<String,String>                sections      = new HashMap<String,String>();
14     private HashMap<String,BitVector>              constants     = new HashMap<String,BitVector>();
15
16     public String getName() { return name; }
17     public String getSection(String sectionName) { return sections.get(sectionName); }
18     public DockDescription getDockDescription(String name) { return docks.get(name); }
19     public Iterator<DockDescription> iterator() { return docks.values().iterator(); }
20     public Iterable<DockDescription> ports() {
21         return ports.values();
22     }
23
24     public final LinkedList<PercolatedPort> percolatedPorts = new LinkedList<PercolatedPort>();
25
26     public ShipDescription(Fleet fleet, String name, BufferedReader r) throws IOException {
27         if (name.endsWith(".ship")) name = name.substring(0, name.length()-".ship".length());
28         this.name = name;
29         this.fleet = fleet;
30         String sectionName = null;
31         StringBuffer sb = new StringBuffer();
32         while(true) {
33             String s = r.readLine();
34             if (s==null || s.startsWith("==")) {
35                 if (sectionName != null) sections.put(sectionName, sb.toString());
36                 if (s==null) break;
37                 sb = new StringBuffer();
38                 sectionName = s.trim();
39                 while(sectionName.startsWith("="))
40                     sectionName = sectionName.substring(1);
41                 while(sectionName.endsWith("="))
42                     sectionName = sectionName.substring(0, sectionName.length()-1);
43                 sectionName = sectionName.trim();
44
45                 if (sectionName.indexOf(':') != -1) {
46                     String subtype = sectionName.substring(sectionName.indexOf(':')+1);
47                     sectionName = sectionName.substring(0, sectionName.indexOf(':'));
48                     boolean good = false;
49                     for(Class c = fleet.getClass(); c!=Object.class; c = c.getSuperclass()) {
50                         if (subtype.equals(c.getSimpleName()))
51                             good = true;
52                     }
53                     if (!good) {
54                         sectionName = null;
55                         continue;
56                     }
57                 }
58                 sectionName = sectionName.trim().toLowerCase();
59                 continue;
60             }
61             sb.append(s+"\n");
62         }
63         for(String s : sections.keySet())
64             processSection(s);
65     }
66
67     public BitVector getConstant(String name) {
68         BitVector c = constants.get(name);
69         if (c==null) throw new RuntimeException("unknown constant " + name);
70         return c;
71     }
72
73     private void processSection(String section) throws IOException {
74         if (section.equals("")) {
75             BufferedReader br = new BufferedReader(new StringReader(sections.get(section)));
76             for(String s = br.readLine(); s != null; s = br.readLine()) {
77                 if (s.trim().length()==0) continue;
78                 String key = s.substring(0, s.indexOf(':')).trim();
79                 String val = s.substring(s.indexOf(':')+1).trim();
80                 if (key.toLowerCase().equals("ship"))
81                     name = val.trim();
82             }
83         } else if (section.equals("constants")) {
84             BufferedReader br = new BufferedReader(new StringReader(sections.get(section)));
85             for(String s = br.readLine(); s != null; s = br.readLine()) {
86                 if (s.indexOf(':')==-1) continue;
87                 String key = s.substring(0, s.indexOf(':')).trim();
88                 if (key.startsWith("constant")) {
89                     String constname = key.substring("constant".length()+1).trim();
90                     String val       = s.substring(s.indexOf(':')+1).trim();
91                     constants.put(constname, new BitVector(fleet.getWordWidth()).set(Integer.parseInt(val)));
92                 }
93             }
94         } else if (section.equals("ports")) {
95             BufferedReader br = new BufferedReader(new StringReader(sections.get(section)));
96             boolean rightSide = false;
97             DockDescription p = null;
98             for(String s = br.readLine(); s != null; s = br.readLine()) {
99                 if (s.trim().length()==0) { rightSide = true; continue; }
100
101                 String key = s.substring(0, s.indexOf(':')).trim();
102                 boolean inbox = false;
103                 boolean dockless = false;
104                 key = key.replaceAll("  +", " ");
105                 if      (key.equals("data in"))   { inbox = true;  }
106                 else if (key.equals("data out"))  { inbox = false; }
107                 else if (key.equals("in"))        { inbox = true;  }
108                 else if (key.equals("dockless out")) { inbox = false; dockless = true; }
109                 else if (key.equals("out"))       { inbox = false; }
110                 else if (key.startsWith("percolate")) { 
111                     key = s;
112                     key = key.substring("percolate".length()+1).trim();
113                     PercolatedPort.PortType type = null;
114                     if (key.startsWith("up")) type = PercolatedPort.PortType.UP;
115                     if (key.startsWith("down")) type = PercolatedPort.PortType.DOWN;
116                     if (key.startsWith("inout")) type = PercolatedPort.PortType.INOUT;
117                     key = key.substring(key.indexOf(':')+1).trim();
118                     String name = key.substring(0, key.indexOf(' '));
119                     int width = Integer.parseInt(key.substring(key.indexOf(' ')).trim());
120                     percolatedPorts.add(new PercolatedPort(name, width, type));
121                     continue;
122                 }
123                 else if (key.startsWith("constant")) {
124                     String constname = key.substring("constant".length()+1).trim();
125                     String val       = s.substring(s.indexOf(':')+1).trim();
126                     p.addConstant(constname, new BitVector(fleet.getWordWidth()).set(Integer.parseInt(val)));
127                     continue;
128                 } else if (key.startsWith("shortcut to")) {
129                     continue;
130                 }
131                 else throw new RuntimeException("unknown port type: \""+key+"\"");
132
133                 p = null;
134                 String val = s.substring(s.indexOf(':')+1).trim();
135                 String boxname = val.indexOf('.') != -1 ? val.substring(0, val.indexOf('.')) : val;
136                 String dest    = val.indexOf('.') != -1 ? val.substring(val.indexOf('.')+1)  : "";
137                 p = docks.get(boxname);
138                 if (p==null) {
139                     p = new DockDescription(this, boxname, !rightSide, inbox, dockless);
140                     ports.put(boxname, p);
141                     if (!dockless) docks.put(boxname, p);
142                 }
143             }
144         }
145     }
146
147     public void printTeX(PrintWriter pw) throws Exception {
148         ShipDescription sd = this;
149         pw.println("\\pagebreak");
150         pw.println("\\section*{The {\\tt "+sd.getName()+"} Ship}");
151         pw.println("\\addcontentsline{toc}{subsection}{"+sd.getName()+"}");
152         String tex = sd.getSection("tex");
153         /*
154         for(DockDescription bbd : sd) {
155             pw.println("{\\bf "+(bbd.isInputDock() ? "Input: " : "Output: ")+"{\\tt "+bbd.getName()+"}}\n\n");
156         }
157         */
158         int boxGap = 5;
159         int boxHeight = 25;
160         int boxWidth = 75;
161
162         int leftSize = 0;
163         int rightSize = 0;
164         for(DockDescription bbd : sd)
165             if (bbd.isLeft()) leftSize += (boxHeight+boxGap);
166             else              rightSize += (boxHeight+boxGap);
167
168         int totalHeight = Math.max(leftSize, rightSize);
169         int shipWidth = (int)(boxWidth * 1.5);
170         int totalWidth = boxGap*2 + boxWidth*2 + shipWidth;
171
172         pw.println("");
173         pw.println("\\begin{center}");
174         pw.println("\\begin{empfile}["+sd.getName()+"]");
175         pw.println("\\begin{emp}["+sd.getName()+"]("+(totalWidth+10)+","+(totalHeight+10)+")");
176         pw.println("  beginfig(1)");
177         pw.println("      pickup pencircle scaled 1pt;");
178         pw.println("      draw "+
179                    "("+((totalWidth-shipWidth)/2)+","+0+")--"+
180                    "("+((totalWidth-shipWidth)/2)+","+totalHeight+")--"+
181                    "("+(totalWidth-((totalWidth-shipWidth)/2))+","+totalHeight+")--"+
182                    "("+(totalWidth-((totalWidth-shipWidth)/2))+","+0+")--"+
183                    "("+((totalWidth-shipWidth)/2)+","+0+");");
184         int left = 0;
185         int right = 0;
186         for(DockDescription bbd : sd) {
187             int ypos = (totalHeight - (boxGap/2) - (bbd.isLeft() ? left : right));
188             int half = (totalWidth-shipWidth)/2;
189             int p1 = bbd.isLeft() ? (half-5) : ((totalWidth-half)+5);
190             int p3 = bbd.isLeft() ? (p1 - boxWidth) : (p1 + boxWidth);
191             if (bbd.isInputDock()) {
192                 int p1x = p1;
193                 p1 = p3;
194                 p3 = p1x;
195             }
196             boolean goo = ((bbd.isLeft() && bbd.isInputDock()) || (!bbd.isLeft() && bbd.isOutputDock()));
197             int p2 = goo ? (p3 - (boxHeight/2)) : (p3 + (boxHeight/2));
198             if (bbd.isLeft()) left += (boxHeight+boxGap);
199             else              right += (boxHeight+boxGap);
200             if (goo) {
201                 pw.println("      label.rt(btex \\tt "+bbd.getName()+" etex, ("+(p1+3)+","+(ypos-boxHeight/2)+"));");
202             } else {
203                 pw.println("      label.lft(btex \\tt "+bbd.getName()+" etex, ("+(p1-3)+","+(ypos-boxHeight/2)+"));");
204             }
205             pw.println("      draw "+
206                        "  ("+p1+","+ypos+")--"+
207                        "  ("+p2+","+ypos+")--"+
208                        "  ("+p3+","+(ypos-(boxHeight/2))+")--"+
209                        "  ("+p2+","+(ypos-boxHeight)+")--"+
210                        "  ("+p1+","+(ypos-boxHeight)+")--"+
211                        "  ("+p1+","+ypos+");");
212             if (bbd.isLeft()) leftSize += boxHeight;
213             else              rightSize += boxHeight;
214         }
215         pw.println("  endfig;");
216         pw.println("\\end{emp}");
217         pw.println("\\end{empfile}");
218         pw.println("\\end{center}");
219         pw.println("");
220
221         if (tex!=null)
222             pw.println(tex);
223     }
224
225 }