package org.openntf.xrest.xsp.exec.convertor;

import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.Vector;

import org.openntf.xrest.xsp.exec.Context;
import org.openntf.xrest.xsp.model.MapJsonType;
import org.openntf.xrest.xsp.model.MappingField;
import org.openntf.xrest.xsp.model.RouteProcessor;
import org.openntf.xrest.xsp.utils.NotesObjectRecycler;

import com.ibm.commons.util.io.json.JsonJavaObject;
import com.ibm.commons.util.io.json.JsonObject;

import lotus.domino.Document;
import lotus.domino.Item;
import lotus.domino.NotesException;

public class Document2JsonConverter {

	private final Context context;
	private final RouteProcessor routeProcessor;
	private final Document doc;

	public Document2JsonConverter(Document doc, RouteProcessor routeProcessor, Context context) {
		this.context = context;
		this.routeProcessor = routeProcessor;
		this.doc = doc;
	}

	public JsonObject buildJsonFromDocument() throws NotesException {
		Set<String> itemProcessed = new HashSet<String>();
		JsonObject jo = new JsonJavaObject();
		@SuppressWarnings("unchecked")
		Vector<Item> documentItems = doc.getItems();
		Map<String, MappingField> fieldDefinition = routeProcessor.getMappingFields();
		for (Item item : documentItems) {
			if (!itemProcessed.contains(item.getName()) && fieldDefinition.containsKey(item.getName().toLowerCase())) {
				MappingField mf = fieldDefinition.get(item.getName().toLowerCase());
				if (!mf.isWriteOnly()) {
					processItem(jo, item, mf);
					itemProcessed.add(item.getName());
				}
			}
		}
		for (MappingField field : routeProcessor.getFormulaFields()) {
			if (!field.isWriteOnly()){
				processFormulaToJson(jo, field, doc);
			}
		}
		NotesObjectRecycler.recycleObjects(documentItems.toArray());
		return jo;
	}

	private void processFormulaToJson(JsonObject jo, MappingField field, Document doc) throws NotesException {
		Vector<?> result = context.getSession().evaluate(field.getFormula(), doc);
		field.getType().processValuesToJsonObject(result, jo, field.getJsonName());
		NotesObjectRecycler.recycleObjects(result.toArray());
	}

	private void processItem(JsonObject jo, Item item, MappingField mappingField) throws NotesException {
		MapJsonType mjType = mappingField.getType();
		switch (item.getType()) {
		case Item.OTHEROBJECT:
		case Item.ATTACHMENT:
		case Item.NOTELINKS:
		case Item.SIGNATURE:
			break;
		case Item.MIME_PART:
		case Item.RICHTEXT:
			mjType.processItemToJsonObject(item, jo, mappingField.getJsonName());
			break;
		default:
			mjType.processItemToJsonObject(item, jo, mappingField.getJsonName());
		}
	}

}

@@ -756,16 +756,22 @@
 nverter(
+final 
 Document
@@ -775,16 +775,22 @@
 ent doc,
+ final
  RoutePr
@@ -812,16 +812,22 @@
 ocessor,
+ final
  Context
@@ -993,16 +993,95 @@
 ption %7B%0A
+%09%09JsonObject jo = new JsonJavaObject();%0A%09%09if (null == doc) %7B%0A%09%09%09return jo;%0A%09%09%7D%0A
 %09%09Set%3CSt
@@ -1129,48 +1129,8 @@
 ();%0A
-%09%09JsonObject jo = new JsonJavaObject();%0A
 %09%09@S
@@ -1715,16 +1715,17 @@
 eOnly())
+ 
 %7B%0A%09%09%09%09pr
@@ -1884,16 +1884,22 @@
 aToJson(
+final 
 JsonObje
@@ -1904,16 +1904,22 @@
 ject jo,
+ final
  Mapping
@@ -1930,16 +1930,22 @@
 d field,
+ final
  Documen
@@ -2216,16 +2216,22 @@
 essItem(
+final 
 JsonObje
@@ -2236,16 +2236,22 @@
 ject jo,
+ final
  Item it
@@ -2253,16 +2253,22 @@
 em item,
+ final
  Mapping

Fix NPE when document is null.