/*
 * 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.layout.Widget", {

	/**
	 * コンストラクタ
	 */
	initialize: function(){
		this.parent = null;
		this.children = null;
		this.tabIndex = -1;
	},

	/**
	 * このマスカット部品を格納しているレイアウトを取得します。
	 *
	 * マスカット部品はツリー構造を持ち、レイアウトはそのルート要素
	 * となるノードです。
	 *
	 * @return このマスカット部品を格納しているレイアウト
	 */
	getLayout: function(){
		var parent = this.getParent();
		return parent ? parent.getLayout() : null;
	},
	
	/**
	 * このマスカット部品の親となるマスカット部品を取得します。
	 *
	 * @return このマスカット部品の親となるマスカット部品
	 */
	getParent: function(){
		return this.parent;
	},
	
	/**
	 * このマスカット部品の親となるマスカット部品を設定します。
	 *
	 * @param parent このマスカット部品の親となるマスカット部品
	 */
	setParent: function(parent){
		this.parent = parent;
	},
	
	/**
	 * このマスカット部品に子ノードとなるマスカット部品を追加します。
	 *
	 * @param parent 子ノードとなるマスカット部品
	 */
	addChild: function(child){
		if (!this.children) {
			this.children = [];
		}
		this.children.push(child);
		child.setParent(this);
	},

	/**
	 * このマスカット部品の子ノードの配列を取得します。
	 *
	 * @return このマスカット部品の子ノードの配列
	 */
	getChildren: function(){
		return this.children;
	},

	/**
	 * このマスカット部品の部品 ID を取得します。部品 ID はレイアウト内で
	 * 一意の値となる必要があります。
	 *
	 * @return このマスカット部品の部品 ID
	 */
	getWidgetId: function(){
		return null;
	},

	/**
	 * このマスカット部品が参照している Ajax 部品を返します。
	 *
	 * @return このマスカット部品が参照している Ajax 部品
	 */
	getWidget: function(){
		return null;
	},

	/**
	 * このマスカット部品が参照する Ajax 部品を生成し、その Ajax 部品への
	 * 参照を返します。
	 *
	 * @param このマスカット部品の親となるマスカット部品
	 *
	 * @return 生成した Ajax 部品
	 */
	createWidget: function(parent) {
		return null;
	},

	/**
	 * Ajax 部品を生成後の後処理を行います。
	 */
    postCreateWidget: function() {
    },

	/**
	 * このマスカット部品が使用しているリソースを開放します。
	 */
	dispose: function() {
		maskat.lang.Object.dispose(this);
	},

	/**
	 * このマスカット部品が参照している HTML 要素を返します。
	 *
	 * @return このマスカット部品が参照している HTML 要素
	 */
	getElement: function(){
		return null;
	},
	
	/**
	 * このマスカット部品に含まれるコントロール要素を返します。
	 *
	 * コントロール要素は HTML DOM 要素のうち、以下のいずれかのクラスに属する
	 * ものです。
	 *
	 *  - HTMLAnchorElement
	 *  - HTMLInputElement
	 *  - HTMLSelectElement
	 *  - HTMLTextAreaElement
	 *
	 * 詳細については「Document Object Model (DOM) Level 2 Specification」を
	 * 参照してください。
	 * http://www.w3.org/TR/2000/CR-DOM-Level-2-20000510/html.html 
	 *
	 * @return このマスカット部品に含まれるコントロール要素
	 */
	getControlElement: function(){
		return null;
	},
	
	/**
	 * このマスカット部品が保持しているデータ値を取得します。
	 *
	 * @return このマスカット部品が保持しているデータ値
	 */
	getValue: function(){
		return this.value;
	},
	
	/**
	 * このマスカット部品にデータ値を格納します。
	 *
	 * @param value このマスカット部品に格納するデータ値
	 */
	setValue: function(value){
		this.value = value;
	},
	
	/**
	 * このマスカット部品にデータ値をリセットします。
	 */
	clear: function(){
		delete this.value;
	},
	
	/**
	 * このマスカット部品に対するキーイベントを処理します。
	 *
	 * @param event キーイベント
	 *
	 * @return 部品がキーイベントを処理した場合は false、それ以外は true
	 */
	handleKeyEvent: function(event){
		return true;
	},
	
	/**
	 * このマスカット部品にフォーカスを設定します。
	 */
	setFocus: function(){
	},
	
	/**
	 * このマスカット部品のフォーカス移動が可能かを返します。
	 *
	 * @return 部品にフォーカスを移動できる場合はtrue、できない場合はfalse
	 */
	canFocus: function() {
	    return this.tabIndex > -1 && this.isEnabled();
    },
    
    /**
     * このマスカット部品が表示されているかを返します。
     *
     * @return 部品が表示されている場合はtrue、非表示の場合はfalse
     */
    isEnabled: function() {
		return true;
    },
    
    /**
     * このマスカット部品の表示、非表示を定義します。
     *
     * @param enable 表示の場合true、非表示の場合false
     */
    setEnabled: function(enable) {
	},
	
	/**
	 * このマスカット部品にキーイベントリスナを設定します。
	 *
	 * @param element イベントリスナを定義するエレメント
	 */
	addKeyEventListener: function(element){
		element._layoutId = this.getLayout().getWidgetId();
		element._widgetName = this.name;
		
		maskat.util.CrossBrowser.addEventListener(element, "keydown",
			maskat.key.KeyEventManager.getInstance().handle);
	},
	
	/**
	 * このマスカット部品のタブインデックスを返します。
	 *
	 * @return タブインデックス
	 */
	getTabIndex: function() {
		return this.tabIndex;
	},
	
	/**
	 * このマスカット部品のタブインデックスグループ名を返します。
	 *
	 * @return タブインデックスグループ名
	 */
	getTabIndexGroupName: function() {
		return this.tabIndexGroupName;
	},
	
	/**
	 * このマスカット部品で発生したイベントをリスナに通知します。
	 *
	 * @param eventType イベントタイプ
	 */
	notifyEvent: function(eventType) {
		var layout = this.getLayout();
		var event = new maskat.event.Event(layout, this, eventType);
		layout.dispatchEvent(event);
	},

	/**
	 * マスカット部品のツリー構造を走査する WidgetVisitor を受け入れます。
	 *
	 * @param visitor 受け入れる WidgetVisitor のインスタンス
	 */
	accept: function(visitor) {
		var visitChildren = visitor.visit(this);
		var children = this.getChildren();
		if (visitChildren && children) {
			for (var i = 0; i < children.length; i++) {
				if (children[i] instanceof maskat.layout.Widget) {
					children[i].accept(visitor);
				}
			}
		}
		visitor.postVisit(this);
	}
	
});
