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