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.Field;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.apache.log4j.Logger;
import org.jugile.util.Buffer;
import org.jugile.util.DBConnection;
import org.jugile.util.Jugile;
/**
* <i>"this is verse"</i> <b>()</b>
*
* <br/>==========<br/>
*
* here is doc
*
* @author jukka.rahkonen@iki.fi
*
*/
public class BoMap<E extends Bo> extends Jugile implements Iterable<E> {
static Logger log = Logger.getLogger(BoMap.class);
private Map<Long,E> items = new HashMap<Long,E>(2);
private final DomainData dd;
private final Class<E> clazz;
protected Class<E> getClazz() { return clazz; }
public BoMap(Class<E> cl, DomainData dd) {
clazz = cl;
this.dd = dd;
}
protected void add(E o) {
// add new created object
if (o == null) return;
if (!o.isNew() && !o.isOrigin()) fail("only new or origin objects can be added");
items.put(o.id(),o);
//log.debug("added " + o + "to " + this);
}
protected E getCopy(long id) {
E o = items.get(id);
if (o == null) return null;
E res = (E)o.copy(bi());
//log.debug("created copy: " + res);
return res;
}
protected E getOrCreateOld(long id) {
if (id <= 0) return null;
E o = items.get(id);
if (o == null) {
o = (E)Bo.createOld(clazz,id);
items.put(id,o);
//log.debug("created old " + o + "to " + this);
}
return o;
}
public int size() { return items.size(); }
public void remove(E o) {
if (o != null) items.remove(o.id());
}
public E remove(long id) {
//log.debug("remove: " + id);
return items.remove(id);
}
public boolean contains(E o) {
if (o == null) return false;
return contains(o.id());
}
public boolean contains(long id) {
return items.containsKey(id);
}
private Iterator<E> iterator;
public Iterator<E> iterator() {
iterator = new BoMapIterator(this);
return iterator;
}
public void remove() {
iterator.remove();
}
/**
* Wrapper for underlying collection (eg. Trove uses custom iterators).
*/
private class BoMapIterator implements Iterator<E> {
Iterator<E> i = null;
public BoMapIterator(BoMap<E> bm) { i = bm.items.values().iterator(); }
public boolean hasNext() { return i.hasNext(); }
public E next() { return i.next(); }
public void remove() { i.remove(); }
}
protected E _first() {
iterator();
if (iterator.hasNext()) return iterator.next();
return null;
}
protected void parse(List<String> headers, List<String> cols) {
E o = getOrCreateOld(parseLongSafe(cols.get(0)));
// set private fields
try { o.parse(dd,headers,cols); } catch (Exception e) { fail(e); }
}
// for testing
protected E getOriginal(long id) { return items.get(id); }
public String csv() {
if (items.size() == 0) return ""; // empty set
Buffer buf = new Buffer();
buf.ln(_first()._headerRow());
if (items.size() > 0) {
Iterator<E> i2 = items.values().iterator();
while (i2.hasNext()) {
E o = i2.next();
buf.ln(o._delta());
}
}
return buf.toString();
}
public String nncsv() throws Exception {
if (items.size() == 0) return ""; // empty set
//log.debug("nncsv() first: " + _first() + "to " + this);
Buffer buf = new Buffer();
for (Field f : _first().nns()) {
String cn1 = f.getName();
if (items.size() > 0) {
buf.ln(_first()._nnHeader(f));
Iterator<E> i2 = items.values().iterator();
while (i2.hasNext()) {
E o = i2.next();
BoMap<E> m = (BoMap<E>)o.getBoMap(cn1);
if (m.size() > 0) {
buf.add(((Bo)o).getId());
for (Bo bo : m) {
// items() of n-n collection, added
buf.add(Bo.CSVDELIMITER + bo.getId());
}
buf.nl();
}
}
}
}
return buf.toString();
}
// This is needed for optimization - incredible increase in performance
private BoInfo bi;
protected BoInfo bi() {
if (bi == null) bi = _first().bi();
return bi;
}
protected int writeAllToDB(DBConnection c) throws Exception {
if (items.size() == 0) return 0; // empty set
int count = 0;
String cname = Jugile.getClassName(getClazz());
// add added and merge modified
Iterator<E> i2 = items.values().iterator();
while (i2.hasNext()) {
E o = i2.next();
o.setIsNew(true);
o._dbWriteFlds(c,bi());
o.setIsNew(false);
count++;
if ((count%100) == 0) {
c.commit();
log.info(" "+cname+" commit: " + count + " uow: " + dd.d().getCommitSize());
}
o.writeAllNNToDB(c,bi()); // n-n data
}
return count;
}
public String toString() {
String res = "[BoMap " + getClassName(clazz) + " "+ hex(this.hashCode());
res += " size:"+size();
if (dd == null) res += " FLD";
res += "] ";
return res;
}
protected void dump(Buffer buf) throws Exception {
// Person BoMap: 5430D082
// 5430D082 Person (2,1,0,-,p1,-)
// family: 5430D082
buf.ln(getClassName(clazz) + " BoMap: " + hex(this.hashCode()));
buf.incrIndent();
for (Bo o : this) o.dump(buf);
buf.decrIndent();
buf.nl();
}
protected void dumpShort(Buffer buf) throws Exception {
// persons: 5430D082
// items: 5430D082, 5430D082
buf.ind().add("items: ");
int ind = 0;
for (Bo o : this) {
if (ind++ > 0) buf.add(", ");
buf.add(o.realHash());
}
buf.nl();
}
protected void stats(Stats st) {
st.setSize((Class<Bo>)clazz, size());
for (Bo o : this) {
o.stats(st,bi());
}
}
}