function CONFIG_CUSTOM(custom_props) {
    if (typeof custom_props != "undefined") {
	for (i in custom_props) {
	    this[i] = custom_props[i];
	}
    }
}

function CONFIG_CONFIG(custom_props) {
    this.db_server = null;
    this.db_name = null;
    this.db_group = null;
    this.control_group = null;
    this.db_mask = null;

    this.experiment = "0-0";
    this.window = "0";
    
    this.width = 0;
    this.height = 0;
    
    this.aggregation = null;
    this.interpolate = null;
    this.show_marks = null;
    this.show_gaps = null;
    
    this.virtual = null;
    this.srctree = null;
    
    this.pageid = null;
    
    this.module = null;
    
    this.custom = new CONFIG_CUSTOM(custom_props);

}

function CONFIG_EXTRA(custom_props) {
    this.format = null;
    this.resample = null;
    this.mask_mode = null;
    
    this.custom = new CONFIG_CUSTOM(custom_props);
}

CONFIG_CONFIG.prototype.Clone = function(skip_custom) {
    if (typeof skip_custom == "undefined") skip_custom = false;
    
    var res = new Object;
    for (i in this) {
	if ((this[i])&&(typeof this[i] == "object")) {
	    if (!skip_custom) {
	        res[i] = objectClone(this[i]);
	    }
	} else {
	    res[i] = this[i];
	}
    }
    return res;
}

function CONFIG() {
    this.custom_props = new Object;	/* Array causes problems here, due to 'in' cycling over its methods */
    this.custom_extra = new Object;

    this.cfg = new CONFIG_CONFIG(this.custom_props);
    this.cfg_extra = new CONFIG_EXTRA(this.custom_extra);
    
    this.win_width = 0;
    this.win_from = 0;
    this.win_to = 0;
    this.win_min = 0;
    this.win_max = 0;
    
    this.sel_from = 0;
    this.sel_to = 0;

    this.confirmed = 0;
    this.initializing = true;
    this.ready = false;

    this.objlist = new Array;
    
    this.history = new HISTORY(this.HistoryEvent(this));
}

CONFIG.prototype.RegisterUpdater = function(updater) {
    // DS: Multiple updaters support
    this.updater = updater;
}

CONFIG.prototype.Register = function(obj) {
    this.objlist.push(obj);
}

CONFIG.prototype.RegisterCustomProperty = function (property, default_value, extra) {
    if (typeof extra == "undefined") extra = false;
    
    if (typeof default_value == "undefined") {
	if (extra) {
	    if (typeof this.custom_extra[property] == "undefined") {
		this.custom_extra[property] = null;
	    }
	} else {
	    if (typeof this.custom_props[property] == "undefined") {
		this.custom_props[property] = null;
	    }
	}
    } else {
	if (extra) this.custom_extra[property] = default_value;
	else this.custom_props[property] = default_value;
    }
}


CONFIG.prototype.SetSource = function(server, db, group, cgroup, mask) {
    this.cfg.db_server  = server;
    this.cfg.db_name = db;
    this.cfg.db_group = group;
    this.cfg.control_group = cgroup;
    this.cfg.db_mask = mask;
}



CONFIG.prototype.SetInterval = function(from, to) {
    this.cfg.experiment = from + '-' + to;
}

CONFIG.prototype.SetWindow = function(width, from, to, miny, maxy) {
    if (width<0) {
	this.win_width = -1;
	
	if (miny != maxy) {
	    this.win_min = miny;
	    this.win_max = maxy;
	}
	if (from != to) {
	    this.win_from = from;
	    this.win_to = to;
	}
	
    	if ((this.win_from!=this.win_to)&&(this.win_min!=this.win_max)) {
	    this.cfg.window = this.win_from + '-' + this.win_to + ',' + this.win_min + ':' + this.win_max;
	} else if (this.win_min!=this.win_max) {
	    this.cfg.window = this.win_min + ':' + this.win_max;
	} else if (this.win_from!=this.win_to) {
	    this.cfg.window = this.win_from + '-' + this.win_to;
	} else {
	    this.win_width = 0;
	    this.cfg.window = 0;
	}
    } else {
	this.win_width = width;

	this.win_from = 0;
	this.win_to = 0;
	this.win_min = 0;
	this.win_max = 0;

	this.cfg.window = width;
    }
}

