function Changes_runner(changes, opts) {
	var self = this;	
	this._changes = changes;
	this._running = 0;
	this._timeoutid = 0;
	var defaults = { 'update_freq' : 10000 };
	this._opts = jQuery.extend({}, defaults, opts);
}

Changes_runner.prototype._update = function () {
	this._changes.update();
	this._set_new_update();	
}

Changes_runner.prototype._set_new_update = function () {
	var self = this;
	if (this._running && this._opts['update_freq']) {
		this._timeoutid = setTimeout( function () { self._update(); }, this._opts['update_freq']);
	}
}

Changes_runner.prototype.start = function () {
	if (this._running == 0) {
		this._running = 1;
		this._update();
	}
}

Changes_runner.prototype.stop = function () {
	if (this._running) {	
		this._running = 0;
		clearTimeout(this._timeoutid);
	}
}


function Changes(servers) {
	if (servers) {
		this._servers = {};
		this._servers['async'] = servers[0];
		this._servers['sync'] = servers[1];
	}
	this._listeners = [];
	this.init_data();
}

Changes.VERSION = 1002;

Changes.prototype.get_sync_srv = function () { 
	return this._servers['sync']; 
}
Changes.prototype.get_async_srv = function () { 
	return this._servers['async']; 
}

Changes.prototype.get_last_update = function () { return this._last_update; }
Changes.prototype.set_last_update = function (lu) { this._last_update = lu; }
Changes.prototype.get_pevts = function () { return this._pevts; }
Changes.prototype.set_pevts = function (pevts) { this._pevts = pevts; }
Changes.prototype.get_data = function () { return this._data; }
Changes.prototype.set_data = function (data) { this._data = data; }

Changes.prototype._handle_error = function (err) {
	throw err;
}

Changes.prototype.add_listener = function (listener) {
	this._listeners.push(listener);
}
	
Changes.prototype.call_listeners = function (data) {
	for (var i=0; i < this._listeners.length; ++i) {
		this._listeners[i](data);
	}
}

Changes.prototype.init_data = function () {
	this._pevts = {};
	this._data = {};
	this._last_update = 0;
}

Changes.prototype.update = function () {
}

Changes.prototype._handle_data = function (data) {
	if ((data == null || typeof(data) != "object") || data.length < 2) {
		this._handle_error("data format");
	}
	if (data[0] < 0) {
		if (data[1] == "timeout") {
			console.log("timeout");
			return;
		}
		this._handle_error(data[1]);
	}
	if (data.length != 3) {
		this._handle_error(data[1]);
	}

	var ver = data[2];
	if (ver != Changes.VERSION) {
		this._handle_error("version: " + ver);
	}
	
	// data: status, updata|errmsg
	// upddata: lu, cdata
	var upddata = data[1];
	var lu = upddata[0];
	var cdata = upddata[1];
	this.set_last_update(lu);
	this._update_data(cdata);
	this.call_listeners(cdata);			
}

Changes.prototype._update_data = function (data) {

}

Changes.prototype._update_missing_pevts = function (peids) {
	var newpeids = {};    
	var npevts = 0;    // new peid count 
	for (var i in peids) {
		var peid = peids[i];
		if (!this._pevts[peid]) {
			 newpeids[peid] = 1;
			++npevts;
		}
	}	
	if (npevts > 0) {
		var pevts = this.get_sync_srv().get_pevts(newpeids);
		if (pevts[0] >= 0) {
			var pevtdata = pevts[1];
			for (var peid in pevtdata) {
				this._pevts[peid] = pevtdata[peid];
			}
		}
		else {	
			// pevt[1]: error message	
			this._handle_error(pevts[1]);
		}
	}
	return npevts;
}	

function Changes_screen(changes, opts) {
	if (changes) {
		var self = this;
		this._opts = opts || {};
		
		this._changes = changes;
		this._changes.add_listener(function (data) {
			self.update(data);
		});
		this._container = null;
	}
}

Changes_screen.prototype.get_changes = function () { return this._changes; }

Changes_screen.prototype.set_opts = function (opts) {
	jQuery.extend(this._opts, opts);
}

Changes_screen.prototype.get_opts = function () {
	return this._opts;
}

Changes_screen.prototype.attach_container = function (p) {
	this._container = p;
}

Changes_screen.prototype.get_container = function () {
	return this._container;
}

Changes_screen.prototype.create = function () {
}

Changes_screen.prototype.refresh = function () {
}

Changes_screen.prototype.update = function (data) {
}


function Peid_ot_changes_screen(changes, opts) {
	Changes_screen.apply(this, [ changes, opts ]);
}

extend(Peid_ot_changes_screen, Changes_screen);

Peid_ot_changes_screen.prototype._find_row = function (peid, ot) {
	return document.getElementById(this._get_row_id(peid, ot));
}

Peid_ot_changes_screen.prototype._get_row_id = function (peid, ot) {
	return "omvt_" + peid + "_" + ot;
}

Peid_ot_changes_screen.prototype._get_peid_ot = function (id) {
	if (id.search(/^omvt_(\d+)_(\d+)$/) != -1) {
		var peid = RegExp.$1;
		var ot = RegExp.$2;
		return [ peid, ot ];
	}
	return 0;
}

Peid_ot_changes_screen.prototype._get_row_data = function (id) {
	if ((d = this._get_peid_ot(id))) {
		var cdata = this._changes._data;
		if (cdata[d[0]] && cdata[d[0]][d[1]])
			return cdata[d[0]][d[1]]; 
	}	
	return 0;
}


