//*********************************************************************************************
//
// Author: 			Dackral Scott Phillips
//
// File: 			SWOGXMLDocument.java
//
//	Date:				August 5, 2K2
//
// Description:	This is a java program written to satisfy the requirements necessary to
//						fulfill my master's degree.  This program creates a Sematic Web Ontology
//						Generator (SWOG).  It's primary purpose is to give semantic web newbies
//						an introduction to the syntax.  It provides help menus for beginning
//						users as well as an advanced code viewer with highlighted syntax.
//
//	Copyright © 2002 by Dackral Scott Phillips.  All Rights Reserved.
//
//*********************************************************************************************

// Syntax Highlighting Class Source Code Modified from 
// Java Developers Journal.com "Syntax Highlighting," Volume: 4 Issue: 7, p. 62 
// URL: http://www.sys-con.com/java/source/4-7/code.cfm?Page=62
// to process XML.

	//Import necessary files

   import java.util.*;
   import java.awt.*;
   import javax.swing.text.*;

    class SWOGXMLDocument extends DefaultStyledDocument
   {
      private String word = ""; 		//current word to check for highlighting
      private int currentPos = 0;	//current cursor position
      private int insideTag = 0;		//check to see if keywords are inside tags, e.g. < >
   
		//Highlighting styles for each of the types of higlighting to be done

      private SimpleAttributeSet kw = new SimpleAttributeSet(); 
      private SimpleAttributeSet attr = new SimpleAttributeSet(); 
      private SimpleAttributeSet nspc = new SimpleAttributeSet(); 
      private SimpleAttributeSet string = new SimpleAttributeSet(); 
      private SimpleAttributeSet normal = new SimpleAttributeSet(); 
      private SimpleAttributeSet comments = new SimpleAttributeSet(); 
   
      private Vector classes = new Vector(); 		//Vector to hold class keywords
      private Vector namespaces = new Vector();		//Vector to hold namespace keywords
      private Vector attributes = new Vector();		//Vector to hold attribute keywords
   
      private int mode;		//What made am I in now?
      public static final int STRING_MODE = 10;		//highlight strings
      public static final int COMMENT_MODE = 11; 	//highlight comments
      public static final int TEXT_MODE = 12;  		//Normal text mode
   
       public SWOGXMLDocument() 
      { 
      // Define the Ontology keywords for highlighting and add to the vectors
      
      //XML Classes
      
         classes.addElement("xml");
         classes.addElement("xmlns");
      
      // XML Attributes 
      
         attributes.addElement("version");
         attributes.addElement("lang");
      
      // RDF Classes
      
         classes.addElement("RDF"); 
         classes.addElement("Statment"); 
         classes.addElement("Property");
         classes.addElement("Description");
         classes.addElement("Bag");
         classes.addElement("Seq");
         classes.addElement("Alt");
      
      // RDF Attributes
      
         attributes.addElement("subject"); 
         attributes.addElement("predicate");
         attributes.addElement("object");
         attributes.addElement("type");
         attributes.addElement("value");
         attributes.addElement("li");
         attributes.addElement("about");
         attributes.addElement("aboutEach");
         attributes.addElement("aboutEachPrefix");
         attributes.addElement("ID");
         attributes.addElement("bagID");
         attributes.addElement("resource");
         attributes.addElement("parseType");
      
      // RDFS Classes
      
         classes.addElement("Resource"); 
         classes.addElement("Class"); 
         classes.addElement("ConstraintResource"); 
         classes.addElement("ConstraintProperty");
         classes.addElement("Literal");
         classes.addElement("Container");
         classes.addElement("ContainerMembershipProperty");
      
      // RDFS Attributes
         attributes.addElement("comment"); 
         attributes.addElement("label"); 
         attributes.addElement("subClassOf"); 
         attributes.addElement("subPropertyOf"); 
         attributes.addElement("seeAlso"); 
         attributes.addElement("isDefinedBy"); 
         attributes.addElement("domain"); 
         attributes.addElement("range");
      
      // DAML + OIL Classes
      
         classes.addElement("Datatype");
         classes.addElement("Thing");
         classes.addElement("Nothing");
         classes.addElement("Restriction");
         classes.addElement("ObjectProperty");
         classes.addElement("DatatypeProperty");
         classes.addElement("TransitiveProperty");
         classes.addElement("UniqueProperty");
         classes.addElement("UnambiguousProperty");
         classes.addElement("List");
         classes.addElement("Ontology");
      
      // DAML + OIL Attributes
      
         attributes.addElement("equivalentTo");
         attributes.addElement("sameClassAs");
         attributes.addElement("samePropertyAs");
         attributes.addElement("sameIndividualAs");
         attributes.addElement("disjointWith");
         attributes.addElement("differentIndividualFrom");
         attributes.addElement("disjointUnionOf");
         attributes.addElement("unionOf");
         attributes.addElement("intersectionOf");
         attributes.addElement("complementOf");
         attributes.addElement("oneOf");
         attributes.addElement("onProperty");
         attributes.addElement("toClass");
         attributes.addElement("hasValue");
         attributes.addElement("hasClass");
         attributes.addElement("minCardinality");
         attributes.addElement("maxCardinality");
         attributes.addElement("cardinality");
         attributes.addElement("hasClassQ");
         attributes.addElement("minCardinalityQ");
         attributes.addElement("maxCardinalityQ");
         attributes.addElement("cardinalityQ");
         attributes.addElement("inverseOf");
         attributes.addElement("nil");
         attributes.addElement("first");
         attributes.addElement("rest");
         attributes.addElement("item");
         attributes.addElement("versionInfo");
         attributes.addElement("imports");
      
      // Dublic Core Attributes
      
         attributes.addElement("title");
         attributes.addElement("contributor");
         attributes.addElement("creator");
         attributes.addElement("publisher");
         attributes.addElement("subject");
         attributes.addElement("description");
         attributes.addElement("date");
         attributes.addElement("format");
         attributes.addElement("identifier");
         attributes.addElement("language");
         attributes.addElement("relation");
         attributes.addElement("source");
         attributes.addElement("coverage");
         attributes.addElement("rights");
      
      // OilEd Attributes
      
         attributes.addElement("creationDate");
      
      // Namespaces
      
         namespaces.addElement("xsd");
         namespaces.addElement("rdf");
         namespaces.addElement("rdfs");
         namespaces.addElement("daml");
         namespaces.addElement("dc");
         namespaces.addElement("oiled");
      
      
         StyleConstants.setBold(kw, true);		//Keywords in Bold
         StyleConstants.setBold(attr, true);		//Attributes in Bold
         StyleConstants.setBold(nspc, true);		//Namespaces in Bold
         StyleConstants.setForeground(kw, new Color(0x800080)); 	//Keywords - purple
         StyleConstants.setForeground(attr, Color.blue);				//Attributes - blue
         StyleConstants.setForeground(nspc, Color.red);				//Namespaces - Red
         StyleConstants.setForeground(string, Color.green); 		//Strings - green
         StyleConstants.setForeground(normal, Color.black); 		//Text - black
         StyleConstants.setForeground(comments, Color.orange); 	//Comments - orange
         mode = TEXT_MODE;		//Start in Text Mode
      } 
   
       public void processChar(String str)
      { 
         char strChar = str.charAt(0); 	//check the current character
         if ((mode != this.COMMENT_MODE) && (mode != this.STRING_MODE)) //We don't care about strings and comments
         { 
            mode = TEXT_MODE; 
         } 
         switch (strChar)
         { 
            case('<'):	//we're inside a tag now
               {
                  insideTag = 1;
                  checkForKeyword();	//start checking for classes, attributes, and namespaces
                  break;
               }
            case('>'):
               { 
                  checkForKeyword();	//check for classes, attributes, and namespaces
                  insideTag = 0;			//end of the tag
                  break;
               }
            case (' '): 
            case ('='): 
            case(':'):
            case('/'):
            case('?'):
            case('\n'):
               { 
                  checkForKeyword();	//check for classes, attributes, and namespaces
               
                  if (mode == STRING_MODE && strChar == '\n')	//Strings shouldn't last more than 1 line
                  { 
                     mode = TEXT_MODE; 
                  } 
               } 
               break; 
            case ('"'):		//Color a quotation mark like a string
               { 
                  insertTextString(str, currentPos);  
                  this.checkForString();	//see if we're inside or outside of a string
               } 
               break;
            case ('!'):
            case ('-'):
               { 
                  checkForComment(); //Have we seen !-- ?
               } 
               break; 
         } 
      
         if (mode == this.TEXT_MODE)
         { 
            this.checkForString(); 	//See if we need to change to another mode
            this.checkForComment();
         } 
      
         if (mode == this.STRING_MODE)
         { 
            insertTextString(str, this.currentPos); //Highlight strings
         }
      
         if (mode == this.COMMENT_MODE)
         { 
            insertCommentString(str, this.currentPos); //Highlight Comments
         } 
      }
   
       private void processChar(char strChar)	//Convert the current character into a string 
      { 
         char[] chrstr = new char[1]; 
         chrstr[0] = strChar; 
         String str = new String(chrstr); 
         processChar(str); 
      }
   
       public void insertString(int offs, String str, AttributeSet a) throws BadLocationException
      { 
         super.insertString(offs, str, normal); //Default is no highlighting
         int strLen = str.length(); 	//get the length of the string to highlight
         int endpos = offs + strLen; 	//get the end position of the string to highlight
         int strpos; 
         for (int i = offs; i < endpos; i++)	//move through all the characters and process them
         { 
            currentPos = i; 
            strpos = i - offs; 
            processChar(str.charAt(strpos)); 
         } 
         currentPos = offs; 
      }
   
       private void insertKeyword(String str, int pos, int type)
      { 
         if ((mode != STRING_MODE) && (mode != COMMENT_MODE))	//Don't highlight keywords in strings and comments
         {
            try
            { 
            //remove the old word and formatting 
            
               this.remove(pos - str.length(), str.length()); 
            
            /*replace it with the same word, but new formatting 
            *we MUST call the super class insertString method here, otherwise we 
            *would end up in an infinite loop !!!!!*/ 
            
               switch(type)
               {
                  case 1:	//Highlight a class
                     {
                        super.insertString(pos - str.length(), str, kw); 
                        break;
                     }
                  case 2:	//Highlight an attribute
                     {
                        super.insertString(pos - str.length(), str, attr); 
                        break;
                     }
                  case 3:	//Highlight a namespace
                     {
                        super.insertString(pos - str.length(), str, nspc); 
                        break;
                     }
               }
            } 
                catch (Exception ex)
               { 
                  ex.printStackTrace(); 
               } 
         }
      }
   
       private void insertTextString(String str, int pos)
      { 
         if (mode != COMMENT_MODE)	//Don't highlight strings in comments
         {
            try
            { 
            //remove the old word and formatting 
               this.remove(pos,str.length()); 
               super.insertString(pos, str, string); //Highlight the string
            } 
                catch (Exception ex)
               { 
                  ex.printStackTrace(); 
               } 
         }
      } 
   
       private void insertCommentString(String str, int pos)
      {
         if (mode != STRING_MODE)	//Don't highlight comments in strings
         { 
            try
            { 
            //Remove the old word and formatting 
            
               this.remove(pos,str.length()); 
               super.insertString(pos, str, comments); //Highlight the comment
            } 
                catch (Exception ex)
               { 
                  ex.printStackTrace(); 
               } 
         }
      }
   
       private void checkForKeyword()
      { 
         if ((mode != STRING_MODE) && (mode != COMMENT_MODE))	//keywords don't occur in strings and comments
         {
         
            int offs = this.currentPos; 
         
            Element element = this.getParagraphElement(offs); 
            String elementText = ""; 
            try
            { 
            //This gets our chunk of current text for the element we're on 
            
               elementText = this.getText(element.getStartOffset(), element.getEndOffset() - element.getStartOffset()); 
            } 
                catch(Exception ex)
               { 
               //Whoops! 
               
                  System.out.println("no text"); 
               }
         
            int strLen = elementText.length(); 
         
            if (strLen == 0) //Nothing to highlight
            {
               return;
            } 
            int i = 0; 
         
            if (element.getStartOffset() > 0)
            { 
            //Translates backward if neccessary 
            
               offs = offs - element.getStartOffset(); 
            } 
            if ((offs >= 0) && (offs <= strLen-1))
            { 
               i = offs; 
               while (i > 0)
               { 
               //The while loop walks back until we hit a delimiter 
               
                  i--; 
                  char charAt = elementText.charAt(i);
               
               //Delimiters: If i == 0 then we're at the begininng 
               
                  if ((i == 0) | (charAt == ' ') | (charAt == ':') | (charAt == '<') | (charAt == '>') | (charAt == '=') | (charAt == '/') | (charAt == '?'))
                  { 
                     if(i != 0)
                     { 
                        i++; 
                     } 
                  
                  //Skip the period	[Don't know why this is here --Dack]
                  
                     word = elementText.substring(i, offs); 
                     String s = word.trim(); 
                  
                  //This is what actually checks for a matching keyword, attribute, and namespace
						//Only highlight things inside of tags

                     if ((classes.contains(s)) && (insideTag == 1))
                     { 
                        insertKeyword(word, currentPos, 1); 
                     }
                     else if ((attributes.contains(s)) && (insideTag == 1))
                     { 
                        insertKeyword(word, currentPos, 2); 
                     } 
                     else if ((namespaces.contains(s)) && (insideTag == 1))
                     { 
                        insertKeyword(word, currentPos, 3); 
                     }  
                     break; 
                  } 
               } 
            }
         } 
      } 
   
       private void checkForComment()
      { 
         int offs = this.currentPos; 
         Element element = this.getParagraphElement(offs); 
         String elementText = ""; 
         try
         { 
            //This gets our chunk of current text for the element we're on 
         
            elementText = this.getText(element.getStartOffset(), element.getEndOffset() - element.getStartOffset()); 
         } 
             catch(Exception ex){ 
               //Whoops! 
            
               System.out.println("no text"); 
            }
      
         int strLen = elementText.length(); 
      
         if (strLen == 0) 
         {
            return;
         }
      
         int i = 0; 
      
         if (element.getStartOffset() > 0)
         { 
            //Translates backward if neccessary 
         
            offs = offs - element.getStartOffset(); 
         } 
         if ((offs >= 1) && (offs <= strLen-1))
         { 
            i = offs; 
         
				//Check for an end of a comment

            if ((mode == COMMENT_MODE) && (elementText.charAt(i) == '-') && (elementText.charAt(i - 1) == '-')) 
            { 
               mode = TEXT_MODE; 
               this.insertCommentString("--", currentPos - 1); 
            }
				
				//Check for the beginning of a comment
            if ((mode == TEXT_MODE) && (elementText.charAt(i) == '-') && (elementText.charAt(i - 1) == '-') && (elementText.charAt(i - 2) == '!'))
            {
               mode = COMMENT_MODE; 
               this.insertCommentString("!--", currentPos - 2); 
            } 
         } 
      } 
   
       private void checkForString()
      { 
         int offs = this.currentPos; 
         Element element = this.getParagraphElement(offs); 
         String elementText = ""; 
         try
         { 
            //This gets our chuck of current text for the element we're on 
         
            elementText = this.getText(element.getStartOffset(), element.getEndOffset() - element.getStartOffset()); 
         } 
             catch(Exception ex)
            { 
               //Whoops! 

               System.out.println("no text"); 
            }
      
         int strLen = elementText.length(); 
         if (strLen == 0) 
         {
            return;
         } 
         int i = 0; 
      
         if (element.getStartOffset() > 0)
         { 
            //Translates backward if neccessary 
         
            offs = offs - element.getStartOffset(); 
         }
      
         int quotes = 0;
      
         if ((offs >= 0) && (offs <= strLen-1))
         { 
            i = offs; 
         
            while (i > 0)
            { 
               //The while loop walks back until we hit a delimiter 
            
               char charAt = elementText.charAt(i); 
               if ((charAt == '"'))
               { 
                  quotes++;
               } 
               i--; 
            }
         
            if ((quotes % 2) != 0)	//Count the quote marks
            {	
               mode = STRING_MODE;	//If odd, we're still inside a string
            }
            else
            {
               mode = TEXT_MODE;		//If even, we aren't
            }
         } 
      } 
   }