% How the diagnosis goes:
    % Call "hellodoctor" - asks patient for their name and checks if they are in the database
    % If in database - check if they've already been diagnosed
        % If not diagnosed - go through initial examination
        % If already diagnosed - ask if they want to enter new symptoms/enter new tests
    % Initial exmination: answer y/n to symptoms,
        % If y, then add to their list of symptoms
    % If symptom points >= 2, then order for tests -- else diagnose as no CAD
    % After getting all test resuls - add points up
    % Use total points to make CAD risk analysis (using point system from table)

% Patients
patient(jane).
patient(edima).
patient(tiffany).
patient(joseph).
patient(john).

%% Basic information about each patient
age(jane, 21).
age(edima, 20).
age(tiffany, 57).
age(joseph, 82).
age(john, 45).

sex(jane, female).
sex(edima, female).
sex(tiffany, female).
sex(joseph, male).
sex(john, male).

:- dynamic has_symptom/2.
:- dynamic current_patient/1.
:- dynamic already_diagnosed/1.
:- dynamic symptom_points/2.
:- dynamic total_points/2.

hellodoctor :- write("Welcome! Can we start with your name?"), nl, check_patient_records.

check_patient_records :- read(Name), patient(Name), retract_name(Name).
check_patient_records :- write("I'm sorry. I only examine patients in my current patient records."), !.

retract_name(Name) :- current_predicate(patient/1), retractall(current_patient(patient(_))), assert(current_patient(patient(Name))), path.
retract_name(Name) :- assert(current_patient(patient(Name))), path.

path :- current_patient(patient(Name)), current_predicate(already_diagnosed/1), already_diagnosed(Name), write("Welcome back, "), write(Name), write("! Would you like to enter new symptoms/order new tests? (new_symptoms/new_tests)"), nl, choice.
path :- current_patient(patient(Name)), write("Hello, "), write(Name), write("! Let's start you examination by asking a few questions about your symptoms."), nl, initial_examination.
 

%% ---- INITIAL EXAMINATION ---- %%

initial_examination :- symptoms(L), check_symptoms(L), check_points.

symptoms(L) :- findall(Symptom, symptom(Symptom), L). % Returns a list of all symptoms

check_symptoms([H|T]) :- symptom_questions(H, Q), ask_symptom(H, Q), check_symptoms(T).
check_symptoms([]) :- !.

ask_symptom(Symptom, Q) :- write(Q), nl, read(Y), Y = y, current_patient(patient(Patient)), assert(has_symptom(Patient, Symptom)).
ask_symptom(_, _) :- !.

check_points :- get_symptoms(L), calculate_points(L, 0).

calculate_points([H|T], TotalPoints) :- symptom_point(H, Point), NewPoint is TotalPoints + Point, calculate_points(T, NewPoint).
calculate_points([], TotalPoints) :- TotalPoints >= 2, order_tests, !.
calculate_points([], TotalPoints) :- write("Not enough symptoms. You most likely do not have CAD."), current_patient(patient(Patient)), assert(already_diagnosed(Patient)), assert(total_points(Patient, TotalPoints)), !.


%% -- ORDERING TESTS -- %%

order_tests :- write("Ordering tests for more conclusive results."), nl, get_test_results.

get_test_results :- tests(L), check_tests(L), make_diagnosis.
tests(L) :- findall(Test, test_type(Test), L). % returns a list of all test types

check_tests([]) :- !.
check_tests([H|T]) :- ask_test(H), check_tests(T).

ask_test(Test) :- write("What is the patient's test result for "), write(Test), write("?"), nl, read(Result), current_patient(patient(Patient)), positive_test(Test, Result), assert(has_symptom(Patient, Test)).
ask_test(_) :- !.

make_diagnosis :- current_patient(patient(Patient)), check_age, calulate_total_points, total_points(Patient, TotalPoints), interpret_points(TotalPoints), assert(already_diagnosed(Patient)).
make_diagnosis :- current_patient(patient(Patient)), calulate_total_points, total_points(Patient, TotalPoints), interpret_points(TotalPoints), assert(already_diagnosed(Patient)).

