﻿//<using>
//  nui/nui.js
//  nui/prototype.js
//  nui/lang.js
//  nui/util.js
//</using>

/**
 * NUI.Widget 
 * Copyright 2007, NetRanking.cn
 *
 * @namespace NUI.Util
 */
NUI.Widget = (function(){
    // private and static variables
    var g_ht = NUI.Util.DataStructure.HashTable,
        g_dom = NUI.Util.DomService,
        g_minId = 0, 
        g_maxId = 4294967295;
    
    /**
     * @methods _getUsableId
     * @private
     * @return An random id that has not been used by any element of the document yet.
     */
    function _getUsableId() {
        var count = 0;
        while( NUI.Util.DomService.getNode("nuiwidget_" + g_minId) && count < g_maxId ) {
            count ++;
            g_minId ++;
            if(g_minId >= g_maxId)
                g_minId = 0;
        }
        if(count == g_maxId) {
            NUI.Widget.Alert("Error : can not get legal widget id");
            return null;
        }
        return "nuiwidget_" + ( g_minId++ );    // should ++ !!!
    };
    
    return {
        /**
         * The base class of widget. Widgets maybe inherit from it. 
         * A widget that inherit from Base can specify an "id", else the default is will be used, which is 
         * create by method _getUsableId(). Remeber to specify an "id" yourself. It will reduce the time
         * to render the widget.
         * @class NUI.Widget.Base
         * @param vSecret {object} Widget's shared secret information. 
         *  It always has variables: "id", "document" and "nameSpace".
         * @return The base instance.
         */
        Base : function(vSecret) {
            vSecret = vSecret || {};                                // Shared secret information
            vSecret.id = vSecret.id || _getUsableId();              // Widget's id
            vSecret.document = vSecret.document || document;        // The document where that the widget created
            vSecret.nameSpace = vSecret.nameSpace || NUI.Widget;    // The namespace, e.t. NUI.Widget 
            
            var m_childrenCache = new g_ht();                       // The widget's children cache
            NUI.Util.ObjectService.annex(vSecret, {
                /**
                 * Get the dom ref of the widget's child. 
                 * If the child is in cache, get it from the cache. Else try to get it from the document
                 * @param vId {int}
                 */
                getChild : function(vId) {
                    var obj =  m_childrenCache.getValue(vId);
                    
                    function _linkToTop(vNode) {
                        var parent = vNode;
                        while(parent != null && parent != that.nodeEntity) {
                            parent = parent.parentNode;
                        }
                        return (parent==that.nodeEntity);
                    };
                    /**
                     * 1. (obj==null) means the child is not in cache
                     * 2. (_linkToTop(obj)) means the dom tree of that.nodeEntity has been modified and 
                     *      the cache of obj is TOO OLD, we should re-get it from the dom tree.
                     */
                    if(obj == null || !_linkToTop(obj)) {
                        obj = g_dom.getNode(vId, {
                            root : that.nodeEntity
                        });
                        m_childrenCache.setValue(vId, obj);
                    }
                    return obj;
                }
            });
            
            var that = {
                /**
                 * Get the widget's id.
                 * @method getId
                 * @return {string} id
                 */
                getId : function() {
                    return (vSecret && vSecret.id) ? vSecret.id : null;
                },
                
                /**
                 * The document object of the widget.
                 * MAKE SURE TO realize this variable in the widgets that inherit form NUI.Widget.Base
                 * @variable nodeEntity
                 */
                nodeEntity : null,
                
                /**
                 * Attach widget to the target node.
                 * @method attachTo
                 * @param vNode {object|string}. The node (or its id) that the widget will attach to.
                 */
                attachTo : function(vNode) {
                    var parent = g_dom.getNode(vNode);
                    if(!parent)
                        return;
                    if( this.nodeEntity ){
                        g_dom.removeChildren(parent);
                        g_dom.appendNode(parent, this.nodeEntity);
                    }
                },
                
                /**
                 * Append widget to the target node.
                 * @method appendTo
                 * @param vNode {object|string}. The node (or its id) that the widget will attach to.
                 */
                appendTo : function(vNode) {
                    var parent = g_dom.getNode(vNode);
                    if(!parent)
                        return;
                    if( this.nodeEntity ){
                        g_dom.appendNode(parent, this.nodeEntity);
                    }
                },
                
                /**
                 * Append widget behind the target node.
                 * @method appendBehind
                 * @param vNode {object|string}. The node (or its id) that the widget will attach to.
                 */
                appendBehind : function(vNode) {
                    if(!vNode)
                        return;
                    if( this.nodeEntity ){
                        g_dom.insertBehind(vNode, this.nodeEntity);
                    }
                },
                
                /**
                 * Distroy the document object of the widget.
                 * @method destroy
                 */
                destroy : function() {
                    g_dom.destroyNode(this.nodeEntity);
                }
            };
            
            return that;
        },
        
        RichEditor : {},
        
        //buttons
        Button : {},
        
        //inputs
        Input : {},
        
        //panel
        Panel : {},
        
        //pupups
        Dropdown : function(vChild, vAttributes) {},
        Fog : function(vSecret) {},
        Alert : function(vMsg, vAttribute) {},
        Confirm : function(vMsg, vFunc, vAttribute) {},
        Popup : function(vChild, vAttribute) {},
        Waiting : {
            start : function(vMsg) {},
            end : function() {}
        },
        
        //players
        MediaPlayer : {},
        
        //tools
        Accessory : {},
        TimeSelector : function() {},
        AccountSelector : function() {},
        ServiceSelector : function() {},
        
        //open flash chart
        Ofc : function(vDataUrl, vAttributes) {},
        FusionCharts : function(swf, id, w, h, debugMode, registerWithJS, c, scaleMode, lang, detectFlashVersion, autoInstallRedirect) {},
        
        Table : {},
        
        DatePicker : function() {},
        DatespanSelector : function() {},
        
        Source : {},
        Query : {}
    };
})();
