// FILE. . . . . /home/hak/hlt/src/hlt/osfv1/apps/v1/sources/PsiTermBuilder.java
// EDIT BY . . . Hassan Ait-Kaci
// ON MACHINE. . Hak-Laptop
// STARTED ON. . Wed Sep 11 14:16:17 2013

// Last modified on Fri Sep 13 09:40:06 2013 by hak

/**
 * Using the given hash set of tags already associated to previously
 * constructed &psi;-terms, this builds an uninterpreted &psi;-term
 * structure out of the syntactic parts given as arguments.
 *
 * <p>
 *
 * <b>N.B.</b> This (and merge and prettyPrint of PsiTerm) does not seem to
 * work properly. The problem has to do with how dereferencing alters
 * sub-structures while they are being built (or visited). The alternative
 * approach would be to keep the raw psiterm structure built by the parser
 * and compile it directly rather than trying to do this partial evaluation.
 * Execution of the compiled code should then result in a buildable (and
 * printable) structure.
 *
 */
PsiTerm buildPsiTerm (HashSet tags, Tag tag, SortExpression sort, Stack keys, Stack subterms)
{
  tag = tag.deref();	// dereference the tag to get to the correct one if needed
  
  PsiTerm pst = null;		// this is the new psiterm to build and return
  PsiTerm previous = null;	// this is a previously existing psiterm

  // if the tag is a reoccurring tag
  if (tags.contains(tag))	
    {
      // build this term with a newly generated tag:
      pst = buildPsiTerm(tags,
			 Tag.newTag(),
			 sort,
			 keys,
			 subterms).deref();
      // retrieve the tag's term, marking the tag as shared (due to the reoccurrence):
      previous = tag.deref().markAsShared().term();
      // merge the newer term into the previous one and return it:
      previous.merge(pst);
      return previous.deref();
    }

  // the tag has not occurred before:
  pst = new PsiTerm(tag).setSort(sort);	// construct a new psiterm with the given tag and sort
  tags.add(tag);			// and add the tag to the tag occurrences

  // build the subterms if there are any:
  if (subterms != null) // then keys != null as well
    while (!subterms.empty())
      {
	// get the current raw subterm to build:
	RawPsiTerm sub = (RawPsiTerm)subterms.pop();
	// build the current subterm
	PsiTerm subterm = buildPsiTerm(tags,
				       Tag.getTag(sub.tag),
				       sub.sort,
				       sub.keys,
				       sub.subterms).deref();

	System.out.println("    >>> built subterm: \n        "+subterm.displayForm(8));

	// get the current subterm's key
	Object key = keys.pop();

	if (key == null)
	  // this is an implicitly contiguous position
	  {
	    // retrieve the dereferenced possibly existing subterm:
	    previous = pst.getNextContiguousPositionSubterm();
	    if (previous == null)
	      pst.addContiguousPositionSubterm(subterm);
	    else
	      previous.merge(subterm.deref());

	    continue;
	  }

	if (key instanceof Integer)
	  // this is an explicitly specified position
	  {
	    int position = ((Integer)key).intValue();
	    previous = pst.getSubterm(position);
	    if (previous == null)
	      pst.setSubterm(position,subterm);
	    else
	      previous.merge(subterm.deref());

	    continue;
	  }

	// this is a feature subterm
	Feature feature = Feature.getFeature((String)key);

	previous = pst.getSubterm(feature);
	if (previous == null)
	  pst.setSubterm(feature,subterm);
	else
	  previous.merge(subterm.deref());
      }
  
  return pst.deref();    
}
