package wbeer.core;

import java.lang.* ;
import java.util.* ;

public class Parser extends Vector {
  public Lexicon lex ;
  public Fstack fst ;
  public String msg ;
  public String sub ;
  public StringTokenizer mytokenizer ;
  public String mystr ;
  private int chainid ;

  public Parser() {
    lex = null ;
    fst = new Fstack() ;
    chainid = 0 ;
  }

  private void coverFeature( Word top , Word bottom ) {
    if ( top == null ) {
      return ;
    }
    if ( bottom == null ) {
      return ;
    }
    for ( int i = 0 ; i < top.size() ; i++ ) {
      Feature f = ( Feature )top.elementAt( i ) ;
      for ( int j = 0 ; j < bottom.size() ; j++ ) {
        Feature g = ( Feature )bottom.elementAt( j ) ;
        boolean f_headside , g_headside ;

        if ( f.eachside != g.eachside ) {
          continue ;
        }

        if ( f.eachside ) {
          f_headside = g.headside ;
          g_headside = g.headside ;
        } else {
          f_headside = f.headside ;
          g_headside = g.headside ;
        }

        if ( g.checked || g.covered ) {
          continue ;
        }
        if ( g.obligatory ) {
          continue ;
        }
        if ( g.inherent ) {
          continue ;
        }
        if ( !f.name.equals( g.name ) ) {
          continue ;
        }
        if ( f_headside != g_headside ) {
          continue ;
        }
        g.inherent = f.inherent ;
        g.value    = f.value ;
        g.covered  = true ;
        f.headside = f_headside ;
        g.headside = g_headside ;
/*
        f.eachside = false ;
        g.eachside = false ;
 */
        break ;
      }
    }
  }

  private boolean mergeCheck( Word left , Word right ) {
    if ( left == null ) {
      return false ;
    }
    if ( right == null ) {
      return false ;
    }
    if ( right.parent != null ) {
      if ( right.parent != left ) {
        return false ;
      }
    }
    Word lastphrase   = ( Word )elementAt( size() - 1 ) ;
    Word targetphrase = lastphrase ;

    if ( lastphrase == right ) {
      lastphrase = size() > 1 ? ( Word )elementAt( size() - 2 ) : null ;
    }
    if ( lastphrase == null ) {
      return false ;
    }
    for ( int i = 0 ; i < right.size() ; i++ ) {
      Feature f = ( Feature )right.elementAt( i ) ;
      if ( f.checked || f.covered ) {
        continue ;
      }
      for ( int j = left.size() - 1 ; j >= 0 ; j-- ) {
        Feature g = ( Feature )left.elementAt( j ) ;
        boolean f_headside , g_headside ;
        if ( f.eachside && g.eachside ) {
          continue ;
        }
        if ( f.eachside ) {
          f_headside = g.headside ? false : true ;
          g_headside = g.headside ;
        } else if ( g.eachside ) {
          f_headside = f.headside ;
          g_headside = f.headside ? false : true ;
        } else {
          f_headside = f.headside ;
          g_headside = g.headside ;
        }

        if ( right.parent != null ) {
          if ( f_headside ) {
            return false ;
          }
        }

        if ( g.checked || g.covered ) {
          continue ;
        }
        if ( !g.name.equals( f.name ) ) {
          continue ;
        }
        if ( !g.inherent && !f.inherent ) {
          continue ;
        }
        if ( g_headside == f_headside ) {
          continue ;
        }
        if ( g.inherent && f.inherent ) {
          if ( !g.value.equals( f.value ) ) {
            continue ;
          }
        }

        Feature inherentside  = g.inherent ? g     : f ;
        Feature redundantside = g.inherent ? f     : g  ;
        Feature headside      = g_headside ? f     : f ;
        Feature noheadside    = g_headside ? f     : g  ;
        boolean rgt_prj       = g_headside ? false : true  ;

        if ( noheadside.w.isGoverned() ) {
          if ( !headside.w.isGovernor( noheadside.w ) ) {
            continue ;
          } else {
            return true ;
          }
        }
        if ( !left.rightDownFrom( lastphrase ) ) {
          continue ;
        }
        return true ;
      }
    }
    return false ;
  }

