Package org.jmol.script

Source Code of org.jmol.script.ScriptVariable$Sort

/* $RCSfile$
* $Author: hansonr $
* $Date: 2009-06-05 07:42:12 -0500 (Fri, 05 Jun 2009) $
* $Revision: 10958 $
*
* Copyright (C) 2003-2005  The Jmol Development Team
*
* Contact: jmol-developers@lists.sf.net
*
*  This library is free software; you can redistribute it and/or
*  modify it under the terms of the GNU Lesser General Public
*  License as published by the Free Software Foundation; either
*  version 2.1 of the License, or (at your option) any later version.
*
*  This library is distributed in the hope that it will be useful,
*  but WITHOUT ANY WARRANTY; without even the implied warranty of
*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
*  Lesser General License for more details.
*
*  You should have received a copy of the GNU Lesser General Public
*  License along with this library; if not, write to the Free Software
*  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*/

package org.jmol.script;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.BitSet;
import java.util.Collections;
import java.util.Comparator;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import javax.vecmath.Matrix3f;
import javax.vecmath.Matrix4f;
import javax.vecmath.Point3f;
import javax.vecmath.Point4f;
import javax.vecmath.Vector3f;

import org.jmol.modelset.Bond.BondSet;
import org.jmol.util.BitSetUtil;
import org.jmol.util.Escape;
import org.jmol.util.Parser;

import org.jmol.util.Measure;
import org.jmol.util.Quaternion;
import org.jmol.util.TextFormat;

public class ScriptVariable extends Token {

  final private static ScriptVariable vT = new ScriptVariable(on, 1, "true");
  final private static ScriptVariable vF = new ScriptVariable(off, 0, "false");
  final static ScriptVariable vAll = new ScriptVariable(all, "all");

  public int index = Integer.MAX_VALUE;

  private final static int FLAG_CANINCREMENT = 1;
  private final static int FLAG_LOCALVAR = 2;

  private int flags = ~FLAG_CANINCREMENT & FLAG_LOCALVAR;
  String name;

  public ScriptVariable() {
    tok = string;
    value = "";
  }

  public ScriptVariable(int tok) {
    this.tok = tok;
  }

  public ScriptVariable(int tok, int intValue, Object value) {
    super(tok, intValue, value);
  }

  public ScriptVariable(int tok, Object value) {
    super(tok, value);
  }

  public ScriptVariable(int tok, int intValue) {
    super(tok, intValue);
  }

  public ScriptVariable(BitSet bs, int index) {
    value = bs;
    this.index = index;
    tok = bitset;
  }

  public ScriptVariable(Token x) {
    tok = x.tok;
    intValue = x.intValue;
    value = x.value;
  }
 
  static public String typeOf(ScriptVariable x) {
    int tok = (x == null ? nada : x.tok);
    switch (tok) {
    case on:
    case off:
      return "boolean";
    case bitset:
      return (x.value instanceof BondSet ? "bondset" : "bitset");
    case integer:
    case decimal:
    case point3f:
    case point4f:
    case string:
    case varray:
    case hash:
    case matrix3f:
    case matrix4f:
      return astrType[tok];
    }
    return "?";
  }

  public static int sizeOf(Token x) {
    switch (x == null ? nada : x.tok) {
    case bitset:
      return BitSetUtil.cardinalityOf(bsSelect(x));
    case on:
    case off:
      return -1;
    case integer:
      return -2;
    case decimal:
      return -4;
    case point3f:
      return -8;
    case point4f:
      return -16;
    case matrix3f:
      return -32;
    case matrix4f:
      return -64;
    case string:
      return ((String) x.value).length();
    case varray:
      return x.intValue == Integer.MAX_VALUE ? ((ScriptVariable)x).getList().size()
          : sizeOf(selectItem(x));
    case hash:
      return ((Map) x.value).size();
    default:
      return 0;
    }
  }

  public static ScriptVariable intVariable(int intValue) {
    return new ScriptVariable(integer, intValue);
  }

  static public boolean isVariableType(Object x) {
    return (x instanceof ScriptVariable
        || x instanceof BitSet
        || x instanceof Boolean
        || x instanceof Float
        || x instanceof Integer
        || x instanceof Point3f    // stored as point3f
        || x instanceof Vector3f   // stored as point3f
        || x instanceof Point4f    // stored as point4f
        || x instanceof Quaternion // stored as point4f
        || x instanceof String
        || x instanceof Map  // stored as Map<String, ScriptVariable>
        || x instanceof List    // stored as list
        || x instanceof ScriptVariable[] // stored as list
        || x instanceof double[]   // stored as list
        || x instanceof float[]    // stored as list
        || x instanceof float[][]  // stored as list
        || x instanceof Float[]    // stored as list
        || x instanceof int[]      // stored as list
        || x instanceof int[][]    // stored as list
        || x instanceof Point4f[]  // stored as list
        || x instanceof String[]); // stored as list
  }

