package com.thaiopensource.xml.dtd;

import java.util.Vector;

class Decl {
  static final int REFERENCE = 0; // entity
  static final int REFERENCE_END = 1;
  static final int ELEMENT = 2; // params
  static final int ATTLIST = 3; // params
  static final int ENTITY = 4;  // params
  static final int NOTATION = 5; // params
  static final int INCLUDE_SECTION = 6; // params + decls
  static final int IGNORE_SECTION = 7; // params + value
  static final int COMMENT = 8; // value
  static final int PROCESSING_INSTRUCTION = 9; // value
  
  Decl(int type) {
    this.type = type;
  }

  int type;
  Vector params;
  String value;
  Entity entity;
  Vector decls;

  public boolean equals(Object obj) {
    if (obj == null || !(obj instanceof Decl))
      return false;
    Decl other = (Decl)obj;
    if (this.type != other.type)
      return false;
    if (this.entity != other.entity)
      return false;
    if (this.value != null && !this.value.equals(other.value))
      return false;
    if (this.params != null) {
      int n = this.params.size();
      if (other.params.size() != n)
	return false;
      for (int i = 0; i < n; i++)
	if (!this.params.elementAt(i).equals(other.params.elementAt(i)))
	  return false;
    }
    return true;
  }

  TopLevel createTopLevel(DtdBuilder db) {
    switch (type) {
    case COMMENT:
      return new Comment(value);
    case ELEMENT:
      return createElementDecl();
    case ATTLIST:
      return createAttlistDecl();
    case ENTITY:
      return createEntityDecl(db);
    case INCLUDE_SECTION:
      return createIncludedSection(db);
    case IGNORE_SECTION:
      return createIgnoredSection();
    }
    return null;
  }

  ElementDecl createElementDecl() {
    ParamStream ps = new ParamStream(params, true);
    ps.advance();
    String name = ps.value;
    return new ElementDecl(name, Param.paramsToModelGroup(ps));
  }

  AttlistDecl createAttlistDecl() {
    ParamStream ps = new ParamStream(params, true);
    ps.advance();
    String name = ps.value;
    return new AttlistDecl(name, Param.paramsToAttributeGroup(ps));
  }
    
  TopLevel createEntityDecl(DtdBuilder db) {
    ParamStream ps = new ParamStream(params);
    ps.advance();
    if (ps.type != Param.PERCENT)
      return createGeneralEntityDecl(db, ps.value);
    ps.advance();
    String name = ps.value;
    Entity entity = db.lookupParamEntity(name);
    if (entity.decl == null)
      entity.decl = this;
    if (entity.decl != this)
      return null;
    switch (entity.semantic) {
    case Entity.SEMANTIC_MODEL_GROUP:
      entity.modelGroup = entity.toModelGroup();
      return new ModelGroupDef(name, entity.modelGroup);
    case Entity.SEMANTIC_ATTRIBUTE_GROUP:
      entity.attributeGroup = 
	Param.paramsToAttributeGroup(entity.parsed);
      return new AttributeGroupDef(name, entity.attributeGroup);
    case Entity.SEMANTIC_DATATYPE:
      entity.datatype = Param.paramsToDatatype(entity.parsed);
      return new DatatypeDef(name, entity.datatype);
    case Entity.SEMANTIC_ENUM_GROUP:
      entity.enumGroup = Particle.particlesToEnumGroup(entity.parsed);
      return new EnumGroupDef(name, entity.enumGroup);
    case Entity.SEMANTIC_FLAG:
      entity.flag = Param.paramsToFlag(entity.parsed);
      return new FlagDef(name, entity.flag);
    }
    return null;
  }

  TopLevel createGeneralEntityDecl(DtdBuilder db, String name) {
    Entity entity = db.lookupGeneralEntity(name);
    if (entity.decl == null)
      entity.decl = this;
    if (entity.decl != this)
      return null;
    if (entity.text == null)
      return null;
    return new InternalEntityDecl(name, new String(entity.text));
  }

  IncludedSection createIncludedSection(DtdBuilder db) {
    Flag flag = Param.paramsToFlag(params);
    Vector contents = declsToTopLevel(db, decls);
    TopLevel[] tem = new TopLevel[contents.size()];
    for (int i = 0; i < tem.length; i++)
      tem[i] = (TopLevel)contents.elementAt(i);
    return new IncludedSection(flag, tem);
  }

  static Vector declsToTopLevel(DtdBuilder db, Vector decls) {
    Vector v = new Vector();
    int n = decls.size();
    for (int i = 0; i < n; i++) {
      TopLevel t = ((Decl)decls.elementAt(i)).createTopLevel(db);
      if (t != null)
	v.addElement(t);
    }
    return v;
  }

  IgnoredSection createIgnoredSection() {
    return new IgnoredSection(Param.paramsToFlag(params), value);
  }
}

@@ -1357,24 +1357,155 @@
 ent(value);%0A
+    case PROCESSING_INSTRUCTION:%0A      return createProcessingInstruction();%0A    case NOTATION:%0A      return createNotationDecl();%0A
     case ELE
@@ -4512,11 +4512,600 @@
 ue);%0A  %7D
+%0A%0A  ProcessingInstruction createProcessingInstruction() %7B%0A    int len = value.length();%0A    int i;%0A    for (i = 0; i %3C len && !isWS(value.charAt(i)); i++)%0A      ;%0A    String target = value.substring(0, i);%0A    if (i %3C len) %7B%0A      for (++i; i %3C len && isWS(value.charAt(i)); i++)%0A%09;%0A    %7D%0A    return new ProcessingInstruction(target, value.substring(i, len));%0A  %7D%0A%0A  static private boolean isWS(char c) %7B%0A    switch (c) %7B%0A    case '%5Cn':%0A    case '%5Cr':%0A    case '%5Ct':%0A    case ' ':%0A      return true;%0A    %7D%0A    return false;%0A  %7D%0A  %0A  NotationDecl createNotationDecl() %7B%0A    return null;%0A  %7D
 %0A%7D%0A

Create ProcessingInstruction objects.