bootstrap
[www.jankratochvil.net.git] / project / FordFulk / FordFulk / FordFulk.java
1 import java.applet.*;
2 import java.awt.*;
3 import java.util.*;
4 import java.net.*;
5 import java.io.*;
6
7 public
8 class FordFulk extends Applet
9 {
10 int WIRESHIFT=8,WIREARROW=16;
11 double NODEGAPSCALE=1./2;
12 double WIREFONTSCALE=1.,NODEFONTSCALE=3./2;
13 double WIRECAPBALANCE=3./5,WIREFLGBALANCE=4./5;
14 int WIREFLGRADIUS=8;
15 FordFulkNet net;
16 Color wirecolor=Color.blue,
17                         wiretextfgcolor=Color.yellow,
18                         wiretextbgcolor=Color.black,
19                         wireflgyescolor=Color.green,
20                         wireflgnocolor =Color.red,
21                         wirebackcolor  =Color.green,
22                         nodeactivecolor=Color.magenta,
23                         nodepassedcolor=Color.blue,
24                         tgttextfgcolor =Color.white,
25                         tgttextbgcolor =Color.black,
26                         tgtarrowcolor  =Color.cyan;
27 String DATAFN;
28
29 List codelist;
30 TextField linenotext,stopattext,statustext;
31 Button singlestep,nextlinestep,advancestep,continuerun,stopnow,resetnow;
32 Choice codespeed;
33 FordFulkTextArea guidearea;
34 int lineno=0,stopat=0,linestot=0;
35 boolean stopplus=false;
36 static String cs_s[]={"fastest","100ms","1/2s","2s"},stext[]={"Working...","Delaying...","Ready."};
37 Hashtable guides=new Hashtable();
38
39 FordFulkThread thread;
40 boolean suspendtest=true,suspendbug=true;
41 long BUGGYSLEEP=100;
42
43         static String sectionToString(FordFulkDataStream is,String sep) throws IOException
44         {
45                 String s="",l;
46                 boolean f=true;
47                 while ((l=is.getLine())!=null) { if (f) f=false; else s+=sep; s+=l; }
48                 is.nextSection();
49                 return s;
50         }
51
52         static StreamTokenizer sectionStreamTokenizer(FordFulkDataStream is) throws IOException
53         { return new StreamTokenizer(new StringBufferInputStream(sectionToString(is,"\n"))); }
54
55         static Vector readNumberChunk(FordFulkDataStream ffds,int divisor) throws IOException
56         {
57                 StreamTokenizer fs=sectionStreamTokenizer(ffds);
58                 Vector r=new Vector();
59                 do switch (fs.nextToken()) {
60                         case fs.TT_NUMBER:
61                                 r.addElement(new Integer(new Double(fs.nval).intValue()));
62                                 continue;
63                         case fs.TT_EOF: break;
64                         default:
65                                 throw new IOException("Unexpected data type "+fs.ttype+",nval="+fs.nval+",sval="+fs.sval);
66                         } while (fs.ttype!=fs.TT_EOF);
67                 if ((r.size()%divisor)!=0) throw new IOException("Trailing specification of number data (div="+divisor+")");
68                 return r;
69         }
70
71         public void initError(String s,Exception e)
72         { s="Applet init error: "+s+" of \""+DATAFN+"\": "+e.toString(); showStatus(s); System.out.println(s); }
73
74         public TextField labeledText(Panel p,String lab,String ini)
75         {
76                 Panel p1=new Panel();
77                 p1.setLayout(new GridBagLayout());
78                 if (lab!=null) p1.add(new Label(lab));
79                 TextField r=new TextField(ini,ini.length());
80                 r.setEditable(false);
81                 p1.add(r);
82                 p.add(p1);
83                 return r;
84                 }
85
86         public void init()
87         {
88                 DATAFN=getParameter("DataFile");
89                 setLayout(new GridLayout(1,0));
90                 Vector pnts,wires,inis;
91                 { Panel p=new Panel();
92                         GridBagLayout gb=new GridBagLayout();
93                         p.setLayout(gb);
94                         GridBagConstraints gbc=new GridBagConstraints();
95                         gbc.fill=GridBagConstraints.BOTH;
96                         gbc.gridwidth=GridBagConstraints.REMAINDER;
97                         gbc.weightx=1;
98                         p.setBackground(Color.lightGray);
99                         try {
100                                 { Panel p1=new Panel();
101                                         p1.setLayout(new FlowLayout());
102                                         linenotext=labeledText(p1,"Line","-   ");
103                                         stopattext=labeledText(p1,"Stop","-   ");
104                                         { Panel p2=new Panel();
105                                                 p2.setLayout(new GridBagLayout());
106                                                 p2.add(new Label("Delay"));
107                                                 p2.add(codespeed=new Choice());
108                                                 for (int i=0;i<4;i++) codespeed.addItem(cs_s[i]);
109                                                 codespeed.select(1);
110                                                 p1.add(p2);
111                                                 }
112                                         statustext=labeledText(p1,null,stext[0]);
113                                         gbc.weighty=0;
114                                         gb.setConstraints(p1,gbc);
115                                         p.add(p1);
116                                         }
117                                 { Panel p1=new Panel();
118                                         p1.setLayout(new GridLayout(2,3));
119                                         p1.add(singlestep  =new Button("Single step" ));
120                                         p1.add(nextlinestep=new Button("Stop @ next" ));
121                                         p1.add(advancestep =new Button("Any further" ));
122                                         p1.add(continuerun =new Button("Continue/Run"));
123                                         p1.add(stopnow     =new Button("Stop now"    ));
124                                         p1.add(resetnow    =new Button("Reset & stop"));
125                                         gbc.weighty=1;
126                                         gb.setConstraints(p1,gbc);
127                                         p.add(p1);
128                                         }
129                                 codelist=new List(20,false);
130                                 FordFulkDataStream f=new FordFulkDataStream(new URL(getDocumentBase(),DATAFN).openStream());
131                                 String line;
132                                 while ((line=f.getLine())!=null) {
133                                         codelist.addItem(": "+line);
134                                         linestot++;
135                                         }
136                                 int lnol=new Integer(linestot).toString().length();
137                                 for (int i=1;i<=linestot;i++) {
138                                         String s="0000"+new Integer(i).toString();
139                                         codelist.replaceItem(s.substring(s.length()-lnol)+codelist.getItem(i-1),i-1);
140                                         }
141                                 f.nextSection();
142
143                                 for (;;) {
144                                         Vector which;
145                                         f.lineLimit(1);
146                                         which=readNumberChunk(f,1);
147                                         if (which.size()==0) break;
148                                         int lj=0;
149                                         String rng="";
150                                         boolean mult=false;
151                                         for (int i=0;i<which.size();i++) {
152                                                 int j=((Integer)which.elementAt(i)).intValue();
153                                                 if (j<0) { mult=true; rng+=" to "+(lj=-j); }
154                                                 else {
155                                                         if (rng.length()!=0) { mult=true; rng+=", "; }
156                                                         rng+=(lj=j);
157                                                         }
158                                                 }
159                                         String s=(!mult && lj==0?"":("Comment for line"+(mult?"s ":" ")+rng+":\n"));
160                                         s+=sectionToString(f," ").replace('|','\n');
161                                         lj=0;
162                                         for (int i=0;i<which.size();i++) {
163                                                 int j=((Integer)which.elementAt(i)).intValue();
164                                                 if (j<0) while (lj<=-j) {
165                                                         guides.put(new Integer(lj),s);
166                                                         lj++;
167                                                         }
168                                                 else guides.put(new Integer(j),s);
169                                                 lj=Math.abs(j);
170                                                 }
171                                         }
172
173                                 pnts=readNumberChunk(f,2);
174                                 wires=readNumberChunk(f,3);
175                                 inis=readNumberChunk(f,2);
176                                 if (inis.size()!=2) throw new IOException("Source/dest chunk must have 2 values, not "+inis.size()+"!");
177                                 }
178                         catch (MalformedURLException e) { initError("Malformed URL",e); return; }
179                         catch (IOException e) { initError("Read",e); return; }
180                         net=new FordFulkNet(this);
181                         net.setup(pnts,wires,inis);
182                         gbc.weighty=32;
183                         gbc.gridheight=GridBagConstraints.REMAINDER;
184                         gb.setConstraints(net,gbc);
185                         p.add(net);
186                         add(p);
187                 }
188                 { Panel p=new Panel();
189                         GridBagLayout gb=new GridBagLayout();
190                         p.setLayout(gb);
191                         GridBagConstraints gbc=new GridBagConstraints();
192                         gbc.fill=GridBagConstraints.BOTH;
193                         gbc.gridwidth=GridBagConstraints.REMAINDER;
194                         gbc.weightx=1;
195                         gbc.weighty=3;
196                         gb.setConstraints(codelist,gbc);
197                         p.add(codelist);
198
199                         guidearea=new FordFulkTextArea();
200                         guidearea.setEditable(false);
201                         gbc.weighty=1;
202                         gb.setConstraints(guidearea,gbc);
203                         p.add(guidearea);
204                         add(p);
205                         }
206         }
207
208         public void start()
209         {
210                 lineno=0; codeListSelect();
211                 newStopAt(0);
212                 javaCleanCode(true);
213                 thread=new FordFulkThread(this,false);
214                 thread.start();
215                 new FordFulkThread(this,true).start();
216         }
217         
218         public synchronized void setNumText(TextField t,int i,boolean ifplus)
219         {
220                 String s;
221                 switch (i) {
222                         case -1: s="single"; break;
223                         case 0:  s="stop";   break;
224                         case Integer.MAX_VALUE: s="never"; break;
225                         default: s=new Integer(i).toString()+(ifplus?"+":"");
226                         }
227                 t.setText(s);
228 }
229
230         public synchronized void codeListSelect()
231         {
232                 setNumText(linenotext,lineno,false);
233                 if (lineno!=0) {
234                         codelist.select(lineno-1);
235                         codelist.makeVisible(lineno-1);
236                         }
237                 else codelist.deselect(codelist.getSelectedIndex());
238                 String s=(String)guides.get(new Integer(lineno));
239                 if (s==null) s="Sorry, no guide defined for line "+lineno+".";
240                 guidearea.setRawText(s);
241         }
242
243         public synchronized void newStopAt(int newstop)
244         {
245                 setNumText(stopattext,stopat=newstop,stopplus);
246                 if (thread==null) return;
247                 thread.resume(); thread.interrupt();
248         }
249
250         public synchronized boolean handleEvent(Event ev)
251         {
252                 if (ev.target==codelist && (ev.id==ev.LIST_SELECT || ev.id==ev.LIST_DESELECT || ev.id==ev.ACTION_EVENT))
253                         { newStopAt(codelist.getSelectedIndex()+1); return true; }
254                 switch (ev.id) {
255                         case ev.LIST_SELECT:
256                                 break;
257                         case ev.ACTION_EVENT:
258                                 if (ev.target==nextlinestep)
259                                         { stopplus=false; newStopAt(lineno+1); return true; }
260                                 if (ev.target==singlestep)
261                                         { newStopAt(-1); return true; }
262                                 if (ev.target==continuerun)
263                                         { newStopAt(Integer.MAX_VALUE); return true; }
264                                 if (ev.target==advancestep)
265                                         { stopplus=true; newStopAt(lineno+1); return true; }
266                                 if (ev.target==stopnow)
267                                         { newStopAt(0); return true; }
268                                 if (ev.target==resetnow)
269                                         {
270                                                 lineno=0; codeListSelect();
271                                                 newStopAt(0);
272                                                 javaCleanCode(true);
273                                                 return true;
274                                         }
275                                 break;
276                         }
277                 return false;
278         }
279
280         public String getAppletInfo()
281         {
282                 return(
283                         "FordFulk by Jan Kratochvil <short@ucw.cz> in 1998.\n"+
284                         "Redistribution permitted under GNU General Public License (AKA GPL) version 2 (exactly) found on ftp://prep.ai.mit.edu/pub/gnu/GPL."
285                         );
286         }
287
288         public static void drawLine(Graphics g,Point p1,Point p2)
289         { g.drawLine(p1.x,p1.y,p2.x,p2.y); }
290         public static void drawString(Graphics g,String s,FordFulkPoint p,Color Bg,boolean docen,double fntscl)
291         {
292                 Font of=g.getFont();
293                 g.setFont(new Font(of.getName(),of.getStyle(),(int)(of.getSize()*fntscl)));
294                 FontMetrics m=g.getFontMetrics();
295                 int w=m.stringWidth(s);
296                 if (docen) p.translate(-w/2.,+m.getAscent()/2.);
297                 Point ip=p.point();
298                 if (Bg!=null) {
299                         int h=m.getAscent()+m.getDescent();
300                         Color tc=g.getColor();
301                         g.setColor(Bg);
302                         g.fillRect(ip.x,ip.y-m.getAscent(),w,h);
303                         g.setColor(tc);
304                         }
305                 g.drawString(s,ip.x,ip.y);
306                 g.setFont(of);
307         }
308         public static void fillCircleColor(Graphics g,Point p,int r,Color c)
309         {
310                 if (c!=null) g.setColor(c);
311                 g.fillOval(p.x,p.y,r,r);
312         }
313
314 Enumeration l2e=null;
315 FordFulkWire l3w=null,l5w=null,l20w=null;
316 Vector l6v=null;
317 int l7S=0,l9T=0,l17D=0,l18J=0,l19I=0;
318
319         public synchronized void javaCleanCode(boolean hard)
320         {
321         FordFulk main=this; //for future separation
322
323                 Enumeration e=main.net.W.elements();
324                 while (e.hasMoreElements()) {
325                         FordFulkWire w=(FordFulkWire)e.nextElement();
326                         w.flgforw=w.flgback=null;
327                         if (hard) w.T=0;
328                         }
329                 for (int i=0;i<main.net.nodes;i++) {
330                         main.net.A[i].state=null;
331                         main.net.A[i].back=-1;
332                         }
333                 for (int i=0;i<7;i++) main.net.tgtseta(i,null);
334                 main.net.tgtsetD(null);
335                 main.net.repaint();
336         }
337
338         public int javaCode()
339         {
340         FordFulk main=this; //for future separation
341
342                 switch (lineno) {
343                         case 0:
344                                 javaCleanCode(true);
345                                 break;
346                         case 1:
347                                 break;
348                         case 2:
349                                 l2e=main.net.W.elements();
350                                 break;
351                         case 3:
352                                 if (!l2e.hasMoreElements()) {
353                                         main.net.repaint();
354                                         return 6;
355                                         }
356                                 l3w=(FordFulkWire)l2e.nextElement();
357                                 main.net.tgtseta(0,main.net.A[l3w.i]);
358                                 main.net.tgtseta(1,l3w);
359                                 main.net.tgtseta(2,null);
360                                 main.net.tgtseta(3,main.net.A[l3w.j]);
361                                 main.net.repaint();
362                                 break;
363                         case 4:
364                                 l3w.flgforw=((l3w.T<l3w.C) ?main.wireflgyescolor:main.wireflgnocolor);
365                                 l5w=(FordFulkWire)main.net.W.get(new Point(l3w.j,l3w.i));
366                                 main.net.tgtseta(2,l5w);
367                                 main.net.repaint();
368                                 break;
369                         case 5:
370                                 l3w.flgback=((l5w!=null && l5w.T>0) ?main.wireflgyescolor:main.wireflgnocolor);
371                                 for (int i=0;i<=3;i++) main.net.tgtseta(i,null);
372                                 main.net.repaint();
373                                 return 3;
374                         case 6:
375                                 main.net.A[main.net.iniS].state=main.nodeactivecolor;
376                                 l6v=new Vector();
377                                 l6v.addElement(new Integer(main.net.iniS));
378                                 main.net.repaint();
379                                 break;
380                         case 7:
381                                 if (l6v.size()==0) return 14;
382                                 l7S=((Integer)l6v.elementAt(0)).intValue();
383                                 main.net.tgtseta(4,main.net.A[l7S]);
384                                 main.net.repaint();
385                                 break;
386                         case 8:
387                                 if (l7S==main.net.iniD) return 14;
388                                 l9T=-1;
389                                 break;
390                         case 9:
391                                 while (++l9T<main.net.nodes)
392                                         if (main.net.A[l9T].state==null) {
393                                                 main.net.tgtseta(6,main.net.A[l9T]);
394                                                 main.net.repaint();
395                                                 return 0;
396                                                 }
397                                 main.net.tgtseta(5,null);
398                                 main.net.tgtseta(6,null);
399                                 main.net.repaint();
400                                 return 13;
401                         case 10:
402                                 FordFulkWire wST=(FordFulkWire)main.net.W.get(new Point(l7S,l9T));
403                                 FordFulkWire wTS=(FordFulkWire)main.net.W.get(new Point(l9T,l7S));
404                                 if (!((wST!=null && wST.flgforw==main.wireflgyescolor)
405                                         ||(wTS!=null && wTS.flgback==main.wireflgyescolor)))
406                                         return 9;
407                                 main.net.tgtseta(5,wST);
408                                 main.net.repaint();
409                                 break;
410                         case 11:
411                                 main.net.A[l9T].state=main.nodeactivecolor;
412                                 l6v.addElement(new Integer(l9T));
413                                 main.net.repaint();
414                                 break;
415                         case 12:
416                                 main.net.A[l9T].back=l7S;
417                                 main.net.repaint();
418                                 return 9;
419                         case 13:
420                                 l6v.removeElementAt(0);
421                                 main.net.A[l7S].state=main.nodepassedcolor;
422                                 main.net.repaint();
423                                 return 7;
424                         case 14:
425                                 if (l6v.size()!=0) return 16;
426                                 break;
427                         case 15:
428                                 return 99;
429                         case 16:
430                                 int i;
431                                 for (i=0;i<main.net.nodes;i++) main.net.A[i].backused=false;
432                                 i=main.net.iniD;
433                                 for (i=main.net.iniD;i>=0;i=main.net.A[i].back) main.net.A[i].backused=true;
434                                 for (i=0;i<main.net.nodes;i++)
435                                         if (!main.net.A[i].backused) main.net.A[i].back=-1;
436                                 main.net.repaint();
437                                 break;
438                         case 17:
439                                 l17D=Integer.MAX_VALUE;
440                                 main.net.tgtsetD("inf");
441                                 main.net.repaint();
442                                 break;
443                         case 18:
444                         case 24:
445                                 main.net.tgtseta(0,main.net.A[l19I=main.net.iniD]);
446                                 main.net.repaint();
447                                 break;
448                         case 19:
449                         case 25:
450                                 main.net.tgtseta(1,null);
451                                 main.net.tgtseta(3,main.net.A[l18J=l19I]);
452                                 if ((l19I=main.net.A[l18J].back)==-1) {
453                                         main.net.tgtseta(0,null);
454                                         main.net.tgtseta(1,null);
455                                         main.net.repaint();
456                                         return lineno+5;//19->24,25->30
457                                         }
458                                 main.net.tgtseta(0,main.net.A[l19I]);
459                                 l20w=(FordFulkWire)main.net.W.get(new Point(l19I,l18J));
460                                 main.net.tgtseta(1,l20w);
461                                 main.net.repaint();
462                                 break;
463                         case 20:
464                         case 26:
465                                 if (l20w==null || l20w.flgforw!=main.wireflgyescolor) return lineno+2;//20->22,26->28
466                                 main.net.tgtseta(1,l20w);
467                                 main.net.repaint();
468                                 break;
469                         case 21:
470                                 l17D=Math.min(l17D,l20w.C-l20w.T);
471                                 main.net.tgtsetD(new Integer(l17D).toString());
472                                 main.net.repaint();
473                                 break;
474                         case 27:
475                                 l20w.T+=l17D;
476                                 main.net.repaint();
477                                 break;
478                         case 22:
479                         case 28:
480                                 if (l20w==null || l20w.flgback!=main.wireflgyescolor) return lineno-3;//22->19,28->25
481                                 break;
482                         case 23:
483                                 l17D=Math.min(l17D,((FordFulkWire)main.net.W.get(new Point(l18J,l19I))).T);
484                                 main.net.tgtsetD(new Integer(l17D).toString());
485                                 main.net.repaint();
486                                 return 19;
487                         case 29:
488                                 ((FordFulkWire)main.net.W.get(new Point(l18J,l19I))).T-=l17D;
489                                 main.net.repaint();
490                                 break;
491                         case 30:
492                                 javaCleanCode(false);
493                                 break;
494                         case 31:
495                                 return 1;
496                         }
497                 return 0;
498         }
499
500         public synchronized void cycle()
501         {
502                 statustext.setText(stext[0]);
503                 codeListSelect();
504                 if (stopat==0) return;
505                 int newline;
506                 if ((newline=javaCode())==0) newline=lineno+1;
507                 if (newline>linestot) {
508                         newline=0;
509                         setNumText(stopattext,stopat=0,stopplus=false);
510                         }
511                 if (stopat==-1 || stopat==newline || (stopat<newline && stopplus))
512                         setNumText(stopattext,stopat=0,stopplus=false);
513                 lineno=newline;
514                 codeListSelect();
515         }
516 }
517
518 class FordFulkTextArea extends TextArea
519 {
520 private String conts="";
521 static final int VBARWIDTH=40,CHARWIDTH=8;
522 boolean painted=false,once=true;
523 int lastwidth=-1;
524
525         public void setRawText(String s)
526         {
527                 if (conts==s) return;
528                 conts=s;
529                 lastwidth=-1;
530                 if (!painted) rawRefresh(null);
531                 repaint();
532         }
533
534         public void paint(Graphics g)
535         {
536                 if (!painted) {
537                         painted=true;
538                         if (!once)
539                                 System.out.println("M$ Internet Explorer TextArea paint() override bug was a false alarm, this JVM is OK, sorry.");
540                         }
541                 rawRefresh(g.getFontMetrics());
542                 super.paint(g);
543         }
544
545         public synchronized void rawRefresh(FontMetrics m)
546         {
547                 int cols=Math.max(10,size().width-VBARWIDTH);
548                 if (cols==lastwidth) return;
549                 String s=new String(conts),line="",nline;
550                 int totc=0;
551                 setText("");
552                 int spl=(m==null?CHARWIDTH/2:m.stringWidth(" "));
553                 int ll=Integer.MAX_VALUE,cl;
554                 while ((cl=s.length())<ll && cl>0) {
555                         cl=ll;
556                         int i,j;
557                         if (s.charAt(0)=='\n') {
558                                 appendText(line+"\n");
559                                 line="";
560                                 s=s.substring(1);
561                                 continue;
562                                 }
563                         while ((i=s.indexOf(' '))==0) s=s.substring(1);
564                         if (i==-1) i=s.length();
565                         if ((j=s.substring(0,i).indexOf('\n'))!=-1) i=j;
566                         nline=new String(line);
567                         if (line.length()!=0) nline+=" ";
568                         nline+=s.substring(0,i);
569                         int thisw;
570                         if (m!=null) thisw=m.stringWidth(nline);
571                         else thisw=nline.length()*CHARWIDTH;
572                         if (thisw>cols && line.length()!=0) {
573                                 appendText(line+"\n");
574                                 line=s.substring(0,i);
575                                 }
576                         else line=nline;
577                         s=s.substring(i);
578                         }
579                 appendText(line);
580         }
581 }
582
583 class FordFulkThread extends Thread
584 {
585 FordFulk main;
586 static int cs_v[]={0,100,500,2000};
587 boolean justfortest;
588
589         public FordFulkThread(FordFulk _main,boolean _justfortest)
590         {
591                 main=_main;
592                 if (justfortest=_justfortest) setDaemon(true);
593         }
594
595         public void run()
596         {
597                 if (justfortest) {
598                         while (main.suspendtest) {
599                                 try {
600                                         main.thread.countStackFrames();
601                                         main.suspendbug=false;
602                                         main.thread.resume();
603                                         if (!main.suspendtest) break;
604                                         }
605                                 catch (IllegalThreadStateException e) {}
606                                 try { sleep(main.BUGGYSLEEP); }
607                                 catch (InterruptedException e) {}
608                                 }
609                         stop();
610                         return;
611                         }
612                 suspend();
613                 main.suspendtest=false;
614                 if (main.suspendbug)
615                         System.out.println("Netscape Communicator suspend() bug, workarounding it...");
616                 for (;;) {
617                         main.cycle();
618                         if (main.stopat==0) {
619                                 main.statustext.setText(main.stext[2]);
620                                 while (main.stopat==0) {
621                                         if (!main.suspendbug) suspend();
622                                         else try { sleep(main.BUGGYSLEEP); }
623                                         catch (InterruptedException e) {}
624                                         }
625                                 }
626                         else {
627                                 main.statustext.setText(main.stext[1]);
628                                 if (main.guidearea.once) {
629                                         main.guidearea.once=false;
630                                         System.out.println("M$ Internet Explorer TextArea paint() override bug, workarounding it...");
631                                         }
632                                 try { sleep((long)cs_v[main.codespeed.getSelectedIndex()]); }
633                                 catch (InterruptedException e) {}
634                                 }
635                         }
636         }
637 }
638
639 class FordFulkDataStream extends DataInputStream
640 {
641 private String TERM="-";
642 private int togo=-1;
643
644         public FordFulkDataStream(InputStream s)
645         { super(s); }
646         public void lineLimit(int _togo)
647         { togo=_togo; }
648
649         public String getLine() throws IOException
650         {
651                 if (togo==0) return null;
652                 String l=readLine();
653                 if (l==null) { togo=0; return null; }
654                 if (l.trim().compareTo(TERM)==0) { togo=0; return null; }
655                 togo--;
656                 return l;
657         }
658
659         public void nextSection() throws IOException
660         {
661                 if (togo!=0) throw new IOException("nextSection() but togo=="+togo+"!");
662                 togo=-1;
663         }
664 }
665
666 class FordFulkPoint
667 {
668 double x,y;
669
670         public FordFulkPoint(int _x,int _y)
671         { x=_x; y=_y; }
672         public FordFulkPoint(double _x,double _y)
673         { x=_x; y=_y; }
674         public FordFulkPoint(FordFulkPoint p)
675         { x=p.x; y=p.y; }
676         public FordFulkPoint(Point p)
677         { x=p.x; y=p.y; }
678         public FordFulkPoint(FordFulkPoint p1,FordFulkPoint p2,double w)
679         { x=p1.point().x*(1-w)+p2.point().x*w; y=p1.point().y*(1-w)+p2.point().y*w; }
680         public FordFulkPoint(FordFulkPoint p1,FordFulkPoint p2) //arit. avg
681         { x=(p1.x+p2.x)/2; y=(p1.y+p2.y)/2; }
682         public void sub(FordFulkPoint p)
683         { x-=p.x; y-=p.y; }
684         public void sub(Point p)
685         { sub(new FordFulkPoint(p)); }
686         public Point point()
687         { return new Point((int)x,(int)y); }
688         public Dimension dimension()
689         { return new Dimension((int)x,(int)y); }
690         public void translate(double _x,double _y)
691         { x+=_x; y+=_y; }
692         public void translate(FordFulkPoint p)
693         { translate(p.x,p.y); }
694         public void rotplus90()
695         { double t=x; x=-y; y=t; }
696         public void rotminus90()
697         { double t=x; x=y; y=-t; }
698         public double length()
699         { return Math.sqrt(x*x+y*y); }
700         public void multiply(double c)
701         { x*=c; y*=c; }
702         public void normalize(double len)
703         { multiply(len/length()); }
704         public void negate()
705         { x=-x; y=-y; }
706         public String toString()
707         { return "FFP(x="+x+",y="+y+")"; }
708 }
709
710 interface FordFulkTargetable
711 {
712         public FordFulkPoint center();
713         public FordFulkPoint ffpSize();
714 }
715
716 class FordFulkWire implements FordFulkTargetable
717 {
718 FordFulk main;
719 int i,j;
720 int C,T=0;
721 Color flgforw=null,flgback=null;
722
723 FordFulkPoint p1,p2;
724
725         public FordFulkWire(FordFulk _main,int _i,int _j,int _C)
726         { main=_main; i=_i; j=_j; C=_C; }
727         public void setup12(int shift)
728         {
729 FordFulkPoint rln;
730                 p1=main.net.A[i].center();
731                 p2=main.net.A[j].center();
732                 rln=new FordFulkPoint(p2);
733                 rln.sub(p1);
734                 rln.rotplus90();
735                 rln.normalize(shift);
736                 p1.translate(rln); p2.translate(rln);
737         }
738         public synchronized void drawArrow(Graphics g,int shift)
739         {
740                 setup12(shift);
741                 anyArrow(main,g,p1,p2,main.net.nodeSize/2);
742         }
743
744         public static void anyArrow(FordFulk main,Graphics g,FordFulkPoint p1,FordFulkPoint p2,double shorten)
745         {
746 FordFulkPoint arrdir,arrwing,efix;
747
748                 arrdir=new FordFulkPoint(p2);
749                 arrdir.sub(p1);
750                 efix=new FordFulkPoint(arrdir);
751                 efix.normalize(-(shorten-1));
752                 p2.translate(efix);
753                 FordFulk.drawLine(g,p1.point(),p2.point());
754                 arrdir.normalize(main.WIREARROW);
755                 arrwing=new FordFulkPoint(arrdir);
756                 arrwing.rotplus90();
757                 arrdir=new FordFulkPoint(arrdir,arrwing);
758                 arrdir.negate();
759                 arrwing=new FordFulkPoint(p2); arrwing.translate(arrdir);
760                 FordFulk.drawLine(g,p2.point(),arrwing.point());
761                 arrdir.rotminus90();
762                 arrwing=new FordFulkPoint(p2); arrwing.translate(arrdir);
763                 FordFulk.drawLine(g,p2.point(),arrwing.point());
764                 efix.negate();
765                 p1.translate(efix);
766         }
767
768         public synchronized FordFulkPoint center()
769         {
770                 setup12(main.WIRESHIFT);
771                 return new FordFulkPoint(p1,p2);
772         }
773         public FordFulkPoint ffpSize()
774         { return new FordFulkPoint(1,1); }
775
776         public synchronized void paint(Graphics g)
777         {
778                 if (main==null) return;
779                 g.setColor(main.wirecolor);
780                 drawArrow(g,main.WIRESHIFT);
781
782                 g.setColor(main.wiretextfgcolor);
783                 FordFulk.drawString(g,T+"/"+C,
784                         new FordFulkPoint(p1,p2,main.WIRECAPBALANCE),
785                         main.wiretextbgcolor,true,main.WIREFONTSCALE);
786                 if (flgforw!=null)
787                         FordFulk.fillCircleColor(g,
788                                 new FordFulkPoint(p1,p2,main.WIREFLGBALANCE).point(),
789                                 main.WIREFLGRADIUS,flgforw);
790                 if (flgback!=null)
791                         FordFulk.fillCircleColor(g,
792                                 new FordFulkPoint(p1,p2,1-main.WIREFLGBALANCE).point(),
793                                 main.WIREFLGRADIUS,flgback);
794         }
795 }
796
797 class FordFulkNode implements FordFulkTargetable
798 {
799 FordFulk main;
800 int no; String no_s;
801 Color state=null;
802 int back=-1;
803 boolean backused;
804 Point pxy;
805
806         public FordFulkNode(FordFulk _main,int _no,Point _pxy)
807         {
808                 main=_main; pxy=_pxy;
809                 no_s=new Integer(no=_no).toString();
810                 if (no==main.net.iniS) no_s+="s";
811                 if (no==main.net.iniD) no_s+="d";
812         }
813
814         public FordFulkPoint ffpSize()
815         { return new FordFulkPoint(main.net.nodeSize,main.net.nodeSize); }
816         public Dimension size()
817         { return ffpSize().dimension(); }
818         public FordFulkPoint ffpLocation()
819         { return new FordFulkPoint(
820                         main.net.unitShift.x+main.net.unitSize.x*pxy.x,
821                         main.net.unitShift.y+main.net.unitSize.y*pxy.y);
822         }
823         public Point location()
824         { return ffpLocation().point(); }
825         public Rectangle bounds()
826         { return new Rectangle(location(),size()); }
827
828         public void justBack(Graphics g)
829         {
830                 if (no<0 || back<0) return;
831                 FordFulkWire ffw=new FordFulkWire(main,no,back,0);
832                 g.setColor(main.wirebackcolor);
833                 ffw.drawArrow(g,0);
834         }
835
836         public void paint(Graphics g)
837         {
838                 if (no<0) return;
839                 Rectangle me=bounds();
840                 g.setColor(main.net.getBackground());
841                 g.fillOval(me.x,me.y,me.width,me.height);
842                 g.setColor(main.net.getForeground());
843                 g.drawOval(me.x,me.y,me.width,me.height);
844                 g.setColor(state);
845                 FordFulk.drawString(g,no_s,center(),null,true,main.NODEFONTSCALE);
846         }
847
848         public FordFulkPoint center()
849         {
850                 FordFulkPoint xy=ffpLocation(),wh=ffpSize();
851                 return new FordFulkPoint(xy.x+wh.x/2,xy.y+wh.y/2);
852         }
853 }
854
855 class FordFulkNet extends Panel
856 {
857 FordFulk main;
858 int nodes;
859 FordFulkNode A[];
860 Hashtable W=new Hashtable();
861 int iniS,iniD;
862 Vector blind=new Vector();
863 int nodesx=1,nodesy=1;
864 double nodeSize;
865 FordFulkPoint unitShift,unitSize;
866
867 String tgts[]={"i","Eij","Eji","j","s","Est","t",null};
868 FordFulkTargetable tgta[]=new FordFulkTargetable[7];
869
870         public FordFulkNet(FordFulk _main)
871         { main=_main; }
872         public void setup(Vector pnts,Vector wires,Vector inis)
873         {
874                 setBackground(Color.white);
875                 nodes=pnts.size()/2;
876                 iniS=((Integer)inis.elementAt(0)).intValue();
877                 iniD=((Integer)inis.elementAt(1)).intValue();
878                 Hashtable ndh=new Hashtable();
879                 for (int i=0;i<nodes;i++) {
880                         int y=((Integer)pnts.elementAt(i*2  )).intValue(),
881                                         x=((Integer)pnts.elementAt(i*2+1)).intValue();
882                         nodesy=Math.max(nodesy,y+1);
883                         nodesx=Math.max(nodesx,x+1);
884                         ndh.put(new Point(x,y),new Integer(i));
885                         }
886                 A=new FordFulkNode[nodes];
887                 for (int i=0;i<7;i++) tgta[i]=null;
888                 for (int y=0;y<nodesy;y++)
889                 for (int x=0;x<nodesx;x++) {
890                         Integer ii;
891                         Point pxy=new Point(x,y);
892                         if ((ii=(Integer)ndh.get(pxy))==null)
893                                 blind.addElement(new FordFulkNode(main,-1,pxy));
894                         else
895                                 A[ii.intValue()]=new FordFulkNode(main,ii.intValue(),pxy);
896                         }
897                 int wirecnt=wires.size()/3;
898                 for (int i=0;i<wirecnt;i++) addWire(
899                                 ((Integer)wires.elementAt(i*3  )).intValue(),
900                                 ((Integer)wires.elementAt(i*3+1)).intValue(),
901                                 ((Integer)wires.elementAt(i*3+2)).intValue());
902         }
903         public void remWire(int i,int j)
904         { W.remove(new Point(i,j)); repaint(); }
905         public void addWire(int i,int j,int C)
906         { W.put(new Point(i,j),new FordFulkWire(main,i,j,C)); repaint(); }
907
908         public synchronized void tgtsetD(String d)
909         { tgts[7]=(d==null?null:"+"+d); }
910         public synchronized void tgtseta(int i,FordFulkTargetable tgt)
911         { tgta[i]=tgt; }
912         public synchronized void paint(Graphics gg)
913         {
914                 if (A==null) return;
915                 Dimension sz=size();
916                 Image img=createImage(sz.width,sz.height);
917                 Graphics g=img.getGraphics();
918
919                 unitSize=new FordFulkPoint(
920                         sz.width /(nodesx+1-main.NODEGAPSCALE),
921                         sz.height/(nodesy+1-main.NODEGAPSCALE));
922                 nodeSize=Math.min(unitSize.x,unitSize.y);
923                 unitShift=new FordFulkPoint(
924                         unitSize.x*(1-main.NODEGAPSCALE)+(unitSize.x-nodeSize)/2,
925                         unitSize.y*(1-main.NODEGAPSCALE)+(unitSize.y-nodeSize)/2);
926                 nodeSize*=main.NODEGAPSCALE;
927                 //System.out.println("nodeSize="+nodeSize+",unitShift="+unitShift+",unitSize="+unitSize+",nodesx="+nodesx+",nodesy="+nodesy);
928
929                 Enumeration e=W.elements();
930                 while (e.hasMoreElements()) ((FordFulkWire)e.nextElement()).paint(g);
931                 for (int i=0;i<nodes;i++) A[i].justBack(g);
932                 for (int i=0;i<nodes;i++) A[i].paint(g);
933
934                 double dist=sz.width/9.;
935                 FontMetrics m=g.getFontMetrics();
936                 int fny=sz.height-2*m.getLeading()-(m.getAscent()+m.getDescent())/2;
937                 for (int i=0;i<7;i++) {
938                         if (tgta[i]==null) continue;
939                         double fnx=(i+1)*dist;
940                         g.setColor(main.tgttextfgcolor);
941                         FordFulk.drawString(g," "+tgts[i]+" ",new FordFulkPoint(fnx,(double)fny),main.tgttextbgcolor,true,1.);
942                         g.setColor(main.tgtarrowcolor);
943                         FordFulkWire.anyArrow(main,g,new FordFulkPoint(fnx,(double)(sz.height-m.getHeight()-1)),tgta[i].center(),tgta[i].ffpSize().x/4);
944                         }
945                 if (tgts[7]!=null) {
946                         g.setColor(main.tgttextfgcolor);
947                         FordFulk.drawString(g," d="+tgts[7]+" ",new FordFulkPoint(8*dist,(double)(fny-1)),main.tgttextbgcolor,true,1.);
948                         }
949                 gg.drawImage(img,0,0,this);
950         }
951         public void update(Graphics gg)
952         { paint(gg); }
953 }