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

angular.module("aconf").directive("aconfWidget", function(aconfErrorFormat) {
    return {
	restrict: "E",
	scope: {field: "=", formField: "="},
	templateUrl: "directive/widget.html"
    };
}).directive("aconfField", function(aconfErrorFormat) {
    return {
	restrict: "A",
	transclude: true,
	scope: {field: "=aconfField"},
	require: ["^^aconfLayout", "^^aconfNode"],
	link: {
	    pre: function(scope, element, attrs, ctrl, transclude) {
		var layout = ctrl[0];
		var node = ctrl[1];

		scope.name = scope.field.name;
		scope.condition = scope.field.meta.condition;

		var data = node.data;
		scope.value = data.get(scope.name);
		scope.status = function() { return data.status(scope.name); };
		scope.delete = function() {
		    layout.updateRequest(data.delete(scope.name));
		};

		transclude(scope, function(clone) { element.append(clone); });
	    }
	},
	controller: function($scope) {
	    Object.defineProperty(this, "scope", {get: function() {
		return $scope;
	    }});
	    this.setError = function(resp) {
		$scope.error = resp ? aconfErrorFormat(resp) : null;
	    };
	}
    };
}).directive("aconfSync", function($q, aconfErrorFormat, aconfExclusive) {
    return {
	restrict: "C",
	require: ["^^aconfField", "^^aconfLayout", "^^aconfNode", "ngModel"],
	link: function(scope, element, attrs, ctrl) {
	    var field = ctrl[0];
	    var layout = ctrl[1];
	    var node = ctrl[2];
	    var model = ctrl[3];

	    var data = node.data;

	    function getStatus() { return data.status(scope.name); }

	    switch (getStatus()) {
	    case "invalid":
		model.$setValidity("aconf", false);
		break;
	    case "changed":
		model.$setDirty();
	    }

	    var initial = true;
	    model.$asyncValidators.aconf = function(modelValue, viewValue) {
		if (aconfExclusive.isRunning) return $q.when();

		var value = modelValue || viewValue;
		if (value === "") value = null;
		else if (value instanceof Date)
		    value = value.toISOString().substring(0, 10);

		var def;

		if (initial && getStatus() != "invalid" && !scope.condition)
		    def = $q.when(null);

		else if (scope.set)
		    def = value ? data.add(scope.name) :
		    data.delete(scope.name);

		else def = data.set(scope.name, value);

		initial = false;

		def.then(function(txnValid) {
		    field.setError();
		    if (!data.status(scope.name)) model.$setPristine();
		    if (txnValid != null) {
			layout.validationReady(txnValid);
			node.updated(scope.name);
		    }

		}, function(resp) {
		    field.setError(resp);
		    layout.validationReady(false);
		});

		return def;
	    }
	}
    };
}).directive("aconfBasicInput", function() {
    return {
	restrict: "E",
	transclude: true,
	templateUrl: "directive/basic-input.html"
    };
}).directive("aconfDelButton", function() {
    return {
	restrict: "E",
	scope: {},
	templateUrl: "directive/del-button.html",
	require: "?^^aconfField",
	link: function(scope, element, attrs, ctrl) {
	    if (ctrl && ctrl.scope.field.removable) scope.delete = ctrl.scope.delete;
	}
    };
}).directive("aconfError", function() {
    return {restrict: "E", templateUrl: "directive/error.html"};

}).directive("aconfInput", function() {
    return {
	restrict: "E", transclude: true, templateUrl: "directive/input.html"
    };

}).directive("aconfAudio", function() {
    return {
	restrict: "E",
	scope: true,
	templateUrl: "directive/audio.html",
	require: "^^aconfLayout",
	link: function(scope, element, attrs, ctrl) {
	    scope.play = function() {
		ctrl.query(scope.value).then(function(data) {
		    element.html($("<audio>").attr({
			src: data.data, autoplay: true, controls: true
		    }));
		});
	    };
	}
    };
}).directive("aconfDate", function() {
    return {
	restrict: "E",
	scope: true,
	templateUrl: "directive/date.html",
	link: {
	    pre: function(scope) {
		scope.value = new Date(scope.value);
		scope.opened = false;
		scope.open = function(event) {
		    event.preventDefault();
		    event.stopPropagation();
		    scope.opened = true;
		}
	    }
	}
    };
}).directive("aconfLink", function() {
    return {
	restrict: "E",
	scope: {label: "@", path: "=", status: "="},
	templateUrl: "directive/link.html"
    };
}).directive("aconfSelect", function() {
    return {
	restrict: "E",
	templateUrl: "directive/select.html",
	link: {
	    pre: function(scope, element) {
		scope.choices = _.filter(scope.field.meta.choice, function(ch) {
		    return ch.enabled || ch.value == scope.value;
		});
		if (!scope.field.meta.required || !scope.value)
		    scope.choices.unshift({value: null, "ui-value": "(none)"});
	    }
	}
    };
});
