15.1.117. tablet_qt/diagnosis/icd9cm.cpp

/*
    Copyright (C) 2012, University of Cambridge, Department of Psychiatry.
    Created by Rudolf Cardinal (rnc1001@cam.ac.uk).

    This file is part of CamCOPS.

    CamCOPS is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    CamCOPS is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with CamCOPS. If not, see <https://www.gnu.org/licenses/>.
*/

#include "icd9cm.h"

#include <QDebug>
#include <QMap>
#include <QObject>

const QString Icd9cm::XSTRING_TASKNAME("icd9cm");

const QString RANGE_PREFIX("range");  // in string names

// ============================================================================
// Main functions
// ============================================================================

Icd9cm::Icd9cm(
    CamcopsApp& app, QObject* parent, bool dummy_creation_no_xstrings
) :
    DiagnosticCodeSet(
        app, XSTRING_TASKNAME, "ICD-9-CM", parent, dummy_creation_no_xstrings
    )
{
    m_creation_stack.push(DepthItemPair(0, nullptr));
    // root: depth 0, no parent
    addIcd9cmCodes(BASE_CODES);
}

void Icd9cm::addIcd9cmCodes(const QStringList& codes)
{
    // Conceptually: as for Icd10.
    for (const QString& c : codes) {
        const QString desc = xstring(c);

        const bool show_code_in_full_name = !c.startsWith(RANGE_PREFIX);
        addIndividualIcd9cmCode(c, desc, show_code_in_full_name);

        // Any special sub-codes?
        const int length = c.length();
        if (length == 5 && c.startsWith("295.")) {
            // Types of schizophrenia
            addSchizophrenia(c, desc);
        } else if (length == 5 && c.startsWith("296") && (c.endsWith('0') || c.endsWith('1') || c.endsWith('2') || c.endsWith('3') || c.endsWith('4') || c.endsWith('5') || c.endsWith('6'))) {
            // Episodic affective disorders, 296.0 - 296.6
            addEpisodicAffective(c, desc);
        } else if (length == 5 && (c.startsWith("303") || c.startsWith("304") || c.startsWith("305"))) {
            // Substance-induced disorders
            // The sub-codes often have a different heading from the
            // main stem, in which case we specify them separately with the
            // strings having an "x" suffix.
            QString subdescprefix;
            if (c == "303.0" || c == "305.0" || c == "305.2" || c == "305.3"
                || c == "305.4" || c == "305.5" || c == "305.6" || c == "305.7"
                || c == "305.8" || c == "305.9") {
                subdescprefix = xstring(c + "x");
            } else {
                subdescprefix = desc;
            }
            addSubstance(c, subdescprefix);
        }
    }
}

void Icd9cm::addIndividualIcd9cmCode(
    const QString& code, const QString& desc, const bool show_code_in_full_name
)
{
    if (code.isEmpty()) {
        qCritical() << Q_FUNC_INFO << "zero-length code! Ignoring";
        return;
    }

    // Establish depth of new one
    int depth = code.length();
    // do any depth modifications here, if required:
    if (code.startsWith(RANGE_PREFIX)) {
        // longer description, but higher in the hierarchy
        depth = 1;
    }

    while (depth <= m_creation_stack.top().first) {
        m_creation_stack.pop();
    }
    DiagnosticCode* parent = m_creation_stack.top().second;
    const bool selectable
        = ((code.length() > 4 && !code.startsWith(RANGE_PREFIX)) ||
           // plus some specific ones with no children:
           code == "311" || code == "316" || code == "317" || code == "319");
    DiagnosticCode* newchild
        = addCode(parent, code, desc, selectable, show_code_in_full_name);
    m_creation_stack.push(DepthItemPair(depth, newchild));
}

void Icd9cm::addSubcodes(
    const QString& basecode,
    const QString& basedesc,
    const QVector<CodeDescriptionPair>& level1
)
{
    for (const auto& extra1 : level1) {
        const QString code = QString("%1%2").arg(basecode, extra1.first);
        const QString desc
            = QString("%1, %2").arg(basedesc, xstring(extra1.second));
        addIndividualIcd9cmCode(code, desc);
    }
}

