/*
 * $Header: /home/cvspublic/jakarta-slide/src/share/org/apache/slide/search/basic/expression/LikeExpression.java,v 1.2 2004/11/16 14:38:22 luetzkendorf Exp $
 * $Revision: 1.2 $
 * $Date: 2004/11/16 14:38:22 $
 *
 * ====================================================================
 *
 * Copyright 1999 The Apache Software Foundation 
 *
 * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */
package org.apache.slide.search.basic.expression;

import org.apache.slide.common.SlideException;
import org.apache.slide.content.NodeProperty;
import org.apache.slide.search.InvalidQueryException;
import org.apache.slide.search.basic.ComparableResource;
import org.apache.slide.search.basic.ComparableResourcesPool;
import org.apache.slide.search.basic.Literals;
import org.jdom.Element;


/**
 * Implements the like operator.
 */
public class LikeExpression extends ComparePropertyExpression
{

    private static char WILDCARD_STRING = '%';
    private static char WILDCARD_CHAR = '_';
 
    public LikeExpression(Element e,
            ComparableResourcesPool requestedResourcesPool)
            throws InvalidQueryException
    {
        super(e, requestedResourcesPool, true);
    }
    
    
    protected boolean compare(ComparableResource item)
    {
        try {
            NodeProperty value = item.getProperty(
                    comparedProperty.getProperty(),
                    comparedProperty.getPropNamespace());
            if (value != null) {
                return wildcardEquals(
                        comparedProperty.getLiteral(),
                        0,
                        value.getValue().toString(),
                        0);
            }
        } catch (SlideException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } 
        return false;
    }
    
    public String toString () {
        return super.toString(Literals.LIKE);
    }
    
    /**
     * Determines if a word matches a wildcard pattern.
     * <small>Taken from Lucenes WildcardTermEnum.</small>
     */
    public static final boolean wildcardEquals(String pattern, int patternIdx,
      String string, int stringIdx)
    {
      for (int p = patternIdx; ; ++p)
      {
        for (int s = stringIdx; ; ++p, ++s)
        {
          // End of string yet?
          boolean sEnd = (s >= string.length());
          // End of pattern yet?
          boolean pEnd = (p >= pattern.length());

          // If we're looking at the end of the string...
          if (sEnd)
          {
            // Assume the only thing left on the pattern is/are wildcards
            boolean justWildcardsLeft = true;

            // Current wildcard position
            int wildcardSearchPos = p;
            // While we haven't found the end of the pattern,
            // and haven't encountered any non-wildcard characters
            while (wildcardSearchPos < pattern.length() && justWildcardsLeft)
            {
              // Check the character at the current position
              char wildchar = pattern.charAt(wildcardSearchPos);
              // If it's not a wildcard character, then there is more
              // pattern information after this/these wildcards.

              if (wildchar != WILDCARD_CHAR && wildchar != WILDCARD_STRING)
              {
                justWildcardsLeft = false;
              }
              else
              {
                // Look at the next character
                wildcardSearchPos++;
              }
            }

            // This was a prefix wildcard search, and we've matched, so
            // return true.
            if (justWildcardsLeft)
            {
              return true;
            }
          }

          // If we've gone past the end of the string, or the pattern,
          // return false.
          if (sEnd || pEnd)
          {
            break;
          }

          // Match a single character, so continue.
          if (pattern.charAt(p) == WILDCARD_CHAR)
          {
            continue;
          }

          //
          if (pattern.charAt(p) == WILDCARD_STRING)
          {
            // Look at the character beyond the '*'.
            ++p;
            // Examine the string, starting at the last character.
            for (int i = string.length(); i >= s; --i)
            {
              if (wildcardEquals(pattern, p, string, i))
              {
                return true;
              }
            }
            break;
          }
          if (pattern.charAt(p) != string.charAt(s))
          {
            break;
          }
        }
        return false;
      }
    }
    
    public static void main(String[] args) {
        System.out.println(wildcardEquals("test*", 0, "testtest", 0));
        System.out.println(wildcardEquals("test*", 0, "tesxtest", 0));
    }
    
}
