quick minor path updates (#1968)
[openemr.git] / ccdaservice / serveccda.js
blob02e22e90fa02b0a1f0d005054e11b1235203db87
1 /**
2  *
3  * Copyright (C) 2016-2018 Jerry Padgett <sjpadgett@gmail.com>
4  *
5  * LICENSE: This program is free software: you can redistribute it and/or modify
6  *  it under the terms of the GNU Affero General Public License as
7  *  published by the Free Software Foundation, either version 3 of the
8  *  License, or (at your option) any later version.
9  *
10  *  This program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *  GNU Affero General Public License for more details.
14  *
15  *  You should have received a copy of the GNU Affero General Public License
16  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
17  *
18  * @package OpenEMR
19  * @author Jerry Padgett <sjpadgett@gmail.com>
20  * @link http://www.open-emr.org
21  */
23 "use strict";
24 var net = require('net');
25 var to_json = require('xmljson').to_json;
26 var bbg = require('oe-blue-button-generate');
27 //var bbm = require('blue-button-model'); //for use set global-not needed here
28 //var fs = require('fs');
29 //var bb = require('blue-button');
30 var fs = require('fs');
32 var server = net.createServer();
33 var conn = ''; // make our connection scope global to script
34 var oidFacility = "";
35 var all = "";
36 var npiProvider = "";
37 var npiFacility = "";
39 // some useful routines for populating template sections
40 function validate(toValidate, ref, retObj) {
41     for (var p in ref) {
42         if (typeof ref[p].dataType === "undefined") {
43             retObj[p] = {};
44             if (!toValidate[p]) toValidate[p] = {};
45             validate(toValidate[p], ref[p], retObj[p]);
46         } else {
47             if (typeof toValidate === "undefined") toValidate = {};
48             var trimmed = trim(toValidate[p]);
49             retObj[p] = typeEnforcer(ref[p].dataType, trimmed);
50         }
51     }
52     return retObj;
55 function typeEnforcer(type, val) {
56     var validVal;
57     switch (type) {
58         case "boolean":
59             if (typeof val === "string") {
60                 validVal = val.toLowerCase() === "true";
61             } else {
62                 validVal = !!val;
63             }
64             break;
65         case "string":
66             if ((val === null) || (val === "undefined") || (typeof val === "undefined")) {
67                 validVal = '';
68             } else if (typeof val == "object") {
69                 validVal = '';
70             } else {
71                 validVal = trim(String(val));
72             }
73             break;
74         case "array":
75             if (typeof val === 'undefined' || val === null) {
76                 validVal = [];
77             } else if (Array.isArray(val)) {
78                 validVal = [];
79                 val.forEach(function (v) {
80                     validVal.push(trim(v));
81                 });
82             } else {
83                 validVal = [trim(val)];
84             }
85             break;
86         case "integer":
87             var asInt = parseInt(val, 10);
88             if (isNaN(asInt)) asInt = 0;
89             validVal = asInt;
90             break;
91         case "number":
92             var asNum = parseFloat(val);
93             if (isNaN(asNum)) asNum = 0;
94             validVal = asNum;
95             break;
96     }
97     return validVal;
100 function trim(s) {
101     if (typeof s === 'string') return s.trim();
102     return s;
105 function safeId(s) {
106     return trim(s).toLowerCase().replace(/[^a-zA-Z0-9]+/g, '-').replace(/\-+$/, '');
109 function fDate(str) {
110     str = String(str); // at least ensure string so cast it...
112     if (Number(str) === 0) {
113         return (new Date()).toISOString().slice(0,10).replace(/-/g,"");
114     }
115     if (str.length === 8 || (str.length === 14 && (1 * str.substring(12, 14)) === 0)) {
116         return [str.slice(0, 4), str.slice(4, 6), str.slice(6, 8)].join('-')
117     } else if (str.length === 10 && (1 * str.substring(0, 2)) <= 12) {
118         // case mm/dd/yyyy or mm-dd-yyyy
119         return [str.slice(6, 10), str.slice(0, 2), str.slice(3, 5)].join('-')
120     } else if (str.length === 14 && (1 * str.substring(12, 14)) > 0) {
121         // maybe a real time so parse
122     }
123     return str;
126 function getPrecision(str) {
127     str = String(str);
128     let pflg = "day";
130     if (Number(str) === 0) {
131         return "day";
132     }
133     if (str.length > 8) {
134         pflg = "minute";
135     }
136     if (str.length > 12) {
137         pflg = "second";
138     }
140     return pflg;
143 function templateDate(date, precision) {
144     return [{'date': fDate(date), 'precision': precision}]
147 function cleanCode(code) {
148     return code.replace(/[.#]/, "");
151 function isOne(who) {
152     try {
153         if (who !== null && typeof who === 'object') {
154             return who.hasOwnProperty('extension') || who.hasOwnProperty('id') ? 1 : Object.keys(who).length;
155         }
156     }
157     catch (e) {
158         return false;
159     }
160     return 0;
163 function headReplace(content) {
164     var r = '<?xml version="1.0" encoding="UTF-8"?>\n' +
165         '<ClinicalDocument xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="urn:hl7-org:v3 http://xreg2.nist.gov:8080/hitspValidation/schema/cdar2c32/infrastructure/cda/C32_CDA.xsd"' +
166         ' xmlns="urn:hl7-org:v3" xmlns:mif="urn:hl7-org:v3/mif">\n';
167     r += content.substr(content.search(/<realmCode/i));
168     return r;
171 // Data model for Blue Button
172 function populateDemographic(pd, g) {
173     let guardian = [{
174         "relation": g.relation,
175         "addresses": [{
176             "street_lines": [g.address],
177             "city": g.city,
178             "state": g.state,
179             "zip": g.postalCode,
180             "country": g.country,
181             "use": "primary home"
182         }],
183         "names": [{
184             "last": g.display_name, //@todo parse first/last
185             "first": g.display_name
186         }],
187         "phone": [{
188             "number": g.telecom,
189             "type": "primary home"
190         }]
191     }];
193     return {
194         "name": {
195             "middle": [pd.mname],
196             "last": pd.lname,
197             "first": pd.fname
198         },
199         "dob": {
200             "point": {
201                 "date": fDate(pd.dob),
202                 "precision": "day"
203             }
204         },
205         "gender": pd.gender.toUpperCase(),
206         "identifiers": [{
207             "identifier": oidFacility,
208             "extension": "PT-" + pd.id
209         }],
210         "marital_status": pd.status.toUpperCase() || "U",
211         "addresses": [{
212             "street_lines": [pd.street],
213             "city": pd.city,
214             "state": pd.state,
215             "zip": pd.postalCode,
216             "country": pd.country,
217             "use": "primary home"
218         }],
219         "phone": [{
220             "number": pd.phone_home,
221             "type": "primary home"
222         }],
223         "race": pd.race,
224         "ethnicity": pd.ethnicity || "U",
225         "languages": [{
226             "language": pd.language,
227             "preferred": true,
228             "mode": "Expressed spoken",
229             "proficiency": "Good"
230         }],
231         "religion": pd.religion.toUpperCase() || "",
232         /*"birthplace":'', {
233             "city": "",
234             "state": "",
235             "zip": "",
236             "country": ""
237         },*/
238         "attributed_provider": {
239             "identity": [
240                 {
241                     "root": "2.16.840.1.113883.4.6",
242                     "extension": npiFacility || "UNK"
243                 }
244             ],
245             "phone": [{
246                 "number": all.encounter_provider.facility_phone || "",
247             }],
248             "name": [
249                 {
250                     "full": all.encounter_provider.facility_name || ""
251                 }
252             ]
253         },
254         "guardians": g.display_name ? guardian : ''
255     }
259 function populateProviders() {
260     return {
261         "providers": [
262             {
263                 "identity": [
264                     {
265                         "root": "2.16.840.1.113883.4.6",
266                         "extension": all.primary_care_provider.provider[0].npi || "UNK"
267                     }
268                 ],
269                 "type": [
270                     {
271                         "name": all.primary_care_provider.provider[0].physician_type || "Not Avail",
272                         "code": all.primary_care_provider.provider[0].physician_type_code || "",
273                         "code_system_name": "Provider Codes"
274                     }
275                 ],
276                 "name": [
277                     {
278                         "last": all.primary_care_provider.provider[0].lname || "",
279                         "first": all.primary_care_provider.provider[0].fname || ""
280                     }
281                 ],
282                 "address": [
283                     {
284                         "street_lines": [
285                             all.encounter_provider.facility_street
286                         ],
287                         "city": all.encounter_provider.facility_city,
288                         "state": all.encounter_provider.facility_state,
289                         "zip": all.encounter_provider.facility_postal_code,
290                         "country": all.encounter_provider.facility_country_code
291                     }
292                 ],
293                 "phone": [
294                     {
295                         "value": {
296                             "number": all.encounter_provider.facility_phone || "",
298                         }
299                     }],
300                 "organization": [
301                     {
302                         "identifiers": [
303                             {
304                                 "identifier": "2.16.840.1.113883.19.5.9999.1393" //@todo need facility oid
305                             }
306                         ],
307                         "name": [
308                             all.encounter_provider.facility_name
309                         ],
310                         "address": [
311                             {
312                                 "street_lines": [
313                                     all.encounter_provider.facility_street
314                                 ],
315                                 "city": all.encounter_provider.facility_city,
316                                 "state": all.encounter_provider.facility_state,
317                                 "zip": all.encounter_provider.facility_postal_code,
318                                 "country": all.encounter_provider.facility_country_code
319                             }
320                         ],
321                         "phone": [
322                             {
323                                 "number": all.encounter_provider.facility_phone,
324                                 "type": "primary work"
325                             }
326                         ]
327                     }
328                 ]
330             }
331         ]
334     }
337 function populateMedication(pd) {
338     pd.status = 'Completed'; //@todo invoke prescribed
339     return {
340         "date_time": {
341             "low": {
342                 "date": fDate(pd.start_date),
343                 "precision": "day"
344             },
345             /*"high": {
346                 "date": pd.end_date ? fDate(pd.end_date) : "",
347                 "precision": "day"
348             }*/
349         },
350         "identifiers": [{
351             "identifier": pd.sha_extension,
352             "extension": pd.extension || "UNK"
353         }],
354         "status": pd.status,
355         "sig": pd.direction,
356         "product": {
357             "identifiers": [{
358                 "identifier": "2a620155-9d11-439e-92b3-5d9815ff4ee8",
359                 "extension": "UNK"
360             }],
361             "unencoded_name": pd.drug,
362             "product": {
363                 "name": pd.drug,
364                 "code": pd.rxnorm,
365                 /*"translations": [{
366                     "name": pd.drug,
367                     "code": pd.rxnorm,
368                     "code_system_name": "RXNORM"
369                 }],*/
370                 "code_system_name": "RXNORM"
371             },
372             //"manufacturer": ""
373         },
374         "supply": {
375             "date_time": {
376                 "low": {
377                     "date": fDate(pd.start_date),
378                     "precision": "day"
379                 }
380             },
381             "repeatNumber": "0",
382             "quantity": "0",
383             "author": {
384                 "date_time": {
385                     "point": {
386                         "date": fDate(pd.start_date),
387                         "precision": getPrecision(fDate(pd.start_date))
388                     }
389                 },
390                 "identifiers": [{
391                     "identifier": "2.16.840.1.113883.4.6",
392                     "extension": pd.npi || "UNK"
393                 }],
394                 "name": {
395                     "prefix": pd.title,
396                     "last": pd.lname,
397                     "first": pd.fname
398                 }
399             },
400             "instructions": {
401                 "code": {
402                     "name": "instruction",
403                     "code": "409073007",
404                     "code_system_name": "SNOMED CT"
405                 },
406                 "free_text": pd.instructions || "None Available"
407             },
408         },
409         "administration": {
410             "route": {
411                 "name": pd.route || "",
412                 "code": pd.route_code || "",
413                 "code_system_name": "Medication Route FDA"
414             },
415             "form": {
416                 "name": pd.form,
417                 "code": pd.form_code,
418                 "code_system_name": "Medication Route FDA"
419             },
420             "dose": {
421                 "value": parseFloat(pd.size),
422                 "unit": pd.unit,
423             },
424             /*"rate": {
425                 "value": parseFloat(pd.dosage),
426                 "unit": ""
427             },*/
428             "interval": {
429                 "period": {
430                     "value": parseFloat(pd.dosage),
431                     "unit": pd.interval
432                 },
433                 "frequency": true
434             }
435         },
436         "performer": {
437             "identifiers": [{
438                 "identifier": "2.16.840.1.113883.4.6",
439                 "extension": pd.npi || "UNK"
440             }],
441             "organization": [{
442                 "identifiers": [{
443                     "identifier": pd.sha_extension,
444                     "extension": pd.extension || "UNK"
445                 }],
446                 "name": [pd.performer_name]
447             }]
448         },
449         "drug_vehicle": {
450             "name": pd.form,
451             "code": pd.form_code,
452             "code_system_name": "RXNORM"
453         },
454         /*"precondition": {
455             "code": {
456                 "code": "ASSERTION",
457                 "code_system_name": "ActCode"
458             },
459             "value": {
460                 "name": "none",
461                 "code": "none",
462                 "code_system_name": "SNOMED CT"
463             }
464         },
465         "indication": {
466             "identifiers": [{
467                 "identifier": "db734647-fc99-424c-a864-7e3cda82e703",
468                 "extension": "45665"
469             }],
470             "code": {
471                 "name": "Finding",
472                 "code": "404684003",
473                 "code_system_name": "SNOMED CT"
474             },
475             "date_time": {
476                 "low": {
477                     "date": fDate(pd.start_date),
478                     "precision": "day"
479                 }
480             },
481             "value": {
482                 "name": pd.indications,
483                 "code": pd.indications_code,
484                 "code_system_name": "SNOMED CT"
485             }
486         },*/
487         /*"dispense": {
488             "identifiers": [{
489                 "identifier": "1.2.3.4.56789.1",
490                 "extension": "cb734647-fc99-424c-a864-7e3cda82e704"
491             }],
492             "performer": {
493                 "identifiers": [{
494                     "identifier": "2.16.840.1.113883.19.5.9999.456",
495                     "extension": "2981823"
496                 }],
497                 "address": [{
498                     "street_lines": [pd.address],
499                     "city": pd.city,
500                     "state": pd.state,
501                     "zip": pd.zip,
502                     "country": "US"
503                 }],
504                 "organization": [{
505                     "identifiers": [{
506                         "identifier": "2.16.840.1.113883.19.5.9999.1393"
507                     }],
508                     "name": [pd.performer_name]
509                 }]
510             },
511             "product": {
512                 "identifiers": [{
513                     "identifier": "2a620155-9d11-439e-92b3-5d9815ff4ee8"
514                 }],
515                 "unencoded_name": pd.drug,
516                 "product": {
517                     "name": pd.drug,
518                     "code": pd.rxnorm,
519                     "translations": [{
520                         "name": pd.drug,
521                         "code": pd.rxnorm,
522                         "code_system_name": "RXNORM"
523                     }],
524                     "code_system_name": "RXNORM"
525                 },
526                 "manufacturer": ""
527             }
528         }*/
529     };
532 function populateEncounter(pd) {
533     return {
534         "encounter": {
535             "name": pd.visit_category ? pd.visit_category : '',
536             "code": pd.encounter_procedures ? pd.encounter_procedures.procedures.code : '',
537             "code_system_name": "CPT4",
538             "translations": [{
539                 "name": "Ambulatory",
540                 "code": "AMB",
541                 "code_system_name": "ActCode"
542             }]
543         },
544         "identifiers": [{
545             "identifier": pd.sha_extension,
546             "extension": pd.extension
547         }],
548         "date_time": {
549             "point": {
550                 "date": fDate(pd.date),
551                 "precision": "second" //getPrecision(fDate(pd.date_formatted))
552             }
553         },
554         "performers": [{
555             "identifiers": [{
556                 "identifier": "2.16.840.1.113883.4.6",
557                 "extension": pd.npi || "UNK"
558             }],
559             "code": [{
560                 "name": pd.physician_type,
561                 "code": pd.physician_type_code,
562                 "code_system_name": "SNOMED CT"
563             }],
564             "name": [
565                 {
566                     "last": pd.lname || "",
567                     "first": pd.fname || ""
568                 }
569             ],
570             "phone": [
571                 {
572                     "number": pd.work_phone,
573                     "type": "work place"
574                 }
575             ]
576         }],
577         "locations": [{
578             "name": pd.location,
579             "location_type": {
580                 "name": pd.location_details,
581                 "code": "1160-1",
582                 "code_system_name": "HealthcareServiceLocation"
583             },
584             "address": [{
585                 "street_lines": [pd.facility_address],
586                 "city": pd.facility_city,
587                 "state": pd.facility_state,
588                 "zip": pd.facility_zip,
589                 "country": pd.facility_country
590             }]
591         }],
592         "findings": [{
593             "identifiers": [{
594                 "identifier": pd.sha_extension,
595                 "extension": pd.extension
596             }],
597             "value": {
598                 "name": pd.encounter_reason,
599                 "code": "",
600                 "code_system_name": "SNOMED CT"
601             },
602             "date_time": {
603                 "low": {
604                     "date": fDate(pd.date),
605                     "precision": "day"
606                 }
607             }
608         }]
609     };
612 function populateAllergy(pd) {
613     return {
614         "identifiers": [{
615             "identifier": "36e3e930-7b14-11db-9fe1-0800200c9a66",
616             "extension": pd.id || "UNK"
617         }],
618         "date_time": {
619             "point": {
620                 "date": fDate(pd.startdate),
621                 "precision": "day"
622             }
623         },
624         "observation": {
625             "identifiers": [{
626                 "identifier": "4adc1020-7b14-11db-9fe1-0800200c9a66",
627                 "extension": pd.extension || "UNK"
628             }],
629             "allergen": {
630                 "name": pd.title,
631                 "code": pd.rxnorm_code === 0 ? "" : pd.rxnorm_code,
632                 "code_system_name": "RXNORM"
633             },
634             "intolerance": {
635                 "name": "Propensity to adverse reactions to drug",
636                 "code": pd.snomed_code || "420134006",
637                 "code_system_name": "SNOMED CT"
638             },
639             "date_time": {
640                 "low": {
641                     "date": fDate(pd.startdate),
642                     "precision": "day"
643                 }
644             },
645             "status": {
646                 "name": pd.allergy_status,
647                 "code": pd.status_code === 0 ? "" : pd.status_code,
648                 "code_system_name": "SNOMED CT"
649             },
650             "reactions": [{
651                 "identifiers": [{
652                     "identifier": "4adc1020-7b14-11db-9fe1-0800200c9a64"
653                 }],
654                 "date_time": {
655                     "low": templateDate(pd.startdate, "day"),
656                     "high": templateDate(pd.enddate, "day")
657                 },
658                 "reaction": {
659                     "name": pd.reaction_text,
660                     "code": pd.reaction_code === 0 ? "" : pd.reaction_code,
661                     "code_system_name": "SNOMED CT"
662                 },
663                 "severity": {
664                     "code": {
665                         "name": pd.outcome,
666                         "code": pd.outcome_code === 0 ? "" : pd.outcome_code,
667                         "code_system_name": "SNOMED CT"
668                     },
669                     /*"interpretation": {
670                         "name": "",
671                         "code": "",
672                         "code_system_name": "Observation Interpretation"
673                     }*/
674                 }
675             }],
676             "severity": {
677                 "code": {
678                     "name": pd.outcome,
679                     "code": pd.outcome_code === 0 ? "" : pd.outcome_code,
680                     "code_system_name": "SNOMED CT"
681                 },
682                 /*"interpretation": {
683                     "name": "UNK",
684                     "code": "",
685                     "code_system_name": "Observation Interpretation"
686                 }*/
687             }
688         }
689     };
692 function populateProblem(pd) {
693     return {
694         "date_time": {
695             "low": {
696                 "date": fDate(pd.start_date_table),
697                 "precision": "day"
698             },
699             /*"high": {
700                 "date": fDate(pd.end_date),
701                 "precision": "day"
702             }*/
703         },
704         "identifiers": [{
705             "identifier": pd.sha_extension,
706             "extension": pd.extension || "UNK"
707         }],
708         "problem": {
709             "code": {
710                 "name": trim(pd.title),
711                 "code": cleanCode(pd.code),
712                 "code_system_name": "ICD10"
713             },
714             "date_time": {
715                 "low": {
716                     "date": fDate(pd.start_date),
717                     "precision": "day"
718                 },
719                 /*"high": {
720                     "date": fDate(pd.end_date),
721                     "precision": getPrecision()
722                 }*/
723             }
724         },
725         "performer": [
726             {
727                 "identifiers": [
728                     {
729                         "identifier": "2.16.840.1.113883.4.6",
730                         "extension": all.primary_care_provider.provider[0].npi || "UNK"
731                     }
732                 ],
733                 "name": [
734                     {
735                         "last": all.primary_care_provider.provider[0].lname || "",
736                         "first": all.primary_care_provider.provider[0].fname || ""
737                     }
738                 ]
739             }],
740         "onset_age": pd.age,
741         "onset_age_unit": "Year",
742         "status": {
743             "name": pd.status,
744             "date_time": {
745                 "low": {
746                     "date": fDate(pd.start_date),
747                     "precision": "day"
748                 },
749                 /*"high": {
750                     "date": fDate(pd.end_date),
751                     "precision": getPrecision()
752                 }*/
753             }
754         },
755         "patient_status": pd.observation,
756         "source_list_identifiers": [{
757             "identifier": pd.sha_extension,
758             "extension": pd.extension || "UNK"
759         }]
760     };
764 function populateProcedure(pd) {
765     return {
766         "procedure": {
767             "name": pd.description,
768             "code": pd.code,
769             "code_system_name": "CPT4"
770         },
771         "identifiers": [{
772             "identifier": "d68b7e32-7810-4f5b-9cc2-acd54b0fd85d",
773             "extension": pd.extension
774         }],
775         "status": "completed",
776         "date_time": {
777             "point": {
778                 "date": fDate(pd.date),
779                 "precision": "day"
780             }
781         },
782         /*"body_sites": [{
783             "name": "",
784             "code": "",
785             "code_system_name": ""
786         }],
787         "specimen": {
788             "identifiers": [{
789                 "identifier": "c2ee9ee9-ae31-4628-a919-fec1cbb58683"
790             }],
791             "code": {
792                 "name": "",
793                 "code": "",
794                 "code_system_name": "SNOMED CT"
795             }
796         },*/
797         "performers": [{
798             "identifiers": [{
799                 "identifier": "2.16.840.1.113883.4.6",
800                 "extension": pd.npi || "UNK"
801             }],
802             "address": [{
803                 "street_lines": [pd.address],
804                 "city": pd.city,
805                 "state": pd.state,
806                 "zip": pd.zip,
807                 "country": ""
808             }],
809             "phone": [{
810                 "number": pd.work_phone,
811                 "type": "work place"
812             }],
813             "organization": [{
814                 "identifiers": [{
815                     "identifier": pd.facility_sha_extension,
816                     "extension": pd.facility_extension
817                 }],
818                 "name": [pd.facility_name],
819                 "address": [{
820                     "street_lines": [pd.facility_address],
821                     "city": pd.facility_city,
822                     "state": pd.facility_state,
823                     "zip": pd.facility_zip,
824                     "country": pd.facility_country
825                 }],
826                 "phone": [{
827                     "number": pd.facility_phone,
828                     "type": "work place"
829                 }]
830             }]
831         }],
832         "procedure_type": "procedure"
833     };
836 function populateResult(pd) {
837     let icode = pd.subtest.abnormal_flag;
838     switch (pd.subtest.abnormal_flag.toUpperCase()) {
839         case "NO":
840             icode = "Normal";
841             break;
842         case "YES":
843             icode = "Abnormal";
844             break;
845         case "":
846             icode = "UNK";
847             break;
848     }
849     return {
850         "identifiers": [{
851             "identifier": pd.subtest.root,
852             "extension": pd.subtest.extension
853         }],
854         "result": {
855             "name": pd.title,
856             "code": pd.subtest.result_code || "",
857             "code_system_name": "LOINC"
858         },
859         "date_time": {
860             "point": {
861                 "date": fDate(pd.date_ordered),
862                 "precision": "day"
863             }
864         },
865         "status": pd.order_status,
866         "reference_range": {
867             "range": pd.subtest.range //OpenEMR doesn't have high/low so show range as text.
868         },
869         /*"reference_range": {
870             "low": pd.subtest.range,
871             "high": pd.subtest.range,
872             "unit": pd.subtest.unit
873         },*/
874         "interpretations": [icode],
875         "value": parseFloat(pd.subtest.result_value) || pd.subtest.result_value || "",
876         "unit": pd.subtest.unit
877     };
880 function getResultSet(results) {
882     if (!results) return '';
884     let tResult = results.result[0] || results.result;
885     var resultSet = {
886         "identifiers": [{
887             "identifier": tResult.root,
888             "extension": tResult.extension
889         }],
890         "author": [
891             {
892                 "date_time": {
893                     "point": {
894                         "date": fDate(tResult.date_ordered),
895                         "precision": getPrecision(fDate(tResult.date_ordered))
896                     }
897                 },
898                 "identifiers": [
899                     {
900                         "identifier": "2.16.840.1.113883.4.6",
901                         "extension": all.primary_care_provider.provider.npi || "UNK"
902                     }
903                 ],
904                 "name": [
905                     {
906                         "last": all.primary_care_provider.provider.lname || "",
907                         "first": all.primary_care_provider.provider.fname || ""
908                     }
909                 ]
910             }],
911         "result_set": {
912             "name": tResult.test_name,
913             "code": tResult.test_code,
914             "code_system_name": "LOINC"
915         }
916     };
917     var rs = [];
918     var many = [];
919     var theone = {};
920     var count = 0;
921     many.results = [];
922     try {
923         count = isOne(results.result);
924     } catch (e) {
925         count = 0;
926     }
927     if (count > 1) {
928         for (let i in results.result) {
929             theone[i] = populateResult(results.result[i]);
930             many.results.push(theone[i]);
931         }
932     } else if (count !== 0) {
933         theone = populateResult(results.result);
934         many.results.push(theone);
935     }
936     rs.results = Object.assign(resultSet);
937     rs.results.results = Object.assign(many.results);
938     return rs;
941 function getPlanOfCare(pd) {
942     return {
943         "plan": {
944             "name": pd.code_text,
945             "code": pd.code,
946             "code_system_name": "SNOMED CT"
947         },
948         "identifiers": [{
949             "identifier": "9a6d1bac-17d3-4195-89a4-1121bc809b4a"
950         }],
951         "date_time": {
952             "center": {
953                 "date": fDate(pd.date),
954                 "precision": "day"
955             }
956         },
957         "type": "observation",
958         "status": {
959             "code": pd.status
960         },
961         "subType": pd.description
962     };
965 function populateVital(pd) {
966     return [{
967         "identifiers": [{
968             "identifier": "2.16.840.1.113883.3.140.1.0.6.10.14.1",
969             "extension": pd.extension_bps
970         }],
971         "vital": {
972             "name": "Blood Pressure Systolic",
973             "code": "8480-6",
974             "code_system_name": "LOINC"
975         },
976         "status": "completed",
977         "date_time": {
978             "point": {
979                 "date": fDate(pd.effectivetime),
980                 "precision": getPrecision(fDate(pd.effectivetime))
981             }
982         },
983         "value": parseFloat(pd.bps),
984         "unit": "mm[Hg]"
985     }, {
986         "identifiers": [{
987             "identifier": "2.16.840.1.113883.3.140.1.0.6.10.14.1",
988             "extension": pd.extension_bpd
989         }],
990         "vital": {
991             "name": "Blood Pressure Diastolic",
992             "code": "8462-4",
993             "code_system_name": "LOINC"
994         },
995         "status": "completed",
996         "date_time": {
997             "point": {
998                 "date": fDate(pd.effectivetime),
999                 "precision": getPrecision(fDate(pd.effectivetime))
1000             }
1001         },
1002         "interpretations": ["Normal"],
1003         "value": parseFloat(pd.bpd),
1004         "unit": "mm[Hg]"
1005     }, {
1006         "identifiers": [{
1007             "identifier": "2.16.840.1.113883.3.140.1.0.6.10.14.1",
1008             "extension": pd.extension_pulse
1009         }],
1010         "vital": {
1011             "name": "Heart Rate",
1012             "code": "8867-4",
1013             "code_system_name": "LOINC"
1014         },
1015         "status": "completed",
1016         "date_time": {
1017             "point": {
1018                 "date": fDate(pd.effectivetime),
1019                 "precision": getPrecision(fDate(pd.effectivetime))
1020             }
1021         },
1022         "interpretations": ["Normal"],
1023         "value": parseFloat(pd.pulse),
1024         "unit": "/min"
1025     }, {
1026         "identifiers": [{
1027             "identifier": "2.16.840.1.113883.3.140.1.0.6.10.14.1",
1028             "extension": pd.extension_breath
1029         }],
1030         "vital": {
1031             "name": "Respiratory Rate",
1032             "code": "9279-1",
1033             "code_system_name": "LOINC"
1034         },
1035         "status": "completed",
1036         "date_time": {
1037             "point": {
1038                 "date": fDate(pd.effectivetime),
1039                 "precision": getPrecision(fDate(pd.effectivetime))
1040             }
1041         },
1042         "interpretations": ["Normal"],
1043         "value": parseFloat(pd.breath),
1044         "unit": "/min"
1045     }, {
1046         "identifiers": [{
1047             "identifier": "2.16.840.1.113883.3.140.1.0.6.10.14.1",
1048             "extension": pd.extension_temperature
1049         }],
1050         "vital": {
1051             "name": "Body Temperature",
1052             "code": "8310-5",
1053             "code_system_name": "LOINC"
1054         },
1055         "status": "completed",
1056         "date_time": {
1057             "point": {
1058                 "date": fDate(pd.effectivetime),
1059                 "precision": getPrecision(fDate(pd.effectivetime))
1060             }
1061         },
1062         "interpretations": ["Normal"],
1063         "value": parseFloat(pd.temperature),
1064         "unit": "degF"
1065     }, {
1066         "identifiers": [{
1067             "identifier": "2.16.840.1.113883.3.140.1.0.6.10.14.1",
1068             "extension": pd.extension_height
1069         }],
1070         "vital": {
1071             "name": "Height",
1072             "code": "8302-2",
1073             "code_system_name": "LOINC"
1074         },
1075         "status": "completed",
1076         "date_time": {
1077             "point": {
1078                 "date": fDate(pd.effectivetime),
1079                 "precision": getPrecision(fDate(pd.effectivetime))
1080             }
1081         },
1082         "interpretations": ["Normal"],
1083         "value": parseFloat(pd.height),
1084         "unit": pd.unit_height
1085     }, {
1086         "identifiers": [{
1087             "identifier": "2.16.840.1.113883.3.140.1.0.6.10.14.1",
1088             "extension": pd.extension_weight
1089         }],
1090         "vital": {
1091             "name": "Weight Measured",
1092             "code": "3141-9",
1093             "code_system_name": "LOINC"
1094         },
1095         "status": "completed",
1096         "date_time": {
1097             "point": {
1098                 "date": fDate(pd.effectivetime),
1099                 "precision": getPrecision(fDate(pd.effectivetime))
1100             }
1101         },
1102         "interpretations": ["Normal"],
1103         "value": parseFloat(pd.weight),
1104         "unit": pd.unit_weight
1105     }, {
1106         "identifiers": [{
1107             "identifier": "2.16.840.1.113883.3.140.1.0.6.10.14.1",
1108             "extension": pd.extension_BMI
1109         }],
1110         "vital": {
1111             "name": "BMI (Body Mass Index)",
1112             "code": "39156-5",
1113             "code_system_name": "LOINC"
1114         },
1115         "status": "completed",
1116         "date_time": {
1117             "point": {
1118                 "date": fDate(pd.effectivetime),
1119                 "precision": getPrecision(fDate(pd.effectivetime))
1120             }
1121         },
1122         "interpretations": ["Normal"],
1123         "value": parseFloat(pd.BMI),
1124         "unit": "kg/m2"
1125     }];
1128 function populateSocialHistory(pd) {
1129     return {
1130         "date_time": {
1131             "low": templateDate(pd.date, "day")
1132             //"high": templateDate(pd.date, "day")
1133         },
1134         "identifiers": [{
1135             "identifier": pd.sha_extension,
1136             "extension": pd.extension
1137         }],
1138         "code": {
1139             "name": pd.element
1140         },
1141         "value": pd.description
1142     };
1145 function populateImmunization(pd) {
1146     return {
1147         "date_time": {
1148             "point": {
1149                 "date": fDate(pd.administered_on),
1150                 "precision": "month"
1151             }
1152         },
1153         "identifiers": [{
1154             "identifier": "e6f1ba43-c0ed-4b9b-9f12-f435d8ad8f92",
1155             "extension": pd.extension || "UNK"
1156         }],
1157         "status": "complete",
1158         "product": {
1159             "product": {
1160                 "name": pd.code_text,
1161                 "code": pd.cvx_code,
1162                 "code_system_name": "CVX"
1163                 /*"translations": [{
1164                     "name": "",
1165                     "code": "",
1166                     "code_system_name": "CVX"
1167                 }]*/
1168             },
1169             "lot_number": "1",
1170             "manufacturer": "UNK"
1171         },
1172         "administration": {
1173             "route": {
1174                 "name": pd.route_of_administration,
1175                 "code": pd.route_code,
1176                 "code_system_name": "Medication Route FDA"
1177             },
1178             "dose": {
1179                 "value": 50,
1180                 "unit": "mcg"
1181             }
1182         },
1183         "performer": {
1184             "identifiers": [{
1185                 "identifier": "2.16.840.1.113883.4.6",
1186                 "extension": npiProvider
1187             }],
1188             "name": [{
1189                 "last": pd.lname,
1190                 "first": pd.fname
1191             }],
1192             "address": [{
1193                 "street_lines": [pd.address],
1194                 "city": pd.city,
1195                 "state": pd.state,
1196                 "zip": pd.zip,
1197                 "country": "US"
1198             }],
1199             "organization": [{
1200                 "identifiers": [{
1201                     "identifier": "2.16.840.1.113883.4.6",
1202                     "extension": npiFacility
1203                 }],
1204                 "name": [pd.facility_name]
1205             }]
1206         },
1207         "instructions": {
1208             "code": {
1209                 "name": "immunization education",
1210                 "code": "171044003",
1211                 "code_system_name": "SNOMED CT"
1212             },
1213             "free_text": "Needs Attention for more data."
1214         }
1215     };
1218 function populatePayer(pd) {
1219     return {
1220         "identifiers": [{
1221             "identifier": "1fe2cdd0-7aad-11db-9fe1-0800200c9a66"
1222         }],
1223         "policy": {
1224             "identifiers": [{
1225                 "identifier": "3e676a50-7aac-11db-9fe1-0800200c9a66"
1226             }],
1227             "code": {
1228                 "code": "SELF",
1229                 "code_system_name": "HL7 RoleCode"
1230             },
1231             "insurance": {
1232                 "code": {
1233                     "code": "PAYOR",
1234                     "code_system_name": "HL7 RoleCode"
1235                 },
1236                 "performer": {
1237                     "identifiers": [{
1238                         "identifier": "2.16.840.1.113883.19"
1239                     }],
1240                     "address": [{
1241                         "street_lines": ["123 Insurance Road"],
1242                         "city": "Blue Bell",
1243                         "state": "MA",
1244                         "zip": "02368",
1245                         "country": "US",
1246                         "use": "work place"
1247                     }],
1248                     "phone": [{
1249                         "number": "(781)555-1515",
1250                         "type": "work place"
1251                     }],
1252                     "organization": [{
1253                         "name": ["Good Health Insurance"],
1254                         "address": [{
1255                             "street_lines": ["123 Insurance Road"],
1256                             "city": "Blue Bell",
1257                             "state": "MA",
1258                             "zip": "02368",
1259                             "country": "US",
1260                             "use": "work place"
1261                         }],
1262                         "phone": [{
1263                             "number": "(781)555-1515",
1264                             "type": "work place"
1265                         }]
1266                     }],
1267                     "code": [{
1268                         "code": "PAYOR",
1269                         "code_system_name": "HL7 RoleCode"
1270                     }]
1271                 }
1272             }
1273         },
1274         "guarantor": {
1275             "code": {
1276                 "code": "GUAR",
1277                 "code_system_name": "HL7 Role"
1278             },
1279             "identifiers": [{
1280                 "identifier": "329fcdf0-7ab3-11db-9fe1-0800200c9a66"
1281             }],
1282             "name": [{
1283                 "prefix": "Mr.",
1284                 "middle": ["Frankie"],
1285                 "last": "Everyman",
1286                 "first": "Adam"
1287             }],
1288             "address": [{
1289                 "street_lines": ["17 Daws Rd."],
1290                 "city": "Blue Bell",
1291                 "state": "MA",
1292                 "zip": "02368",
1293                 "country": "US",
1294                 "use": "primary home"
1295             }],
1296             "phone": [{
1297                 "number": "(781)555-1212",
1298                 "type": "primary home"
1299             }]
1300         },
1301         "participant": {
1302             "code": {
1303                 "name": "Self",
1304                 "code": "SELF",
1305                 "code_system_name": "HL7 Role"
1306             },
1307             "performer": {
1308                 "identifiers": [{
1309                     "identifier": "14d4a520-7aae-11db-9fe1-0800200c9a66",
1310                     "extension": "1138345"
1311                 }],
1312                 "address": [{
1313                     "street_lines": ["17 Daws Rd."],
1314                     "city": "Blue Bell",
1315                     "state": "MA",
1316                     "zip": "02368",
1317                     "country": "US",
1318                     "use": "primary home"
1319                 }],
1320                 "code": [{
1321                     "name": "Self",
1322                     "code": "SELF",
1323                     "code_system_name": "HL7 Role"
1324                 }]
1325             },
1326             "name": [{
1327                 "prefix": "Mr.",
1328                 "middle": ["A."],
1329                 "last": "Everyman",
1330                 "first": "Frank"
1331             }]
1332         },
1333         "policy_holder": {
1334             "performer": {
1335                 "identifiers": [{
1336                     "identifier": "2.16.840.1.113883.19",
1337                     "extension": "1138345"
1338                 }],
1339                 "address": [{
1340                     "street_lines": ["17 Daws Rd."],
1341                     "city": "Blue Bell",
1342                     "state": "MA",
1343                     "zip": "02368",
1344                     "country": "US",
1345                     "use": "primary home"
1346                 }]
1347             }
1348         },
1349         "authorization": {
1350             "identifiers": [{
1351                 "identifier": "f4dce790-8328-11db-9fe1-0800200c9a66"
1352             }],
1353             "procedure": {
1354                 "code": {
1355                     "name": "Colonoscopy",
1356                     "code": "73761001",
1357                     "code_system_name": "SNOMED CT"
1358                 }
1359             }
1360         }
1361     };
1364 function populateHeader(pd) {
1365     var head = {
1366         "identifiers": [
1367             {
1368                 "identifier": oidFacility,
1369                 "extension": "TT988"
1370             }
1371         ],
1372         "code": {
1373             "name": "Continuity of Care Document",
1374             "code": "34133-9",
1375             "code_system_name": "LOINC"
1376         },
1377         "template": [
1378             "2.16.840.1.113883.10.20.22.1.1",
1379             "2.16.840.1.113883.10.20.22.1.2"
1380         ],
1381         "title": "Clinical Health Summary",
1382         "date_time": {
1383             "point": {
1384                 "date": fDate(pd.created_time) || "",
1385                 "precision": getPrecision(fDate(pd.created_time))
1386             }
1387         },
1388         "author": {
1389             "author": [
1390                 {
1391                     "identifiers": [
1392                         {
1393                             "identifier": "2.16.840.1.113883.4.6",
1394                             "extension": pd.author.npi || "UNK"
1395                         }
1396                     ],
1397                     "name": [
1398                         {
1399                             "last": pd.author.lname,
1400                             "first": pd.author.fname
1401                         }
1402                     ],
1403                     "address": [
1404                         {
1405                             "street_lines": [
1406                                 pd.author.streetAddressLine
1407                             ],
1408                             "city": pd.author.city,
1409                             "state": pd.author.state,
1410                             "zip": pd.author.postalCode,
1411                             "country": pd.author.country
1412                         }
1413                     ],
1414                     "phone": [
1415                         {
1416                             "number": pd.author.telecom,
1417                             "use": "work place"
1418                         }
1419                     ],
1420                     "code": [
1421                         {
1422                             "name": "UNK",
1423                             "code": ""
1424                         }
1425                     ],
1426                     "organization": [
1427                         {
1428                             "identity": [
1429                                 {
1430                                     "root": "2.16.840.1.113883.4.6",
1431                                     "extension": npiFacility || "UNK"
1432                                 }
1433                             ],
1434                             "name": [
1435                                 pd.encounter_provider.facility_name
1436                             ],
1437                             "address": [
1438                                 {
1439                                     "street_lines": [
1440                                         pd.encounter_provider.facility_street
1441                                     ],
1442                                     "city": pd.encounter_provider.facility_city,
1443                                     "state": pd.encounter_provider.facility_state,
1444                                     "zip": pd.encounter_provider.facility_postal_code,
1445                                     "country": pd.encounter_provider.facility_country_code
1446                                 }
1447                             ],
1448                             "phone": [
1449                                 {
1450                                     "number": pd.encounter_provider.facility_phone,
1451                                     "type": "work primary"
1452                                 }
1453                             ]
1454                         }
1455                     ]
1456                 }
1457             ]
1458         },
1459         "custodian": {
1460             "identity": [
1461                 {
1462                     "root": "2.16.840.1.113883.4.6",
1463                     "extension": npiFacility || "UNK"
1464                 }
1465             ],
1466             "name": [
1467                 pd.encounter_provider.facility_name
1468             ],
1469             "address": [
1470                 {
1471                     "street_lines": [
1472                         pd.encounter_provider.facility_street
1473                     ],
1474                     "city": pd.encounter_provider.facility_city,
1475                     "state": pd.encounter_provider.facility_state,
1476                     "zip": pd.encounter_provider.facility_postal_code,
1477                     "country": pd.encounter_provider.facility_country_code
1478                 }
1479             ],
1480             "phone": [
1481                 {
1482                     "number": pd.encounter_provider.facility_phone,
1483                     "type": "work primary"
1484                 }
1485             ]
1486         },
1487         /*"data_enterer": {
1488             "identifiers": [
1489                 {
1490                     "identifier": "2.16.840.1.113883.4.6",
1491                     "extension": "999999943252"
1492                 }
1493             ],
1494             "name": [
1495                 {
1496                     "last": pd.data_enterer.lname,
1497                     "first": pd.data_enterer.fname
1498                 }
1499             ],
1500             "address": [
1501                 {
1502                     "street_lines": [
1503                         pd.data_enterer.streetAddressLine
1504                     ],
1505                     "city": pd.data_enterer.city,
1506                     "state": pd.data_enterer.state,
1507                     "zip": pd.data_enterer.postalCode,
1508                     "country": pd.data_enterer.country
1509                 }
1510             ],
1511             "phone": [
1512                 {
1513                     "number": pd.data_enterer.telecom,
1514                     "type": "work place"
1515                 }
1516             ]
1517         },
1518         "informant": {
1519             "identifiers": [
1520                 {
1521                     "identifier": "2.16.840.1.113883.19.5",
1522                     "extension": "KP00017"
1523                 }
1524             ],
1525             "name": [
1526                 {
1527                     "last": pd.informer.lname || "",
1528                     "first": pd.informer.fname || ""
1529                 }
1530             ],
1531             "address": [
1532                 {
1533                     "street_lines": [
1534                         pd.informer.streetAddressLine || ""
1535                     ],
1536                     "city": pd.informer.city,
1537                     "state": pd.informer.state,
1538                     "zip": pd.informer.postalCode,
1539                     "country": pd.informer.country
1540                 }
1541             ],
1542             "phone": [
1543                 {
1544                     "number": pd.informer.telecom || "",
1545                     "type": "work place"
1546                 }
1547             ]
1548         },*/
1549         "service_event": { // @todo maybe move this to attributed or write z-schema template
1550             "code": {
1551                 "name": "",
1552                 "code": "",
1553                 "code_system_name": "SNOMED CT"
1554             },
1555             "date_time": {
1556                 "low": {
1557                     "date": "",
1558                     "precision": getPrecision()
1559                 },
1560                 "high": {
1561                     "date": pd.created_time,
1562                     "precision": getPrecision()
1563                 }
1564             },
1565             "performer": [
1566                 {
1567                     "performer": [
1568                         {
1569                             "identifiers": [
1570                                 {
1571                                     "identifier": "2.16.840.1.113883.4.6",
1572                                     "extension": "PseudoMD-1"
1573                                 }
1574                             ],
1575                             "name": [
1576                                 {
1577                                     "last": pd.information_recipient.lname,
1578                                     "first": pd.information_recipient.fname
1579                                 }
1580                             ],
1581                             "address": [
1582                                 {
1583                                     "street_lines": [
1584                                         pd.information_recipient.streetAddressLine
1585                                     ],
1586                                     "city": pd.information_recipient.city,
1587                                     "state": pd.information_recipient.state,
1588                                     "zip": pd.information_recipient.postalCode,
1589                                     "country": pd.information_recipient.country
1590                                 }
1591                             ],
1592                             "phone": [
1593                                 {
1594                                     "number": pd.information_recipient.telecom,
1595                                     "type": "work place"
1596                                 }
1597                             ],
1598                             "organization": [
1599                                 {
1600                                     "identifiers": [
1601                                         {
1602                                             "identifier": "2.16.840.1.113883.19.5.9999.1393"
1603                                         }
1604                                     ],
1605                                     "name": [
1606                                         pd.encounter_provider.facility_name
1607                                     ],
1608                                     "address": [
1609                                         {
1610                                             "street_lines": [
1611                                                 pd.encounter_provider.facility_street
1612                                             ],
1613                                             "city": pd.encounter_provider.facility_city,
1614                                             "state": pd.encounter_provider.facility_state,
1615                                             "zip": pd.encounter_provider.facility_postal_code,
1616                                             "country": pd.encounter_provider.facility_country_code
1617                                         }
1618                                     ],
1619                                     "phone": [
1620                                         {
1621                                             "number": pd.encounter_provider.facility_phone,
1622                                             "type": "primary work"
1623                                         }
1624                                     ]
1625                                 }
1626                             ],
1627                             "code": [
1628                                 {
1629                                     "name": "UNK",
1630                                     "code": "",
1631                                     "code_system_name": "Provider Codes"
1632                                 }
1633                             ]
1634                         }
1635                     ],
1636                     "code": {
1637                         "name": "Primary Performer",
1638                         "code": "PP",
1639                         "code_system_name": "Provider Role"
1640                     }
1641                 }
1642             ]
1643         }
1644     };
1645     return head;
1648 function getMeta(pd) {
1649     var meta = {};
1650     meta = {
1651         "type": "CCDA",
1652         "identifiers": [
1653             {
1654                 "identifier": "2.16.840.1.113883.19.5.99999.1",
1655                 "extension": "TT988"
1656             }
1657         ],
1658         "confidentiality": "Normal",
1659         "set_id": {
1660             "identifier": "2.16.840.1.113883.19.5.99999.19",
1661             "extension": "sTT988"
1662         }
1663     }
1664     return meta;
1667 function genCcda(pd) {
1668     var doc = {};
1669     var data = {};
1670     var count = 0;
1671     var many = [];
1672     var theone = {};
1674     all = pd;
1675     npiProvider = all.primary_care_provider.provider[0].npi;
1676     oidFacility = all.encounter_provider.facility_oid;
1677     npiFacility = all.encounter_provider.facility_npi;
1679 // Demographics
1680     let demographic = populateDemographic(pd.patient, pd.guardian, pd);
1681     Object.assign(demographic, populateProviders());
1682     data.demographics = Object.assign(demographic);
1684 // vitals
1685     many.vitals = [];
1686     try {
1687         count = isOne(pd.history_physical.vitals_list.vitals);
1688     } catch (e) {
1689         count = 0
1690     }
1691     if (count > 1) {
1692         for (let i in pd.history_physical.vitals_list.vitals) {
1693             theone = populateVital(pd.history_physical.vitals_list.vitals[i]);
1694             many.vitals.push.apply(many.vitals, theone);
1695         }
1696     } else if (count === 1) {
1697         theone = populateVital(pd.history_physical.vitals_list.vitals);
1698         many.vitals.push(theone);
1699     }
1700     data.vitals = Object.assign(many.vitals);
1701 // Medications
1702     let meds = [];
1703     let m = {};
1704     meds.medications = [];
1705     try {
1706         count = isOne(pd.medications.medication);
1707     } catch (e) {
1708         count = 0
1709     }
1710     if (count > 1) {
1711         for (let i in pd.medications.medication) {
1712             m[i] = populateMedication(pd.medications.medication[i]);
1713             meds.medications.push(m[i]);
1714         }
1715     } else if (count !== 0) {
1716         m = populateMedication(pd.medications.medication);
1717         meds.medications.push(m);
1718     }
1719     data.medications = Object.assign(meds.medications);
1720 // Encounters
1721     let encs = [];
1722     let enc = {};
1723     encs.encounters = [];
1724     try {
1725         count = isOne(pd.encounter_list.encounter);
1726     } catch (e) {
1727         count = 0
1728     }
1729     if (count > 1) {
1730         for (let i in pd.encounter_list.encounter) {
1731             enc[i] = populateEncounter(pd.encounter_list.encounter[i]);
1732             encs.encounters.push(enc[i]);
1733         }
1734     } else if (count !== 0) {
1735         enc = populateEncounter(pd.encounter_list.encounter);
1736         encs.encounters.push(enc);
1737     }
1738     data.encounters = Object.assign(encs.encounters);
1740 // Allergies
1741     let allergies = [];
1742     let allergy = {};
1743     allergies.allergies = [];
1744     try {
1745         count = isOne(pd.allergies.allergy);
1746     } catch (e) {
1747         count = 0
1748     }
1749     if (count > 1) {
1750         for (let i in pd.allergies.allergy) {
1751             allergy[i] = populateAllergy(pd.allergies.allergy[i]);
1752             allergies.allergies.push(allergy[i]);
1753         }
1754     } else if (count !== 0) {
1755         allergy = populateAllergy(pd.allergies.allergy);
1756         allergies.allergies.push(allergy);
1757     }
1758     data.allergies = Object.assign(allergies.allergies);
1760 // Problems
1761     let problems = [];
1762     let problem = {};
1763     problems.problems = [];
1764     try {
1765         count = isOne(pd.problem_lists.problem);
1766     } catch (e) {
1767         count = 0
1768     }
1769     if (count > 1) {
1770         for (let i in pd.problem_lists.problem) {
1771             problem[i] = populateProblem(pd.problem_lists.problem[i], pd);
1772             problems.problems.push(problem[i]);
1773         }
1774     } else if (count !== 0) {
1775         problem = populateProblem(pd.problem_lists.problem);
1776         problems.problems.push(problem);
1777     }
1778     data.problems = Object.assign(problems.problems);
1779 // Procedures
1780     many = [];
1781     theone = {};
1782     many.procedures = [];
1783     try {
1784         count = isOne(pd.procedures.procedure);
1785     } catch (e) {
1786         count = 0
1787     }
1788     if (count > 1) {
1789         for (let i in pd.procedures.procedure) {
1790             theone[i] = populateProcedure(pd.procedures.procedure[i]);
1791             many.procedures.push(theone[i]);
1792         }
1793     } else if (count !== 0) {
1794         theone = populateProcedure(pd.procedures.procedure);
1795         many.procedures.push(theone);
1796     }
1798     data.procedures = Object.assign(many.procedures);
1799 // Results
1800     if (pd.results)
1801         data.results = Object.assign(getResultSet(pd.results, pd)['results']);
1803 // Immunizations
1804     many = [];
1805     theone = {};
1806     many.immunizations = [];
1807     try {
1808         count = isOne(pd.immunizations.immunization);
1809     } catch (e) {
1810         count = 0;
1811     }
1812     if (count > 1) {
1813         for (let i in pd.immunizations.immunization) {
1814             theone[i] = populateImmunization(pd.immunizations.immunization[i]);
1815             many.immunizations.push(theone[i]);
1816         }
1817     } else if (count !== 0) {
1818         theone = populateImmunization(pd.immunizations.immunization);
1819         many.immunizations.push(theone);
1820     }
1821     data.immunizations = Object.assign(many.immunizations);
1822 // Plan of Care
1823     many = [];
1824     theone = {};
1825     many.plan_of_care = [];
1826     try {
1827         count = isOne(pd.planofcare); // ccm doesn't send array of items
1828     } catch (e) {
1829         count = 0
1830     }
1831     if (count > 1) {
1832         for (let i in pd.planofcare.item) {
1833             theone[i] = getPlanOfCare(pd.planofcare.item[i]);
1834             many.plan_of_care.push(theone[i]);
1835         }
1836     } else if (count !== 0) {
1837         theone = getPlanOfCare(pd.planofcare.item);
1838         many.plan_of_care.push(theone);
1839     }
1841     data.plan_of_care = Object.assign(many.plan_of_care);
1842     // Social History
1843     many = [];
1844     theone = {};
1845     many.social_history = [];
1846     try {
1847         count = isOne(pd.history_physical.social_history.history_element);
1848     } catch (e) {
1849         count = 0
1850     }
1851     if (count > 1) {
1852         for (let i in pd.history_physical.social_history.history_element) {
1853             if (i > 0) break;
1854             theone[i] = populateSocialHistory(pd.history_physical.social_history.history_element[i]);
1855             many.social_history.push(theone[i]);
1856         }
1857     } else if (count !== 0) {
1858         theone = populateSocialHistory(pd.history_physical.social_history.history_element);
1859         many.social_history.push(theone);
1860     }
1862     data.social_history = Object.assign(many.social_history);
1864     // ------------------------------------------ End Sections ----------------------------------------//
1866     doc.data = Object.assign(data);
1867     let meta = getMeta(pd);
1868     let header = populateHeader(pd);
1870     meta.ccda_header = Object.assign(header);
1871     doc.meta = Object.assign(meta);
1872     let xml = bbg.generateCCD(doc);
1874     // Debug
1875     /*fs.writeFile("bbtest.json", JSON.stringify(doc, null, 4), function (err) {
1876         if (err) {
1877             return console.log(err);
1878         }
1879         console.log("Json saved!");
1880     });
1881     fs.writeFile("bbtest.xml", xml, function (err) {
1882         if (err) {
1883             return console.log(err);
1884         }
1885         console.log("Xml saved!");
1886     });*/
1888     return xml;
1891 function processConnection(connection) {
1892     conn = connection; // make it global
1893     var remoteAddress = conn.remoteAddress + ':' + conn.remotePort;
1894     //console.log(remoteAddress);
1895     conn.setEncoding('utf8');
1897     function eventData(xml) {
1898         xml = xml.replace(/(\u000b|\u001c)/gm, "").trim();
1899         // Sanity check from service manager
1900         if (xml === 'status' || xml.length < 80) {
1901             conn.write("statusok" + String.fromCharCode(28) + "\r\r");
1902             conn.end('');
1903             return;
1904         }
1906         // ---------------------start--------------------------------
1907         let doc = "";
1908         xml = xml.toString().replace(/\t\s+/g, ' ').trim();
1910         to_json(xml, function (error, data) {
1911             // console.log(JSON.stringify(data, null, 4));
1912             if (error) { // need try catch
1913                 console.log('toJson error: ' + error + 'Len: ' + xml.length);
1914                 return;
1915             }
1916             doc = genCcda(data.CCDA);
1917         });
1919         doc = headReplace(doc);
1920         doc = doc.toString().replace(/(\u000b|\u001c|\r)/gm, "").trim();
1921         //console.log(doc);
1922         let chunk = "";
1923         let numChunks = Math.ceil(doc.length / 1024);
1924         for (let i = 0, o = 0; i < numChunks; ++i, o += 1024) {
1925             chunk = doc.substr(o, 1024);
1926             conn.write(chunk);
1927         }
1929         conn.write(String.fromCharCode(28) + "\r\r" + '');
1930         conn.end();
1932     }
1934     function eventCloseConn() {
1935         //console.log('connection from %s closed', remoteAddress);
1936     }
1938     function eventErrorConn(err) {
1939         //console.log('Connection %s error: %s', remoteAddress, err.message);
1940     }
1942     // Connection Events //
1943     conn.on('data', eventData);
1944     conn.once('close', eventCloseConn);
1945     conn.on('error', eventErrorConn);
1948 function setUp(server) {
1949     server.on('connection', processConnection);
1950     server.listen(6661, 'localhost', function () {
1951         //console.log('server listening to %j', server.address());
1952     });
1955 setUp(server);