// ============================================================================
// Episodic affective disorders
// ============================================================================

const QVector<Icd9cm::CodeDescriptionPair> Icd9cm::EPISODIC_AFFECTIVE_L1{
    // The 296.x0 - 296.x6 codes
    {"0", "affective_x0"},
    {"1", "affective_x1"},
    {"2", "affective_x2"},
    {"3", "affective_x3"},
    {"4", "affective_x4"},
    {"5", "affective_x5"},
    {"6", "affective_x6"},
};

void Icd9cm::addEpisodicAffective(
    const QString& basecode, const QString& basedesc
)
{
    addSubcodes(basecode, basedesc, EPISODIC_AFFECTIVE_L1);
}

// ============================================================================
// Substance-induced
// ============================================================================

const QVector<Icd9cm::CodeDescriptionPair> Icd9cm::SUBSTANCE_L1{
    // The 304.x0 - 304.x3 (and 305.x0 - 305.x3) codes
    {"0", "substance_x0"},
    {"1", "substance_x1"},
    {"2", "substance_x2"},
    {"3", "substance_x3"},
};

void Icd9cm::addSubstance(const QString& basecode, const QString& basedesc)
{
    addSubcodes(basecode, basedesc, SUBSTANCE_L1);
}

// ============================================================================
// Schizophrenia
// ============================================================================

const QVector<Icd9cm::CodeDescriptionPair> Icd9cm::SCHIZOPHRENIA_L1{
    // The 295.x0 - 295.x5 codes
    {"0", "schizophrenia_x0"},
    {"1", "schizophrenia_x1"},
    {"2", "schizophrenia_x2"},
    {"3", "schizophrenia_x3"},
    {"4", "schizophrenia_x4"},
    {"5", "schizophrenia_x5"},
};

void Icd9cm::addSchizophrenia(const QString& basecode, const QString& basedesc)
{
    addSubcodes(basecode, basedesc, SCHIZOPHRENIA_L1);
}

// ============================================================================
// Main codes
// ============================================================================