  /**
   * @param x
   * @return  a ScriptVariable of the input type, or if x is null, then a new ScriptVariable,
   *     or, if the type is not found, a string version
   */
  public static ScriptVariable getVariable(Object x) {
    if (x == null)
      return new ScriptVariable();
    if (x instanceof ScriptVariable)
      return (ScriptVariable) x;

    // the eight basic types are:
    // boolean, integer, decimal, string, point3f, point4f, bitset, and list
    // listf is a special temporary type for storing results
    // of .all in preparation for .bin in the case of xxx.all.bin
    // but with some work, this could be developed into a storage class

    if (x instanceof Boolean)
      return getBoolean(((Boolean) x).booleanValue());
    if (x instanceof Integer)
      return new ScriptVariable(integer, ((Integer) x).intValue());
    if (x instanceof Float)
      return new ScriptVariable(decimal, x);
    if (x instanceof String) {
      x = unescapePointOrBitsetAsVariable(x);
      if (x instanceof ScriptVariable)
        return (ScriptVariable) x;
      return new ScriptVariable(string, x);
    }
    if (x instanceof Point3f)
      return new ScriptVariable(point3f, x);
    if (x instanceof Vector3f)
      return new ScriptVariable(point3f, new Point3f((Vector3f) x));
    if (x instanceof BitSet)
      return new ScriptVariable(bitset, x);
    if (x instanceof Point4f)
      return new ScriptVariable(point4f, x);
    // note: for quaternions, we save them {q1, q2, q3, q0}
    // While this may seem odd, it is so that for any point4 --
    // planes, axisangles, and quaternions -- we can use the
    // first three coordinates to determine the relavent axis
    // the fourth then gives us offset to {0,0,0} (plane),
    // rotation angle (axisangle), and cos(theta/2) (quaternion).
    if (x instanceof Quaternion)
      return new ScriptVariable(point4f, ((Quaternion) x).toPoint4f());
    if (x instanceof Matrix3f)
      return new ScriptVariable(matrix3f, x);
    if (x instanceof Matrix4f)
      return new ScriptVariable(matrix4f, x);
    if (x instanceof Float[])
      return new ScriptVariable(listf, x);
    if (x instanceof Map) {
      Map ht = (Map) x;
      Iterator e = ht.keySet().iterator();
      while (e.hasNext()) {
        if (!(ht.get(e.next()) instanceof ScriptVariable)) {
          Map x2 = new Hashtable();
          e = ht.keySet().iterator();
          while (e.hasNext()) {
            String key = (String) e.next();
            x2.put(key, getVariable(ht.get(key)));
          }
          x = x2;
        }
        break; // just need to check the first one
      }
      return new ScriptVariable(hash, x);
    }

    // all the rest are stored as list
    // at least for now, still saving as a string,
    // but ultimately, that should not be necessary

    List objects = null;
    if (x instanceof List) {
      // will be turned into list
      List v = (List) x;
      int len = v.size();
      if (len > 0 && v.get(0) instanceof ScriptVariable)
        return new ScriptVariable(varray, v);
      objects = new ArrayList();
      for (int i = 0; i < len; i++)
        objects.add(getVariable(v.get(i)));
      return new ScriptVariable(varray, objects);
    }
    if (x instanceof ScriptVariable[]) {
      objects = new ArrayList();
      ScriptVariable[] v = (ScriptVariable[]) x;
      objects = new ArrayList();
      for (int i = 0; i < v.length; i++)
        objects.add(v[i]);
      return new ScriptVariable(varray, objects);
    }
    if (x instanceof String[]) {
      String[] s = (String[]) x;
      objects = new ArrayList();
      for (int i = 0; i < s.length; i++)
        objects.add(getVariable(s[i]));
      return new ScriptVariable(varray, objects);
    }
    if (x instanceof int[]) {
      int[] ix = (int[]) x;
      objects = new ArrayList();
      for (int i = 0; i < ix.length; i++)
        objects.add(getVariable(Integer.valueOf(ix[i])));
      return new ScriptVariable(varray, objects);
    }
    if (x instanceof float[]) {
      float[] f = (float[]) x;
      objects = new ArrayList();
      for (int i = 0; i < f.length; i++)
        objects.add(getVariable(Float.valueOf(f[i])));
      return new ScriptVariable(varray, objects);
    }
    if (x instanceof double[]) {
      double[] f = (double[]) x;
      objects = new ArrayList();
      for (int i = 0; i < f.length; i++)
        objects.add(getVariable(Float.valueOf((float) f[i])));
      return new ScriptVariable(varray, objects);
    }
    if (x instanceof int[][]) {
      int[][] ix = (int[][]) x;
      objects = new ArrayList();
      for (int i = 0; i < ix.length; i++)
        objects.add(getVariable(ix[i]));
      return new ScriptVariable(varray, objects);
    }
    if (x instanceof float[][]) {
      float[][] fx = (float[][]) x;
      objects = new ArrayList();
      for (int i = 0; i < fx.length; i++)
        objects.add(getVariable(fx[i]));
      return new ScriptVariable(varray, objects);
    }
    return new ScriptVariable(string, Escape.toReadable(x));
  }

