package org.jugile.daims;
/*
Copyright (C) 2011-2011 Jukka Rahkonen email: jukka.rahkonen@iki.fi
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 Public 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 Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import org.apache.log4j.Logger;
import org.jugile.util.DBConnection;
import org.jugile.util.DBPool;
import org.jugile.util.IDOComparator;
import org.jugile.util.Proxy;
import org.jugile.util.Query;
/**
* <i>"this is verse"</i> <b>()</b>
*
* <br/>==========<br/>
*
* here is doc
*
* @author jukka.rahkonen@iki.fi
*
*/
public abstract class BoCollection<E extends Bo> extends BoMapDelta<E> implements Iterable<E> {
static Logger log = Logger.getLogger(BoCollection.class);
public BoCollection(Class<E> cl) { super(cl); }
protected void setOrigin(BoCollection<E> bc) { origin = bc.origin; }
private boolean readonly = false;
//protected void setReadOnly() { readonly = true; }
// ----------- old collection services ----------------
private Iterator<E> iterator = null;
public final Iterator<E> iterator() {
iterator = new BoCollectionIterator(this);
return iterator;
}
private Iterator<E> mapIterator() {
if (readonly) return origin.iterator();
return super.deltaIterator();
}
public void add(BoCollection<E> bc) { for (E o : bc) add(o); }
public int size() {
if (q == null) return getSize();
int s = 0;
for (E o : this) s++; // must iterate through if query != null
return s;
}
// for testing
public void iterate() {
for (E o : this) {
print(" item: " + o);
}
}
/**
* Query iterator.
*/
private class BoCollectionIterator implements Iterator<E> {
Iterator<E> i = null;
BoCollection<E> bc = null;
private E next = null;
List<E> items = null; // query items in collection
public BoCollectionIterator(BoCollection<E> bc) {
this.bc = bc;
if (bc.q != null) {
Iterator<E> i2 = bc.mapIterator();
items = new ArrayList<E>();
while (i2.hasNext()) {
items.add(i2.next());
}
i = items.iterator();
} else {
i = bc.mapIterator();
}
next = getNext();
}
private E getNext() {
while (i.hasNext()) {
E o = i.next();
if (bc.q != null) {
if (bc.q.eval(o)) return o;
} else {
return o;
}
}
return null;
}
public E next() {
E res = next;
next = getNext();
return res;
}
public boolean hasNext() { return next != null; }
public void remove() { fail("remove not supported");}
}
public final E next() {
if (iterator == null) iterator = iterator(); // if used directly outside of loop
return iterator.next();
}
public final boolean hasNext() {
if (iterator == null) iterator = iterator(); // if used directly outside of loop
return iterator.hasNext();
}
public final List<E> list() {
List<E> res = new ArrayList<E>();
for (E o : this) res.add(o);
return res;
}
private Query q = null;
public Query q() {
if (q == null) q = new Query();
return q;
}
public void reset() {
q = null;
iterator = null;
}
public boolean contains(E o) {
if (o == null) return false;
if (readonly) return origin.contains(o);
return (get(o.id()) != null);
}
public BoCollection<E> q(String op, String fld, Object value) {
q().and(op, fld, value); return this;
}
public BoCollection<E> q(String op, Method filterMethod, Object[] filterParams) {
q().filter(op, filterMethod, filterParams); return this;
}
public List<E> page(int page, int size, String sortcrit) {
return (List<E>)page((List)sort(sortcrit), page, size);
}
private boolean hasPrevPage = false;
private boolean hasNextPage = false;
public boolean hasPrevPage() { return hasPrevPage; }
public boolean hasNextPage() { return hasNextPage; }
private int pageNum = 0;
public int getPageNum() { return pageNum; }
public List<E> sort(String crit) {
List<E> res = list();
Collections.sort(res, new IDOComparator(crit));
return res;
}
public List<E> first(int count) { return first(count,"id");}
public List<E> first(int count, String sort) {
List<E> res = sort(sort);
if (count > res.size()) count = res.size();
return res.subList(0, count);
}
public E first(String sort) {
List<E> res = first(1,sort);
if (res.size() > 0) return res.get(0);
return null;
}
public E unique() {
Query q2 = q;
if (size() > 1) {
String querystr = "";
try {
if (q2 != null) querystr = q2.toString();
} catch (Exception e) {}
//Jugile.fail("Not unique $on : " + size() + " q: "+querystr);
log.error("Not unique $on : " + size() + " q: "+querystr);
return first("id");
}
iterator = null;
if(!hasNext()) return null;
return next();
}
/**
* Paging starts from 0.
*/
public List<E> page(List<E> list, int page, int size) {
int start = page*size;
int end = start + size;
if (start >= list.size()) start = list.size();
if (start < 0) start = 0;
if (end >= list.size()) end = list.size();
if (end < 0) end = 0;
if (start > 0 && (page-1)* size <= list.size()) hasPrevPage = true;
else hasPrevPage = false;
if (end < list.size()) hasNextPage = true;
else hasNextPage = false;
pageNum = page;
return list.subList(start, end);
}
public List<E> sublist(int start, int end, String sortcrit) {
return sublist((List)sort(sortcrit), start, end);
}
public List<E> sublist(List<E> list, int start, int end) {
// sanity checks
int size = list.size();
if (end > size) end = size;
if (start > size) start = size;
if (end < 0) end = 0;
if (start < 0) start = 0;
if (end < start) end = start;
return list.subList(start, end);
}
// ---- logical operations -----
public BoCollection<E> and(BoCollection<E> res, BoCollection<E> m) {
for (E o : this) { if (m.contains(o)) res.add(o); }
//res.origin = origin; // TODO: check how it works when objs are modified
return res;
}
public BoCollection<E> or(BoCollection<E> res, BoCollection<E> m) {
for (E o : this) res.add(o);
for (E o : m) res.add(o);
return res;
}
public BoCollection<E> xor(BoCollection<E> res, BoCollection<E> m) {
for (E o : m) if (!contains(o)) res.add(o);
for (E o : this) if (!m.contains(o)) res.add(o);
return res;
}
public BoCollection<E> not(BoCollection<E> res, BoCollection<E> m) {
for (E o : this) if (!m.contains(o)) res.add(o);
return res;
}
public BoCollection<E> keep(BoCollection<E> res, String mname) {
for (E o : this) if (isTrue(o,mname)) res.add(o);
return res;
}
public BoCollection<E> not(BoCollection<E> res, String mname) {
for (E o : this) if (!isTrue(o,mname)) res.add(o);
return res;
}
private boolean isTrue(Object item, String mname) {
Proxy p = new Proxy(item);
return isTrue(p.call(mname));
}
private boolean isTrue(Object res) {
if (res instanceof Boolean) {
if ((Boolean)res) return true;
return false;
}
return res != null;
}
// ----- sql interface -----
public List<E> fromDb() { return fromDb(null); }
public List<E> fromDb(String sql) {
Query q2 = q();
Bo bo = getProto();
if (sql == null) sql = "where " + q2.toSql();
sql = "select " + bo._getSelectFlds() +" from " + bo.table() + " " + sql;
List<E> res = new ArrayList<E>();
DBPool db = DBPool.getPool();
DBConnection c = db.getConnection();
try {
c.prepare(sql);
for (List<Object> row : c.select()) {
long id = (Integer)row.get(0);
E o = (E)bo.createOld(bo.getClass(), id);
o._setState(null,bo.bi(),row);
res.add(o);
}
} catch (Exception e) {
log.error("dbread failed",e);
try { c.rollback(); } catch (Exception e2) { fail(e2);}
} finally {
try { c.free(); } catch (Exception e) {}
}
return res;
}
}