const QStringList Icd9cm::BASE_CODES{
    "range_290_294", "290",    "290.0",  "290.1",  "290.10", "290.11",
    "290.12",        "290.13", "290.2",  "290.20", "290.21", "290.3",
    "290.4",         "290.40", "290.41", "290.42", "290.43", "290.8",
    "290.9",         "291",    "291.0",  "291.1",  "291.2",  "291.3",
    "291.4",         "291.5",  "291.8",  "291.81", "291.82", "291.89",
    "291.9",         "292",    "292.0",  "292.1",  "292.11", "292.12",
    "292.2",         "292.8",  "292.81", "292.82", "292.83", "292.84",
    "292.85",        "292.89", "292.9",  "293",    "293.0",  "293.1",
    "293.8",         "293.81", "293.82", "293.83", "293.84", "293.89",
    "293.9",         "294",    "294.0",  "294.1",  "294.10", "294.11",
    "294.2",         "294.20", "294.21", "294.8",  "294.9",

    "range_295_299", "295",    "295.0",  "295.1",  "295.2",  "295.3",
    "295.4",         "295.5",  "295.6",  "295.7",  "295.8",  "295.9",
    "296",           "296.0",  "296.1",  "296.2",  "296.3",  "296.4",
    "296.5",         "296.6",  "296.7",  "296.8",  "296.80", "296.81",
    "296.82",        "296.89", "296.9",  "296.90", "296.99", "297",
    "297.0",         "297.1",  "297.2",  "297.3",  "297.8",  "297.9",
    "298",           "298.0",  "298.1",  "298.2",  "298.3",  "298.4",
    "298.8",         "298.9",  "299",    "299.0",  "299.00", "299.01",
    "299.1",         "299.10", "299.11", "299.8",  "299.80", "299.81",
    "299.9",         "299.90", "299.91",

    "range_300_316", "300",    "300.0",  "300.00", "300.01", "300.02",
    "300.09",        "300.1",  "300.10", "300.11", "300.12", "300.13",
    "300.14",        "300.15", "300.16", "300.19", "300.2",  "300.20",
    "300.21",        "300.22", "300.23", "300.29", "300.3",  "300.4",
    "300.5",         "300.6",  "300.7",  "300.8",  "300.81", "300.82",
    "300.89",        "300.9",  "301",    "301.0",  "301.1",  "301.10",
    "301.11",        "301.12", "301.13", "301.2",  "301.20", "301.21",
    "301.22",        "301.3",  "301.4",  "301.5",  "301.50", "301.51",
    "301.59",        "301.6",  "301.7",  "301.8",  "301.81", "301.82",
    "301.83",        "301.84", "301.89", "301.9",  "302",    "302.0",
    "302.1",         "302.2",  "302.3",  "302.4",  "302.5",  "302.50",
    "302.51",        "302.52", "302.53", "302.6",  "302.7",  "302.70",
    "302.71",        "302.72", "302.73", "302.74", "302.75", "302.76",
    "302.79",        "302.8",  "302.81", "302.82", "302.83", "302.84",
    "302.85",        "302.89", "302.9",  "303",    "303.0",  "303.0x",
    "303.9",         "304",    "304.0",  "304.1",  "304.2",  "304.3",
    "304.4",         "304.5",  "304.6",  "304.7",  "304.8",  "304.9",
    "305",           "305.0",  "305.0x", "305.1",  "305.2",  "305.2x",
    "305.3",         "305.3x", "305.4",  "305.4x", "305.5",  "305.5x",
    "305.6",         "305.6x", "305.7",  "305.7x", "305.8",  "305.8x",
    "305.9",         "305.9x", "306",    "306.0",  "306.1",  "306.2",
    "306.3",         "306.4",  "306.50", "306.51", "306.52", "306.53",
    "306.59",        "306.6",  "306.7",  "306.8",  "306.9",  "307",
    "307.0",         "307.1",  "307.2",  "307.20", "307.21", "307.22",
    "307.23",        "307.3",  "307.4",  "307.40", "307.41", "307.42",
    "307.43",        "307.44", "307.45", "307.46", "307.47", "307.48",
    "307.49",        "307.5",  "307.50", "307.51", "307.52", "307.53",
    "307.54",        "307.59", "307.6",  "307.7",  "307.8",  "307.80",
    "307.81",        "307.89", "307.9",  "308",    "308.0",  "308.1",
    "308.2",         "308.3",  "308.4",  "308.9",  "309",    "309.0",
    "309.1",         "309.2",  "309.21", "309.22", "309.23", "309.24",
    "309.28",        "309.29", "309.3",  "309.4",  "309.8",  "309.81",
    "309.82",        "309.83", "309.89", "309.9",  "310",    "310.0",
    "310.1",         "310.2",  "310.8",  "310.81", "310.89", "310.9",
    "311",           "312",    "312.0",  "312.00", "312.01", "312.02",
    "312.03",        "312.1",  "312.10", "312.11", "312.12", "312.13",
    "312.2",         "312.20", "312.21", "312.22", "312.23", "312.3",
    "312.30",        "312.31", "312.32", "312.33", "312.34", "312.35",
    "312.39",        "312.4",  "312.8",  "312.81", "312.82", "312.89",
    "312.9",         "313",    "313.0",  "313.1",  "313.2",  "313.21",
    "313.22",        "313.23", "313.3",  "313.8",  "313.81", "313.82",
    "313.83",        "313.89", "313.9",  "314",    "314.0",  "314.00",
    "314.01",        "314.1",  "314.2",  "314.8",  "314.9",  "315",
    "315.0",         "315.00", "315.01", "315.02", "315.09", "315.1",
    "315.2",         "315.3",  "315.31", "315.32", "315.34", "315.35",
    "315.39",        "315.4",  "315.5",  "315.8",  "315.9",  "316",

    "range_317_319", "317",    "318",    "318.0",  "318.1",  "318.2",
    "319",

    "range_V71_V82", "V71.09",
};