  /**
   * creates a NEW version of the variable
   *
   *
   * @param v
   * @param asCopy  create a new set of object pointers
   *                for an array; copies an associative array
   * @return  new ScriptVariable
   */
  public ScriptVariable set(ScriptVariable v, boolean asCopy) {
    // note: bitset, point3f ,point4f will not be copied
    //       because they are essentially immutable here
    index = v.index;
    intValue = v.intValue;
    tok = v.tok;
    value = v.value;
    if (asCopy) {
      switch (tok) {
      case hash:
        value = new Hashtable((Map) v.value);
        break;
      case varray:
        List o2 = new ArrayList();
        List o1 = v.getList();
        for (int i = 0; i < o1.size(); i++)
          o2.add(o1.get(i));
        value = o2;
        break;
      }
    }
    return this;
  }

  public ScriptVariable setName(String name) {
    this.name = name;
    flags |= FLAG_CANINCREMENT;
    //System.out.println("Variable: " + name + " " + intValue + " " + value);
    return this;
  }

  public ScriptVariable setGlobal() {
    flags &= ~FLAG_LOCALVAR;
    return this;
  }

  public boolean canIncrement() {
    return tokAttr(flags, FLAG_CANINCREMENT);
  }

  public boolean increment(int n) {
    if (!canIncrement())
      return false;
    switch (tok) {
    case integer:
      intValue += n;
      break;
    case decimal:
      value = new Float(((Float) value).floatValue() + n);
      break;
    default:
      value = nValue(this);
      if (value instanceof Integer) {
        tok = integer;
        intValue = ((Integer) value).intValue();
      } else {
        tok = decimal;
      }
    }
    return true;
  }

  public boolean asBoolean() {
    return bValue(this);
  }

  public int asInt() {
    return iValue(this);
  }

  public float asFloat() {
    return fValue(this);
  }

  public String asString() {
    return sValue(this);
  }

  public Object getValAsObj() {
    return (tok == integer ? Integer.valueOf(intValue) : value);
  }

  // math-related Token static methods

  private final static Point3f pt0 = new Point3f();

  /**
   *
   * @param x
   * @return   Object-wrapped value
   */
 
  public static Object oValue(ScriptVariable x) {
    switch (x == null ? nada : x.tok) {
    case on:
      return Boolean.TRUE;
    case nada:
    case off:
      return Boolean.FALSE;
    case integer:
      return Integer.valueOf(x.intValue);
    default:
      return x.value;
    }
  }

  /**
   *
   * @param x
   * @return  numeric value -- integer or decimal
   */
  public static Object nValue(Token x) {
    int iValue;
    switch (x == null ? nada : x.tok) {
    case decimal:
      return x.value;
    case integer:
      iValue = x.intValue;
      break;
    case string:
      if (((String) x.value).indexOf(".") >= 0)
        return new Float(toFloat((String) x.value));
      iValue = (int) toFloat((String) x.value);
      break;
    default:
      iValue = 0;
    }
    return Integer.valueOf(iValue);
  }

  // there are reasons to use Token here rather than ScriptVariable
  // some of these functions, in particular iValue, fValue, and sValue
 
  public static boolean bValue(Token x) {
    switch (x == null ? nada : x.tok) {
    case on:
      return true;
    case off:
      return false;
    case integer:
      return x.intValue != 0;
    case decimal:
    case string:
    case varray:
      return fValue(x) != 0;
    case bitset:
      return iValue(x) != 0;
    case point3f:
    case point4f:
    case matrix3f:
    case matrix4f:
      return Math.abs(fValue(x)) > 0.0001f;
    default:
      return false;
    }
  }

  public static int iValue(Token x) {
    switch (x == null ? nada : x.tok) {
    case on:
      return 1;
    case off:
      return 0;
    case integer:
      return x.intValue;
    case decimal:
    case varray:
    case string:
    case point3f:
    case point4f:
    case matrix3f:
    case matrix4f:
      return (int) fValue(x);
    case bitset:
      return BitSetUtil.cardinalityOf(bsSelect(x));
    default:
      return 0;
    }
  }

  public static float fValue(Token x) {
    switch (x == null ? nada : x.tok) {
    case on:
      return 1;
    case off:
      return 0;
    case integer:
      return x.intValue;
    case decimal:
      return ((Float) x.value).floatValue();
    case varray:
      int i = x.intValue;
      if (i == Integer.MAX_VALUE)
        return ((ScriptVariable)x).getList().size();
    case string:
      return toFloat(sValue(x));
    case bitset:
      return iValue(x);
    case point3f:
      return ((Point3f) x.value).distance(pt0);
    case point4f:
      return Measure.distanceToPlane((Point4f) x.value, pt0);
    case matrix3f:
      Point3f pt = new Point3f();
      ((Matrix3f) x.value).transform(pt);
      return pt.distance(pt0);
    case matrix4f:
      Point3f pt1 = new Point3f();
      ((Matrix4f) x.value).transform(pt1);
      return pt1.distance(pt0);
    default:
      return 0;
    }
  }

