package io.citrine.jcc.query;

import com.fasterxml.jackson.annotation.JsonGetter;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonSetter;
import io.citrine.jpif.obj.system.System;

import java.util.HashMap;
import java.util.Map;
import java.util.Set;

/**
 * Class to store a single PIF search hit.
 *
 * @author Kyle Michel
 */
public class PifSearchHit {

    /**
     * Set the id of the record that was matched.
     *
     * @param id String with the id of the record.
     * @return This object.
     */
    @JsonSetter("id")
    public PifSearchHit setId(final String id) {
        this.id = id;
        return this;
    }

    /**
     * Get the id of the record that was matched.
     *
     * @return String with the id of the matched record or a null pointer if not set.
     */
    @JsonGetter("id")
    public String getId() {
        return this.id;
    }

    /**
     * Set the system that was matched.
     *
     * @param system {@link System} object to save in the result
     * @return This object.
     */
    @JsonSetter("system")
    public PifSearchHit setSystem(final System system) {
        this.system = system;
        return this;
    }

    /**
     * Get the system that was matched.
     *
     * @return {@link System} object for the record that was matched or a null pointer if it has not been set.
     */
    @JsonGetter("system")
    public System getSystem() {
        return this.system;
    }

    /**
     * Set the map of extracted values.
     *
     * @param extracted Map of extracted value names to values.
     * @return This object.
     */
    @JsonSetter("extracted")
    protected PifSearchHit setExtracted(final Map<String, String> extracted) {
        this.extracted = extracted;
        return this;
    }

    /**
     * Add to the map of extracted values.
     *
     * @param key Name of the extracted value.
     * @param value Value that was extracted.
     * @return This object.
     */
    @JsonIgnore
    public PifSearchHit addExtracted(final String key, final String value) {
        if (this.extracted == null) {
            this.extracted = new HashMap<>();
        }
        this.extracted.put(key, value);
        return this;
    }

    /**
     * Get the map of extracted values.
     *
     * @return Map of extracted field keys to values.
     */
    @JsonGetter("extracted")
    protected Map<String, String> getExtracted() {
        return this.extracted;
    }

    /**
     * Get the list of extracted value keys.
     *
     * @return Set with the extracted keys.
     */
    @JsonIgnore
    public Set<String> getExtractedKeys() {
        return (this.extracted == null) ? null : this.extracted.keySet();
    }

    /**
     * Get an extracted value by its key.
     *
     * @param key String with the key of the extracted value.
     * @return String with the value of the input key or a null pointer if that key is not available.
     */
    @JsonIgnore
    public String getExtractedValue(final String key) {
        return (this.extracted == null) ? null : this.extracted.get(key);
    }

    /**
     * Get an extracted value by its key or return a default value.
     *
     * @param key String with the key of the extracted value.
     * @param defaultValue String with the default value to return if the key does not exist.
     * @return Value with the input key or the input default.
     */
    @JsonIgnore
    public String getExtractedValueOrDefault(final String key, final String defaultValue) {
        return (this.extracted == null) ? defaultValue : this.extracted.getOrDefault(key, defaultValue);
    }

    /** Id of the record. */
    private String id;

    /** Pif system that was matched. */
    private System system;

    /** Map of extracted fields. */
    private Map<String, String> extracted;
}
@@ -222,16 +222,89 @@
 System;%0A
+import io.citrine.jpif.util.PifObjectMapper;%0A%0Aimport java.io.IOException;
 %0Aimport 
@@ -1062,30 +1062,22 @@
  system 
-%7B@link System%7D
+String
  object 
@@ -1201,21 +1201,21 @@
 (final S
-ystem
+tring
  system)
@@ -1286,25 +1286,25 @@
  /**%0A     * 
-G
+S
 et the syste
@@ -1314,32 +1314,154 @@
 hat was matched.
+ This function serializes the system when added. If serialization fails then%0A     * the system is saved as a null pointer.
 %0A     *%0A     * @
@@ -1460,22 +1460,28 @@
      * @
-return
+param system
  %7B@link 
@@ -1499,115 +1499,884 @@
 ect 
-for the record that was matched or a null pointer if it has not been set.%0A     */%0A    @JsonGetter(%22system%22)
+to save in the result.%0A     * @return This object.%0A     */%0A    public PifSearchHit setSystem(final System system) %7B%0A        try %7B%0A            this.setSystem(PifObjectMapper.getInstance().writeValueAsString(system));%0A        %7D%0A        catch (IOException e) %7B%0A            this.system = null;%0A        %7D%0A        return this;%0A    %7D%0A%0A    /**%0A     * Get the system that was matched.%0A     *%0A     * @return String with the record that was matched or a null pointer if it has not been set.%0A     */%0A    @JsonGetter(%22system%22)%0A    public String getSystem() %7B%0A        return this.system;%0A    %7D%0A%0A    /**%0A     * Get the system that was matched as a %7B@link System%7D object. This function deserializes the search result each%0A     * time that it is called! If deserialization fails this returns a null pointer.%0A     *%0A     * @return %7B@link System%7D object that was matched.%0A     */%0A    @JsonIgnore
 %0A   
@@ -2391,32 +2391,38 @@
 System getSystem
+Object
 () %7B%0A        ret
@@ -2418,35 +2418,185 @@
         
-return this.system;
+try %7B%0A            return PifObjectMapper.getInstance().readValue(this.system, System.class);%0A        %7D%0A        catch (IOException e) %7B%0A            return null;%0A        %7D
 %0A    %7D%0A%0A
@@ -4869,21 +4869,21 @@
 rivate S
-ystem
+tring
  system;

allow set/get of system strings