package org.netxilia.server.js;
import static org.netxilia.server.jslib.NetxiliaGlobal.$;
import static org.stjs.javascript.Global.$array;
import static org.stjs.javascript.Global.$castArray;
import static org.stjs.javascript.Global.$map;
import static org.stjs.javascript.Global.encodeURIComponent;
import static org.stjs.javascript.Global.parseInt;
import static org.stjs.javascript.JSStringAdapter.charCodeAt;
import static org.stjs.javascript.JSStringAdapter.fromCharCode;
import static org.stjs.javascript.JSStringAdapter.replace;
import org.netxilia.server.js.data.JsAreaReference;
import org.netxilia.server.js.data.JsCellReference;
import org.netxilia.server.jslib.NetxiliaJQuery;
import org.stjs.javascript.Array;
import org.stjs.javascript.Map;
import org.stjs.javascript.Reference;
import org.stjs.javascript.RegExp;
import org.stjs.javascript.RegExpMatch;
import org.stjs.javascript.functions.Function1;
import org.stjs.javascript.jquery.Position;
public class Utils {
public static RegExp regexRef = new RegExp("(?:([\\w.]+)!)?([$]?)([A-Za-z]+)([$]?)([0-9]+)");
public static RegExp regexAreaOrRef = new RegExp(regexRef.source + "(:" + regexRef.source + ")?");
public static class StartEnd {
public int start;
public int end;
public StartEnd(int start, int end) {
this.start = start;
this.end = end;
}
}
public void positionUnder(String src, String target) {
NetxiliaJQuery $src = $(src);
Position pos = $src.offset();
Position parentPos = $src.offsetParent().offset();
int h = $src.outerHeight();
$(target).css($map("top", pos.top - parentPos.top + h, "left", pos.left - parentPos.left));
}
/**
*
* @param spec
* is an array of any of 'f', 'm', 'l' (for 'first', 'middle', 'last')
* @param start
* @param end
* @return tests console.info(intervals(['f'], 1, 2)); console.info(intervals(['f'], 1, 1));
* console.info(intervals(['f', 'm'], 1, 2)); console.info(intervals(['f', 'l'], 1, 2));
* console.info(intervals(['f', 'l', 'm'], 1, 2));
*/
public Array<StartEnd> intervals(Array<String> spec, final int s, final int e) {
Array<StartEnd> r = $array();
if ($.inArray("f", spec) >= 0 && s != 0) {
r.push(new StartEnd(s - 1, e - 1));
}
if ($.inArray("m", spec) >= 0 && e - 1 >= s) {
r.push(new StartEnd(s, e - 1));
}
if ($.inArray("l", spec) >= 0) {
r.push(new StartEnd(s, e));
}
// collapse intervals
for (int i = r.$length() - 1; i > 0; --i) {
if (r.$get(i).start == r.$get(i - 1).end + 1) {
r.$set(i - 1, new StartEnd(r.$get(i - 1).start, r.$get(i).end));
r.splice(i, 1);
}
}
return r;
}
public JsAreaReference parseAreaReference(String areaRef) {
final Array<String> refs = $castArray(areaRef.split(":"));
if (refs.$length() != 2) {
return null;
}
return new JsAreaReference(parseCellReference(refs.$get(0)), parseCellReference(refs.$get(1)));
}
public JsCellReference parseCellReference(String ref) {
RegExpMatch m = regexRef.exec(ref);
if (m == null) {
return null;
}
return new JsCellReference(m.$get(1), parseInt(m.$get(5)) - 1, columnLabelIndex(m.$get(3)));
}
public Array<JsAreaReference> findReferencesInFormula(String formula) {
RegExpMatch m = regexAreaOrRef.exec(formula);
Array<JsAreaReference> refs = $array();
String crtText = formula;
while (m != null) {
JsCellReference tl = new JsCellReference(m.$get(1), parseInt(m.$get(5)) - 1, columnLabelIndex(m.$get(3)));
JsCellReference br = tl;
if (m.$get(9) != null) {
br = new JsCellReference(m.$get(7), parseInt(m.$get(11)) - 1, columnLabelIndex(m.$get(9)));
refs.push(new JsAreaReference(tl, br));
crtText = crtText.substring(m.index + m.$get(0).length());
m = regexAreaOrRef.exec(crtText);
}
}
return refs;
}
public int columnLabelIndex(String str) {
// Converts A to 1, B to 2, Z to 26, AA to 27.
int num = 0;
str = str.toUpperCase();
for (int i = 0; i < str.length(); i++) {
int digit = charCodeAt(str, i) - 65; // 65 == 'A'.
num = (num * 26) + digit;
}
return num;
}
public String columnLabel(int col) {
// TODO convert to more than one-letter code
return fromCharCode(String.class, 65 + col);
}
@SuppressWarnings("unchecked")
public boolean isEmptyObject(Object obj) {
for (String name : (Map<String, Object>) obj) {
return false;
}
return true;
}
public Map<String, String> reverseMap(Map<String, String> map) {
if (map == null) {
return null;
}
Map<String, String> newMap = $map();
for (String f : map) {
newMap.$put(map.$get(f), f);
}
return newMap;
}
public Diff<String> diff(final Array<String> oldList, final Array<String> newList) {
if (oldList == null) {
return new Diff<String>() {
{
added = newList;
deleted = $array();
}
};
}
if (newList == null) {
return new Diff<String>() {
{
added = $array();
deleted = newList;
}
};
}
Diff<String> ret = new Diff<String>() {
{
added = $array();
deleted = $array();
}
};
for (int i : oldList) {
if ($.inArray(oldList.$get(i), newList) < 0) {
ret.deleted.push(oldList.$get(i));
}
}
for (int i : newList) {
if ($.inArray(newList.$get(i), oldList) < 0) {
ret.added.push(newList.$get(i));
}
}
return ret;
};
public String url(Object... arguments) {
String url = (String) arguments[0];
final Reference<Integer> p = new Reference<Integer>() {
{
value = 0;
}
};
final Array<Object> params = $castArray(arguments);
return replace(url, new RegExp("\\{\\}", "g"), new Function1<String, String>() {
public String $invoke(String m) {
p.value++;
return encodeURIComponent((String) params.$get(p.value));
}
});
}
}