  public static String sValue(Token x) {
    StringBuffer sb;
    Map map;
    if (x == null)
      return "";
    int i;
    switch (x.tok) {
    case on:
      return "true";
    case off:
      return "false";
    case integer:
      return "" + x.intValue;
    case point3f:
      return Escape.escape((Point3f) x.value);
    case point4f:
      return Escape.escape((Point4f) x.value);
    case matrix3f:
      return Escape.escape((Matrix3f) x.value);
    case matrix4f:
      return Escape.escape((Matrix4f) x.value);
    case bitset:
      return Escape.escape(bsSelect(x), !(x.value instanceof BondSet));
    case varray:
    case hash:
      if (x.tok == Token.varray) {
        List sv = ((ScriptVariable) x).getList();
        i = x.intValue;
        if (i <= 0)
          i = sv.size() - i;
        if (i != Integer.MAX_VALUE)
          return (i < 1 || i > sv.size() ? "" : sValue((ScriptVariablesv.get(i - 1)));
      }
      sb = new StringBuffer();
      map = new Hashtable();
      sValueArray(sb, (ScriptVariable) x, map, 0, false);
      return sb.toString();
    case string:
      String s = (String) x.value;
      i = x.intValue;
      if (i <= 0)
        i = s.length() - i;
      if (i == Integer.MAX_VALUE)
        return s;
      if (i < 1 || i > s.length())
        return "";
      return "" + s.charAt(i - 1);
    case decimal:
    default:
      return "" + x.value;
    }
  }

  private static void sValueArray(StringBuffer sb, ScriptVariable vx,
                                  Map map, int level,
                                  boolean isEscaped) {
    switch (vx.tok) {
    case hash:
      if (map.containsKey(vx)) {
        sb.append(isEscaped ? "{}" : vx.name == null ? "<circular reference>"
            : "<" + vx.name + ">");
        break;
      }
      map.put(vx, Boolean.TRUE);
      Map ht = (Map) vx.value;
      Object[] keys = ht.keySet().toArray();
      Arrays.sort(keys);

      if (isEscaped) {
        sb.append("{ ");
        String sep = "";
        for (int i = 0; i < keys.length; i++) {
          String key = (String) keys[i];
          sb.append(sep).append(Escape.escape(key)).append(':');
          sValueArray(sb, (ScriptVariable) ht.get(key), map, level + 1, true);
          sep = ", ";
        }
        sb.append(" }");
        break;
      }
      for (int i = 0; i < keys.length; i++) {
        sb.append(keys[i]).append("\t:");
        ScriptVariable v = getVariable(ht.get(keys[i]));
        StringBuffer sb2 = new StringBuffer();
        sValueArray(sb2, v, map, level + 1, isEscaped);
        String value = sb2.toString();
        sb.append(value.indexOf("\n") >= 0 ? "\n" : "\t");
        sb.append(value).append("\n");
      }
      break;
    case varray:
      if (map.containsKey(vx)) {
        sb.append(isEscaped ? "[]" : vx.name == null ? "<circular reference>"
            : "<" + vx.name + ">");
        break;
      }
      map.put(vx, Boolean.TRUE);
      if (isEscaped)
        sb.append("[");
      List sx = vx.getList();
      for (int i = 0; i < sx.size(); i++) {
        if (isEscaped && i > 0)
          sb.append(",");
        ScriptVariable sv = (ScriptVariable) sx.get(i);
        sValueArray(sb, sv, map, level + 1, isEscaped);
        if (!isEscaped)
          sb.append("\n");
      }
      if (isEscaped)
        sb.append("]");
      break;
    default:
      if (!isEscaped)
        for (int j = 0; j < level - 1; j++)
          sb.append("\t");
      sb.append(isEscaped ? vx.escape() : sValue(vx));
    }
  }

  public static Point3f ptValue(ScriptVariable x) {
    switch (x.tok) {
    case point3f:
      return (Point3f) x.value;
    case string:
      Object o = Escape.unescapePoint((String) x.value);
      if (o instanceof Point3f)
        return (Point3f) o;
    }
    return null;
 

  public static Point4f pt4Value(ScriptVariable x) {
    switch (x.tok) {
    case point4f:
      return (Point4f) x.value;
    case string:
      Object o = Escape.unescapePoint((String) x.value);
      if (!(o instanceof Point4f))
        break;
      return (Point4f) o;
    }
    return null;
  }

  private static float toFloat(String s) {
    if (s.equalsIgnoreCase("true"))
      return 1;
    if (s.equalsIgnoreCase("false") || s.length() == 0)
      return 0;
    return Parser.parseFloatStrict(s);
  }

  public static ScriptVariable concatList(ScriptVariable x1, ScriptVariable x2,
                                          boolean asNew) {
    List v1 = x1.getList();
    List v2 = x2.getList();
    if (!asNew) {
      if (v2 == null)
        v1.add(new ScriptVariable(x2));
      else
        for (int i = 0; i < v2.size(); i++)
          v1.add(v2.get(i));
      return x1;
    }
    List vlist = new ArrayList(
        (v1 == null ? 1 : v1.size()) + (v2 == null ? 1 : v2.size()));

    if (v1 == null)
      vlist.add(x1);
    else
      for (int i = 0; i < v1.size(); i++)
        vlist.add(v1.get(i));
    if (v2 == null)
      vlist.add(x2);
    else
      for (int i = 0; i < v2.size(); i++)
        vlist.add(v2.get(i));
    return getVariable(vlist);
  }

  public static BitSet bsSelect(Token x) {
    x = selectItem(x, Integer.MIN_VALUE);
    return (BitSet) x.value;
  }

  public static BitSet bsSelect(ScriptVariable var) {
    if (var.index == Integer.MAX_VALUE)
      var = selectItem(var);
    return (BitSet) var.value;
  }

  public static BitSet bsSelectRange(Token x, int n) {
    x = selectItem(x);
    x = selectItem(x, (n <= 0 ? n : 1));
    x = selectItem(x, (n <= 0 ? Integer.MAX_VALUE - 1 : n));
    return (BitSet) x.value;
  }

  public static ScriptVariable selectItem(ScriptVariable var) {
    // pass bitsets created by the select() or for() commands
    // and all arrays by reference
    if (var.index != Integer.MAX_VALUE ||
        var.tok == varray && var.intValue == Integer.MAX_VALUE)
      return var;
    return selectItem(var, Integer.MIN_VALUE);
  }

  public static Token selectItem(Token var) {
    return selectItem(var, Integer.MIN_VALUE);
  }

  public static ScriptVariable selectItem(ScriptVariable var, int i2) {
    return (ScriptVariable) selectItem((Token) var, i2);
  }

  public static Token selectItem(Token tokenIn, int i2) {
    switch (tokenIn.tok) {
    case matrix3f:
    case matrix4f:
    case bitset:
    case varray:
    case string:
      break;
    default:
      return tokenIn;
    }

    // negative number is a count from the end

    BitSet bs = null;
    String s = null;

    int i1 = tokenIn.intValue;
    if (i1 == Integer.MAX_VALUE) {
      // no selections have been made yet --
      // we just create a new token with the
      // same bitset and now indicate either
      // the selected value or "ALL" (max_value)
      if (i2 == Integer.MIN_VALUE)
        i2 = i1;
      ScriptVariable v = new ScriptVariable(tokenIn.tok, i2, tokenIn.value);
      return v;
    }
    int len = 0;
    boolean isInputSelected = (tokenIn instanceof ScriptVariable && ((ScriptVariable) tokenIn).index != Integer.MAX_VALUE);
    ScriptVariable tokenOut = new ScriptVariable(tokenIn.tok, Integer.MAX_VALUE);

    switch (tokenIn.tok) {
    case bitset:
      if (tokenIn.value instanceof BondSet) {
        tokenOut.value = new BondSet((BitSet) tokenIn.value,
            ((BondSet) tokenIn.value).getAssociatedAtoms());
        bs = (BitSet) tokenOut.value;
        len = BitSetUtil.cardinalityOf(bs);
        break;
      }
      bs = BitSetUtil.copy((BitSet) tokenIn.value);
      len = (isInputSelected ? 1 : BitSetUtil.cardinalityOf(bs));
      tokenOut.value = bs;
      break;
    case varray:
      len = ((ScriptVariable)tokenIn).getList().size();
      break;
    case string:
      s = (String) tokenIn.value;
      len = s.length();
      break;
    case matrix3f:
      len = -3;
      break;
    case matrix4f:
      len = -4;
      break;
    }

    if (len < 0) {
      // matrix mode [1][3] or [13]
      len = -len;
      if (i1 > 0 && Math.abs(i1) > len) {
        int col = i1 % 10;
        int row = (i1 - col) / 10;
        if (col > 0 && col <= len && row <= len) {
          if (tokenIn.tok == matrix3f)
            return new ScriptVariable(decimal, new Float(
                ((Matrix3f) tokenIn.value).getElement(row - 1, col - 1)));
          return new ScriptVariable(decimal, new Float(
              ((Matrix4f) tokenIn.value).getElement(row - 1, col - 1)));
        }
        return new ScriptVariable(string, "");
      }
      if (Math.abs(i1) > len)
        return new ScriptVariable(string, "");
      float[] data = new float[len];
      if (len == 3) {
        if (i1 < 0)
          ((Matrix3f) tokenIn.value).getColumn(-1 - i1, data);
        else
          ((Matrix3f) tokenIn.value).getRow(i1 - 1, data);
      } else {
        if (i1 < 0)
          ((Matrix4f) tokenIn.value).getColumn(-1 - i1, data);
        else
          ((Matrix4f) tokenIn.value).getRow(i1 - 1, data);
      }
      if (i2 == Integer.MIN_VALUE)
        return getVariable(data);
      if (i2 < 1 || i2 > len)
        return new ScriptVariable(string, "");
      return getVariable(new Float(data[i2 - 1]));
    }

    // "testing"[0] gives "g"
    // "testing"[-1] gives "n"
    // "testing"[3][0] gives "sting"
    // "testing"[-1][0] gives "ng"
    // "testing"[0][-2] gives just "g" as well
    if (i1 <= 0)
      i1 = len + i1;
    if (i1 < 1)
      i1 = 1;
    if (i2 == 0)
      i2 = len;
    else if (i2 < 0)
      i2 = len + i2;

    if (i2 > len)
      i2 = len;
    else if (i2 < i1)
      i2 = i1;

    switch (tokenIn.tok) {
    case bitset:
      if (isInputSelected) {
        if (i1 > 1)
          bs.clear();
        break;
      }
      int n = 0;
      for (int j = bs.nextSetBit(0); j >= 0; j = bs.nextSetBit(j + 1))
        if (++n < i1 || n > i2)
          bs.clear(j);
      break;
    case string:
      if (i1 < 1 || i1 > len)
        tokenOut.value = "";
      else
        tokenOut.value = s.substring(i1 - 1, i2);
      break;
    case varray:
      if (i1 < 1 || i1 > len || i2 > len)
        return new ScriptVariable(string, "");
      if (i2 == i1)
        return (ScriptVariable) ((ScriptVariable) tokenIn).getList().get(i1 - 1);
      List o2 = new ArrayList();
      List o1 = ((ScriptVariable) tokenIn).getList();
      n = i2 - i1 + 1;
      for (int i = 0; i < n; i++)
        o2.add(new ScriptVariable((ScriptVariable) o1.get(i + i1 - 1)));
      tokenOut.value = o2;
      break;
    }
    return tokenOut;
  }

  public boolean setSelectedValue(int selector, ScriptVariable var) {
    if (selector == Integer.MAX_VALUE)
      return false;
    int len;
    switch (tok) {
    case matrix3f:
    case matrix4f:
      len = (tok == matrix3f ? 3 : 4);
      if (selector > 10) {
        int col = selector % 10;
        int row = (selector - col) / 10;
        if (col > 0 && col <= len && row <= len) {
          if (tok == matrix3f)
            ((Matrix3f) value).setElement(row - 1, col - 1, fValue(var));
          else
            ((Matrix4f) value).setElement(row - 1, col - 1, fValue(var));
          return true;
        }
      }
      if (selector != 0 && Math.abs(selector) <= len
          && var.tok == varray) {
        List sv = var.getList();
        if (sv.size() == len) {
          float[] data = new float[len];
          for (int i = 0; i < len; i++)
            data[i] = fValue((ScriptVariablesv.get(i));
          if (selector > 0) {
            if (tok == matrix3f)
              ((Matrix3f) value).setRow(selector - 1, data);
            else
              ((Matrix4f) value).setRow(selector - 1, data);
          } else {
            if (tok == matrix3f)
              ((Matrix3f) value).setColumn(-1 - selector, data);
            else
              ((Matrix4f) value).setColumn(-1 - selector, data);
          }
          return true;
        }
      }
      return false;
    case string:
      String str = (String) value;
      int pt = str.length();
      if (selector <= 0)
        selector = pt + selector;
      if (--selector < 0)
        selector = 0;
      while (selector >= str.length())
        str += " ";
      value = str.substring(0, selector) + sValue(var)
          + str.substring(selector + 1);
      return true;
    case varray:
      len = getList().size();
      if (selector <= 0)
        selector = len + selector;
      if (--selector < 0)
        selector = 0;
      if (len <= selector) {
        for (int i = len; i <= selector; i++)
          getList().add(getVariable(""));
      }
      getList().set(selector, var);
      return true;
    }
    return false;
  }

  public String escape() {
    switch (tok) {
    case on:
      return "true";
    case off:
      return "false";
    case integer:
      return "" + intValue;
    case bitset:
      return Escape.escape((BitSet)value, !(value instanceof BondSet));
    case varray:
    case hash:
      StringBuffer sb = new StringBuffer();
      Map map = new Hashtable();
      sValueArray(sb, this, map, 0, true);
      return sb.toString();     
    case point3f:
      return Escape.escape((Point3f)value);
    case point4f:
      return Escape.escape((Point4f)value);
    case matrix3f:
      return Escape.escape((Matrix3f)value);
    case matrix4f:
      return Escape.escape((Matrix4f)value);
    default:
      return Escape.escape(value);
    }
  }

  public static Object unescapePointOrBitsetAsVariable(Object o) {
    if (o == null)
      return o;
    Object v = null;
    String s = null;
    if (o instanceof ScriptVariable) {
      ScriptVariable sv = (ScriptVariable) o;
      switch (sv.tok) {
      case point3f:
      case point4f:
      case matrix3f:
      case matrix4f:
      case bitset:
        v = sv.value;
        break;
      case string:
        s = (String) sv.value;
        break;
      default:
        s = sValue(sv);
        break;
      }
    } else if (o instanceof String) {
      s = (String) o;
    }
    if (s != null && s.length() == 0)
      return s;
    if (v == null)
      v = Escape.unescapePointOrBitsetOrMatrixOrArray(s);
    if (v instanceof Point3f)
      return (new ScriptVariable(point3f, v));
    if (v instanceof Point4f)
      return new ScriptVariable(point4f, v);
    if (v instanceof BitSet) {
      if (s != null && s.indexOf("[{") == 0)
        v = new BondSet((BitSet) v);
      return new ScriptVariable(bitset, v);
    }
    if (v instanceof Matrix3f)
      return (new ScriptVariable(matrix3f, v));
    if (v instanceof Matrix4f)
      return new ScriptVariable(matrix4f, v);
    return o;
  }

  public static ScriptVariable getBoolean(boolean value) {
    return new ScriptVariable(value ? vT : vF);
  }
 
  public static Object sprintf(String strFormat, ScriptVariable var) {
    if (var == null)
      return strFormat;
    int[] vd = (strFormat.indexOf("d") >= 0 || strFormat.indexOf("i") >= 0 ? new int[1]
        : null);
    float[] vf = (strFormat.indexOf("f") >= 0 ? new float[1] : null);
    double[] ve = (strFormat.indexOf("e") >= 0 ? new double[1] : null);
    boolean getS = (strFormat.indexOf("s") >= 0);
    boolean getP = (strFormat.indexOf("p") >= 0 && var.tok == point3f
        || strFormat.indexOf("q") >= 0 && var.tok == point4f);
    Object[] of = new Object[] { vd, vf, ve, null, null};
    if (var.tok != varray)
      return sprintf(strFormat, var, of, vd, vf, ve, getS, getP);
    List sv = var.getList();
    String[] list2 = new String[sv.size()];
    for (int i = 0; i < list2.length; i++)
      list2[i] = sprintf(strFormat, (ScriptVariablesv.get(i), of, vd, vf, ve, getS, getP);
    return list2;
  }

  private static String sprintf(String strFormat, ScriptVariable var, Object[] of,
                                int[] vd, float[] vf, double[] ve, boolean getS, boolean getP) {
    if (vd != null)
      vd[0] = iValue(var);
    if (vf != null)
      vf[0] = fValue(var);
    if (ve != null)
      ve[0] = fValue(var);
    if (getS)
      of[3] = sValue(var);
    if (getP)
      of[4]= var.value;
    return TextFormat.sprintf(strFormat, of );
  }

  /**
   * sprintf       accepts arguments from the format() function
   *               First argument is a format string.
   * @param args
   * @return       formatted string
   */
  public static String sprintf(ScriptVariable[] args) {
    switch(args.length){
    case 0:
      return "";
    case 1:
      return sValue(args[0]);
    }
    String[] format = TextFormat.split(TextFormat.simpleReplace(sValue(args[0]), "%%","\1"), '%');
    StringBuffer sb = new StringBuffer();
    sb.append(format[0]);
    for (int i = 1; i < format.length; i++) {
      Object ret = sprintf(TextFormat.formatCheck("%" + format[i]), (i < args.length ? args[i] : null));
      if (ret instanceof String[]) {
        String[] list = (String[]) ret;
        for (int j = 0; j < list.length; j++)
          sb.append(list[j]).append("\n");
        continue;
      }
      sb.append(ret);
    }
    return sb.toString();
  }
 
  public String toString() {
    return super.toString() + "[" + name + "] index =" + index + " hashcode=" + hashCode();
  }

  public static BitSet getBitSet(ScriptVariable x, boolean allowNull) {
    switch (x.tok) {
    case bitset:
      return bsSelect(x);
    case varray:
      BitSet bs = new BitSet();
      List sv = (List) x.value;
      for (int i = 0; i < sv.size(); i++)
        if (!((ScriptVariable) sv.get(i)).unEscapeBitSetArray(bs) && allowNull)
          return null;
      return bs;
    }
    return (allowNull ? null : new BitSet());
  }

  public static boolean areEqual(ScriptVariable x1, ScriptVariable x2) {
    if (x1.tok == string && x2.tok == string)
      return sValue(x1).equalsIgnoreCase(
          sValue(x2));
    if (x1.tok == point3f && x2.tok == point3f)
      return (((Point3f) x1.value).distance((Point3f) x2.value) < 0.000001);
    if (x1.tok == point4f && x2.tok == point4f)
      return (((Point4f) x1.value).distance((Point4f) x2.value) < 0.000001);
    return (Math.abs(fValue(x1)
        - fValue(x2)) < 0.000001);
  }

  protected class Sort implements Comparator {
    private int arrayPt;
   
    protected Sort(int arrayPt) {
      this.arrayPt = arrayPt;
    }
   
    public int compare(Object ox, Object oy) {
      ScriptVariable x = (ScriptVariable) ox;
      ScriptVariable y = (ScriptVariable) oy;
      if (x.tok != y.tok) {
        if (x.tok == Token.decimal || x.tok == Token.integer
            || y.tok == Token.decimal || y.tok == Token.integer) {
          float fx = fValue(x);
          float fy = fValue(y);
          return (fx < fy ? -1 : fx > fy ? 1 : 0);
        }
        if (x.tok == Token.string || y.tok == Token.string)
          return sValue(x).compareTo(sValue(y));
      }
      switch (x.tok) {
      case string:
        return sValue(x).compareTo(sValue(y));
      case varray:
        List sx = x.getList();
        List sy = y.getList();
        if (sx.size() != sy.size())
          return (sx.size() < sy.size() ? -1 : 1);
        int iPt = arrayPt;
        if (iPt < 0)
          iPt += sx.size();
        if (iPt < 0 || iPt >= sx.size())
          return 0;
        return compare(sx.get(iPt), sy.get(iPt));
      default:
        float fx = fValue(x);
        float fy = fValue(y);
        return (fx < fy ? -1 : fx > fy ? 1 : 0);
      }
    }
  }
 
  /**
   *
   * @param arrayPt   1-based or Integer.MIN_VALUE to reverse
   * @return sorted or reversed array
   */
  public ScriptVariable sortOrReverse(int arrayPt) {
    List x = getList();
    if (x == null || x.size() < 2)
      return this;
    if (arrayPt == Integer.MIN_VALUE) {
      // reverse
      int n = x.size();
      for (int i = 0; i < n; i++) {
        ScriptVariable v = (ScriptVariable) x.get(i);
        x.set(i, x.get(--n));
        x.set(n, v);
      }
    } else {
      Collections.sort(getList(), new Sort(--arrayPt));
    }
    return this;
  }

  public boolean unEscapeBitSetArray(BitSet bs) {
    switch(tok) {
    case string:
      BitSet bs1 = Escape.unescapeBitset((String) value);
      if (bs1 == null)
        return false;
      bs.or(bs1);
      return true;
    case bitset:
      bs.or((BitSet) value);
      return true;
    }
    return false;  
  }

  public static BitSet unEscapeBitSetArray(List x, boolean allowNull) {
    BitSet bs = new BitSet();
    for (int i = 0; i < x.size(); i++)
      if (!((ScriptVariable) x.get(i)).unEscapeBitSetArray(bs) && allowNull)
        return null;
    return bs;
  }

  public static String[] listValue(Token x) {
    if (x.tok != varray)
      return new String[] { sValue(x) };
    List sv = ((ScriptVariable) x).getList();
    String[] list = new String[sv.size()];
    for (int i = sv.size(); --i >= 0;)
      list[i] = sValue((ScriptVariable) sv.get(i));
    return list;
  }

  public static float[] flistValue(Token x, int nMin) {
    if (x.tok != varray)
      return new float[] { fValue(x) };
    List sv = ((ScriptVariable) x).getList();
    float[] list;
    list = new float[Math.max(nMin, sv.size())];
    if (nMin == 0)
      nMin = list.length;
    for (int i = Math.min(sv.size(), nMin); --i >= 0;)
      list[i] = fValue((ScriptVariable) sv.get(i));
    return list;
  }

  public void toArray() {
    int dim;
    Matrix3f m3 = null;
    Matrix4f m4 = null;
    switch (tok) {
    case matrix3f:
      m3 = (Matrix3f) value;
      dim = 3;
      break;
    case matrix4f:
      m4 = (Matrix4f) value;
      dim = 4;
      break;
    default:
      return;
    }
    tok = varray;
    List o2 = new ArrayList(dim);
    for (int i = 0; i < dim; i++) {
      float[] a = new float[dim];
      if (m3 == null)
        m4.getRow(i, a);
      else
        m3.getRow(i, a);
      o2.set(i,getVariable(a));
    }
    value = o2;
  }

  public ScriptVariable mapValue(String key) {
    return (tok == hash ? (ScriptVariable) ((Map) value).get(key) : null);
  }

  public List getList() {
    return (tok == varray ? (List) value : null);
  }
}
TOP

Related Classes of org.jmol.script.ScriptVariable$Sort

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.