/*
 * Copyright (c) 2012-2014 Kaarle Ritvanen
 * See LICENSE file for license details
 */

define(
    ["aconf/dom", "aconf/error", "jquery", "underscore"],
    function(dom, formatError, $, _) {
	return {
	    extend: function(spec) {
		var res = Object.create(this);
		for (key in spec) res[key] = spec[key];
		return res;
	    },

	    new: function(data, name, meta, level, editable, removable) {
		return Object.create(this).init(
		    data, name, meta, level, editable, removable
		);
	    },

	    init: function(data, name, meta, level, editable, removable) {
		this.data = data;
		this.name = name;
		this.meta = meta;
		this.level = level;

		function appendRemoveButton(el) {
		    if (removable) {
			var link = dom.href().click(function() {
			    data.delete(name).done(function(txnValid) {
				$("#content").trigger("reload", [txnValid]);
			    })
			}).text("Delete");
			el = dom.makeRow(el);
			if (el.is("tr")) link = $("<td>").html(link);
			el.append(link);
		    }

		    return el;
		}

		var value = data.get(name);

		if (!editable || !meta.editable) {
		    var el = this.staticRender(value, meta);
		    if (el) {
			el = appendRemoveButton(el);

			_.each(["start", "updated"], function(event) {
			    el.on(event, function(event) {
				event.stopPropagation();
			    });
			});
			dom.setStatus(el, data.status(name));
			return el;
		    }
		}

		this.makeEl();
		this.dynamic = meta.dynamic;
		this.visible = true;

		this.wrapped = appendRemoveButton(this.wrap());
		this.wrapped.data("description", meta.description);

		this.handleResponse(this.requestData(value, meta));

		var self = this;

		function validate() {
		    self.request.done(function(value) {
			self.validate(value);
		    });
		}

		this.wrapped.on("start", function(event) {
		    if (data.status(name) == "invalid") validate();
		    else self.setVisible();
		    event.stopPropagation();
		});

		this.wrapped.on("updated", function(event, field) {
		    if (self.dynamic) self.refresh();
		    if (!field ||
			self.dynamic ||
			(meta.condition && field in meta.condition))
			validate();
		    event.stopPropagation();
		});

		return this.wrapped;
	    },

	    makeEl: function() { this.el = this.createEl();	},

	    requestData: function(value, meta) {
		return $.Deferred().resolve(value, meta);
	    },

	    refreshData: function() {
		var def = $.Deferred();
		var self = this;
		this.data.metaRequest(this.name).done(function(data) {
		    def.resolve(self.get(), data);
		});
		return def;
	    },

	    handleResponse: function(request) {
		this.request = request;
		var self = this;
		request.done(function(value, meta) {
		    if (request != self.request) return;
		    self.render(value, meta);
		    self.updateStatus();
		});
	    },

	    refresh: function() { this.handleResponse(this.refreshData()); },

	    wrap: function() { return this.el; },

	    updateStatus: function() {
		this.setStatus(this.data.status(this.name));
	    },

	    showStatus: true,

	    setStatus: function(status) {
		if (this.el && this.showStatus)
		    dom.setStatus(this.statusEl(), status);
	    },

	    statusEl: function() { return this.el; },

	    setVisible: function() {
		this.visible = this.data.match(this.meta.condition);
		if (this.wrapped)
		    this.wrapped.trigger("setVisible", [this.visible]);
	    },

	    validate: function(value) { this.setVisible(); },

	    formatValidationError: function(xhr) {
		if (_.isString(xhr)) return xhr;

		if (xhr.statusCode().status == 422)
		    return _.values($.parseJSON(xhr.responseText)).join("\n");

		return formatError("Error", xhr);
	    }
	};
    }
);
