//
// This software is now distributed according to
// the Lesser Gnu Public License.  Please see
// http://www.gnu.org/copyleft/lesser.txt for
// the details.
//    -- Happy Computing!
//
package com.stevesoft.pat;

import java.util.*;

/**
 * If Multi were not split into a second stage, then a nested Multi would try to
 * re-use the same count variable and the whole thing would break.
 */
class Multi_stage2 extends PatternSub
{
  Pattern nextRet;

  patInt count;

  patInt matchMin, matchMax;

  public boolean matchFewest = false;

  public String toString()
  {
    String ret = "";
    ret += sub.toString();
    ret += "{" + matchMin + "," + matchMax + "}";
    if (matchFewest)
    {
      ret += "?";
    }
    ret += parent.nextString();
    return ret;
  }

  Multi_stage2(patInt a, patInt b, Pattern p) throws RegSyntax
  {
    if (p == null)
    {
      RegSyntaxError.endItAll("Multiple match of Null pattern requested.");
    }
    sub = p;
    nextRet = this;
    sub.setParent(this);
    matchMin = a;
    matchMax = b;
    count = new patInt(0);
    // we must have b > a > -1 for this
    // to make sense.
    if (!a.lessEq(b))
    {
      // throw new BadMultiArgs();
      RegSyntaxError.endItAll("Bad Multi Args: " + a + ">" + b);
    }
    patInt i = new patInt(-1);
    if (a.lessEq(i))
    {
      // throw new BadMultiArgs();
      RegSyntaxError.endItAll("Bad Multi Args: " + a + "< 0");
    }
  }

  public Pattern getNext()
  {
    return nextRet;
  }

  int pos_old = -1;

  public int matchInternal(int pos, Pthings pt)
  {
    sub.setParent(this);

    int canUse = -1;

    // check for some forms of infinite recursion...
    if (pos_old >= 0 && pos == pos_old)
    {
      return -1;
    }
    pos_old = pos;

    if (matchMin.lessEq(count))
    {
      canUse = pos;
    }
    if (!count.lessEq(matchMax) || pos > pt.src.length())
    {
      return -1;
    }

    if ((matchFewest || count.equals(matchMax)) && canUse >= 0)
    {
      Pattern n = super.getNext();
      if (n == null)
      {
        return canUse;
      }
      int ret = testMatch(n, pos, pt);
      if (ret >= 0)
      {
        return ret;
      }
      else
      {
        canUse = -1;
      }
    }

    count.inc();
    try
    {
      if (count.lessEq(matchMax))
      {
        int r = testMatch(sub, pos, pt);
        if (r >= 0)
        {
          return r;
        }
      }
    } finally
    {
      count.dec();
    }

    if (!matchFewest && canUse >= 0)
    {
      Pattern n = super.getNext();
      if (n == null)
      {
        return canUse;
      }
      int ret = testMatch(n, pos, pt);
      return ret;
    }
    else
    {
      return canUse;
    }
  }

  public Pattern clone1(Hashtable h)
  {
    try
    {
      Multi_stage2 m = new Multi_stage2(matchMin, matchMax, sub.clone(h));
      m.matchFewest = matchFewest;
      return m;
    } catch (RegSyntax rs)
    {
      return null;
    }
  }
};