check_age :- current_patient(patient(Patient)), age(Patient, Age), Age > 50, assert(has_symptom(Patient, age)).

calulate_total_points :- get_symptoms(L), calulate_total_points(L, 0).
calulate_total_points([H|T], Total) :- current_patient(patient(Patient)), has_symptom(Patient, H), NewTotal is Total + 1, calulate_total_points(T, NewTotal).
calulate_total_points([_|T], Total) :- calulate_total_points(T, Total).
calulate_total_points([], Total) :- current_patient(patient(Patient)), assert(total_points(Patient, Total)), !.

interpret_points(DiagnosisPoints) :- DiagnosisPoints = 0, write("No CAD risk.").
interpret_points(DiagnosisPoints) :- DiagnosisPoints =< 3, write("CAD risk present.").
interpret_points(DiagnosisPoints) :- DiagnosisPoints =< 6, write("Expressed CAD risk present.").
interpret_points(DiagnosisPoints) :- DiagnosisPoints =< 9, write("Highly expressed CAD risk.").


%% ---- BELIEF REVISION ---- %%

choice :- read(Choice), Choice = new_symptoms, new_symptoms.
choice :- new_tests.

rediagnose :- current_patient(patient(Patient)), retractall(total_points(Patient, _)), calulate_total_points, total_points(Patient, TotalPoints), interpret_points(TotalPoints).


%% -- NEW SYMPTOMS -- %%

new_symptoms :- display_current_symptoms, nl, write("What is your new symptom?"), nl, read(NewSymptom), symptom(NewSymptom), current_patient(patient(Patient)), assert(has_symptom(Patient, NewSymptom)), rediagnose.
new_symptoms :- write("Entered symptom is not a CAD symptom. Please try again. (Possible symptoms are: "), symptoms(L), write(L), write(" ).").

display_current_symptoms :- get_symptoms(L), write("Here are your current symptoms:"), write(L).
get_symptoms(C) :- current_predicate(has_symptom/2), current_patient(patient(Patient)), findall(X, has_symptom(Patient, X), C). % Returns list of all confirmed symptoms for current patient


%% -- NEW TESTS -- %%

retract_test(Test) :- current_predicate(has_symptom/2), current_patient(patient(Name)), has_symptom(Name, Test), retractall(has_symptom(Name, Test)).

new_tests :- write("Which test are you entering for the patient?"), nl, read(TestType), test_type(TestType), new_tests(TestType).
new_tests :- write("Not a CAD test.").
new_tests(Test) :- retract_test(Test), ask_test(Test), rediagnose.
new_tests(Test) :- ask_test(Test), rediagnose.

%% UTILITIES %%

% Ask a bunch of yes or no questions to get the patients diagnosis
symptom_questions(chestPain, "Are you experiencing any chest pain or chest discomfort? (y/n)").
symptom_questions(inactivity, "Do you get less than 30 minutes of excercise everyday? (y/n)").
symptom_questions(smoking, "Are you currently a smoker? (y/n)").
symptom_questions(familyHistory, "Do you have a family history of coronary artery disease? (y/n)").

% Symptom points
symptom_point(chestPain, 2).
symptom_point(inactivity, 1).
symptom_point(smoking, 1).
symptom_point(familyHistory, 1).
                                                                                
% Initial symptoms
symptom(chestPain).
symptom(inactivity).
symptom(smoking).
symptom(familyHistory).

%% Test types
test_type(bloodPressure).
test_type(cholesterol).
test_type(bloodSugar).
test_type(bmi).
test_type(waistHipRatio).

%% Tests
positive_test(bloodPressure, Result) :- Result > 140.
positive_test(cholesterol, Result) :- Result > 5.6.
positive_test(bloodSugar, Result) :- Result > 6.1.
positive_test(bmi, Result) :- Result > 25.
positive_test(waistHipRatio, Result) :- current_patient(patient(Patient)), sex(Patient, male), Result > 1.0.
positive_test(waistHipRatio, Result) :- current_patient(patient(Patient)), sex(Patient, female), Result > 0.9.
