gt:             Transition tr = trs[i];
context: package org.kohsuke.bali.writer;
  
  import java.io.File;
  import java.io.FileOutputStream;
  import java.io.FileWriter;
  import java.io.IOException;
  import java.io.InputStream;
  import java.io.OutputStream;
  import java.io.PrintWriter;
  import java.io.StringWriter;
  import java.text.MessageFormat;
  import java.util.ArrayList;
  import java.util.HashMap;
  import java.util.Iterator;
  
  import org.kohsuke.bali.automaton.Alphabet;
  import org.kohsuke.bali.automaton.AttributeAlphabet;
  import org.kohsuke.bali.automaton.DataAlphabet;
  import org.kohsuke.bali.automaton.ElementAlphabet;
  import org.kohsuke.bali.automaton.InterleaveAlphabet;
  import org.kohsuke.bali.automaton.ListAlphabet;
  import org.kohsuke.bali.automaton.NameSignature;
  import org.kohsuke.bali.automaton.NonExistentAttributeAlphabet;
  import org.kohsuke.bali.automaton.State;
  import org.kohsuke.bali.automaton.TextAlphabet;
  import org.kohsuke.bali.automaton.Transition;
  import org.kohsuke.bali.automaton.TreeAutomaton;
  import org.kohsuke.bali.automaton.ValueAlphabet;
  import org.kohsuke.bali.datatype.DatatypeImpl;
  import org.kohsuke.bali.datatype.Parameter;
  import org.kohsuke.bali.datatype.Value;
  import org.relaxng.datatype.Datatype;
  
  import com.sun.msv.util.StringPair;
  
  /**
   * Produces C++ code for Windows/Visual C++ environment
   * that works with MSXML.
   * 
   * @author Kohsuke Kawaguchi (kk@kohsuke.org)
   */
  public class WinCppWriter implements AutomatonWriter {
  
      public WinCppWriter( String namespaceName, String className, File outDir ) throws IOException {
          this.namespaceName = namespaceName;
          this.className = className;
          
          targetDir = outDir;
          cppFile =    new PrintWriter( new FileWriter( new File( outDir, className+".cpp" ) ) );
          headerFile = new PrintWriter( new FileWriter( new File( outDir, className+".h" ) ) );
      }
  
      /** Namespace to put the generated code, or null if no namespace is necessary. */
      private final String namespaceName;
      
      private final String className;
      
      /** Writer connected to the generated source file. */
      private final PrintWriter cppFile;
      
      /** Writer connected to the generated header file. */
      private final PrintWriter headerFile;
      
      /** The directory to which all the generated files will be placed. */
      private final File targetDir;
      
      /**
       * Stores objects and assign them continuous index number that 
       * starts from 0.
       * <p>
       * Used to store transitions into one array.
       */
      private class IndexMap
      {
          /** back-end storage. */
          private final HashMap core = new HashMap();
          /** storage for reverse look up */
          private final ArrayList list = new ArrayList();
          
          /** Gets the index assigned to the given object. */
          public int get( Object o ) {
              // let it cause an error if the object is not in the table
              return ((Integer)core.get(o)).intValue();
          }
          
          /** Gets the object with the specified index. */
          public Object get( int index ) {
              return list.get(index);
          }
          
          public int size() { return list.size(); }
          
          /**
           * Stores a new object into the map.
           * 
           * If the specified object is new, this method assigns a new
           * index and returns it. If it is already contained in this set,
           * just return the existing index number.
           */
          public int put( Object o ) {
              Object v = core.get(o);
              if(v!=null)     return ((Integer)v).intValue();
              
              // new object. assign a new number
              core.put( o, new Integer(index) );
              list.add( o );
              return index++;
          }
          
          public boolean contains( Object o ) {
              return core.containsKey(o);
          }
          
          private int index = 0;
      }
  
      
      
      
      public void write(TreeAutomaton automaton) throws IOException {
          // initialize buffers
          datatypesCode = new StringWriter();
          datatypesWriter = new PrintWriter(datatypesCode);
          datatypes = new IndexMap();
          
          nameTestsCode = new StringWriter();
          nameTestsWriter = new PrintWriter(nameTestsCode);
          
          cppFile.println("#include \"stdafx.h\"");
          cppFile.println("#include \"validateletImpl.h\"");
          cppFile.println("#include \""+className+".h\"");
          cppFile.println();
  
          if( namespaceName!=null )
              cppFile.println("namespace "+namespaceName+" {");
          
          cppFile.println("using namespace MSXML2;");
          cppFile.println("using namespace bali;");
          cppFile.println("using namespace bali::transition;");
          cppFile.println();
          
          cppFile.println("SingleState states[];");
          cppFile.println("Datatype* datatypes[];");
          cppFile.println("NameSignature nameTests[];");
          cppFile.println();
          
          
          // do the real work
          
          State[] states = automaton.getStates();
          
          // print attributes
          IndexMap amap = printAlphabets( automaton, AttributeAlphabet.class, "Att", "aTr",
              new Printer() {
                  public void print(Transition tr, int previousIndex) {
                      AttributeAlphabet a = (AttributeAlphabet)tr.alphabet;
                      
                      cppFile.println(MessageFormat.format(
                          "  '{' '{' {0},{1} '}',{2},states+{3},states+{4},{5} '}',",
                          new Object[] {
                              new Integer(a.name.mask),
                              new Integer(a.name.test),
                              a.repeated?"true":"false",
                              new Integer(tr.left.id),
                              new Integer(tr.right.id),
                              (previousIndex==-1)?"NULL":"aTr+"+previousIndex }));
                  }
                  public void printEmptyLine() {
                      cppFile.println(" { {-1,-1}, false,NULL,NULL,NULL },");
                  }
              });
          
          // print datatype alphabets
          IndexMap dmap = printAlphabets( automaton, TextAlphabet.class, "Data", "dTr",
              new Printer() {
                  public void print(Transition tr, int previousIndex) {
                      if( tr.alphabet instanceof DataAlphabet ) {
                          DataAlphabet d = (DataAlphabet)tr.alphabet;
                          
                          cppFile.println(MessageFormat.format(
                              "  '{' states+{0},states+{1},datatypes+{2},{3} '}',",
                              new Object[] {
                                  new Integer(tr.left.id),
                                  new Integer(tr.right.id),
                                  new Integer(printDatatype(d.datatype)),
                                  (previousIndex==-1)?"NULL":"dTr+"+previousIndex }));
                      }
                      if( tr.alphabet instanceof ValueAlphabet ) {
                          ValueAlphabet v = (ValueAlphabet)tr.alphabet;
                          
                          cppFile.println(MessageFormat.format(
                              "  '{' NULL,states+{1},datatypes+{2},{3} '}',",
                              new Object[] {
                                  null,
                                  new Integer(tr.right.id),
                                  new Integer(printDatatype(v)),
                                  (previousIndex==-1)?"NULL":"dTr+"+previousIndex }));
                      }
                  }
                  public void printEmptyLine() {
                      cppFile.println(" { NULL,NULL,NULL,NULL },");
                  }
              });
          
          // print elements
          IndexMap emap = printAlphabets( automaton, ElementAlphabet.class, "Element", "eTr",
              new Printer() {
                  public void print(Transition tr, int previousIndex) {
                      ElementAlphabet e = (ElementAlphabet)tr.alphabet;
                      
                      cppFile.println(MessageFormat.format(
                          "  '{' '{' {0},{1} '}',states+{2},states+{3},{4} '}',",
                          new Object[] {
                              new Integer(e.name.mask),
                              new Integer(e.name.test),
                              new Integer(tr.left.id),
                              new Integer(tr.right.id),
                              (previousIndex==-1)?"NULL":"eTr+"+previousIndex }));
                  }
                  public void printEmptyLine() {
                      cppFile.println(" { {-1,-1}, NULL,NULL,NULL },");
                  }
              });
          
          // print interleaves
          IndexMap imap = printAlphabets( automaton, InterleaveAlphabet.class, "Interleave", "iTr",
              new Printer() {
                  public void print(Transition tr, int previousIndex) {
                      InterleaveAlphabet i = (InterleaveAlphabet)tr.alphabet;
                      
                      cppFile.println(MessageFormat.format(
                          "  '{' states+{0},states+{1},states+{2},{3},{4} '}',",
                          new Object[] {
                              new Integer(tr.left.id),
                              new Integer(tr.right.id),
                              new Integer(i.join.id),
                              i.textToLeft?"true":"false",
                              (previousIndex==-1)?"NULL":"iTr+"+previousIndex }));
                  }
                  public void printEmptyLine() {
                      cppFile.println(" { NULL,NULL,NULL,false,NULL },");
                  }
              });
          
          // print lists
          IndexMap lmap = printAlphabets( automaton, ListAlphabet.class, "List", "lTr",
              new Printer() {
                  public void print(Transition tr, int previousIndex) {
                      ListAlphabet l = (ListAlphabet)tr.alphabet;
                      
                      cppFile.println(MessageFormat.format(
                          "  '{' states+{0},states+{1},{2} '}',",
                          new Object[] {
                              new Integer(tr.left.id),
                              new Integer(tr.right.id),
                              (previousIndex==-1)?"NULL":"lTr+"+previousIndex }));
                  }
                  public void printEmptyLine() {
                      cppFile.println(" { NULL,NULL,NULL },");
                  }
              });
          
          // print nonAtts
          IndexMap nmap = printAlphabets( automaton, NonExistentAttributeAlphabet.class, "NoAtt", "nTr",
              new Printer() {
                  public void print(Transition tr, int previousIndex) {
                      NonExistentAttributeAlphabet n = (NonExistentAttributeAlphabet)tr.alphabet;
                      
                      cppFile.println(MessageFormat.format(
                          "  '{' states+{0},nameTests+{1},{2},nameTests+{3},{4},{5} '}',",
                          new Object[] {
                              new Integer(tr.right.id),
                              printNameTests(n.negativeNameTests),
                              new Integer(n.negativeNameTests.length),
                              printNameTests(n.positiveNameTests),
                              new Integer(n.positiveNameTests.length),
                              (previousIndex==-1)?"NULL":"nTr+"+previousIndex }));
                  }
                  public void printEmptyLine() {
                      cppFile.println(" { NULL,NULL,0,NULL,0,NULL },");
                  }
              });
          
          
          {// print datatype objects
              String str = datatypesCode.getBuffer().toString();
              if(str.length()!=0) {
                  cppFile.println("static Datatype* datatypes[] = {");
                  cppFile.write(str);
                  cppFile.println("};");
                  cppFile.println();
              }
          }
          
          {// print name signatures
              String str = nameTestsCode.getBuffer().toString();
              if(str.length()!=0) {
                  cppFile.println("static NameSignature nameTests[] = {");
                  cppFile.write(str);
                  cppFile.println("};");
                  cppFile.println();
              }
          }
          
          // print states
          cppFile.println("static StateInfo stateInfos[] = {");
          for( int i=0; i<states.length; i++ ) {
              cppFile.println(MessageFormat.format(
                  "'{' {0},{1},{2},{3},{4},{5},{6},{7},{8} '}',",
                  new Object[] {
                      Util.padl(Integer.toString(i),4),
                      states[i].isFinal?"true ":"false",
                      states[i].isPersistent()?"true ":"false",
                      findFirstTransition(states[i],"aTr",amap,AttributeAlphabet.class),
                      findFirstTransition(states[i],"dTr",dmap,TextAlphabet.class),
                      findFirstTransition(states[i],"eTr",emap,ElementAlphabet.class),
                      findFirstTransition(states[i],"iTr",imap,InterleaveAlphabet.class),
                      findFirstTransition(states[i],"lTr",lmap,ListAlphabet.class),
                      findFirstTransition(states[i],"nTr",nmap,NonExistentAttributeAlphabet.class) }));
          }
          cppFile.println("};");
          cppFile.println();
          cppFile.println(MessageFormat.format("static SingleState states[{0}];",
              new Object[]{ new Integer(states.length) }));
          cppFile.println();
          
          
          // print name literals
          StringPair[] literals = automaton.listNameCodes();
          if( literals.length!=0 ) {
              cppFile.println("static NameLiteral nameLiterals[] = {");
              for( int i=0; i<literals.length; i++ ) {
                  String uri = literals[i].namespaceURI;
                  String local = literals[i].localName;
                  if( uri==TreeAutomaton.IMPOSSIBLE )     uri = "*";
                  if( local==TreeAutomaton.IMPOSSIBLE )   local = "*";
                  cppFile.println(MessageFormat.format("  '{' L{0},L{1},{2} '}',",
                      new Object[]{
                          Util.toCppString(uri),
                          Util.toCppString(local),
                          new Integer( automaton.getNameCode(literals[i]) ) }));
              }
              cppFile.println("};");
              cppFile.println();
          }
          
          cppFile.println("// schema object");
          cppFile.println(MessageFormat.format("Schema {0}(states,stateInfos,{1},states+0,{2},{3},{4});",
              new Object[]{
                  className,
                  new Integer(states.length),
                  (literals.length!=0)?"nameLiterals":"NULL",
                  new Integer(literals.length),
                  new Integer(automaton.getNameCode(TreeAutomaton.WILDCARD)) }));
          cppFile.println();
          
          
          cppFile.println( MessageFormat.format(
              "ISAXContentHandler* create{0}SAXValidatelet() '{'\n"+
              "    ComObject<Validatelet>* p = new ComObject<Validatelet>();\n"+
              "    p->AddRef();\n"+
              "    p->setSchema(&{1});\n"+
              "    return p;\n"+
              "'}'", new Object[]{ Util.capitalizeFirst(className), className } ));
  
          cppFile.println( MessageFormat.format(
              "bali::IValidatelet* create{0}DOMValidatelet() '{'\n"+
              "    ComObject<Validatelet>* p = new ComObject<Validatelet>();\n"+
              "    p->AddRef();\n"+
              "    p->setSchema(&{1});\n"+
              "    return p;\n"+
              "'}'", new Object[]{ Util.capitalizeFirst(className), className } ));
          
          
          cppFile.println("}");   // close namespace
          
          
          headerFile.println(MessageFormat.format(
              "#pragma once\n"+
              "\n"+
              "\n"+
              "// for this validatelet to compile,\n"+
              "// stdafx.h needs to have the following lines.\n"+
              "/*\n"+
              "#import <msxml4.dll>\n"+
              "#include <crtdbg.h>\n"+
              "#include \"validatelet.h\"\n"+
              "*/\n"+
              "\n"+
              "\n"+
              "// create a new instance of validatelet.\n"+
              "// A validatelet will be returned with its reference count\n"+
              "// incremented to 1. Thus it's the caller's responsibility to\n"+
              "// release the object.\n"+
              "{0}\n"+
              "MSXML2::ISAXContentHandler* create{1}SAXValidatelet();\n"+
              "bali::IValidatelet* create{1}DOMValidatelet();\n"+
              "{2}\n",
              new Object[]{
                  namespaceName!=null?"namespace "+namespaceName+" {":"",
                  Util.capitalizeFirst(className),
                  namespaceName!=null?"}":"" }));
          
          cppFile.close();
          headerFile.close();
          
          copy("validatelet.h");
          copy("validatelet.cpp");
          copy("validateletImpl.h");
      }
      
      
      /** Datatypes are generated into this string. */
      private StringWriter datatypesCode;
      /** Writer object connected to the datatypesCode. */
      private PrintWriter datatypesWriter;
      /** Maintains index for datatypes. */
      private IndexMap datatypes;
  
      /**
       * Generates a datatype definition and returns
       * its index number.
       */
      private int printDatatype( Datatype _dt ) {
          
          DatatypeImpl dt = (DatatypeImpl)_dt;
          
          if( datatypes.contains(dt) )    // this datatype has already been generated
              return datatypes.get(dt);
          
          int idx = datatypes.put(dt);
          
          PrintWriter w = datatypesWriter;
          w.print("  createDatatype(L");
          w.print(Util.toCppString(dt.nsURI));
          w.print(",L");
          w.print(Util.toCppString(dt.name));
          
          // TODO: context
          Parameter[] params = dt.parameters;
          for( int i=0; i<params.length; i++ ) {
              w.print(",L");
              w.print(Util.toCppString(params[i].name));
              w.print(",L");
              w.print(Util.toCppString(params[i].value));
          }
          w.println("),");
          
          return idx;
      }
      
      /**
       * Generates a value alphabet as a datatype definition
       * and returns its index.
       */
      private int printDatatype( ValueAlphabet va ) {
          
          if( datatypes.contains(va) )    // this datatype has already been generated
              return datatypes.get(va);
          
          int dtidx = printDatatype(va.datatype); // generate the underlying datatype first
          
          int idx = datatypes.put(va);
          
          datatypesWriter.println(MessageFormat.format(
              "  createValueDatatype(datatypes+{0},L{1}),",
              new Object[] {
                  new Integer(dtidx),
                  // TODO: context
                  Util.toCppString(((Value)va.value).value) }));
          return idx;
      }
      
      private StringWriter nameTestsCode;
      private PrintWriter nameTestsWriter;
      private int nameTestsSize = 0;
      
      /**
       * Prints all the name tests in one row and returns the index
       * to the first one.
       */
      private Integer printNameTests( NameSignature[] tests ) {
          
          for( int i=0; i<tests.length; i++ )
              nameTestsWriter.println(MessageFormat.format(
                  "  '{' {0},{1} '}',", new Object[] {
                      new Integer(tests[i].mask),
                      new Integer(tests[i].test) }));
          
          int r = nameTestsSize;
          nameTestsSize += tests.length;
          return new Integer(r);
      }
      
      
      
      
      
      
      
      private interface Printer {
          /**
           * Prints an alphabet.
           * 
           * @param previousIndex
           *      -1 if no previous alphabet, or its index.
           */
          public void print( Transition tr, int previousIndex );
  
          /**
           * Prints a dummy empty alphabet.
           */
          public void printEmptyLine();
      }
      
      private IndexMap printAlphabets( TreeAutomaton automaton,
          Class alphabetType, String typeName, String varName, Printer printer ) {
  
          IndexMap map = new IndexMap();
  
          cppFile.println(MessageFormat.format("static {0} {1}[] = '{'",
              new Object[]{typeName,varName}));
          
          boolean hasAlphabet = false;
          
          State[] states = automaton.getStates();
          for( int i=0; i<states.length; i++ ) {
              Object o = printAlphabets(alphabetType,map,states[i],printer);
              hasAlphabet |= o!=null;
          }
          
          if(!hasAlphabet)
              // if no alphabet was there, print an empty line (otherwise
              // the compiler will barf.)
              printer.printEmptyLine();
          
          cppFile.println("};");
          cppFile.println("");
          
          return map;
      }
      
      /**
       * Prints all alphabets of the given type
       * and returns the lastly printed alphabet, or null if none.
       */
      private Transition printAlphabets( Class alphabetType, IndexMap map, State st, Printer printer ) {
          Transition last;
          
          if( st.nextState!=null )
              last = printAlphabets(alphabetType,map,st.nextState,printer);
          else
              last = null;
          
          Transition[] trs = st.getTransitions();
          for( int i=0; i<trs.length; i++ ) {
  