#ifndef INCLUDED_LOOP_
#define INCLUDED_LOOP_

#include <iosfwd>

#include "../typedefs/typedefs.h"
#include "../globals/globals.h"
#include "../scenario/scenario.h"
#include "../screening/screening.h"
#include "../densities/densities.h"
#include "../modalities/modalities.h"
#include "../tumorinfo/tumorinfo.h"
#include "../tumor/tumor.h"
#include "../costs/costs.h"

class Options;
class Scenario;

namespace FBB
{
    class CSVTable;
}

class Loop: public Globals
{
//
// 2 -> 1, 5 -> 4, 9 -> 8 if the natural death is before the tumor's onset.
//
    enum Status             // labels in data.cc
    {
        PRESENT,            // 0

        NATURAL_PRE,        // 1 natural death before the 1st screening round
        UNDETECTED_PRE,     // 2 nat. death, undetected tumor, before 1st scr.
        SELF_PRE,           // 3 self-detected tumor before 1st scr.
                          
        NATURAL_DURING,     // 4 nat. death between screening rounds
        UNDETECTED_DURING,  // 5 nat. death, undetected tumor, between scr.
        SELF_DURING,        // 6 self-detected tumor between scr. rounds
        SCREEN_DETECTED,    // 7 screening-detected tumor
                          
        NATURAL_POST,       // 8 nat. death after the last screening round
        UNDETECTED_POST,    // 9 nat. death, undetected tumor, afer last scr.
        SELF_POST,          // 10 self-detected tumor after last scr. round

        Status_END   
    };

    enum                    // round info (per case) '0': not attended
    {
        ATTENDED        = '1',
        FALSE_NEGATIVE  = '2',
        FALSE_POSITIVE  = '3'
    };

    enum
    {
        N_RESULTS = 13              // weird... used in results()
    };

    static StringSet s_availableFiles;
    static char const *s_status[];

    Options const &d_options;
    Status d_status = PRESENT;

    StringVect const &d_labels;

    Scenario d_scenario;
    Costs d_costs;
    Densities d_densities;
    TumorInfo d_tumorInfo;
    Tumor d_tumor;
    Modalities d_modalities;
    Screening d_screening;

    int16_t d_roundDetected;            // -1: no detection
    uint16_t d_modValue;                // value of the used modality/ies

            // Analysis &d_analysis;

            // Beir7 const &d_beir7;
            // Incidence const &d_incidence;

    double d_naturalDeathAge = 0;      // dying age w/o tumor
    double d_deathAge = 0;             // actual dying age

    uint16_t d_nRounds;                 // from Screening::nRounds()

                                        // when screening is used:
    uint16_t d_firstRoundAge;           // age of the first screening round

    uint16_t d_round = 0;               // currently used screening round

    std::string d_roundInfo;

    SizeVect d_nIntervals;              // # interval cancer per round
    SizeVect d_nTrueIntervals;          // # interval cancer per round
                                        //   following a previously attended
                                        //   screening round

//  initialized in resetcounters.cc
//    SizeVect d_nRoundFP;                // # of false-positives per round
//    SizeVect d_nRoundFN;                // # of false-negatives per round
//    SizeVect d_nRoundTP;                // # of true-positives per round
//    SizeVect d_nRoundTN;                // # of true-negatives per round

    SizeVect d_nDetections;

    double d_caseCost;

    double d_biopCosts;                 // sum of biop costs per case
    DoubleVect d_roundBiopCosts;        // and per round

    DoubleVect d_roundCost;             // sum of costs over all scr. rounds
                                        // (org: screeningRoundCosts)

                                    // randomly determined (breast cancer)
                                    // bi-rad indices for the ages of the
                                    // screening rounds, or table S3 indices
                                    // for lung cancer.
    Uint16Vect d_indices;           // ('densities' in the original sources)

    std::string d_timestamp;

    void (*d_tnm)(std::ostream &out);   // noTNM or fillTNM

    ProbGroup::Vector const *d_groupVector; // breast- or lung cancer
                                            // probGroup::Vector to use when
                                            // constructing d_indices

    size_t d_caseIdx;               // case idx currently used by genCases

    public:
        Loop(StringVect const &labels);

        void iterate();

    private:
        double addBiopCosts(double costs);

        bool betaFunction(uint16_t modalityNr);
        void caseInit();
        size_t cases() const;                   // #cases in womenLoop
        Uint16Vect cptIndices() const;          // cpt d_indices
        static void fillTNM(std::ostream &out);
        static void fillZeroes(std::ostream &out, size_t idx);

        void genCases(size_t iter, size_t nCases);      // generates the
                                                        // data matrix

        FBB::CSVTable headerData(size_t iter) const;
        FBB::CSVTable headerRounds(size_t iter) const;

        bool intervalCancer();

        void labels(std::ostream &out) const;

        bool leaving(double screeningAge);

        void maybeFalseNegative(ModBase *modBase, double screeningAge);
        bool falseNegative(ModBase *modBase);
        void tumorDetected(ModBase *modBase, double screeningAge);

        bool falsePositive(ModBase *modBase, double screeningAge);

        double naturalDeathAge();
        static void noTNM(std::ostream &out);
        static std::ofstream open(std::string const &fname);
        static std::ofstream outStream(std::string const &fname, size_t idx);
        void postScreen();

        static std::string replaceDollar(std::string const &settingsFile,
                                         size_t idx);
        void resetCounters();

                                            // # active modalities
        void roundsNcols(FBB::CSVTable &tab) const;
        void roundsColHdrs(FBB::CSVTable &tab) const;
        void roundsMidLevelCols(FBB::CSVTable &tab) const;
        void roundsBottomColNames(FBB::CSVTable &tab) const;

                                            // returns the sensitivity for the
        double sensitivity(ModBase *modBase) const;    // current round  1.cc

        bool left(Status status, double deathAge);  // also logs the reason

        void screen(double screeningAge);
        void screening();
        std::string showRound() const;
        double treatmentCosts(double screeningAge) const;               // .ih

                // NOTE: in the orig. source density NRs are used: 1..4
                //       here density INDICES are usd: 0..3
                // but when writing the data file (e.g., data-0.txt, original
                // name e.g., women-test-i0.txt) a + 1 correction is
                // currently applied
        bool use(ModBase *modBase);         // use this modality
        void writeData(FBB::CSVTable &dataTable, size_t idx) const;
        void writeParameters(size_t iter) const;    // also opens the file
        void writeRounds(FBB::CSVTable &roundTable) const;
};

#endif
