1:- module(ap_cli, [main/1, start/0]).    2
    3:- use_module(library(lists)).    4:- use_module(library(readutil)).    5:- use_module(ap_ui).    6:- use_module(ap_defaults).    7:- use_module(ap_model).    8:- use_module(ap_report).    9:- use_module(ap_simulation).   10:- use_module(ap_compare).   11:- use_module(ap_io).   12:- use_module(ap_audit).   13:- use_module(ap_legal).   14:- use_module(ap_reference).   15:- use_module(ap_calibration).   16:- use_module(ap_version).   17
   18main(Argv) :-
   19    ( Argv = ['--help'|_] -> help
   20    ; Argv = ['--version'|_] -> ap_version:version_string(V), format('~w~n', [V])
   21    ; Argv = ['simulate', File|_] -> cli_simulate_file(File)
   22    ; Argv = ['evaluate', File|_] -> cli_evaluate(File)
   23    ; start
   24    ).
   25
   26start :-
   27    ap_defaults:default_scenario(S),
   28    menu_loop(S).
   29
   30menu_loop(Current) :-
   31    ap_ui:clear_screen,
   32    ap_ui:banner,
   33    format('Skenario aktif: ~w~n', [Current.name]),
   34    format('~n[1] Simulasi cepat (guided)~n', []),
   35    format('[2] Edit semua variabel (advanced)~n', []),
   36    format('[3] Jalankan skenario aktif~n', []),
   37    format('[4] Simulasikan 7 hari ke depan~n', []),
   38    format('[5] Bandingkan respons kebijakan~n', []),
   39    format('[6] Simpan skenario~n', []),
   40    format('[7] Muat skenario~n', []),
   41    format('[8] Lihat audit log lokal~n', []),
   42    format('[9] Metodologi / hukum / referensi~n', []),
   43    format('[10] Evaluasi model dari CSV historis~n', []),
   44    format('[11] Muat skenario contoh~n', []),
   45    format('[12] Export hasil aktif ke JSON~n', []),
   46    format('[0] Keluar~n~n', []),
   47    read_choice(Choice),
   48    dispatch(Choice, Current, Next, Continue),
   49    ( Continue == yes -> menu_loop(Next) ; true ).
   50
   51read_choice(C) :-
   52    format('Pilih: '), flush_output,
   53    read_line_to_string(user_input, S0), normalize_space(string(S), S0),
   54    ( catch(number_string(C0, S), _, fail) -> C=C0 ; C = -1 ).
   55
   56dispatch(1, S0, S, yes) :- !, guided(S0, S), run_and_pause(S).
   57dispatch(2, S0, S, yes) :- !, advanced(S0, S), run_and_pause(S).
   58dispatch(3, S, S, yes) :- !, run_and_pause(S).
   59dispatch(4, S, S, yes) :- !, timeline_screen(S), ap_ui:pause.
   60dispatch(5, S, S, yes) :- !, ap_compare:compare_responses(S, Rs), ap_report:print_comparison(Rs), ap_ui:pause.
   61dispatch(6, S, S, yes) :- !, save_screen(S), ap_ui:pause.
   62dispatch(7, S0, S, yes) :- !, load_screen(S0, S), ap_ui:pause.
   63dispatch(8, S, S, yes) :- !, ap_audit:show_audit, ap_ui:pause.
   64dispatch(9, S, S, yes) :- !, methodology_screen, ap_ui:pause.
   65dispatch(10, S, S, yes) :- !, evaluate_screen, ap_ui:pause.
   66dispatch(11, S0, S, yes) :- !, example_screen(S0, S), run_and_pause(S).
   67dispatch(12, S, S, yes) :- !, export_screen(S), ap_ui:pause.
   68dispatch(0, S, S, no) :- !, format('dadah. jangan lupa: kritik kebijakan ≠ kriminal. 💀~n', []).
   69dispatch(_, S, S, yes) :- format('Pilihan tidak dikenal.~n', []), ap_ui:pause.
   70
   71run_and_pause(S) :-
   72    ap_model:score(S, R),
   73    ap_report:print_report(R),
   74    catch(ap_audit:record_report(R), E, print_message(warning, E)),
   75    ap_ui:pause.
   76
   77guided(S0, S) :-
   78    ap_ui:prompt_string('Nama skenario', S0.name, Name),
   79    scope_options(ScopeOpts), ap_ui:prompt_choice('Skala isu', ScopeOpts, 2, Scope),
   80    issue_options(IssueOpts), ap_ui:prompt_choice('Jenis isu', IssueOpts, 5, Issue),
   81    target_options(TargetOpts), ap_ui:prompt_choice('Target tuntutan', TargetOpts, 1, Target),
   82    ap_ui:prompt_string('Sub-isu singkat', S0.subissue, Sub),
   83    ap_ui:prompt_string('Provinsi', S0.province, Province),
   84    ap_ui:prompt_string('Kota/lokasi umum (tanpa alamat pribadi)', S0.city, City),
   85    ap_ui:prompt_number('Akumulasi keluhan', 0,100,S0.grievance,Grievance),
   86    ap_ui:prompt_number('Kekuatan pemicu', 0,100,S0.trigger,Trigger),
   87    ap_ui:prompt_number('Kepentingan/salience isu',0,100,S0.salience,Salience),
   88    ap_ui:prompt_number('Dukungan publik pada tuntutan',0,100,S0.public_support,Support),
   89    ap_ui:prompt_number('Momentum daring',0,100,S0.online,Online),
   90    ap_ui:prompt_number('Responsivitas/dialog pemerintah',0,100,S0.govt_responsiveness,Resp),
   91    ap_ui:prompt_number('Kualitas bukti input',0,100,S0.evidence_quality,Q),
   92    put_dict(_{name:Name,scope:Scope,issue:Issue,target:Target,subissue:Sub,province:Province,city:City,
   93               grievance:Grievance,trigger:Trigger,salience:Salience,public_support:Support,online:Online,
   94               govt_responsiveness:Resp,evidence_quality:Q}, S0, S).
   95
   96advanced(S0, S) :-
   97    guided(S0, G),
   98    advanced_pairs([
   99      coalition-'Kekuatan koalisi', organization-'Kapasitas organisasi',
  100      economic_stress-'Tekanan ekonomi', institutional_distrust-'Ketidakpercayaan institusional',
  101      incident_shock-'Insiden pemicu tambahan', recent_precedent-'Preseden aksi terbaru',
  102      media_attention-'Perhatian media', regional_relevance-'Relevansi lintas wilayah',
  103      govt_communication-'Kualitas komunikasi pemerintah', organizer_control-'Disiplin/kontrol penyelenggara',
  104      intervention_pressure-'Tekanan/intervensi terhadap aksi'
  105    ], G, S1),
  106    ap_ui:prompt_number('Durasi skenario (hari)',1,365,S1.duration_days,Days),
  107    ap_ui:prompt_number('Populasi area (juta)',0.01,300,S1.population_millions,Pop),
  108    ap_ui:prompt_number('Seed simulasi',1,2147483647,S1.seed,Seed),
  109    notify_options(NOpts), ap_ui:prompt_choice('Status pemberitahuan aksi', NOpts, 3, Notified),
  110    put_dict(_{duration_days:Days,population_millions:Pop,seed:Seed,notified:Notified}, S1, S).
  111
  112advanced_pairs([], S, S).
  113advanced_pairs([Key-Label|Xs], S0, S) :-
  114    get_dict(Key, S0, Default),
  115    ap_ui:prompt_number(Label,0,100,Default,V),
  116    put_dict(Key, S0, V, S1),
  117    advanced_pairs(Xs, S1, S).
  118
  119scope_options(Opts) :- findall(I-V-T, (ap_defaults:scope(I,V), atom_string(V,T)), Opts).
  120issue_options(Opts) :- findall(I-V-T, (ap_defaults:issue(I,V), atom_string(V,T)), Opts).
  121target_options(Opts) :- findall(I-V-T, (ap_defaults:target(I,V), atom_string(V,T)), Opts).
  122notify_options([1-yes-'Ya',2-no-'Tidak',3-unknown-'Tidak diketahui']).
  123
  124timeline_screen(S) :-
  125    ap_simulation:timeline(S, 7, Reports, Events),
  126    format('~nTIMELINE 7 HARI (seed deterministik ~w)~n', [S.seed]),
  127    print_days(Reports, 0),
  128    format('~nEvent drift:~n', []), forall(member(E, Events), format(' - ~w~n',[E])).
  129
  130print_days([], _).
  131print_days([R|Rs], Day) :-
  132    format('Hari +~w: likelihood ~w | spread ~w | escalation ~w | ~w~n',
  133           [Day,R.likelihood,R.spread,R.escalation,R.predicted_state]),
  134    D1 is Day+1, print_days(Rs,D1).
  135
  136save_screen(S) :-
  137    ap_ui:prompt_string('Nama file', 'skenario', F),
  138    catch((ap_io:save_scenario(F,S), format('Tersimpan.~n',[])), E, print_message(error,E)).
  139
  140load_screen(_S0, S) :-
  141    ap_ui:prompt_string('File skenario', 'skenario.ap.pl', F),
  142    catch(ap_io:load_scenario(F,S1), E, (print_message(error,E), fail)), !, S=S1.
  143load_screen(S, S).
  144
  145
  146example_screen(_S0, S) :-
  147    Options = [
  148      1-'scenario_bbm.ap.pl'-'BBM / tekanan ekonomi',
  149      2-'scenario_ukt.ap.pl'-'UKT / pendidikan',
  150      3-'scenario_integritas.ap.pl'-'Integritas / antikorupsi'
  151    ],
  152    ap_ui:prompt_choice('Pilih skenario contoh', Options, 1, Base),
  153    example_file(Base, File),
  154    catch(ap_io:load_scenario(File, S1), E, (print_message(error,E), fail)), !,
  155    S = S1.
  156example_screen(S, S).
  157
  158example_file(Base, File) :-
  159    source_file(ap_cli:start, Here),
  160    file_directory_name(Here, PrologDir),
  161    file_directory_name(PrologDir, PackDir),
  162    directory_file_path(PackDir, examples, ExamplesDir),
  163    directory_file_path(ExamplesDir, Base, File).
  164
  165export_screen(S) :-
  166    ap_model:score(S, R),
  167    ap_ui:prompt_string('Nama file JSON', 'hasil-antisipasipejabat', F),
  168    catch((ap_io:export_report_json(F, R), format('Hasil diekspor ke JSON.~n', [])),
  169          E, print_message(error,E)).
  170
  171methodology_screen :-
  172    format('~nMETODOLOGI SINGKAT~n', []),
  173    format('- Model v0.1 = weighted explainable heuristic, belum diklaim terkalibrasi.~n', []),
  174    format('- Memisahkan likelihood, spread, escalation, pressure, confidence.~n', []),
  175    format('- Turnout memakai bucket, bukan jumlah presisi.~n', []),
  176    format('- Tidak ada profiling individu, daftar aktivis, rute, atau rekomendasi penindakan.~n', []),
  177    ap_legal:legal_summary,
  178    ap_reference:print_references.
  179
  180evaluate_screen :-
  181    ap_ui:prompt_string('CSV historis', 'examples/historical_synthetic.csv', F),
  182    cli_evaluate(F).
  183
  184cli_evaluate(File) :-
  185    catch((ap_calibration:evaluate_csv(File,S), ap_calibration:print_evaluation(S)), E, print_message(error,E)).
  186
  187cli_simulate_file(File) :-
  188    catch((ap_io:load_scenario(File,S), ap_model:score(S,R), ap_report:print_report(R)), E, print_message(error,E)).
  189
  190help :-
  191    format('Antisipasi Pejabat v0.1.0.0~n', []),
  192    format('  swipl antisipasipejabat              # menu interaktif~n', []),
  193    format('  swipl antisipasipejabat --help       # bantuan~n', []),
  194    format('  swipl antisipasipejabat --version    # versi~n', []),
  195    format('  swipl antisipasipejabat simulate FILE.ap.pl~n', []),
  196    format('  swipl antisipasipejabat evaluate FILE.csv~n', [])