  private boolean checkAndMerge( Feature left , Feature right , int size ) {
    int i ;
    sub = null ;
    boolean right_headside , left_headside ;

    if ( left == null ) {
      sub = "left(" + left.name + ") is null at Parser::checkAndMerge()" ;
      return false ;
    }

    if ( right == null ) {
      sub = "right(" + right.name + ") is null at Parser::checkAndMerge()" ;
      return false ;
    }

    if ( right.eachside && left.eachside ) {
      sub = "both are eachside::checkAndMerge()" ;
      return false ;
    }

    if ( right.eachside ) {
      right_headside = left.headside ? false : true ;
      left_headside  = left.headside ;
    } else if ( left.eachside ) {
      right_headside = right.headside ;
      left_headside  = right.headside ? false : true ;
    } else {
      right_headside = right.headside ;
      left_headside  = left.headside ;
    }

    if ( left.checked || left.covered ) {
      sub = "left(" + left.name + ") checked" ;
      return false ;
    }

    if ( right.checked || right.covered ) {
      sub = "right(" + right.name + ") checked" ;
      return false ;
    }

    if ( right.w.parent != null ) {
      if ( right.w.parent != left.w ) {
        sub = "right side governed" ;
        return false ;
      }
      if ( right_headside ) {
        sub = "right side governed and right is headside" ;
        return false ;
      }
    }

    Word lastphrase   = ( Word )elementAt( size ) ;
    Word targetphrase = lastphrase ;

    for ( i = size + 1 ; i < size() ; i++ ) {
      if ( ( ( ( Word )elementAt( i ) ).assoc ).isUpperSide( left.w ) ) {
        sub = "assoc barrier" ;
        return false ;
      }
    }

    if ( lastphrase == right.w ) {
      lastphrase = size > 0 ? ( Word )elementAt( size - 1 ) : null ;
    }

    if ( !left.name.equals( right.name ) ) {
      sub = "left Feature (" + left.name + ") is not equal to "
        + "right Feature (" + right.name + ")" ;
      return false ;
    }

    if ( !left.inherent && !right.inherent ) {
      sub = "left(" + left.name + ") and right(" + right.name + ") both are not inherent" ;
      return false ;
    }

    if ( left_headside == right_headside ) {
      sub = "left.headside == right.headside" ;
      return false ;
    }

    if ( left.inherent && right.inherent ) {
      if ( !left.value.equals( right.value ) ) {
        sub = "left and right both are inherent && left.value != right.value" ;
        return false ;
      }
    }

    Feature inherentside  = left.inherent ? left  : right ;
    Feature redundantside = left.inherent ? right : left  ;
    Feature headside      = left_headside ? left  : right ;
    Feature noheadside    = left_headside ? right : left  ;
    boolean rgt_prj       = left_headside ? false : true  ;

    if ( noheadside.w.isGoverned() ) {
      if ( !headside.w.isGovernor( noheadside.w ) ) {
        sub = "headside(" + noheadside.w.name + ") is governed by (" +
        noheadside.w.parent.name + ") and ..." ;
        return false ;
      } else {
        redundantside.value = inherentside.value ;
        left.inherent = right.inherent = true ;
        left.checked  = right.checked = true ;
        fst.removeElement( left ) ;
        return true ;
      }
    }

    if ( lastphrase == null ) {
      sub = "lastphrase == null" ;
      return false ;
    }

    if ( !left.w.rightDownFrom( lastphrase ) ) {
      sub = "left is not right down from lastphrase" ;
      return false ;
    }

    redundantside.value = inherentside.value ;
    left.inherent       = right.inherent = true ;
    left.checked        = right.checked = true ;
    left.headside       = left_headside ;
    right.headside      = right_headside ;
/*
    left.eachside       = false ;
    right.eachside      = false ;
 */

    Word parent = merge( left.w , right.w , rgt_prj ) ;
    if ( parent == null ) {
      return false ;
    }

    if ( rgt_prj ) {
      headside.nohead = left.w ;
      left.nohead     = left.w ;
      right.nohead    = left.w ;
    } else {
      headside.nohead = right.w ;
      left.nohead     = right.w ;
      right.nohead    = right.w ;
    }

    i = left.w.indexOf( left ) ;
    if ( i >= 0 ) {
/*
      left.w.insertElementAt( headside , i ) ;
      left.w.removeElement( left ) ;
 */
      left.w.setElementAt( headside , i ) ;
    }
    i = right.w.indexOf( left ) ;
    if ( i >= 0 ) {
/*
      right.w.insertElementAt( headside , i ) ;
      right.w.removeElement( left ) ;
 */
      right.w.setElementAt( headside , i ) ;
    }

    if ( targetphrase != lastphrase ) {
      removeElement( targetphrase ) ;
    }

    headside.w    = parent ;
    fst.removeElement( left ) ;

    return true ;
  }

