/*
 * Copyright (c)  2006-2007 Maskat Project.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
maskat.lang.Class.declare("maskat.event.ResponseUnmarshaller", {

	initialize: function(){
		this.soap = false;
		this.ns = "";
		this.rootNode = null;
		this.targets = [];
		this.configured = false;
	},

	unmarshal: function(doc, layout) {
		if (!this.configured) {
			this.configure();
		}

		for (var i = 0; i < this.targets.length; i++) {
			var target = this.targets[i];
			switch (target.type) {
			case "local":
				/* ローカルデータバインディングを実行 */
				var src = layout.getWidget(target.node);
				var value;
				if (src) {
					value = src.getValue();
				} else {
					value = layout.getVariable(target.node);
				}
				
				var dst = layout.getWidget(target.widgetId);
				if (target.workType) {
					var arg1 = src ? src.getWidget() : value;
					var arg2 = dst ? dst.getWidget() : layout.getVariable(target.widgetId);
					target.workType(arg1, arg2);
				} else {
					if (dst) {
						dst.setValue(value);
					} else {
						layout.setVariable(target.widgetId, value);
					}
				}
				break;

			case "remote":
				/* 応答メッセージのバインディングを実行 */
				var values = doc ? target.read(doc) : null;
				var widget = layout.getWidget(target.widgetId);
				if (widget) {
					widget.setValue(values[i], target.teleType);
				} else {
					layout.setVariable(target.widgetId, values[i]);
				}
				break;
			}
		}
	},

	configure: function() {
		this.configured = true;

		for (var i = 0; i < this.targets.length; i++) {
			var target = this.targets[i];
			if (target.type == "local") {
				continue;
			}
			
			if (this.soap) {
				// TODO: add soap envelope
			} else {
				target.setRootElement(this.ns, this.rootNode);
			}
	
			/* 応答メッセージのルート要素に対応するバインディングを生成 */
			var root = target.addElementBinding(this.ns, this.rootNode);

			var wrapper;
			if (target.node) {
				/*
				 * アンマーシャル対象のデータはルート要素の子要素 (wrapper) の
				 * 内部に格納されている
				 */
				wrapper = target.addElementBinding(this.ns, target.node);
				root.addChildBinding(target.node);
				root.addChildBinding("*", { validate: false });
			} else {
				/* アンマーシャル対象のデータはルート要素の内部に格納されている */
				wrapper = root;
			}
	
			var object;
			if (target.childNode) {
				/*
				 * 繰り返し要素が定義されている場合、繰り返し単位となる個々の
				 * 要素をオブジェクトへバインドし、それらを要素とする配列を
				 * マスカット部品または変数にバインドする
				 */
				object = target.addElementBinding(this.ns, target.childNode);
				wrapper.addChildBinding(target.childNode, { property: i, repeat: true });
				wrapper.addChildBinding("*", { validate: false });
			} else if (target.binds) {
				/*
				 * 繰り返し要素は未定義だが、プロパティへのバインドが定義されて
				 * いる場合、単一のオブジェクトへのバインドを定義
				 */
				root.addChildBinding(target.node, { property: i });
				object = wrapper;
			} else {
				/* テキスト要素から文字列へのバインドを定義 */
				wrapper.addChildBinding("#text", { property: i });
				object = null;
			}
	
			if (object && target.binds) {
				/* オブジェクトのプロパティへのバインドを定義 */
				for (var j = 0; j < target.binds.length; j++) {
					var bind = target.binds[j];
					var property = target.addElementBinding(this.ns, bind.node);
					property.addChildBinding("#text", { property: bind.property });
					object.addChildBinding(bind.node);
				}
				object.addChildBinding("*", { validate: false });
			}
		}
	}

});
