cid_app/lib/cid_data_manager.dart
2026-05-02 12:00:02 +02:00

335 lines
No EOL
16 KiB
Dart

import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
import 'global_data.dart';
import 'models.dart';
class CidDataManager {
// ===========================================================================
// METODI PER SCAMBIO DATI (QR/P2P)
// ===========================================================================
static Map<String, dynamic> estraiDatiPerExport() {
String lato = GlobalData.latoCorrente;
String val(String vA, String vB, String l) => l == 'A' ? vA : vB;
bool valB(bool bA, bool bB, String l) => l == 'A' ? bA : bB;
return {
'lato': lato,
'generali': {
'data': GlobalData.dataIncidente,
'ora': GlobalData.ora,
'luogo': GlobalData.luogo,
'feriti': GlobalData.feriti,
'testimoni': GlobalData.testimoni,
'danni_materiali': GlobalData.veicoliDanniMaterialiOltre,
'oggetti_diversi': GlobalData.oggettiDiversiDanniMateriali,
},
'circostanze': _serializeCircostanze(lato == 'A' ? GlobalData.circostanzeA : GlobalData.circostanzeB),
'punti_urto': lato == 'A' ? GlobalData.puntiUrtoA_List : GlobalData.puntiUrtoB_List,
// CASSETTO 1: GRAFICO INCIDENTE (Strade, Auto)
'grafico': {
'tratti_dinamica': GlobalData.tratti.map((t) => t.toMap()).toList(),
'elementi_dinamica': GlobalData.elementi.map((e) => e.toMap()).toList(),
},
// CASSETTO 2: FIRMA (Dati grafici personali)
'firma': _serializePunti(lato == 'A' ? GlobalData.puntiFirmaA : GlobalData.puntiFirmaB),
'contraente': {
'cognome': val(GlobalData.cognomeContraenteA, GlobalData.cognomeContraenteB, lato),
'nome': val(GlobalData.nomeContraenteA, GlobalData.nomeContraenteB, lato),
'cf': val(GlobalData.codiceFiscaleContraenteA, GlobalData.codiceFiscaleContraenteB, lato),
'indirizzo': val(GlobalData.indirizzoContraenteA, GlobalData.indirizzoContraenteB, lato),
'cap': val(GlobalData.capContraenteA, GlobalData.capContraenteB, lato),
'stato': val(GlobalData.statoContraenteA, GlobalData.statoContraenteB, lato),
'tel': val(GlobalData.nTelefonoMailContraenteA, GlobalData.nTelefonoMailContraenteB, lato),
'email': val(GlobalData.emailContraenteA, GlobalData.emailContraenteB, lato),
},
'veicolo': {
'marca': val(GlobalData.marcaETipoA, GlobalData.marcaETipoB, lato),
'targa': val(GlobalData.targaA, GlobalData.targaB, lato),
'stato_imm': val(GlobalData.statoImmatricolazioneA, GlobalData.statoImmatricolazioneB, lato),
'stato_imm2': val(GlobalData.statoImmatricolazione2A, GlobalData.statoImmatricolazione2B, lato),
'rimorchio': val(GlobalData.rimorchioA, GlobalData.rimorchioB, lato),
},
'assicurazione': {
'denominazione': val(GlobalData.denominazioneA, GlobalData.denominazioneB, lato),
'polizza': val(GlobalData.numeroPolizzaA, GlobalData.numeroPolizzaB, lato),
'agenzia': val(GlobalData.agenziaA, GlobalData.agenziaB, lato),
'denom_agenzia': val(GlobalData.denominazioneAgenziaA, GlobalData.denominazioneAgenziaB, lato),
'indirizzo_agenzia': val(GlobalData.indirizzoAgenziaA, GlobalData.indirizzoAgenziaB, lato),
'stato_agenzia': val(GlobalData.statoAgenziaA, GlobalData.statoAgenziaB, lato),
'tel_agenzia': val(GlobalData.nTelMailAgenziaA, GlobalData.nTelMailAgenziaB, lato),
'carta_verde': val(GlobalData.nCartaVerdeA, GlobalData.nCartaVerdeB, lato),
'validita_dal': val(GlobalData.dataInizioDalA, GlobalData.dataInizioDalB, lato),
'validita_al': val(GlobalData.dataScadenzaAlA, GlobalData.dataScadenzaAlB, lato),
'flag_danni': valB(GlobalData.flagDanniMatAssicuratiA, GlobalData.flagDanniMatAssicuratiB, lato),
},
'conducente': {
'cognome': val(GlobalData.cognomeCondA, GlobalData.cognomeCondB, lato),
'nome': val(GlobalData.nomeCondA, GlobalData.nomeCondB, lato),
'nascita': val(GlobalData.dataNascitaCondA, GlobalData.dataNascitaCondB, lato),
'cf': val(GlobalData.codFiscaleCondA, GlobalData.codFiscaleCondB, lato),
'indirizzo': val(GlobalData.indirizzoCondA, GlobalData.indirizzoCondB, lato),
'stato': val(GlobalData.statoCondA, GlobalData.statoCondB, lato),
'tel': val(GlobalData.nTelMailCondA, GlobalData.nTelMailCondB, lato),
'email': val(GlobalData.emailCondA, GlobalData.emailCondB, lato),
'patente': val(GlobalData.nPatenteCondA, GlobalData.nPatenteCondB, lato),
'cat_patente': val(GlobalData.categoriaCondA, GlobalData.categoriaCondB, lato),
'scad_patente': val(GlobalData.scadenzaCondA, GlobalData.scadenzaCondB, lato),
},
'danni_osservazioni': {
'visibili': val(GlobalData.danniVisibiliA, GlobalData.danniVisibiliB, lato),
'osservazioni': val(GlobalData.osservazioniA, GlobalData.osservazioniB, lato),
}
};
}
static void importaDati(Map<String, dynamic> data) {
String latoRemoto = data['lato'] ?? 'B';
// 1. Dati Comuni
if (data['generali'] != null) {
var gen = data['generali'];
if ((gen['data'] ?? "").isNotEmpty) GlobalData.dataIncidente = gen['data'];
if ((gen['ora'] ?? "").isNotEmpty) GlobalData.ora = gen['ora'];
if ((gen['luogo'] ?? "").isNotEmpty) GlobalData.luogo = gen['luogo'];
if (gen['feriti'] != null) GlobalData.feriti = gen['feriti'];
if (gen['testimoni'] != null) GlobalData.testimoni = gen['testimoni'];
if (gen['danni_materiali'] != null) GlobalData.veicoliDanniMaterialiOltre = gen['danni_materiali'];
if (gen['oggetti_diversi'] != null) GlobalData.oggettiDiversiDanniMateriali = gen['oggetti_diversi'];
}
// --- PROTEZIONE GRAFICO (CASSETTO 1) ---
// Solo se i dati arrivano da A, permettiamo di sovrascrivere il grafico comune.
// Se arrivano da B, IGNORIAMO questa chiave (così il disegno di A resta intatto).
if (latoRemoto == 'A' && data['grafico'] != null) {
var graf = data['grafico'];
if (graf['tratti_dinamica'] != null) {
List<dynamic> listRaw = graf['tratti_dinamica'];
GlobalData.tratti = listRaw.map((x) => TrattoPenna.fromMap(x)).toList();
}
if (graf['elementi_dinamica'] != null) {
List<dynamic> listRaw = graf['elementi_dinamica'];
GlobalData.elementi = listRaw.map((x) => ElementoGrafico.fromMap(x)).toList();
}
}
// --- PROTEZIONE FIRMA (CASSETTO 2) ---
// La firma NON viene bloccata. Ognuno ha la sua firma e deve poterla inviare.
// Viene salvata in variabili distinte (puntiFirmaA e puntiFirmaB).
if (data['firma'] != null) {
List<Offset?> puntiFirma = _deserializePunti(data['firma']);
if (latoRemoto == 'A') GlobalData.puntiFirmaA = puntiFirma;
else GlobalData.puntiFirmaB = puntiFirma; // Qui B salva la sua firma
}
// 3. Circostanze
if (data['circostanze'] != null) {
Map<int, bool> mappaCirc = fixCircostanze(data['circostanze']);
if (latoRemoto == 'A') GlobalData.circostanzeA = mappaCirc;
else GlobalData.circostanzeB = mappaCirc;
}
// 4. Punti Urto
if (data['punti_urto'] != null) {
List<String> puntiRecuperati = List<String>.from(data['punti_urto']);
if (latoRemoto == 'A') {
GlobalData.puntiUrtoA_List = puntiRecuperati;
} else {
GlobalData.puntiUrtoB_List = puntiRecuperati;
}
}
void setVal(Function(String) setA, Function(String) setB, dynamic val) {
if (val == null) return;
if (latoRemoto == 'A') setA(val.toString()); else setB(val.toString());
}
void setBool(Function(bool) setA, Function(bool) setB, dynamic val) {
if (val == null) return;
if (latoRemoto == 'A') setA(val as bool); else setB(val as bool);
}
if (data['contraente'] != null) {
var c = data['contraente'];
setVal((v) => GlobalData.cognomeContraenteA = v, (v) => GlobalData.cognomeContraenteB = v, c['cognome']);
setVal((v) => GlobalData.nomeContraenteA = v, (v) => GlobalData.nomeContraenteB = v, c['nome']);
setVal((v) => GlobalData.codiceFiscaleContraenteA = v, (v) => GlobalData.codiceFiscaleContraenteB = v, c['cf']);
setVal((v) => GlobalData.indirizzoContraenteA = v, (v) => GlobalData.indirizzoContraenteB = v, c['indirizzo']);
setVal((v) => GlobalData.capContraenteA = v, (v) => GlobalData.capContraenteB = v, c['cap']);
setVal((v) => GlobalData.statoContraenteA = v, (v) => GlobalData.statoContraenteB = v, c['stato']);
setVal((v) => GlobalData.nTelefonoMailContraenteA = v, (v) => GlobalData.nTelefonoMailContraenteB = v, c['tel']);
setVal((v) => GlobalData.emailContraenteA = v, (v) => GlobalData.emailContraenteB = v, c['email']);
}
if (data['veicolo'] != null) {
var v = data['veicolo'];
setVal((v) => GlobalData.marcaETipoA = v, (v) => GlobalData.marcaETipoB = v, v['marca']);
setVal((v) => GlobalData.targaA = v, (v) => GlobalData.targaB = v, v['targa']);
setVal((v) => GlobalData.statoImmatricolazioneA = v, (v) => GlobalData.statoImmatricolazioneB = v, v['stato_imm']);
setVal((v) => GlobalData.statoImmatricolazione2A = v, (v) => GlobalData.statoImmatricolazione2B = v, v['stato_imm2']);
setVal((v) => GlobalData.rimorchioA = v, (v) => GlobalData.rimorchioB = v, v['rimorchio']);
}
if (data['assicurazione'] != null) {
var a = data['assicurazione'];
setVal((v) => GlobalData.denominazioneA = v, (v) => GlobalData.denominazioneB = v, a['denominazione']);
setVal((v) => GlobalData.numeroPolizzaA = v, (v) => GlobalData.numeroPolizzaB = v, a['polizza']);
setVal((v) => GlobalData.agenziaA = v, (v) => GlobalData.agenziaB = v, a['agenzia']);
setVal((v) => GlobalData.denominazioneAgenziaA = v, (v) => GlobalData.denominazioneAgenziaB = v, a['denom_agenzia']);
setVal((v) => GlobalData.indirizzoAgenziaA = v, (v) => GlobalData.indirizzoAgenziaB = v, a['indirizzo_agenzia']);
setVal((v) => GlobalData.statoAgenziaA = v, (v) => GlobalData.statoAgenziaB = v, a['stato_agenzia']);
setVal((v) => GlobalData.nTelMailAgenziaA = v, (v) => GlobalData.nTelMailAgenziaB = v, a['tel_agenzia']);
setVal((v) => GlobalData.nCartaVerdeA = v, (v) => GlobalData.nCartaVerdeB = v, a['carta_verde']);
setVal((v) => GlobalData.dataInizioDalA = v, (v) => GlobalData.dataInizioDalB = v, a['validita_dal']);
setVal((v) => GlobalData.dataScadenzaAlA = v, (v) => GlobalData.dataScadenzaAlB = v, a['validita_al']);
setBool((v) => GlobalData.flagDanniMatAssicuratiA = v, (v) => GlobalData.flagDanniMatAssicuratiB = v, a['flag_danni']);
}
if (data['conducente'] != null) {
var c = data['conducente'];
setVal((v) => GlobalData.cognomeCondA = v, (v) => GlobalData.cognomeCondB = v, c['cognome']);
setVal((v) => GlobalData.nomeCondA = v, (v) => GlobalData.nomeCondB = v, c['nome']);
setVal((v) => GlobalData.dataNascitaCondA = v, (v) => GlobalData.dataNascitaCondB = v, c['nascita']);
setVal((v) => GlobalData.codFiscaleCondA = v, (v) => GlobalData.codFiscaleCondB = v, c['cf']);
setVal((v) => GlobalData.indirizzoCondA = v, (v) => GlobalData.indirizzoCondB = v, c['indirizzo']);
setVal((v) => GlobalData.statoCondA = v, (v) => GlobalData.statoCondB = v, c['stato']);
setVal((v) => GlobalData.nTelMailCondA = v, (v) => GlobalData.nTelMailCondB = v, c['tel']);
setVal((v) => GlobalData.emailCondA = v, (v) => GlobalData.emailCondB = v, c['email']);
setVal((v) => GlobalData.nPatenteCondA = v, (v) => GlobalData.nPatenteCondB = v, c['patente']);
setVal((v) => GlobalData.categoriaCondA = v, (v) => GlobalData.categoriaCondB = v, c['cat_patente']);
setVal((v) => GlobalData.scadenzaCondA = v, (v) => GlobalData.scadenzaCondB = v, c['scad_patente']);
}
if (data['danni_osservazioni'] != null) {
var d = data['danni_osservazioni'];
setVal((v) => GlobalData.danniVisibiliA = v, (v) => GlobalData.danniVisibiliB = v, d['visibili']);
setVal((v) => GlobalData.osservazioniA = v, (v) => GlobalData.osservazioniB = v, d['osservazioni']);
}
}
// ===========================================================================
// METODI PER SALVATAGGIO CLOUD (FIREBASE)
// ===========================================================================
static Future<String> salvaDati(String sessionId, String lato) async {
final docRef = FirebaseFirestore.instance.collection('scambi_cid').doc(sessionId);
// Estrae tutti i dati dalla memoria locale
Map<String, dynamic> datiExport = estraiDatiPerExport();
// Prepariamo i dati da inviare al server
Map<String, dynamic> updateData = {
'generali': datiExport['generali'],
'lato_$lato': {
...datiExport['contraente'],
...datiExport['veicolo'],
...datiExport['assicurazione'],
...datiExport['conducente'],
'danni_visibili': datiExport['danni_osservazioni']['visibili'],
'osservazioni': datiExport['danni_osservazioni']['osservazioni'],
'circostanze': datiExport['circostanze'],
'punti_urto': datiExport['punti_urto'],
'firma': datiExport['firma'], // <-- La firma è dentro "lato_A" o "lato_B", quindi è al sicuro
'completo': true,
},
'timestamp': FieldValue.serverTimestamp(),
};
// --- PROTEZIONE AGGIUNTIVA PER IL CLOUD ---
// Il GRAFICO lo aggiorniamo nel DB solo se siamo il LATO A.
// Il LATO B non ha diritto di toccare questa chiave.
if (lato == 'A') {
updateData['grafico'] = datiExport['grafico'];
}
await docRef.set(updateData, SetOptions(merge: true));
return sessionId;
}
// --- METODO RECUPERA DATI CLOUD ---
static Future<void> caricaDati(String sessionId, String latoDaCaricare) async {
final doc = await FirebaseFirestore.instance.collection('scambi_cid').doc(sessionId).get();
if (!doc.exists) return;
final data = doc.data()!;
Map<String, dynamic> datiDaImportare = {};
datiDaImportare['lato'] = latoDaCaricare;
if (data['generali'] != null) datiDaImportare['generali'] = data['generali'];
if (data['grafico'] != null) datiDaImportare['grafico'] = data['grafico'];
if (data['lato_$latoDaCaricare'] != null) {
Map<String, dynamic> latoData = data['lato_$latoDaCaricare'];
datiDaImportare['contraente'] = latoData;
datiDaImportare['veicolo'] = latoData;
datiDaImportare['assicurazione'] = latoData;
datiDaImportare['conducente'] = latoData;
datiDaImportare['danni_osservazioni'] = {
'visibili': latoData['danni_visibili'],
'osservazioni': latoData['osservazioni'],
};
datiDaImportare['circostanze'] = latoData['circostanze'];
datiDaImportare['punti_urto'] = latoData['punti_urto'];
datiDaImportare['firma'] = latoData['firma']; // Recupera la firma specifica dal lato
}
importaDati(datiDaImportare);
}
// ===========================================================================
// HELPER SERIALIZZAZIONE
// ===========================================================================
static Map<String, bool> _serializeCircostanze(Map<int, bool> circ) {
return circ.map((key, value) => MapEntry(key.toString(), value));
}
static List<Map<String, double>> _serializePunti(List<Offset?> punti) {
List<Map<String, double>> res = [];
for (var p in punti) {
if (p != null) res.add({'dx': p.dx, 'dy': p.dy});
}
return res;
}
static List<Offset?> _deserializePunti(dynamic lista) {
if (lista is! List) return [];
return lista.map<Offset?>((item) {
if (item == null) return null;
return Offset((item['dx'] as num).toDouble(), (item['dy'] as num).toDouble());
}).toList();
}
static Map<int, bool> fixCircostanze(dynamic rawData) {
Map<int, bool> mappaCirc = {};
if (rawData == null) return mappaCirc;
if (rawData is List) {
// Firebase ha convertito le chiavi intere in un array
for (int i = 0; i < rawData.length; i++) {
if (rawData[i] != null) {
mappaCirc[i] = rawData[i] as bool;
}
}
} else if (rawData is Map) {
// È rimasta una mappa
rawData.forEach((k, v) {
if (v != null) {
mappaCirc[int.tryParse(k.toString()) ?? 0] = v as bool;
}
});
}
return mappaCirc;
}
}