  private Word merge( Word left , Word right , boolean rgt_prj )
  {
    int i ;
    sub = null ;

    if ( left == null || right == null ) {
      sub = "left of right is null at Parser::merge()" ;
      return null ;
    }

    Word headside   = rgt_prj ? right : left  ;
    Word noheadside = rgt_prj ? left  : right ;
    Word parent     = ( Word )headside.clone() ;

    parent.removeAllElements() ;
    for ( i = 0 ; i < headside.size() ; i++ ) {
      Feature f = ( Feature )headside.elementAt( i ) ;
      parent.addElement( f ) ;
    }

    /* 1999/3/1
    parent.parent     = null ;
     */
    parent.parent     = headside.parent ;
    parent.left       = left ;
    parent.right      = right ;
    parent.headside   = headside ;
    parent.noheadside = noheadside ;

if ( false ) { // 1999/3/1
    i = indexOf( left ) ;
    if ( i >= 0 ) {
/* I don't know the reason why following code doesn't work with JDK1.2
 * It does work with JDK1.1
      insertElementAt( parent , i ) ;
      removeElement( left ) ;
 */
      setElementAt( parent , i ) ;
    } else {
      if ( left.parent == null ) {
        sub = "fatal error in Parser::merge()" ;
        return null ;
      }

      if ( left.parent.left == left ) {
        left.parent.left = parent ;
      }

      if ( left.parent.right == left ) {
        left.parent.right = parent ;
      }

      if ( left.parent.headside == left ) {
        left.parent.headside = parent ;
      }

      if ( left.parent.noheadside == left ) {
        left.parent.noheadside = parent ;
      }

      parent.parent = left.parent ;
    }
} else { // 1999/3/1
    i = indexOf( left ) ;
    if ( i >= 0 ) {
      setElementAt( parent , i ) ;
    } else {
      i = indexOf( right ) ;
      if ( i >= 0 && rgt_prj/*<-- temporary solution(1999/3/1)*/ ) {
        setElementAt( parent , i ) ;
      } else {
        if ( headside.parent == null ) {
          sub = "fatal error in Parser::merge()" ;
          return null ;
        }

        if ( headside.parent.left == headside ) {
          headside.parent.left = parent ;
        }

        if ( headside.parent.right == headside ) {
          headside.parent.right = parent ;
        }

        if ( headside.parent.headside == headside ) {
          headside.parent.headside = parent ;
        }

        if ( headside.parent.noheadside == headside ) {
          headside.parent.noheadside = parent ;
        }
      }
    }
} // 1999/3/1

    left.parent  = parent ;
    right.parent = parent ;

    for ( i = 0 ; i < parent.size() ; i++ ) {
      Feature f = ( Feature )headside.elementAt( i ) ;
      f.w = parent ;
    }

    for ( i = 0 ; i < fst.size() ; i++ ) {
      Feature f = ( Feature )fst.elementAt( i ) ;
      if ( f.w == headside ) {
        f.w = parent ;
      }
    }
    coverFeature( headside , noheadside ) ;
    return parent ;
  }

