import * as Context from "@terrencecrowley/context";
import * as LogAbstract from "@terrencecrowley/logabstract";

interface TestEnv { context: Context.IContext, log: LogAbstract.ILog };

import * as OT from "../lib/ottypes";
import * as OTC from "../lib/otcomposite";
import * as OTA from "../lib/otarray";
import * as OTEngine from "../lib/otclientengine";
import * as OTTestServer from "./ottestserver";

export class OTTestClient
{
	env: TestEnv;
	engine: OTEngine.OTClientEngine;
	server: OTTestServer.OTTestServer;
	clientSequenceNo: number;

	// construct
	constructor(env: TestEnv, clientID: string)
		{
			this.env = env;
			this.engine = new OTEngine.OTClientEngine(env.log, '1', clientID);
			this.clientSequenceNo = 0;
		}

	get clientID(): string
		{
			return this.engine.clientID;
		}

	setServer(server: OTTestServer.OTTestServer)
		{
			this.server = server;
		}

	checkForSend(): void
		{
			if (! this.engine.isNeedAck && this.engine.isPending())
				this.server.receive(this.engine.getPending());
		}

	receiveRemoteAction(edit: OTC.OTCompositeResource): void
		{
			// Process this remote event
			this.engine.addRemote(edit);
			this.checkForSend();
		}

	receiveLocalAction(edit: OTC.OTCompositeResource): void
		{
			this.engine.addLocalEdit(edit);
			this.checkForSend();
		}

	tick(): void
		{
			let edit: OTC.OTCompositeResource = new OTC.OTCompositeResource('1', this.clientID);
			let stringEdit: OTA.OTStringResource = new OTA.OTStringResource('text');
			let curState = (this.toValue())['text'];
			let nCur: number = curState ? curState.length : 0;
			stringEdit.generateRandom(nCur, edit.clientID);
			edit.clock = this.engine.serverClock();
			edit.clientSequenceNo = this.clientSequenceNo++;
			edit.edits.push(stringEdit);
			this.receiveLocalAction(edit);
		}

	toValue(): any
		{
			return this.engine.toValue();
		}
};
