var widget={};
if (!document.Widget)
(function(){

    // shortcuts
    var undef = function(param) { return param; }

    // конструктор, одновременно являющийся и фабрикой
    Widget = function( id, wauth, src )
    {
        this._prefs = {};
        this._prefsTabs = [];
        this.id = id;
        this.src = src;
        if (wauth != "") 
        {
            this.addPref("wauth", wauth);
            Widget._wauth[ wauth ] = this;
        }
        this.onLoad = false;
        Widget._widgets[ Widget._widgets.length ] = this;
        if (Widget.Wrapper) new Widget.Wrapper(this);
    };
    document.Widget = Widget;

    Widget._widgets = [];
    Widget._wauth = {};
    Widget.OnLoad = function()
    {
        if (Widget._domloaded) return false;
        Widget._domloaded = true;
        for (var i=0; i<Widget._widgets.length; i++)
            with (Widget._widgets[i])
                if (!_inlineLoading)
                    if (_inlinePending)
                        _inlineFromHtml(_inlinePending);
                    else
                    {
                        if (onload) onload();
                        if (onLoad) onLoad();
                    }
    }
    Widget.XFrameInit = function( proxyUrl )
    {
        Widget._xframe = new y5.XFrameMessage( proxyUrl );
    }
    Widget.JSONInit = function( jsonUrl )
    {
        Widget._jsonUrl = jsonUrl;
    }
    Widget.Get = function( wauth )
    {
        return Widget._wauth[ wauth ];
    }
    // obsolete function, lets get rid of it, pls.
    Widget.GetInstance = function( id )
    {
        for (var i=0; i<Widget._widgets.length; i++)
            if (Widget._widgets[i].id == id)
                return Widget._widgets[i];
    }

    Widget.prototype = {
        _idPrefix : "wd-",
        _prefs   : {},
        idTemplate : /WIDGETID/g,
        _inlineLoading : false,
        _inlinePending : false,
        
        /*
        * Обработчики событий, которые можно перегрузить
        */
        onload : function() {},
        onLoad : function() {},
        onSetValue : function(name,value) {},

        /*
        *  Работа с <auth_token>
        */
        getAuth     : function() { return this.getValue("wauth") },
        getWidgetId : function() { return this.getAuth().split(".")[0] },
        getOwner    : function() { return this.getAuth().split(".")[1] },
        getViewer   : function() { return this.getAuth().split(".")[2] },
        /*
        *  Методы, которыми должен пользоваться разработчик виджета для работы с параметрами
        */
        _setValue : function( name, value )
        {
            this._prefs[ name ].value = value;
        },
        setValue : function( name, value )
        {
            this._setValue(name, value);
            alert("serverside storage not implemented in v. 0.2");
        },
        getValue : function( name )
        {
            if (this._prefs[ name ])
                return this._prefs[ name ];
            else
                return undef();
        },
        /*
        *  Управление внешним видом
        */
        setTitle : function( title )
        {
            if (this.wrapper)
                this.wrapper.setTitle(title);
            else
                if (Widget._xframe !== undef())
                    Widget._xframe.send({
                        name: 'Widget::setTitle',
                        wauth: this.getAuth(),
                        value : title
                    });
        },
        setIFrameHeight : function( newHeight )
        {
            if (this.wrapper)
                this.wrapper.setIFrameHeight(newHeight);
            else
                if (Widget._xframe !== undef())
                    Widget._xframe.send({
                        name: 'Widget::setIFrameHeight',
                        wauth: this.getAuth(),
                        value : newHeight
                    });
        },
        adjustIFrameHeight : function()
        {
            return this.setIFrameHeight( document.body.scrollHeight );
        },
        /*
        *  Удобный метод, возвращает элемент дома, касающийся виджета
        */
        $ : function( idPostfix )
        {
            if (idPostfix == undef())
                return document.getElementById(this._idPrefix + this.id);
            else
                return document.getElementById(this._idPrefix + this.id +idPostfix);
        },
        $$ : function( idPostfix )
        { return this._idPrefix + this.id + idPostfix },

        /*
        *  Дальше пошли методы, которые используются при инициализации виджета.
        */
        inlineFromSrc : function()
        {
            return this.inlineFrom( this.src );
        },
        jsonFromSrc : function()
        {
            return this.jsonFrom( this.src );
        },
        iframeFrom : function(src) // , ["p"], { host_id: "xxx" } )
        {
            src = this._addParams(src,arguments);
            var widget = this;
            y5.Events.observe('dom:loaded', function(){
                if (widget.wrapper.$("iframe").src != src)
                    widget.wrapper.$("iframe").src = src;
             }, y5, true);
        },
        jsonFrom : function(src) // , ["p"], { host_id: "xxx" } )
        {
            src = this._addParams(src,arguments);
            var widget = this;
            var u = y5.Url(Widget._jsonUrl);
            document.write("<script type='text/javascript' src='"+u.query({"url":src,"wauth":this.getAuth()}).get()+"'></script>");
        },
        inlineFrom : function(src) // , ["p"], { host_id: "xxx" } )
        {
            src = this._addParams(src,arguments);
            var widget = this;
            this._inlineLoading = true;
            y5.Get.XML( src, { 
                        onload : function(r) { widget._inlineFromHtml(r.responseText);} 
                    });
        },
        _inlineFromJson : function(json)
        {
            if (json.success) return this._inlineFromHtml(json.result);
            else alert("Could not retrieve widget body in a JSON way:\n"+json.result);
        },
        _inlineFromHtml : function(html)
        {   
            if (!Widget._domloaded) // widget <body> received, but DOM is not ready.
            {
                this._inlineLoading = false;
                this._inlinePending = html;
                return;
            }
            this.$().innerHTML = html.replace(this.idTemplate, this.$$());
            var scriptRe = /<script[^\/>]*>((.|\n)+?)<\/script>/img; // lol, <img>
            var match;
            var widget = this;
            while ((match = scriptRe.exec(html)) != null) 
                eval(match[1]);
            this._inlineLoading = false;
            this._inlinePending = false;
            if (Widget._domloaded && this.onLoad) 
                this.onLoad();
            if (Widget._domloaded && this.onload) 
                this.onload();
        },
        _addParams : function(src, args)
        {
            var url = new y5.URL(location.href);
            var params = {};
            for (var i=1; i<args.length; i++)
            {
                if (args[i] instanceof Array)
                {
                    for (var j=0; j<args[i].length; j++)
                        if (typeof(url.getParam(args[i][j])) != "object")
                            params[args[i][j]] = url.getParam(args[i][j])
                }
                else
                    for (var j in args[i])
                        if (typeof(args[i][j]) != "function" && typeof(args[i][j]) != "object")
                            params[j] = args[i][j];
            }
            return new y5.URL(src).addParams(params).toString();
        },
        addPref : function( name, value )
        {
            this._prefs[name] = value;
        },
        getPrefsFromUrl : function()
        {
            var u = y5.Url(location.href);
            var keys = u.queryKeys();
            for(var i=0; i<keys.length; i++)
                this.addPref( keys[i], u.getParam(keys[i]) );
        },
        log : function(message) {
            y5.Console.log(message, ['Widget']);
        }
    }

    y5.Events.observe('dom:loaded', 
        function() { y5.require(['XFrameMessage'], Widget.OnLoad) },
        y5, true);
})();