  private void makeAllChain() {
    while ( makeOneChain() ) ;
  }

  private void makeAllAssoc() {
    while ( makeOneAssoc() ) ;
  }

  private void fixAllAssoc() {
    while ( fixOneAssoc() ) ;
  }

  public boolean makeRightmostAssoc( Word right , Word left_top ) {
    if ( right.assoc != null ) {
      return false ;
    }
    Word left ;
    for ( left = left_top.right ; left != null ; left = left.right ) {
      boolean all_checked = true ;

      if ( left.assoc == null ) {
        for ( int j = 0 ; j < left.size() ; j++ ) {
          Feature left_f = ( Feature )left.elementAt( j ) ;
          if ( !left_f.checked && !left_f.covered ) {
            continue ;
          }
          boolean checked = false ;
          for ( int k = 0 ; k < right.size() ; k++ ) {
            Feature right_f = ( Feature )right.elementAt( k ) ;
            if ( right_f.checked || right_f.covered ) {
              continue ;
            }
            boolean right_headside , left_headside ;
            if ( right_f.eachside != left_f.eachside ) {
              continue ;
            }
            if ( right_f.eachside ) {
              right_headside = left_f.headside ;
              left_headside  = left_f.headside ;
            } else {
              right_headside = right_f.headside ;
              left_headside  = left_f.headside ;
            }
            if ( left_headside != right_headside ) {
              continue ;
            }
            if ( !left_f.name.equals( right_f.name ) ) {
              continue ;
            }
            if ( left_f.inherent && right_f.inherent ) {
              if ( !left_f.value.equals( right_f.value ) ) {
                continue ;
              }
            }
            checked = true ;
            break ;
          } /* k */
          if ( !checked ) {
            all_checked = false ;
            break ;
          }
        } /*j */

        if ( !all_checked ) {
          continue ;
        }

        boolean has_assoc_Feature = false ;
        for ( int j = 0 ; j < left.size() ; j++ ) {
          Feature left_f = ( Feature )left.elementAt( j ) ;
          if ( left_f.checked || left_f.covered ) {
            continue ;
          }
          for ( int k = 0 ; k < right.size() ; k++ ) {
            Feature right_f = ( Feature )right.elementAt( k ) ;
            if ( right_f.checked || right_f.covered ) {
              continue ;
            }

            if ( right_f.eachside && left_f.eachside ) {
              continue ;
            }

            boolean right_headside , left_headside ;
            if ( right_f.eachside && left_f.eachside ) {
              continue ;
            }

            if ( right_f.eachside ) {
              right_headside = right_f.headside ? false : true ;
              left_headside  = left_f.headside ;
            } else if ( left_f.eachside ) {
              right_headside = right_f.headside ;
              left_headside  = left_f.headside ? false : true ;
            } else {
              right_headside = right_f.headside ;
              left_headside  = left_f.headside ;
            }

            if ( left_headside ) {
              continue ;
            }
            if ( !right_f.headside ) {
              continue ;
            }
            if ( !left_f.name.equals( right_f.name ) ) {
              continue ;
            }
            if ( left_f.inherent && right_f.inherent ) {
              if ( !left_f.value.equals( right_f.value ) ) {
                continue ;
              }
            }
            has_assoc_Feature = true ;
            break ;
          }
          if ( has_assoc_Feature ) {
            break ;
          }
        }

        if ( !has_assoc_Feature ) {
          continue ;
        }

        left.assoc = right ;
        right.assoc = left ;
        return true ;
      }
    }
    return false ;
  }

