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