package aplicare import ( "encoding/json" "os" "time" ) // RoomSnapshot adalah snapshot nilai per ruangan type RoomSnapshot struct { Kapasitas int `json:"kapasitas"` Tersedia int `json:"tersedia"` TersediaPria int `json:"tersedia_pria"` TersediaWanita int `json:"tersedia_wanita"` TersediaPriaWanita int `json:"tersedia_pria_wanita"` } // RoomState adalah state per ruangan dengan perbandingan old vs new type RoomState struct { KodeRuang string `json:"kode_ruang"` KodeKelas string `json:"kodekelas"` NamaRuang string `json:"nama_ruang"` OldValue RoomSnapshot `json:"old_value"` NewValue RoomSnapshot `json:"new_value"` Changed bool `json:"changed"` LastSynced string `json:"last_synced"` } // State adalah struktur utama state.json type State struct { LastUpdated string `json:"last_updated"` Rooms map[string]RoomState `json:"rooms"` // key: kode_ruang } // LoadState membaca state.json dari disk // Mengembalikan empty State (bukan error) jika file belum ada func LoadState(path string) (*State, error) { data, err := os.ReadFile(path) if os.IsNotExist(err) { return &State{Rooms: make(map[string]RoomState)}, nil } if err != nil { return nil, err } var state State if err := json.Unmarshal(data, &state); err != nil { return nil, err } if state.Rooms == nil { state.Rooms = make(map[string]RoomState) } return &state, nil } // SaveState menulis state ke disk func SaveState(path string, state *State) error { state.LastUpdated = time.Now().Format(time.RFC3339) data, err := json.MarshalIndent(state, "", " ") if err != nil { return err } return os.WriteFile(path, data, 0644) } // ComputeDiff membandingkan data SIMRS terbaru dengan state lama. // Mengembalikan state baru dengan field Changed=true hanya untuk yang berubah. func ComputeDiff(old *State, current []BedData) *State { newState := &State{ Rooms: make(map[string]RoomState), } now := time.Now().Format(time.RFC3339) for _, bed := range current { newSnap := RoomSnapshot{ Kapasitas: bed.Kapasitas, Tersedia: bed.Tersedia, TersediaPria: bed.TersediaPria, TersediaWanita: bed.TersediaWanita, TersediaPriaWanita: bed.TersediaPriaWanita, } oldRoom, exists := old.Rooms[bed.KodeRuang] oldSnap := oldRoom.NewValue if !exists { oldSnap = RoomSnapshot{} } changed := !snapshotEqual(oldSnap, newSnap) // Kalau sebelumnya sudah ada lastSynced, pertahankan lastSynced := oldRoom.LastSynced if changed { lastSynced = now } newState.Rooms[bed.KodeRuang] = RoomState{ KodeRuang: bed.KodeRuang, KodeKelas: bed.KodeKelas, NamaRuang: bed.NamaRuang, OldValue: oldSnap, NewValue: newSnap, Changed: changed, LastSynced: lastSynced, } } return newState } // GetChangedBeds mengembalikan hanya BedData yang berubah dari state func GetChangedBeds(state *State, allBeds []BedData) []BedData { changedMap := make(map[string]bool) for kode, room := range state.Rooms { if room.Changed { changedMap[kode] = true } } var changed []BedData for _, bed := range allBeds { if changedMap[bed.KodeRuang] { changed = append(changed, bed) } } return changed } func snapshotEqual(a, b RoomSnapshot) bool { return a.Kapasitas == b.Kapasitas && a.Tersedia == b.Tersedia && a.TersediaPria == b.TersediaPria && a.TersediaWanita == b.TersediaWanita && a.TersediaPriaWanita == b.TersediaPriaWanita }