  public boolean fixOneAssoc() {
    if ( size() < 2 ) {
      return false ;
    }
    for ( int i = size() - 1 ; i >= 1 ; i-- ) {
      Word right = ( Word )elementAt( i ) ;
      Word left  = right.assoc ;
      if ( left == null ) {
        continue ;
      }
      if ( right.parent != null ) {
        continue ;
      }
      Word parent = left.parent ;
      if ( parent == null ) {
        return false ;
      }

      Word right_parent = merge( left , right , true ) ;
      right.parent = left.parent ;
      parent.right = right_parent ;
      parent.noheadside = right_parent ;

      for ( int j = 0 ; j < left.size() ; j++ ) {
        Feature left_f = ( Feature )left.elementAt( j ) ;
        if ( !left_f.checked && !left_f.covered ) {
          continue ;
        }
        for ( int k = 0 ; k < right.size() ; k++ ) {
          Feature right_f = ( Feature )right.elementAt( k ) ;
          if ( right_f.checked || right_f.covered ) {
            continue ;
          }

          boolean right_headside , left_headside ;
          if ( right_f.eachside != left_f.eachside ) {
            continue ;
          }
          if ( right_f.eachside ) {
            right_headside = left_f.headside ;
            left_headside  = left_f.headside ;
          } else {
            right_headside = right_f.headside ;
            left_headside  = left_f.headside ;
          }

          if ( left_headside != right_headside ) {
            continue ;
          }
          if ( !left_f.name.equals( right_f.name ) ) {
            continue ;
          }
          if ( left_f.inherent && right_f.inherent ) {
            if ( !left_f.value.equals( right_f.value ) ) {
              continue ;
            }
          }
          if ( left_f.inherent ) {
            right_f.value = left_f.value ;
            right_f.inherent = true ;
          } else {
            left_f.value = left_f.value ;
            left_f.inherent = true ;
          }
          left_f.covered   = true ;
          right_f.checked  = left_f.checked ;
          right_f.headside = right_headside ;
          left_f.headside  = left_headside ;
          break ;
        }
      }

      for ( int j = 0 ; j < left.size() ; j++ ) {
        Feature left_f = ( Feature )left.elementAt( j ) ;
        if ( left_f.checked || left_f.covered ) {
          continue ;
        }
        for ( int k = 0 ; k < right.size() ; k++ ) {
          Feature right_f = ( Feature )right.elementAt( k ) ;
          if ( right_f.checked || right_f.covered ) {
            continue ;
          }

          boolean right_headside , left_headside ;
          if ( right_f.eachside && left_f.eachside ) {
            continue ;
          }

          if ( right_f.eachside ) {
            right_headside = right_f.headside ? false : true ;
            left_headside  = left_f.headside ;
          } else if ( left_f.eachside ) {
            right_headside = right_f.headside ;
            left_headside  = left_f.headside ? false : true ;
          } else {
            right_headside = right_f.headside ;
            left_headside  = left_f.headside ;
          }

          if ( left_headside ) {
            continue ;
          }
          if ( !right_headside ) {
            continue ;
          }
          if ( !left_f.name.equals( right_f.name ) ) {
            continue ;
          }
          if ( !left_f.inherent && !right_f.inherent ) {
            continue ;
          }
          if ( left_f.inherent && right_f.inherent ) {
            if ( !left_f.value.equals( right_f.value ) ) {
              continue ;
            }
          }
          if ( left_f.inherent ) {
            right_f.value = left_f.value ;
            right_f.inherent = true ;
          } else {
            left_f.value = left_f.value ;
            left_f.inherent = true ;
          }
          left_f.checked   = right_f.checked = true ;
          left_f.headside  = left_headside ;
          break ;
        }
      }

      for ( int j = 0 ; j < parent.size() ; j++ ) {
        Feature parent_f = ( Feature )parent.elementAt( j ) ;
        if ( parent_f.checked || parent_f.covered ) {
          continue ;
        }
        for ( int k = 0 ; k < right.size() ; k++ ) {
          Feature right_f = ( Feature )right.elementAt( k ) ;
          if ( right_f.checked || right_f.covered ) {
            continue ;
          }

          boolean right_headside , parent_headside ;
          if ( right_f.eachside && parent_f.eachside ) {
            continue ;
          }
          if ( right_f.eachside ) {
            right_headside  = parent_f.headside ? false : true ;
            parent_headside = parent_f.headside ;
          } else if ( parent_f.eachside ) {
            right_headside  = right_f.headside ;
            parent_headside = right_f.headside ? false : true ;
          } else {
            right_headside  = right_f.headside ;
            parent_headside = parent_f.headside ;
          }

          if ( parent_headside == right_headside ) {
            continue ;
          }
          if ( !parent_headside ) {
            continue ;
          }
          if ( !parent_f.name.equals( right_f.name ) ) {
            continue ;
          }
          if ( !parent_f.inherent && !right_f.inherent ) {
            continue ;
          }
          if ( parent_f.inherent && right_f.inherent ) {
            if ( !parent_f.value.equals( right_f.value ) ) {
              continue ;
            }
          }
          if ( parent_f.inherent ) {
            right_f.value = parent_f.value ;
            right_f.inherent = true ;
          } else {
            parent_f.value = parent_f.value ;
            parent_f.inherent = true ;
          }
          parent_f.checked   = true ;
          right_f.checked    = true ;
          right_f.headside   = right_headside ;
          parent_f.headside  = parent_headside ;
          break ;
        }
      }
      return true ;
    }
    return false ;
  }