CONFIG.prototype.SetSelection = function(from, to) {
    if (typeof from == "undefined") {
	this.sel_from = 0;
	this.sel_to = 0;
    } else {
	this.sel_from = from;
	this.sel_to = to;
    }
}


CONFIG.prototype.SetExportSettings = function(format, resample, mask_mode) {
    if (format) this.cfg_extra.format = format;
    if (resample) this.cfg_extra.resample = resample;
    if (mask_mode) this.cfg_extra.mask_mode = mask_mode;
    
    this.updater.Notify("ExportSettings");
}


CONFIG.prototype.SetAggregationSettings = function(a, i, marks, gaps) {
    if (a) this.cfg.aggregation = a;
    if (i) this.cfg.interpolate = i;
    if (marks) this.cfg.show_marks = marks;
    if (gaps) this.cfg.show_gaps = gaps;
}


CONFIG.prototype.SetVirtualSettings = function(mode, settings) {
    if (mode) {
	this.cfg.virtual = mode;
	eval("this.cfg." + mode + "=settings");
    } else {
	this.cfg.virtual = null;
    }
}


CONFIG.prototype.SetWikiSettings = function(pageid) {
    this.cfg.pageid = pageid;
}

CONFIG.prototype.ParseWindow = function(winprm) {
    var win;
    
    if (typeof win == "undefined") win = this.cfg.window;
    else win = winprm;

    if (isNaN(win)) {
	this.win_width = -1;
	
	this.win_from = 0;
	this.win_to = 0;
	this.win_min = 0;
	this.win_max = 0;
	
	var err = false;
	var p = win.split(",");
	
	if ((p.legth < 1)||(p.length > 2)) err = true;
	else {
	    var process = function(self, prm) {

		var t = prm.split(":");

		if (t.length == 2) {
		    if ((isNaN(t[0]))||(isNaN(t[1]))) return true;
		    else {
			self.win_min = t[0];
			self.win_max = t[1];
		    }
		} else {
		    t = prm.split("-");

		    if ((t.length == 2)&&(t[0].length>0)) {
			if ((isNaN(t[0]))||(isNaN(t[1]))) return true;
			else {
			    self.win_from = t[0];
			    self.win_to = t[1];
			}
		    } else return true;
		}
		return false;
	    }
	    
	    err = process(this, p[0]);
	    if ((!err)&&(p.length == 2)) err = process(this, p[1]);
	}
		
	
	if (err) {
	    this.win_width = 0;
	    adeiReportError(translate("Invalid window \"%s\" is specified",win));
	}
    } else {
        this.win_width = win;

	this.win_from = 0;
	this.win_to = 0;
	this.win_min = 0;
	this.win_max = 0;
    }
    
    if (typeof win != "undefined") {
	this.SetWindow(this.win_width, this.win_from, this.win_to, this.min, this.max);
    }
}

CONFIG.prototype.ApplyConfig = function(save_on_apply, filter) {
    this.ParseWindow();

//    this.onConfirmation = this.UpdateAndSaveFunction(this, save_on_apply, filter);

    var len = this.objlist.length;
    for (var i = 0; i < len; i++) {
	var obj = this.objlist[i];
//	if (typeof obj.ReadConifg == "function") {	// DS: Comparison fails in Firefox
	if (obj.ReadConfig) {
		//confirm: true,
	    var opts = new Object({
		reset: true,
		success_cb: this.UpdateAndSaveFunction(this, save_on_apply, filter)
	    });

	    if (!this.ready) opts.reload = true;
	    
	    if (typeof filter != "undefined")
		eval("if (obj instanceof " + filter + ") obj.ReadConfig(opts);");
	    else 
		obj.ReadConfig(opts);
	}
    }

//    if (this.updater) this.updater.Update();
}


