/*
 * The contents of this file are subject to the Mozilla Public License Version 1.1
 * (the "License"); you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at <http://www.mozilla.org/MPL/>.
 * 
 * Software distributed under the License is distributed on an "AS IS" basis, WITHOUT
 * WARRANTY OF ANY KIND, either express or implied. See the License for the specific
 * language governing rights and limitations under the License.
 * 
 * The Original Code is the Venice Web Community System.
 * 
 * The Initial Developer of the Original Code is Eric J. Bowersox <erbo@ricochet.com>,
 * for Silverwrist Design Studios.  Portions created by Eric J. Bowersox are
 * Copyright (C) 2004 Eric J. Bowersox/Silverwrist Design Studios.  All Rights Reserved.
 * 
 * Contributor(s): 
 */
package com.silverwrist.venice.htmlcheck.filters;

import java.util.*;
import org.w3c.dom.*;
import com.silverwrist.util.*;
import com.silverwrist.venice.except.*;
import com.silverwrist.venice.htmlcheck.Rewriter;
import com.silverwrist.venice.htmlcheck.RewriterServices;
import com.silverwrist.venice.htmlcheck.MarkupData;
import com.silverwrist.venice.util.XMLLoader;

public class EmoticonRewriter implements Rewriter
{
  /*--------------------------------------------------------------------------------
   * Attributes
   *--------------------------------------------------------------------------------
   */

  private char[] m_prefixchars;
  private Map m_patmap;
  private int m_minlength;

  /*--------------------------------------------------------------------------------
   * Constructor
   *--------------------------------------------------------------------------------
   */

  public EmoticonRewriter(Element root) throws ConfigException
  {
    XMLLoader loader = XMLLoader.get();

    // Get the set of prefix characters.
    String pfxchar = loader.configGetSubElementText(root,"prefix-chars");
    m_prefixchars = pfxchar.toCharArray();

    HashMap tmp = new HashMap();
    m_minlength = Integer.MAX_VALUE;

    // Look for all associated icons.
    NodeList nl = root.getChildNodes();
    for (int i=0; i<nl.getLength(); i++)
    { // look through all the child nodes...
      Node n = nl.item(i);
      if ((n.getNodeType()==Node.ELEMENT_NODE) && n.getNodeName().equals("icon"))
      { // load the icon name
	String icon_name = loader.configGetAttribute((Element)n,"name").intern();

	// get the associated patterns
	NodeList nl2 = n.getChildNodes();
	for (int j=0; j<nl2.getLength(); j++)
	{ // look for <pattern/> elements
	  Node n2 = nl2.item(j);
	  if ((n2.getNodeType()==Node.ELEMENT_NODE) && n2.getNodeName().equals("pattern"))
	  { // get the element text
	    DOMElementHelper h = new DOMElementHelper((Element)n2);
	    String pattern = h.getElementText();
	    if (pfxchar.indexOf(pattern.charAt(0))>=0)
	    { // add pattern and recompute minimum length
	      tmp.put(pattern,icon_name);
	      m_minlength = Math.min(m_minlength,pattern.length());

	    } // end if

	  } // end if
	  // else skip this element

	} // end for
	
      } // end if
      // else skip this element

    } // end for

    if (tmp.isEmpty())
      m_patmap = Collections.EMPTY_MAP;
    else
      m_patmap = Collections.unmodifiableMap(tmp);

  } // end constructor

  /*--------------------------------------------------------------------------------
   * Implementations from interface Rewriter
   *--------------------------------------------------------------------------------
   */

  public String getName()
  {
    return "emoticon";

  } // end getName

  public MarkupData rewrite(String data, RewriterServices svc)
  {
    int pos = Integer.MAX_VALUE;
    for (int i=0; i<m_prefixchars.length; i++)
    { // hunt for the possible beginning of an emoticon sequence
      int foo = data.indexOf(m_prefixchars[i]);
      if (foo>=0)
	pos = Math.min(pos,foo);

    } // end for

    if (pos==Integer.MAX_VALUE)
      return null;  // none present - we can short-circuit matters

    boolean did_replace = false;
    StringBuffer output = new StringBuffer();
    String work = data;
    do
    { // break off the front part of the string
      if (pos>0)
      { // append it and make it work
	output.append(work.substring(0,pos));
	work = work.substring(pos);

      } // end if

      boolean looking = true;
      if (work.length()>=m_minlength)
      { // there's a chance we have a pattern
	for (Iterator it=m_patmap.entrySet().iterator(); looking && it.hasNext(); )
	{ // hunt through all the smiley entries
	  Map.Entry ntry = (Map.Entry)(it.next());
	  String match = ntry.getKey().toString();
	  if (work.startsWith(match))
	  { // found the right smiley
	    looking = false;
	    output.append("<ei:").append(ntry.getValue()).append("/>");
	    work = work.substring(match.length());
	    did_replace = true;

	  } // end if

	} // end for

      } // end if

      if (looking)
      { // no such luck - shift the triggering character over
	output.append(work.charAt(0));
	work = work.substring(1);

      } // end if

      // now look for the next triggering character
      pos = Integer.MAX_VALUE;
      for (int i=0; i<m_prefixchars.length; i++)
      { // hunt for the possible beginning of an emoticon sequence
	int foo = work.indexOf(m_prefixchars[i]);
	if (foo>=0)
	  pos = Math.min(pos,foo);

      } // end for

    } while (pos!=Integer.MAX_VALUE); // end do

    if (!did_replace)
      return null;  // no replacements done, so what's the point?

    output.append(work);  // tack this onto the end
    return new MarkupData(null,output.toString(),null,true);

  } // end rewrite

} // end class EmoticonRewriter
