package cn.com.pc.penguin.core;

import cn.com.pc.penguin.service.DocumentBuilder;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.document.Fieldable;
import org.apache.lucene.document.NumericField;
import org.json.JSONArray;
import org.json.JSONObject;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

/**
 * Created by IntelliJ IDEA.
 * User: huangqinghe
 * To change this template use File | Settings | File Templates.
 */
public class PenguinDocument {
    private String searchType;
	private Collection<String> keys = new ArrayList<String>();
	private Collection<Document> docs = new ArrayList<Document>();

    public PenguinDocument(){
    }

    public PenguinDocument(DocumentBuilder builder){
        try {
            this.searchType = builder.getSearchType().toString();
            this.keys = builder.getKeys();
            this.docs = builder.getDocs();
        } catch (Exception e) {
            e.printStackTrace();  
        }
    }

    public PenguinDocument(JSONObject jdoc) throws Exception {
		super();
		this.searchType = jdoc.getString("searchType");
		JSONArray ks = jdoc.getJSONArray("keys");
		List<String> keys = new ArrayList<String>();
		for(int i=0;i<ks.length();i++) {
			keys.add(ks.getString(i));
		}
		this.keys = keys;

		JSONArray ds = jdoc.getJSONArray("docs");
		List<Document> docs = new ArrayList<Document>();
		for(int i=0;i<ds.length();i++) {
			docs.add(this.jsonToDoc(ds.getJSONObject(i)));
		}
		this.docs = docs;
	}
    
    public String toJSON() throws Exception {
        JSONObject pd = new JSONObject();
        pd.put("searchType", this.getSearchType());
        JSONArray ks = new JSONArray();
        for (String k : this.getKeys()) {
            ks.put(k);
        }
        pd.put("keys", ks);

        JSONArray jdoc = new JSONArray();
        for (Document d : this.getDocs()) {
            jdoc.put(docToJSON(d));
        }
        pd.put("docs", jdoc);
        return pd.toString();
    }

    private JSONObject docToJSON(Document doc) throws Exception {
        JSONObject dj = new JSONObject();
        dj.put("boost", doc.getBoost());
        JSONArray fields = new JSONArray();
        for (Fieldable f : doc.getFields()) {
            JSONObject fj = new JSONObject();
            fj.put("name", f.name());
            fj.put("value", f.stringValue());
            if (f instanceof Field) {
                fj.put("fieldType", "field");
                Field field = (Field) f;
                fj.put("isIndexed", field.isIndexed());
                fj.put("isStored", field.isStored());
                fj.put("isTokenized", field.isTokenized());
                fj.put("omitNorms", field.getOmitNorms());
                fj.put("boost", field.getBoost());
            } else if (f instanceof NumericField) {
                fj.put("fieldType", "numericField");
                NumericField nf = (NumericField) f;
                Number value = nf.getNumericValue();
                fj.put("valueType", value.getClass().getSimpleName());
            } else {
                throw new Exception(f.toString() + " has not supported yet!");
            }
            fields.put(fj);
        }
        dj.put("fields", fields);
        return dj;
    }

    private Document jsonToDoc(JSONObject object) throws Exception {
		Document d = new Document();
		d.setBoost(object.getInt("boost"));
		JSONArray fields = object.getJSONArray("fields");
		for(int i=0;i<fields.length();i++) {
			JSONObject jf = fields.getJSONObject(i);
			String fieldType = jf.getString("fieldType");
			String name = jf.getString("name");
			Fieldable field = null;
			if("field".equals(fieldType)) {
				String value = jf .getString("value");
				boolean isIndexed = jf.getBoolean("isIndexed");
				boolean isStored = jf.getBoolean("isStored");
				boolean isTokenized = jf.getBoolean("isTokenized");
				boolean omitNorms = jf.getBoolean("omitNorms");
				int boost = jf.getInt("boost");

				Field.Store store;
				if(isStored) {
					store = Field.Store.YES;
				} else {
					store = Field.Store.NO;
				}

				Field.Index index = null;
				if(!isIndexed && !isTokenized && omitNorms) {
					index = Field.Index.NO;
				} else if(isIndexed && isTokenized && !omitNorms) {
					index = Field.Index.ANALYZED;
				} else if(isIndexed && !isTokenized && !omitNorms) {
					index = Field.Index.NOT_ANALYZED;
				} else if(isIndexed && !isTokenized && omitNorms) {
					index = Field.Index.NOT_ANALYZED_NO_NORMS;
				} else if(isIndexed && isTokenized && omitNorms) {
					index = Field.Index.ANALYZED_NO_NORMS;
				}

				field = new Field(name,value,store,index);
				field.setBoost(boost);
			} else if("numericField".equals(fieldType)) {
				String valueType = jf.getString("valueType");
				field = new NumericField(name);
				NumericField nf = (NumericField)field;
				if("Long".equals(valueType)) {
					nf.setLongValue(jf.getLong("value"));
				} else if("Integer".equals(valueType)) {
					nf.setIntValue(jf.getInt("value"));
				} else if("Double".equals(valueType)) {
					nf.setDoubleValue(jf.getDouble("double"));
				} else if("Float".equals(valueType)) {
					nf.setFloatValue(Float.valueOf(jf.getString("value")));
				}
			}

			d.add(field);
		}
		return d;
	}

    public String getSearchType() {
        return searchType;
    }

    public void setSearchType(String searchType) {
        this.searchType = searchType;
    }

    public Collection<String> getKeys() {
        return keys;
    }

    public void setKeys(Collection<String> keys) {
        this.keys = keys;
    }

    public Collection<Document> getDocs() {
        return docs;
    }

    public void setDocs(Collection<Document> docs) {
        this.docs = docs;
    }
}