CONFIG.prototype.UpdateAndSaveFunction = function(self, save_on_apply, filter) {
    return function() {
	var len = self.objlist.length;
	for (var i = 0; i < len; i++) {
	    var obj = self.objlist[i];
	    if (obj.ApplyConfig) {
		if (typeof filter != "undefined")
		    eval("if (obj instanceof " + filter + ") obj.ApplyConfig(true);");
		else 
		    obj.ApplyConfig(true);
	    }
	}
	
	if (self.cfg.module) adei.OpenModule(self.cfg.module);

	if (self.updater) self.updater.Update();
	if (save_on_apply) self.Save();
    }
}

/*
CONFIG.prototype.UpdateFunction = function(self) {
    return function() {
	if (self.updater) self.updater.Update();
    }
}
*/

CONFIG.prototype.SetupGeometry = function(node, y) {
	/* correction in IE required */
    if (typeof node == "object") {
	this.cfg.width = node.offsetWidth;
	this.cfg.height = node.offsetHeight;
    } else {
	this.cfg.width = node;
	this.cfg.height = y;
    }
}

/*
CONFIG.prototype.Setup = function(src, ivl, wnd) {
    with (this) {
	SetSource(src.db_server, src.db_name, src.db_group, src.db_mask);
	SetInterval(ivl.start, ivl.end);
	SetWindow(wnd.width, wnd.from, wnd.to, wnd.miny, wnd.maxy);
    }
}
*/


CONFIG.prototype.SetupModule = function(m) {
    if (m != this.cfg.module) {
	if (this.cfg.module) {
	    this.cfg.module = m;
	    this.Save();
	} else {
	    this.cfg.module = m;
	}
    }
}

CONFIG.prototype.GetModule = function() {
    return this.cfg.module;
}

CONFIG.prototype.GetConfig = function() {
    return this.cfg;
}

CONFIG.prototype.GetJSON = function(addon) {
    var res = this.cfg.Clone(true);
    Object.extend(res, this.cfg.custom);
    Object.extend(res, this.cfg_extra);
    Object.extend(res, this.cfg_extra.custom); res.custom = null;
    if (typeof addon != "undefined") Object.extend(res, addon);
    return Object.toJSON(res);

/*
    if (typeof addon == "undefined") return Object.toJSON(this.cfg);
    else return Object.toJSON(Object.extend(this.cfg.Clone(), addon));
*/
}

CONFIG.prototype.GetProps = function(window_type) {
    var res;

    //if (!(cfg instanceof CONFIG_CONFIG)) cfg = this.cfg;

    with (this.cfg) {
	var win = this.cfg.window;
	if (typeof window_type != "undefined") {
	    if (window_type > 0) {
		win = "0";
	    } else if (window_type < 0) {
		if (this.sel_from != this.sel_to) 
		    win = this.sel_from + "-" + this.sel_to;
		else 
		    adeiReportError("The selection is empty. Storing full window", "CONFIG");
	    }
	}
	
	res = "";
	if (this.cfg.module) {
	    res += "module=" + this.cfg.module + "&";
	}
	
	if (this.cfg.pageid) {
	    res += "pageid=" + this.cfg.pageid + "&";
	}
	
	if (db_server) {
	    res += "db_server=" + this.cfg.db_server + "&db_name=" + this.cfg.db_name + "&db_group=" + this.cfg.db_group + "&control_group=" + this.cfg.control_group + "&db_mask=" + this.cfg.db_mask + "&experiment=" + this.cfg.experiment + "&window=" + win;
	    if (this.cfg.aggregation) res += "&aggregation=" + this.cfg.aggregation;
	    if (this.cfg.interpolate) res += "&interpolate=" + this.cfg.interpolate;
	    if (this.cfg.show_marks) res += "&show_gaps=" + this.cfg.show_marks;
	    if (this.cfg.show_gaps) res += "&show_gaps=" + this.cfg.show_gaps;
	    if (this.cfg.module) res+= "&module=" + this.cfg.module;
	    if (this.cfg.virtual) {
		res += "&virtual=" + this.cfg.virtual;
//		alert(this.cfg.virtual);
		if (this.cfg.virtual) {
		    eval("res += \"&\" + this.cfg.virtual + \"=\" + this.cfg." + this.cfg.virtual);
		}
	    }
	} else {
	    res += "no_source";
	}
    }

    with (this.cfg_extra) {
	if (format) res += "&format=" + format;
	if (resample) res += "&resample=" + resample;
	if (mask_mode) res += "&mask_mode=" + mask_mode;
    }
    
    for (var i in this.cfg.custom) {
	if (typeof this.cfg.custom[i] != "object") {
	    res += "&" + i + "=" + this.cfg.custom[i];
	}
    }

    for (var i in this.cfg_extra.custom) {
	if (typeof this.cfg.custom[i] != "object") {
	    res += "&" + i + "=" + this.cfg_extra.custom[i];
	}
    }
    
    return res;
}