  public boolean makeOneAssoc() {
    for ( int i = size() - 1 ; i >= 1 ; i-- ) {
      Word right = ( Word )elementAt( i ) ;
      Word left_top = ( Word )elementAt( i - 1 ) ;
      if ( makeRightmostAssoc( right , left_top ) ) {
        return true ;
      }
    }
    return false ;
  }

  public boolean makeOneChain() {

/*(1999/3/1)
    for ( int i = fst.size() - 1 ; i >= 0 ; i-- ) {
 */
    for ( int i = 0 ; i < fst.size() - 1 ; i++ ) {
      Feature f = ( Feature )fst.elementAt( i ) ;
      if ( f.checked || f.covered || f.chainid >= 0 ) {
        continue ;
      }

/*(1999/3/1)
      for ( int j = 0 ; j < i ; j++ ) {
 */
      for( int j = i + 1 ; j < fst.size() ; j++ ) {
        Feature g = ( Feature )fst.elementAt( j ) ;
        if ( !f.obligatory && !g.obligatory ) {
          continue ;
        }

        if ( f.w == g.w ) {
          continue ;
        }

        if ( g.checked || g.covered || g.chainid >= 0 ) {
          continue ;
        }

        if ( !f.name.equals( g.name ) ) {
          continue ;
        }

        if ( !f.inherent && !g.inherent ) {
          continue ;
        }

        if ( f.headside == g.headside ) {
          continue ;
        }

        if ( f.inherent && g.inherent ) {
          if ( !f.value.equals( g.value ) ) {
            continue ;
          }
        }

        /* problem : (+wh) what do you like
         * what assciates to (+wh) but it must be chained to like .
        if ( f.w.assoc != null || g.w.assoc != null ) {
          msg = "word already associated" ;
          continue ;
        }
        */

        Word inherentside  = f.inherent ? f.w     : g.w ;
        Word redundantside = f.inherent ? g.w     : f.w ;
        Word headside      = f.headside ? f.w     : g.w ;
        Word noheadside    = f.headside ? g.w     : f.w ;

        /* ??? Jun 9 1998
        if ( noheadside.isUpperSide( headside ) ) {
          msg = "recursive translation not allowed" ;
          return false ;
        }
         */

        boolean rgt_prj    = f.headside ? true    : false ;
        String value       = f.inherent ? f.value : g.value ;

        f.value = g.value = value ;
        f.inherent = g.inherent = true ;
        f.checked = g.checked = true ;

        Word empty = rgt_prj ? new Word( "t" ) : new Word( "e" ) ;
        if ( f.headside ) {
          empty.add( g ) ;
          f.nohead = g.w ;
        } else {
          empty.add( f ) ;
          g.nohead = f.w ;
        }
        empty.chainid = noheadside.chainid = chainid ;

/*1999/3/1
        if ( merge( headside , empty , false ) == null ) {
          msg = "fatal error in Parser::makeOneChain()" ;
          return false ;
        }
 */
        // temporary sol.(1999/3/1)
        if ( merge( empty , headside , true ) == null ) {
          msg = "fatal error in Parser::makeOneChain(1)" ;
          return false ;
        }

        f.chainid = g.chainid = chainid ;
        chainid++ ;
        return true ;
      }
    }
    return false ;
  }

