public class Actor extends BaseObject{

    public Actor(String id) {
        super(id);
    }
    

    @Override
    protected String getCategory(){
        return "actor";
    }
} public class Allergy extends Condition{

    private ArrayList<CodedValue> reaction;

    public Allergy(String id){
        super(id);
    }

} public class BaseObject {
    @JsonIgnore
    public static long minDate = -9223372036854775808L;
    @JsonIgnore
    public static long maxDate = 9223372036854775807L;

    private String id;

    public BaseObject(String id) {
        this.id = id;
    }

    protected String getCategory() {
        return "base";
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String toJson(boolean prettyPrint) throws JsonMappingException,
            JsonGenerationException, IOException {
        return JsonMapper.toJson(this, prettyPrint);
    }
} public class Medication extends BaseClinicalObject{
    private long started = BaseObject.minDate;
    private long stopped = BaseObject.maxDate;
    private ArrayList<CodedValue> status;

    public Medication(String id){
        super(id);
        this.status = new ArrayList<CodedValue>();
    }

    public Medication(String id, ArrayList<CodedValue> type, ArrayList<CodedValue> description,
            long started, long stopped, ArrayList<CodedValue> status) {
        super(id, type, description);
        this.started = started;
        this.stopped = stopped;
        this.status = status;
    }

    public long getStarted() {
        return started;
    }

    public void setStarted(long started) {
        this.started = started;
    }

    public ArrayList<CodedValue> getStatus() {
        return status;
    }

    public void setStatus(ArrayList<CodedValue> status) {
        this.status = status;
    }

    public void addStatus(CodedValue status){
        this.status.add(status);
    }

    public void addStatus(Collection<CodedValue> status){
        this.status.addAll(status);
    }

    public long getStopped() {
        return stopped;
    }

    public void setStopped(long stopped) {
        this.stopped = stopped;
    }

} public class Test extends BaseClinicalObject{

    private long collectionTime = BaseObject.minDate;
    private String value ="";
    private String units ="";

    public Test (String id){
        super(id);
    }

    public Test(String id, long collectionTime, ArrayList<CodedValue>type,
            ArrayList<CodedValue> description, String value, String units) {
        super(id, type, description);
        this.collectionTime = collectionTime;
        this.value = value;  //TODO Convert this to handle Coded values
        this.units = units;
    }

    public long getCollectionTime() {
        return collectionTime;
    }

    public void setCollectionTime(long collectionTime) {
        this.collectionTime = collectionTime;
    }

    public String getValue() {
        return value;
    }

    public void setValue(String value) {
        this.value = value;
    }

    public String getUnits() {
        return units;
    }

    public void setUnits(String units) {
        this.units = units;
    }

    public String getValueString() {

        if (!"".equals(units)){
            return value+" "+units;
        }else{
            return value;
        }
    }


} @JsonPropertyOrder({"codingSystem", "version", "values"})
public class CodedValue {

    private String codingSystem;
    private String version;
    private ArrayList<String> values;

    public CodedValue() {
        this.values = new ArrayList<String>();
    }

    public CodedValue(String codingSystem, String version, ArrayList<String> values) {
        this.codingSystem = codingSystem;
        this.version = version;
        this.values = values;
    }

    public String getCodingSystem() {
        return codingSystem;
    }

    public void setCodingSystem(String codingSystem) {
        this.codingSystem = codingSystem;
    }

    public ArrayList<String> getValues() {
        return values;
    }

    public void setValues(ArrayList<String> values) {
        this.values = values;
    }

    public String getVersion() {
        return version;
    }

    public void setVersion(String version) {
        this.version = version;
    }

    public void addValue(String v){
        values.add(v);
    }

    /**
     * Checks equality between two <code>CodedValue</code> objects which means:
     * <ol>
     *  <li>The Coding Systems are the same and</li>
     *  <li>The Version of the Coding Systems are the same and</li>
     *  <li>Both code lists are not empty and
     *  <li>That there is at least one code value in common</li>
     * </ol>
     *
     * @param obj The <code>CodedValue</code> object to compare to
     * @return true only if they are the same c
     */
    @Override
    public boolean equals(Object obj) {
        if (obj == null) {
            return false;
        }
        if (getClass() != obj.getClass()) {
            return false;
        }
        final CodedValue other = (CodedValue) obj;
        if ((this.codingSystem == null) ? (other.codingSystem != null) : !this.codingSystem.equals(other.codingSystem)) {
            return false;
        }
        if ((this.version == null) ? (other.version != null) : !this.version.equals(other.version)) {
            return false;
        }
        if (this.values.isEmpty() || other.values.isEmpty()) {
            return false;
        }
        for (String t : this.values){
            if (other.values.contains(t)){
                return true;
            }
        }
        return false;
    }



    @Override
    public int hashCode() {
        int hash = 7;
        hash = 13 * hash + (this.codingSystem != null ? this.codingSystem.hashCode() : 0);
        hash = 13 * hash + (this.version != null ? this.version.hashCode() : 0);
        hash = 13 * hash + (this.values != null ? this.values.hashCode() : 0);
        return hash;
    }

    @Override
    public String toString(){
        StringBuffer sb = new StringBuffer();
        sb.append(this.codingSystem);
        sb.append(" [");
        sb.append(this.version);
        sb.append("] ");
        sb.append("{");
        for (int x=0; x<this.values.size();x++){
            sb.append(this.values.get(x));
            if (x < this.values.size()-1){
                sb.append(", ");
            }
        }
        sb.append("}");
        return sb.toString();
    }

} public class Condition extends BaseClinicalObject{
    /*
     * This is the date (seconds from epoch) that is
     * the known date that the condition started
     */
    private long onset = BaseObject.minDate;
    /*
     * This is the date (seconds from epoch) that is 
     * the known date that the condition was resolved
     */
    private long resolution = BaseObject.maxDate;
    
    private ArrayList<CodedValue> status;

    public Condition(String id, ArrayList<CodedValue> type, ArrayList<CodedValue> description,
            long onset, ArrayList<CodedValue> status) {
        super(id, type, description);
        this.onset = onset;
        this.status = status;
    }

    @Override
    protected String getCategory(){
        return "diagnosis_condition_problem";
    }

    public Condition(String id) {
        super(id);
        status = new ArrayList<CodedValue>();
    }

    public long getOnset() {
        return onset;
    }

    public void setOnset(long onset) {
        this.onset = onset;
    }

    public long getResolution() {
        return resolution;
    }

    public void setResolution(long resolution) {
        this.resolution = resolution;
    }

    public ArrayList<CodedValue> getStatus() {
        return status;
    }

    public void setStatus(ArrayList<CodedValue> status) {
        this.status = status;
    }

    public void addStatus(CodedValue status){
        this.status.add(status);
    }

} public class Encounter  extends BaseClinicalObject{
    private long occurred = BaseObject.minDate;
    private long ended = BaseObject.maxDate;
    private ArrayList<String> providers;
    private CodedValue indication;

    public Encounter(String id, ArrayList<CodedValue> type, ArrayList<CodedValue> description,
            long occurred, ArrayList<String> providers, CodedValue indication) {
        super(id, type, description);
        this.occurred = occurred;
        this.providers = providers;
        this.indication = indication;
    }

    public Encounter(String id){
        super(id);
        providers = new ArrayList<String>();
    }

    @Override
    protected String getCategory(){
        return "encounter";
    }

    public CodedValue getIndication() {
        return indication;
    }

    public void setIndication(CodedValue indication) {
        this.indication = indication;
    }

    public long getOccured() {
        return occurred;
    }

    public void setOccurred(long occurred) {
        this.occurred = occurred;
    }

    public long getEnded() {
        return ended;
    }

    public void setEnded(long ended) {
        this.ended = ended;
    }

    public ArrayList<String> getProviders() {
        return providers;
    }

    public void addProvider(String a){
        providers.add(a);
    }

    public void setProviders(ArrayList<String> providers) {
        this.providers = providers;
    }


} public class Goal extends BaseClinicalObject{
    private long goalDate = BaseObject.maxDate;
    private String value;
    private String unit;
    public Goal(String id){
        super(id);
    }

    public Goal(String id, ArrayList<CodedValue> type, ArrayList<CodedValue> description,
            long goalDate, String value, String unit) {
        super(id, type, description);
        this.goalDate = goalDate;
        this.value = value;
        this.unit = unit;
    }

    public long getGoalDate() {
        return goalDate;
    }

    public void setGoalDate(long goalDate) {
        this.goalDate = goalDate;
    }

    public String getUnit() {
        return unit;
    }

    public void setUnit(String unit) {
        this.unit = unit;
    }

    public String getValue() {
        return value;
    }

    public void setValue(String value) {
        this.value = value;
    }

public String getValueString() {
    if (!"".equals(unit)){
        return value+" "+unit;
    }else{
        return value;
    }
}
} public class Order extends BaseClinicalObject{

    private long orderDate = BaseObject.maxDate;
    private ArrayList<Goal> goals;
    private ArrayList<BaseClinicalObject> orderRequests;
    public Order (String id){
        super(id);
        goals = new ArrayList<Goal>();
        orderRequests = new ArrayList<BaseClinicalObject>();
    }

    public Order(String id, ArrayList<CodedValue> type, ArrayList<CodedValue> description,
            long orderDate, ArrayList<Goal> goals, String orderrequesttype) {
        super(id, type, description);
        this.orderDate = orderDate;
        if (goals != null){
            this.goals = goals;
        }else{
            this.goals = new ArrayList<Goal>();
        }
    }

    public ArrayList<Goal> getGoals() {
        return goals;
    }

    public void setGoals(ArrayList<Goal> goals) {
        this.goals = goals;
    }

    public void addGoal(Goal g){
        this.goals.add(g);
    }

    public long getOrderDate() {
        return orderDate;
    }

    public void setOrderDate(long orderDate) {
        this.orderDate = orderDate;
    }

    public ArrayList<BaseClinicalObject> getOrderRequests() {
        return orderRequests;
    }

    public void setOrderRequests(ArrayList<BaseClinicalObject> orderRequests) {
        this.orderRequests = orderRequests;
    }

    public void addOrderRequest(BaseClinicalObject orderRequest){
        this.orderRequests.add(orderRequest);
    }
} public class Patient {

    private long birthdate;  // milliseconds from epoch
    private String gender;
    private String first; // First Name
    private String last;  // Last Name
    private ArrayList<CodedValue> race;
    private ArrayList<CodedValue> ethnicity;

    public Patient() {
        race = new ArrayList<CodedValue>();
        ethnicity = new ArrayList<CodedValue>();
    }

    public Patient(long birthdate, String gender, ArrayList<CodedValue> race, ArrayList<CodedValue> ethnicity) {
        this.birthdate = birthdate;
        this.gender = gender;
        this.race = race;
        this.ethnicity = ethnicity;
    }

    public long getBirthdate() {
        return birthdate;
    }

    public void setBirthdate(long birthdate) {
        this.birthdate = birthdate;
    }

    public String getFirst() {
        return first;
    }

    public void setFirst(String first) {
        this.first = first;
    }

    public String getLast() {
        return last;
    }

    public void setLast(String last) {
        this.last = last;
    }

    public ArrayList<CodedValue> getEthnicity() {
        return ethnicity;
    }

    public void setEthnicity(ArrayList<CodedValue> ethnicity) {
        this.ethnicity = ethnicity;
    }

    public String getGender() {
        return gender;
    }

    public void setGender(String gender) {
        this.gender = gender;
    }

    public ArrayList<CodedValue> getRace() {
        return race;
    }

    public void setRace(ArrayList<CodedValue> race) {
        this.race = race;
    }

    public void addRace(CodedValue cv){
        race.add(cv);
    }

    public void addEthnicity(CodedValue cv){
        ethnicity.add(cv);
    }
} public class Procedure extends Encounter{


    public Procedure(String id){
        super(id);
    }

    public Procedure(String id, ArrayList<CodedValue> type, ArrayList<CodedValue> description, long occurred, ArrayList<String> providers, CodedValue indication) {
        super(id, type, description, occurred, providers, indication);
    }

} public class Record {

    private Patient patient;
    private ArrayList<Condition> conditions;
    private ArrayList<Encounter> encounters;
    private ArrayList<Result> results;
    private ArrayList<Medication> medications;
    private ArrayList<Allergy> allergies;
    private ArrayList<Procedure> procedures;
    private ArrayList<Order> orders;
    private ArrayList<Actor> actors;

    public ArrayList<Actor> getActors() {
        return actors;
    }

    public void setActors(ArrayList<Actor> actors) {
        this.actors = actors;
    }

    public ArrayList<Condition> getConditions() {
        return conditions;
    }

    public void setConditions(ArrayList<Condition> conditions) {
        this.conditions = conditions;
    }

    public ArrayList<Encounter> getEncounters() {
        return encounters;
    }

    public void setEncounters(ArrayList<Encounter> encounters) {
        this.encounters = encounters;
    }

    public ArrayList<Result> getResults() {
        return results;
    }

    public void setResults(ArrayList<Result> results) {
        this.results = results;
    }

    public ArrayList<Medication> getMedications() {
        return medications;
    }

    public void setMedications(ArrayList<Medication> medications) {
        this.medications = medications;
    }

    public ArrayList<Allergy> getAllergies() {
        return allergies;
    }

    public void setAllergies(ArrayList<Allergy> allergies) {
        this.allergies = allergies;
    }

    public ArrayList<Procedure> getProcedures() {
        return procedures;
    }

    public void setProcedures(ArrayList<Procedure> procedures) {
        this.procedures = procedures;
    }

    public ArrayList<Order> getOrders() {
        return orders;
    }

    public void setOrders(ArrayList<Order> orders) {
        this.orders = orders;
    }

    public Patient getPatient() {
        return patient;
    }

    public void setPatient(Patient patient) {
        this.patient = patient;
    }

    public String toJson(boolean prettyPrint) throws JsonMappingException,
            JsonGenerationException, IOException {
        return JsonMapper.toJson(this, prettyPrint);
    }
} public class Result extends BaseClinicalObject{

    private long collectionTime = BaseObject.minDate;
    private ArrayList<Test> tests;

    public Result(String id){
        super(id);
        tests = new ArrayList<Test>();
    }

    @Override
    protected String getCategory(){
        return "laboratory_test";
    }

    public long getCollectionTime() {
        return collectionTime;
    }

    public void setCollectionTime(long collectionTime) {
        this.collectionTime = collectionTime;
    }

    public ArrayList<Test> getTests() {
        return tests;
    }

    public void setTests(ArrayList<Test> tests) {
        this.tests = tests;
    }

    public void addTest(Test t){
        this.tests.add(t);
    }

}
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.astm.ccr.ActorReferenceType;
import org.astm.ccr.ActorType;
import org.astm.ccr.ActorType.Person.Name;
import org.astm.ccr.Agent;
import org.astm.ccr.AlertType;
import org.astm.ccr.CCRCodedDataObjectType;
import org.astm.ccr.CodeType;
import org.astm.ccr.CodedDescriptionType;
import org.astm.ccr.ContinuityOfCareRecord;
import org.astm.ccr.DateTimeType;
import org.astm.ccr.EncounterType;
import org.astm.ccr.GoalType;
import org.astm.ccr.PlanOfCareType;
import org.astm.ccr.PlanType;
import org.astm.ccr.ProblemType;
import org.astm.ccr.ProcedureType;
import org.astm.ccr.ResultType;
import org.astm.ccr.SocialHistoryType;
import org.astm.ccr.StructuredProductType;
import org.astm.ccr.StructuredProductType.Product;
import org.astm.ccr.TestType;
import org.codehaus.jackson.JsonGenerationException;
import org.codehaus.jackson.map.JsonMappingException;
import org.joda.time.DateTime;
import org.joda.time.format.DateTimeFormatter;
import org.joda.time.format.ISODateTimeFormat;
import org.ohd.pophealth.json.clinicalmodel.Actor;
import org.ohd.pophealth.json.clinicalmodel.Allergy;
import org.ohd.pophealth.json.clinicalmodel.BaseObject;
import org.ohd.pophealth.json.clinicalmodel.Medication;
import org.ohd.pophealth.json.clinicalmodel.Test;
import org.ohd.pophealth.json.measuremodel.CodedValue;
import org.ohd.pophealth.json.clinicalmodel.Condition;
import org.ohd.pophealth.json.clinicalmodel.Encounter;
import org.ohd.pophealth.json.clinicalmodel.Goal;
import org.ohd.pophealth.json.clinicalmodel.Order;
import org.ohd.pophealth.json.clinicalmodel.Patient;
import org.ohd.pophealth.json.clinicalmodel.Procedure;
import org.ohd.pophealth.json.clinicalmodel.Record;
import org.ohd.pophealth.json.clinicalmodel.Result;
/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package org.ohd.pophealth.ccr.importer;


/**
 * This class handles the extraction of clinical data from the ASTM CCR into a
 * set of standard categories for matching against measures
 * @author ohdohd
 */
public class RecordCreator {

    private final static Logger LOG = Logger.getLogger(RecordCreator.class.getName());
    // Current CCR being worked on
    private ContinuityOfCareRecord ccr;
    // Controlled Vocabulary for working with CCR
    private Vocabulary v;
    // Required TermSets
    private static final String[] requiredTermSets = {"onset", "occurred",
        "resolved", "ended", "collected", "ordered", "gender_male", "gender_female"};
    private DateTimeFormatter fmt = ISODateTimeFormat.dateTimeParser(); // Formatter to parse ISO8601 Date Strings

    /**
     * Construct a RecordCreator using a particular Vocabulary.  There is a base
     * vocabulary that can be used: org.ohd.pophealth.ccr.importer.ccrvocabulary.json
     *
     * @param vocab CCR Vocabulary to use during CCR data extraction
     * @throws InCompleteVocabularyException Thrown if not all of the required
     *      termsets are in the passed Vocabulary.  Can call <code>getRequiredTermSets()</code>
     *      to get a list of required termsets for this RecordCreator
     */
    public RecordCreator(Vocabulary vocab) throws InCompleteVocabularyException {
        //Check that required TermSet are in the vocabulary
        for (String s : requiredTermSets) {
            if (!vocab.isValidTermSet(s)) {
                throw new InCompleteVocabularyException("Did not find required termset: " + s);
            }
        }
        this.v = vocab;
    }

    /**
     * Returns a list of names of required term sets
     *
     * @return Array of termset ids
     */
    public static String[] getRequiredTermSets() {
        return requiredTermSets;
    }

    /**
     * Creates a <code>Record</code> from the passed CCR
     *
     * @param ccr  The CCR as an object generated by JAXB
     * @return  the extracted record
     */
    public Record createRecord(ContinuityOfCareRecord ccr) {
        this.ccr = ccr;
        // Create a new Record and set all the attributes
        Record r = new Record();
        r.setPatient(createPatient());
        r.setActors(createActors());
        r.setConditions(createConditions());
        r.setEncounters(createEncounters());
        r.setProcedures(createProcedures());
        r.setResults(createResults());
        r.setMedications(createMedications());
        r.setAllergies(createAllergies());
        r.setOrders(createOrders());

        if (LOG.isLoggable(Level.FINEST)) {
            try {
                LOG.finest(r.toJson(true));
            } catch (JsonMappingException ex) {
                Logger.getLogger(RecordCreator.class.getName()).log(Level.SEVERE, null, ex);
            } catch (JsonGenerationException ex) {
                Logger.getLogger(RecordCreator.class.getName()).log(Level.SEVERE, null, ex);
            } catch (IOException ex) {
                Logger.getLogger(RecordCreator.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
        return r;
    }

    /*
     * This method walks through the list of CCR Actors and finds the Actor
     * with an <ActorObjectID> equal to the passed actorid.
     */
    private ActorType getActorById(String actorid) {
        for (ActorType a : ccr.getActors().getActor()) {
            if (actorid.equals(a.getActorObjectID())) {
                return a;
            }
        }
        return null;
    }

    /*
     * Extracts the data for the <code>Patient</code> object for the <code>
     * Record</code>
     */
    private Patient createPatient() {
        ActorType pt = getActorById(ccr.getPatient().get(0).getActorID());
        Patient p = new Patient();

        // Set Date Of Birth - Assumes DOB required by CCR Validation
        if (pt.getPerson() != null && pt.getPerson().getDateOfBirth() != null){
            DateTimeType dt = pt.getPerson().getDateOfBirth();
        String dob = dt.getExactDateTime();
        p.setBirthdate(convertISO8601toSecfromEpoch(dob));
        }else{
            p.setBirthdate(BaseObject.minDate);