CONFIG.prototype.ParseProps = function(props, partial, register_custom) {
    var cfg;
    var extra;
    var done = false;
    
    if (typeof partial == "undefined") partial = false;
    if (typeof register_custom == "undefined") register_custom = false;
    
    if (partial) {
	cfg = objectClone(this.cfg);
	extra = objectClone(this.cfg_extra);

	if (/db_server=/.exec(props)) {
	    cfg.db_name = null;
	    cfg.db_group = null;
	    cfg.control_group = null;
	    cfg.db_mask = null;
	} else if (/db_name=/.exec(props)) {
	    cfg.db_group = null;
	    cfg.control_group = null;
	    cfg.db_mask = null;
	} else if (/db_group=/.exec(props)) {
	    cfg.db_mask = null;
	}
	
	if (/experiment=/.exec(props)) {
	    cfg.window = "0";
	}
    } else {
	cfg = new CONFIG_CONFIG(this.custom_props);
	extra = new CONFIG_EXTRA(this.custom_extra);
    }
    
    
    var vars = props.split("&");

    for (var i = 0; i < vars.length; i++) {
	var pair = vars[i].split("=",2);
	if (pair.length != 2) continue;
	
	if (typeof cfg[pair[0]] != "undefined") {
	    cfg[pair[0]] = pair[1];
	    done = true;
	} else if (typeof extra[pair[0]] != "undefined") {
	    extra[pair[0]] = pair[1];
	    done = true;
	} else if (typeof cfg.custom[pair[0]] != "undefined") {
	    cfg.custom[pair[0]] = pair[1];
	    done = true;
	} else if (typeof extra.custom[pair[0]] != "undefined") {
	    extra.custom[pair[0]] = pair[1];
	    done = true;
	} else if (register_custom) {
	    this.RegisterCustomProperty(pair[0]);
	    
	    if (typeof this.custom_props[pair[0]] != "undefined") {
		cfg.custom[pair[0]] = pair[1];
	    } else {
	        extra.custom[pair[0]] = pair[1];
	    }

	    done = true;
	}
    }
    
      // overriding 
    cfg['width'] = this.cfg.width;
    cfg['height'] = this.cfg.height;
    
    if (done) return new Object({'cfg': cfg, 'extra': extra});
    return false;
}


CONFIG.prototype.Save = function() {
    if ((this.cfg)&&(this.history)) {
	this.history.Add(this.GetProps(), this.cfg.Clone());
    }
}

CONFIG.prototype.FixLocation = function(props, hid) {
    if ((this.cfg)&&(this.history)) {
	if (typeof props == "undefined") {
	    var props = this.history.GetProps();
	    
	    if (typeof hid == "undefined")
		var hid = this.history.GetID();
	}
	    
	var new_props = this.GetProps();
	if (props != new_props) this.history.ReplaceLocation(new_props, props, hid);
    }
}

CONFIG.prototype.ReplaceURL = function() {
    this.FixLocation();
}