  public void clear() {
    removeAllElements() ;
    fst.removeAllElements() ;
    mystr = null ;
    chainid = 0 ;
  }

  public void setLexicon( Lexicon lex ) {
    this.lex = lex ;
  }

  public boolean startStep( String str ) {
    boolean ret ;
    msg = sub = null ;
    mystr = str ;

    if ( lex == null ) {
      msg = "no lexicon assigned" ;
      return false ;
    }

    mytokenizer = new StringTokenizer( mystr ) ;

    clear() ;

    if ( !mytokenizer.hasMoreTokens() ) {
      msg = "no words" ;
      return false ;
    }

    if ( !step( mytokenizer.nextToken() ) ) {
      return false ;
    }

    if ( !mytokenizer.hasMoreTokens() ) {
      int count = 0 ;
      for ( int i = 0 ; i < size() ; i++ ) {
        if ( ( ( Word )elementAt( i ) ).assoc == null ) {
          count++ ;
        }
      }
      if ( count > 1 ) { 
        msg = count + " phrase-marker remained" ;
        return false ;
      }
    }
    return true ;
  }

  public boolean nextStep() {
    msg = sub = null ;
    if ( !mytokenizer.hasMoreTokens() ) {
      return false ;
    }

    if ( !step( mytokenizer.nextToken() ) ) {
      return false ;
    }
    return true ;
  }

  public boolean legitimate() {
    int count = 0 ;
    for ( int i = 0 ; i < size() ; i++ ) {
      if ( ( ( Word )elementAt( i ) ).assoc == null ) {
        count++ ;
      }
    }
    if ( count > 1 ) { 
      msg = count + " phrase-marker remained" ;
      return false ;
    }

    if ( !fst.legitimate() ) {
      msg = "illegitimate Feature in Feature stack" ;
      return false ;
    }

    return true ;
  }

  public boolean step( String tok ) {
    return step( tok , null ) ;
  }

  public boolean step( String tok , Word owner ) {
    int i , j ;
    Word w = lex.select( tok , owner ) ;
    if ( w == null ) {
      msg = "illegal Word "+ "(" + tok + ")" ;
      return false ;
    }

    if ( size() >= 1 ) {
      Word left_top = ( Word )elementAt( size() - 1 ) ;
      Word left_rightmost = left_top.rightmost() ;
      if ( mergeCheck( left_rightmost , w ) ) {
        addElement( w ) ;

// appended (1999/3/1)
        makeAllChain() ;

        makeAttachment() ;

        if ( size() > 1 ) {
          w = ( Word )elementAt( size() - 1 ) ;
          left_top = ( Word )elementAt( size() - 2 ) ;
          makeRightmostAssoc( w , left_top ) ;
        }
        return true ;
      }
    }

    addElement( w ) ;
    if ( size() >= 2 ) {
      Word left_top = ( Word )elementAt( size() - 2 ) ;
      if ( !makeRightmostAssoc( w , left_top ) ) {
        makeAllChain() ; // 1999/3/1(see notes.txt)
        return makeAttachment() ;
      } else {
        for ( i = 0 ; i < w.size() ; i++ ) {
          Feature f = ( Feature )w.elementAt( i ) ;
          if ( !f.checked && !f.covered ) {
            fst.addElement( f ) ;
          }
        }
      }
      return true ;
    } else {
      makeAllChain() ; // 1999/3/1(see notes.txt)
      return makeAttachment() ;
    }
  }


