package jgrasp_viewers_python;


import java.math.BigInteger;
import java.util.EnumSet;
import java.util.List;
import jgrasp.PluginOptOut;
import jgrasp.viewer.Util;
import jgrasp.viewer.ViewerCreateData;
import jgrasp.viewer.ViewerException;
import jgrasp.viewer.ViewerInfo;
import jgrasp.viewer.ViewerInitData;
import jgrasp.viewer.ViewerPriorityData;
import jgrasp.viewer.ViewerUpdateData;
import jgrasp.viewer.ViewerValueData;
import jgrasp.viewer.jgrdi.DebugContext;
import jgrasp.viewer.jgrdi.SubValue;
import jgrasp.viewer.jgrdi.SubValueTypes;
import jgrasp.viewer.jgrdi.Value;
import jgrasp.viewer.text.StringListViewWSV;
import org.w3c.dom.Element;


/** A viewer that displays the elements as a list of strings. **/
public class _X_ElementsToStringView extends StringListViewWSV {

   /** Creates a new string list viewer.
    *
    * @param vcd viewer creation data. **/
   public _X_ElementsToStringView(final ViewerCreateData vcd) {
      super(vcd, false);
      if (!vcd.getValue().isArray(vcd.getDebugContext())) {
         throw new PluginOptOut();
      }
   }


   /** {@inheritDoc} **/
   @Override
   public void build(final ViewerInitData vid, final Element initDataIn) {
      super.build(vid, initDataIn);
      vid.setIndexable(true);
   }


   /** {@inheritDoc} **/
   @Override
   public void getInfo(final ViewerInfo vi) {
      vi.setShortDescription("Elements string value viewer");
      vi.setLongDescription("This viewer displays the string value for iterable elements. Selecting an element "
            + "will cause its value to be displayed in a subviewer.");
   }


   /** {@inheritDoc} **/
   @Override
   public int getPriority(final ViewerPriorityData vpd) {
      return 10;
   }


   /** {@inheritDoc} **/
   @Override
   public String getSubviewerLabel(final int index, final String viewerLabel, final int itemIndex,
         final ViewerValueData valueData, final DebugContext context) {
      return " " + getSubviewerTreeLabel(index, viewerLabel, itemIndex, valueData, context);
   }


   /** {@inheritDoc} **/
   @Override
   public String getSubviewerTreeLabel(final int index, final String viewerLabel, final int itemIndex,
         final ViewerValueData valueData, final DebugContext context) {
      return Util.getPythonExprEnd(valueData, itemIndex, context);
   }


   /** {@inheritDoc} **/
   @Override
   public String getViewName() {
      return "Element Strings";
   }


   /** {@inheritDoc} **/
   @Override
   public int update(final ViewerValueData valueData, final ViewerUpdateData data, final DebugContext context,
         final int viewOffset, final int numItemsShown, final int selected, final String[] textOut,
         final Value[] valuesOut, final Value[] selectedValuesOut, final String[] selectedExpressionsOut,
         final String[] errorOut) throws ViewerException {
   
      Value value = valueData.value();
      boolean gotSelection = false;
      List<SubValue> subValues = context.getSubValues(value, EnumSet.of(SubValueTypes.ELEMENTS),
            BigInteger.valueOf(viewOffset), numItemsShown);
      
      for (int i = 0; i < numItemsShown; i++) {
         if (i < subValues.size()) {
            Value element = subValues.get(i).value();
            valuesOut[i] = element;
            if (i + viewOffset == selected && selectedValuesOut.length > 0) {
               selectedValuesOut[0] = element;
               selectedExpressionsOut[0] = getExpr(valueData, selected, context);
               gotSelection = true;
            }
            String str = Util.encodeString(element.toString(context), true);
            if (str.length() > 100) {
               str = str.substring(0, 96) + " ...";
            }
            textOut[i] = Util.getPythonExprEnd(valueData, i + viewOffset, context) + " = " + str;
         }
         else {
            valuesOut[i] = null;
            textOut[i] = " ";
         }
      }
      if (selected >= 0 && !gotSelection && selectedValuesOut.length > 0) {
         List<SubValue> selSubValues = context.getSubValues(value, EnumSet.of(SubValueTypes.ELEMENTS),
               BigInteger.valueOf(selected), 1);
         if (!selSubValues.isEmpty()) {
            Value element = selSubValues.get(0).value();
            selectedValuesOut[0] = element;
            selectedExpressionsOut[0] = getExpr(valueData, selected, context);
         }
      }
   
      try {
         return context.getSubValuesLength(value, EnumSet.of(SubValueTypes.ELEMENTS),
               BigInteger.valueOf(Integer.MAX_VALUE)).intValueExact();
      }
      catch (ArithmeticException e) {
         return Integer.MAX_VALUE;
      }
   }


   /** Gets the expression for a value at a specified index.
    *
    * @param valueData the value update data.
    *
    * @param index the index of interest.
    *
    * @return an expression for the value at the requested index, or null if there is no expression for the current
    * value. **/
   private String getExpr(final ViewerValueData valueData, final int index, final DebugContext context) {
      return Util.getPythonExpr(getVIData(), valueData, index, context);
   }

}