CONFIG.prototype.ReplaceConfig = function() {
    if ((this.cfg)&&(this.history)) {
/*	
	history.back(); // prevent complains from history module???
	var props = this.history.GetProps();
	var new_props = this.GetProps();
	
    	this.history.Replace(props, new_props, this.cfg.Clone());*/
	adeiReportError(translate('ReplaceConfig is not supported, yet'));
    }
}

CONFIG.prototype.HistoryEvent = function (self) {
    return function (newLocation, historyData, historyID) {
	if ((!historyData)||(typeof historyData.Clone != "function")) {
	    //return self.Load();
	    return;
	}
	
	self.cfg = historyData.Clone();
        self.FixLocation(newLocation, historyID);
	self.ApplyConfig();
    }
}

CONFIG.prototype.Load = function(props, partial, register_custom) {
    if (typeof props == "undefined") {
	props = this.history.GetProps();
    }

    if (props) {
	if (typeof partial == "undefined") partial = false;
	if (typeof register_custom == "undefined") register_custom = false;
	
	var cfg = this.ParseProps(props, partial, register_custom);
	if (cfg) {
		/*  This should come first, otherwise the problems in IE6 will
		arise! */
	    if (this.cfg.module) {
		adei.module.Open(this.cfg.module);
	    }

	    if (cfg.cfg.db_server) {
	        this.cfg = cfg.cfg;
		this.cfg_extra = cfg.extra;
		
	        adei.SetStatus(translate("Loading..."), 0);
		this.ApplyConfig(true);
	    } else {
		var have_custom = false;
		for (var i in cfg.cfg.custom) {
		    have_custom = true;
		    break;
		}
		if (!have_custom) {
		    for (var i in cfg.cfg.custom) {
			have_custom = true;
			break;
		    }
		}
		
		if (have_custom) {
	    	    this.cfg = cfg.cfg;
		    this.cfg_extra = cfg.extra;
		
	    	    adei.SetStatus(translate("Loading..."), 0);
		    this.ApplyConfig(true);
		}
	    }
	}
    }
}


CONFIG.prototype.ApplyDataSource = function(srv, db, grp, cgrp, mask, exp) {
    if (typeof srv != "undefined") {
	this.cfg.db_server = srv;
    } else this.cfg.db_server = null;

    if (typeof db != "undefined") {
	this.cfg.db_name = db;
    } else this.cfg.db_name  = null;
    
    if (typeof grp != "undefined") {
	this.cfg.db_group = grp;
    } else this.cfg.db_group  = null;

    if (typeof cgrp != "undefined") {
	this.cfg.control_group = cgrp;
    } else this.cfg.control_group  = null;

    if (typeof mask != "undefined") {
	this.cfg.db_mask = mask;
    } else this.cfg.db_mask  = null;

    if (typeof exp != "undefined") {
	this.cfg.experiment = exp;
	this.cfg.window = "0";
    } /* keeping otherwise */
    

    this.ApplyConfig(true, "SOURCE");
}


/*
CONFIG.prototype.RequestConfirmation = function(onConfirm) {
    if (this.onConfirmation) {
	if (this.onConfirmation == onConfirm) return 1;
	return 2;
    }
    this.onConfirmation = onConfirm;
    return 0;
}
*/

CONFIG.prototype.Confirm = function(me, val) {
/* 
	    BEWARE: 
	    SOURCE can confirm WINDOW with val=2 
	    INTERVAL can confirm WINDOW with val=1

    if (me instanceof SOURCE) this.confirmed |= (1<<val);
    else if (me instanceof INTERVAL) this.confirmed |= 4;
    else if (me instanceof WINDOW) this.confirmed |= 4;
*/

    if (me instanceof SOURCE) this.confirmed |= 1;

    if ((this.confirmed&1)==1) {
	this.confirmed = 0;

	if (this.initializing) {
	    this.ready = true;
	    this.initializing = false;

	    adei.SetStatus(translate("Ready..."), 0);
	    this.Load();
	} else if (this.onConfirmation) {
	    var func = this.onConfirmation;
	    this.onConfirmation = null;
	    func();
	}
    }
}

function configSetupModule(config, m) {
    config.SetupModule(m);
}