  public boolean makeAttachment() {
    int i , j ;
    msg = sub = null ;
    boolean word_checked = false ;

    if ( size() <= 0 ) {
      msg = "fatal error" ;
      return false ;
    }

    Word w = ( Word )elementAt( size() - 1 ) ;
    removeElement( w ) ;

    while ( true ) {
      boolean word_may_projected = false ;
      for ( j = fst.size() - 1 ; j >= 0 ; j-- ) {
        boolean feature_checked = false ;
        Feature left = ( Feature )fst.elementAt( j ) ;
        for ( i = 0 ; i < w.size() ; i++ ) {
          Feature right = ( Feature )w.elementAt( i ) ;
          sub = null ;

          if ( left.w.isUpperSide( ( Word )elementAt( size() - 1 ) ) ) {
            continue ;
          }
          boolean result = checkAndMerge( left , right , ( size() - 1 )) ;
          if ( result ) {
            w = right.w ;
            word_checked = feature_checked = true ;
            word_may_projected = true ;
            break ;
          }
        }
      }
      if ( !word_may_projected ) {
        break ;
      }
    }

    int assoc_num = 0 ;
    for ( i = size() - 1 ; i >= 0 ; i-- ) {
      if ( ( ( Word )elementAt( i ) ).assoc == null ) {
        break ;
      }
      assoc_num++ ;
    }

    while ( true ) {
      boolean word_may_projected = false ;
      for ( j = fst.size() - 1 ; j >= 0 ; j-- ) {
        boolean feature_checked = false ;
        Feature left = ( Feature )fst.elementAt( j ) ;
        for ( i = 0 ; i < w.size() ; i++ ) {
          Feature right = ( Feature )w.elementAt( i ) ;
          sub = null ;
          boolean result = checkAndMerge( left , right , size() - 1 - assoc_num ) ;
          if ( result ) {
            fixAllAssoc() ;
            w = right.w ;
            word_checked = feature_checked = true ;
            word_may_projected = true ;
            break ;
          }
        }
      }
      if ( !word_may_projected ) {
        break ;
      }
    }

    if ( !word_checked && ( assoc_num > 0 ) ) {
      while ( true ) {
        boolean word_may_projected = false ;
        for ( j = fst.size() - 1 ; j >= 0 ; j-- ) {
          boolean feature_checked = false ;
          Feature left = ( Feature )fst.elementAt( j ) ;
          for ( i = 0 ; i < w.size() ; i++ ) {
            Feature right = ( Feature )w.elementAt( i ) ;
            sub = null ;
            boolean result = checkAndMerge( left , right , ( size() - 1 )) ;
            if ( result ) {
              w = right.w ;
              word_checked = feature_checked = true ;
              word_may_projected = true ;
              break ;
            }
          }
        }
        if ( !word_may_projected ) {
          break ;
        }
      }
    }

    if ( !word_checked ) {
      addElement( w ) ;
    }

    for ( i = 0 ; i < w.size() ; i++ ) {
      Feature f = ( Feature )w.elementAt( i ) ;
      if ( !f.checked && !f.covered ) {
        fst.addElement( f ) ;
      }
    }
    return true ;
  }

  public Word doParse( String str ) {
    return doParse( str , null ) ;
  }

  public Word doParse( String str , Word owner ) {
    msg = sub = null ;

    if ( lex == null ) {
      msg = "no lexicon assigned" ;
      return null ;
    }

    StringTokenizer tokenizer = new StringTokenizer( str ) ;

    clear() ;

    while( tokenizer.hasMoreTokens() ) {
      if ( !step( tokenizer.nextToken() , owner ) ) {
        return null ;
      }
    }

    makeAllAssoc() ;
    fixAllAssoc() ;
    makeAllChain() ;
    if ( !legitimate() ) {
      return null ;
    }

    if ( size() > 0 ) {
      return ( Word )elementAt( 0 ) ;
    } else {
      return null ;
    }
  }

  public String treeImage( int offset , boolean fval ) {
    StringBuffer buf = new StringBuffer() ;
    for ( int i = 0 ; i < size() ; i++ ) {
      Word w = ( Word )elementAt( i ) ;
      if ( w.assoc != null ) {
        continue ;
      }
      buf.append( w.treeImage( offset , fval ) ) ;
      buf.append( "\n" ) ;
    }
    return buf.toString() ;
  }

  public String stackImage( int offset ) {
    return fst.stackImage( offset ) ;
  }
}

