blob: 4291f118be5629b1664a9806e0abfc9d99c7012d [file] [log] [blame]
// Copyright 2015 The Vanadium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
import 'dart:async';
import 'dart:convert' show JSON;
enum SimulLevel { turnBased, independent, dependent }
typedef void KeyValueCallback(String key, String value);
class LogWriter {
LogWriter(this.updateCallback, this.users);
final KeyValueCallback updateCallback;
final List<int> users;
String logPrefix; // This can be completely ignored.
bool inProposalMode = false;
int associatedUser;
int _fakeTime = 0;
int _getNextTime() {
_fakeTime++;
return _fakeTime;
}
Map<String, String> _data = new Map<String, String>();
Future onChange(String rowKey, String value, bool duringScan) async {}
void write(SimulLevel s, String value) {
assert(!inProposalMode);
String key = _logKey(associatedUser);
if (s == SimulLevel.dependent) {
// We have to do extra work with "proposals".
inProposalMode = true;
String proposalData = JSON.encode({"key": key, "value": value});
_data[_proposalKey(associatedUser)] = proposalData;
// FAKE: Do some bonus work. Where "everyone else" accepts the proposal.
for (int i = 0; i < users.length; i++) {
if (users[i] != associatedUser) {
_data[_proposalKey(users[i])] = proposalData;
_receiveProposal(proposalData);
}
}
return;
}
_writeData(key, value);
}
// Helper that returns the log key using a mixture of timestamp + user.
String _logKey(int user) {
int ms = _getNextTime();
String key = "$ms-$user";
return key;
}
// Helper that writes data to the "store" and calls the update callback.
void _writeData(String key, String value) {
_data[key] = value;
updateCallback(key, value);
}
// Helper that handles a proposal update for a user.
void _receiveProposal(String proposalData) {
assert(inProposalMode);
// First check if something is already in data.
var pKey = _proposalKey(associatedUser);
String pData = _data[pKey];
if (pData != null) {
// Potentially change your proposal, if that person has higher priority.
Map<String, String> pp = JSON.decode(pData);
Map<String, String> op = JSON.decode(proposalData);
String keyP = pp["key"];
String keyO = op["key"];
if (keyO.compareTo(keyP) < 0) {
// Then switch proposals.
_data[pKey] = proposalData;
}
} else {
// Otherwise, you have no proposal, so take theirs.
_data[pKey] = proposalData;
}
// Given these changes, check if you can commit the full batch.
if (_checkIsProposalDone()) {
Map<String, String> pp = JSON.decode(pData);
String key = pp["key"];
String value = pp["value"];
// WOULD DO A BATCH!
_writeData(key, value);
for (int i = 0; i < users.length; i++) {
_data.remove(_proposalKey(users[i]));
}
inProposalMode = false;
}
}
// More helpers for proposals.
String _proposalKey(int user) {
return "proposal$user";
}
bool _checkIsProposalDone() {
assert(inProposalMode);
String theProposal;
for (int i = 0; i < users.length; i++) {
String altProposal = _data[_proposalKey(users[i])];
if (altProposal == null) {
return false;
} else if (theProposal != null && theProposal != altProposal) {
return false;
}
theProposal = altProposal;
}
return true;
}
}