/*
 * 
 * Please visit http://radeox.org/ for updates and contact.
 * 
 * --LICENSE NOTICE-- This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser
 * General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any
 * later version.
 * 
 * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free
 * Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA --LICENSE NOTICE--
 */
package org.plog4u.wiki.macro.code;
import java.util.HashMap;
import java.util.HashSet;
import org.radeox.filter.context.FilterContext;
import org.radeox.macro.code.SourceCodeFormatter;
/*
 * Abstract C++ syntax based code filter
 *  
 */
abstract public class AbstractCPPBasedCodeFilter implements SourceCodeFormatter {
  public static void appendChar(StringBuffer result, char currentChar) {
    switch (currentChar) {
      case '\"' : // special html escape character
        result.append(""");
        break;
      case '<' : // special html escape character
        result.append("<");
        break;
      case '>' : // special html escape character
        result.append(">");
        break;
      case '&' : // special html escape character
        result.append("&");
        break;
      case '\'' : // special html escape character
        result.append("'");
        break;
      default :
        result.append(currentChar);
    }
  }
  public static void createHashMap(HashMap map, String str) {
    map.put(str, ""+str+"");
  }
  public AbstractCPPBasedCodeFilter() {
  }
  private int appendIdentifier(
    String input,
    int identStart,
    int currentPosition,
    HashMap keywords,
    HashSet objectWords,
    StringBuffer result) {
    String originalIdent = input.substring(identStart, --currentPosition);
    String keywordIdent = originalIdent;
    if (!isKeywordLowerCase()) {
      keywordIdent = keywordIdent.toLowerCase();
    }
    String keywordValue = (String) keywords.get(keywordIdent);
    if (keywordValue!=null) { 
      result.append(keywordValue);
//    } else if (objectWords != null && objectWords.contains(originalIdent)) {
//      result.append("");
//      result.append(originalIdent);
//      result.append("");
    } else {
      result.append(originalIdent);
    }
    return currentPosition;
  }
  public String filter(String input, FilterContext context) {
    char[] source = input.toCharArray();
    int currentPosition = 0;
    int identStart = 0;
    char currentChar = ' ';
    HashMap keywordsSet = getKeywordSet();
    HashSet objectsSet = getObjectSet();
    StringBuffer result = new StringBuffer(input.length() + input.length() / 4);
    boolean identFound = false;
    result.append("");
    try {
      while (true) {
        currentChar = source[currentPosition++];
        //        if (currentChar >= 'a' && currentChar <= 'z' && isKeywordLowerCase()) {
        //          identStart = currentPosition - 1;
        //          identFound = true;
        //          // start of identifier ?
        //          while (currentChar >= 'a' && currentChar <= 'z') {
        //            currentChar = source[currentPosition++];
        //          }
        //          currentPosition = appendIdentifier(input, identStart, currentPosition, keywordsSet, objectsSet, result);
        //          identFound = false;
        //          continue; // while loop
        //        } else
        if ((currentChar >= 'A' && currentChar <= 'Z') || (currentChar == '_') || (currentChar >= 'a' && currentChar <= 'z')) {
          identStart = currentPosition - 1;
          identFound = true;
          // start of identifier ?
          while ((currentChar >= 'a' && currentChar <= 'z') || (currentChar >= 'A' && currentChar <= 'Z') || currentChar == '_') {
            currentChar = source[currentPosition++];
          }
          currentPosition = appendIdentifier(input, identStart, currentPosition, keywordsSet, objectsSet, result);
          identFound = false;
          continue; // while loop
        } else if (currentChar == '\"') { //strings
          result.append("");
          appendChar(result, currentChar);
          while (currentPosition < input.length()) {
            currentChar = source[currentPosition++];
            appendChar(result, currentChar);
            if (currentChar == '\"' && source[currentPosition - 2] != '\\') {
              break;
            }
          }
          result.append("");
          continue;
        } else if (currentChar == '/' && currentPosition < input.length() && source[currentPosition] == '/') {
          // line comment
          result.append("");
          appendChar(result, currentChar);
          appendChar(result, source[currentPosition++]);
          while (currentPosition < input.length()) {
            currentChar = source[currentPosition++];
            appendChar(result, currentChar);
            if (currentChar == '\n') {
              break;
            }
          }
          result.append("");
          continue;
        } else if (currentChar == '/' && currentPosition < input.length() && source[currentPosition] == '*') {
          if (currentPosition < (input.length() - 1) && source[currentPosition + 1] == '*') {
            // javadoc style
            result.append("");
          } else {
            // multiline comment
            result.append("");
          }
          appendChar(result, currentChar);
          appendChar(result, source[currentPosition++]);
          while (currentPosition < input.length()) {
            currentChar = source[currentPosition++];
            appendChar(result, currentChar);
            if (currentChar == '/' && source[currentPosition - 2] == '*') {
              break;
            }
          }
          result.append("");
          continue;
        } else if (currentChar == '<' && isPHPTag() && currentPosition+3 < input.length() && source[currentPosition] == '?'
            && source[currentPosition+1] == 'p'
            && source[currentPosition+2] == 'h'
            && source[currentPosition+3] == 'p') {
          // php start tag
          currentPosition++;
          result.append("<?php");
          continue;
        } else if (currentChar == '?' && isPHPTag() && currentPosition < input.length() && source[currentPosition] == '>') {
          // php start tag
          currentPosition += 4;
          result.append("?>");
          continue;
        } 
        appendChar(result, currentChar);
      }
    } catch (IndexOutOfBoundsException e) {
      if (identFound) {
        currentPosition = appendIdentifier(input, identStart, currentPosition, keywordsSet, null, result);
      }
    }
    result.append("");
    return result.toString();
  }
  /**
   * @return Returns the KEYWORD_SET.
   */
  abstract public HashMap getKeywordSet();
  /**
   * @return Returns the OBJECT_SET.
   */
  abstract public HashSet getObjectSet();
  public int getPriority() {
    return 0;
  }
  /**
   * @return Returns the KEYWORD_MAP.
   */
  public boolean isKeywordLowerCase() {
    return true;
  }
  /**
   *  
   */
  public boolean isPHPTag() {
    return false;
  }
}