// FILE. . . . . /home/hak/hlt/src/hlt/osfv2/io/DisplayFormManager.java
// EDIT BY . . . Hassan Ait-Kaci
// ON MACHINE. . Hak-Laptop
// STARTED ON. . Mon Sep 02 15:36:33 2013

/**
 * @version     Last modified on Tue Jan 21 08:07:48 2014 by hak
 * @author      <a href="mailto:hak@acm.org">Hassan A&iuml;t-Kaci</a>
 * @copyright   &copy; <a href="http://www.hassan-ait-kaci.net/">by the author</a>
 */

package hlt.osf.io;

import hlt.osf.base.Sort;
import hlt.osf.util.BitCode;
import hlt.osf.util.Decoded;
import hlt.osf.exec.Taxonomy;

import hlt.language.util.ArrayList;
import hlt.language.util.IntIterator;

import java.util.HashSet;
import java.util.HashMap;
import java.util.Iterator;

/**
 * This class defines methods that format various OSF constructs to
 * enable them to be legibly displayed.
 */
public class DisplayFormManager
{
  public String displayBottomForm ()
    {
      return Sort.bottom().toString();
    }

  public String displayTopForm ()
    {
      return Sort.top().toString();
    }

  public final String displaySortForm (Sort sort)
  {
    return sort.toString();
  }

  public final String displayForm (Sort sort)
  {
    if (sort.isTop())
      return displayTopForm();

    if (sort.isBottom())
      return displayBottomForm();

    return displaySortForm(sort);    
  }

  /**
   * This is the display form of an array of sorts.
   */
  public final String displaySortsForm (Sort[] sorts)
    {
      if (sorts == null)	// This should never happen!
	return "*null sort array*";

      if (sorts.length == 0)	// This should happen only for the UP of @ or the LB of {}
	return "*no sort*";

      if (sorts.length == 1)
	return sorts[0].toString();      
      
      StringBuilder buf = new StringBuilder("{");
      for (int i=sorts.length; i-->0;)
        buf.append(sorts[i] + (i>0 ? "; ":""));
      return buf.append("}").toString();
    }      

  /**
   * This is the display form of disjunctive sorts which are represented
   * as ArrayLists.
   */
  public final String displaySortsForm (ArrayList sorts)  
    {
      if (sorts == null)	// This should never happen!
	return "*null disjunctive sort*";

      if (sorts.isEmpty())
	return displayBottomForm();

      if (sorts.size() == 1)
	return sorts.get(0).toString();
      
      StringBuilder buf = new StringBuilder("{");
      for (Iterator i=sorts.iterator(); i.hasNext();)
        buf.append(i.next() + (i.hasNext() ? "; " : ""));
      return buf.append("}").toString();
    }

  /**
   * This is the display form of disjunctive sorts which are represented
   * as a BitCode.
   */
  public final String displayForm (BitCode sorts, Taxonomy taxonomy)
    {
      if (sorts == null)	// This should never happen!
	return "*null disjunctive sort*";

      if (sorts.isEmpty())
	return displayBottomForm();

      if (sorts.cardinality() == 1)
	return taxonomy.get(sorts.nextSetBit(0)).toString();
      
      StringBuilder buf = new StringBuilder("{");
      for (IntIterator i=sorts.iterator(); i.hasNext();)
        buf.append(taxonomy.get(i.next()) + (i.hasNext() ? "; " : ""));
      return buf.append("}").toString();
    }

  /**
   * This is the display form of a HashSet of sorts. If the boolean
   * argument is true, a null or empty set will be printed as top
   * otherwise as false. If the set has more than one element, top
   * is not printed.
   */
  public final String displayForm (HashSet sorts, boolean upper)
    {
      if (sorts == null || sorts.isEmpty())
	return upper ? "*EVERYTHING*" : "*NOTHING*";

      if (sorts.size() == 1)
	return sorts.iterator().next().toString();

      StringBuffer buf = new StringBuffer();

      int size = sorts.contains(Sort.top()) ? sorts.size()-1 : sorts.size();
      int count = 0;

      for (Iterator it = sorts.iterator(); it.hasNext();)
	{
	  Sort sort = (Sort)it.next();
	  
	  if (sort.isTop())
	    continue;

	  if (count++ > Decoded.enumSize())
	    {
	      buf.append("... ("+size+" elements in total)");
	      break;
	    }
	  
	  buf.append(sort+" ");
	}

      return buf.toString();
    }

  public String quotedDisplayForm (double x)
    {
      return String.valueOf(x);
    }

  public String unquotedDisplayForm (double x)
    {
      return quotedDisplayForm(x);
    }

  // /**
  //  * The following is a table to keep a record of tags labelling
  //  * psi-terms that have already been displayed and thus need not be
  //  * redisplayed beyond their tag.  This allows printing circular
  //  * objects, and saves on the display form of objects that are
  //  * shared. A tag is of the form <tt>Classname#n</tt>, where
  //  * <tt>Classname</tt> is the name of the class of the tagged object
  //  * and <tt>n</tt> is a number. Therefore, the table <tt>_tags</tt> is
  //  * a table of tables: it maps a classname to a table that maps a
  //  * number to the object it designates.
  //  */
  private final HashMap _tags = new HashMap();

  public DisplayFormManager clearTags ()
    {
      _tags.clear();
      return this;
    }

  // private final String _getTag (ObjectInstance o)
  //   {
  //     HashMap typeTags = (HashMap)_tags.get(o.type());

  //     if (typeTags == null)
  //       {
  //         _tags.put(o.type(),typeTags = new HashMap());
  //         return null;
  //       }

  //     return (String)typeTags.get(o);
  //   }

  // private final String _putTag (ObjectInstance o)
  //   {
  //     HashMap typeTags = (HashMap)_tags.get(o.type());

  //     if (typeTags == null)
  //       _tags.put(o.type(),typeTags = new HashMap());

  //     String tag = "#"+typeTags.size();
  //     typeTags.put(o,tag);

  //     return tag;
  //   }

}
