package eu.dnetlib.functionality.modular.ui.users;

import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Required;

import com.google.common.base.Joiner;
import com.google.common.base.Splitter;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.mongodb.BasicDBObject;
import com.mongodb.BasicDBObjectBuilder;
import com.mongodb.DB;
import com.mongodb.DBCollection;
import com.mongodb.DBCursor;
import com.mongodb.DBObject;

public class MongoAuthorizationDAO implements AuthorizationDAO {
	
	private DB db;

	private static final String AUTH_COLL = "users";


	private static final Log log = LogFactory.getLog(MongoAuthorizationDAO.class);
	
	@Override
	public void updatePermissionLevels(Map<String, Set<PermissionLevel>> map) {
		final DBCollection coll = db.getCollection(AUTH_COLL);
		final List<DBObject> list = Lists.newArrayList();

		for (Entry<String, Set<PermissionLevel>> e : map.entrySet()) {
			final Map<String, String> m = Maps.newHashMap();
			m.put("uid" , e.getKey());
			m.put("levels", serializeLevels(e.getValue()));
			list.add(BasicDBObjectBuilder.start(m).get());
		}
		coll.remove(new BasicDBObject());
		coll.insert(list);
	}
	
	@Override
	public Map<String, Set<PermissionLevel>> getPermissionLevels() {
		final DBCollection coll = db.getCollection(AUTH_COLL);
		final DBCursor cur = coll.find();
		
		final Map<String, Set<PermissionLevel>> res = Maps.newHashMap();
		while (cur.hasNext()) {
			final DBObject o = cur.next();
			res.put((String) o.get("uid"), readLevels(o));
		}
		
		return res;
	}	
	
	@Override
	public Set<PermissionLevel> getPermissionLevels(String uid) {
		final DBCollection coll = db.getCollection(AUTH_COLL);
		
		final DBObject obj = coll.findOne(new BasicDBObject("uid", uid));
		
		return readLevels(obj);
	}

	private Set<PermissionLevel> readLevels(final DBObject obj) {
		final Set<PermissionLevel> set = new HashSet<PermissionLevel>();
		
		if (obj != null) {
			final Object levels = obj.get("levels");
			if (levels != null) {
				for (String s : Splitter.on(",").omitEmptyStrings().trimResults().split(levels.toString())) {
					try {
						set.add(PermissionLevel.valueOf(s));
					} catch (Throwable e) {
						log.error("Invalid permissionLevel: " + s);
					}
				}
			}
		}
		return set;
	}
	
	private String serializeLevels(Set<PermissionLevel> levels) {
		return Joiner.on(",").skipNulls().join(levels);
	}
	
	public DB getDb() {
		return db;
	}

	@Required
	public void setDb(DB db) {
		this.db = db;
	}

}
