/**
 * Updater: updating HTML with right elements.
 */

/**
 * Building HTML for data items.
 */

QikEngine.Updater = Class.create({

    /**
     * Constructor.
     *
     * Hook up for 'Loading' hooks.
     */

    initialize : function()
    {
        QikEngine.showLoading = function() { if ($('loading')) $('loading').show(); };
        QikEngine.hideLoading = function() { if ($('loading')) $('loading').hide(); };
    },

    /**
     * Set user cache object.
     *
     * @type userCache: QikEngine.UserCache
     */

    setUserCache : function(userCache)
    {
        this.userCache = userCache;
    },

    /**
     * Convert duration in seconds to human-readable string.
     *
     * @param duration: duration in seconds
     * @type duration: Integer
     * @return: formatted duration
     * @rtype: String
     */

    durationToString : function(duration)
    {
        var minutes = Math.floor(duration /  60);
        var seconds = duration % 60;

        minutes = minutes.toString();
        seconds = seconds.toString();
        if (seconds.length == 1)
            seconds = '0' + seconds;

        return minutes + ':' + seconds;
    },

    /**
     * Convert UTC SQL-style datetime to local representation
     *
     * @param sql_date: UTC SQL datetime
     * @type sql_date: String
     * @return: local datetime
     * @rtype: String
     */

    dateToString : function(sql_date)
    {
        var m = /(\d+)-(\d+)-(\d+) (\d+):(\d+):(\d+)/.exec(sql_date);

        if (!m)
            return '?';

        return new Date(Date.UTC(m[1], m[2]-1, m[3], m[4], m[5], m[6])).toLocaleString();
    },

    /**
     * Change URL protocol part in URL to one of current page.
     *
     * @param url: url to process
     * @type url: String
     * @return: fixed URL
     * @rtype: String
     */

    fixURLProto : function(url)
    {
        return url.replace(/^http:/, document.location.protocol);
    },

    /**
     * Draw error on page.
     *
     * @param error: exception object
     * @type error: Error
     */

    drawError : function(error)
    {
        console.log("got Error", error);
        var text = error.faultString ? error.faultString : 'Unknown error';

        $('error').update(text.escapeHTML());
        $('error').show();
    },

    /**
     * Hide error block.
     */

    hideError : function()
    {
        $('error').hide();
    },

    /**
     * Build HTML representation of user profile in HTML container.
     *
     * @param root: HTML container
     * @type root: Element
     * @param profile: user's profile
     * @type profile: Object
     */

    buildProfile : function(root, profile)
    {
        root.update('');
        if (profile['thumbnail_url'])
            root.insert(new Element('img', {'class' : 'photo', 'src' : profile['thumbnail_url'], 'title' : profile['full_name']}));
        root.insert(new Element('div', { 'class' : 'username' }).update(new Element('a', { 'href' : this.fixURLProto(profile['profile_page']) }).update(profile['username'].escapeHTML())));
        root.insert(new Element('div', { 'class' : 'full_name' }).update(profile['full_name'].escapeHTML()));
        if (profile['website'])
            root.insert(new Element('div', { 'class' : 'site' }).update(new Element('a', { 'href' : profile['website'] }).update(profile['website'].escapeHTML())));
        root.insert(new Element('div', { 'class' : 'country' }).update(profile['country'].escapeHTML()));
    },

    /**
     * Build HTML representation of stream and return it.
     *
     * @param info: information about stream
     * @type info: Object
     * @param no_highlight: don't highlight new streams
     * @type no_highlight: Boolean
     * @return: HTML element, describing this stream
     * @rtype: Element
     */

    buildStream : function(info, no_highlight)
    {
        var stream = new Element('div', { 'class' : 'stream' } );
        stream.insert(new Element('a', { 'href' : this.fixURLProto(info.url) }).update(new Element('img', { 'src' : this.fixURLProto(info.small_thumbnail_url), 'class' : 'thumbnail small', 'alt' : info.title } )));
        stream.insert(new Element('a', { 'href' : this.fixURLProto(info.url) }).update(new Element('div', { 'class' : 'title' })
            .update(info.title.escapeHTML())));
        stream.insert(new Element('div', { 'class' : 'when' })
            .insert(new Element('span', { 'class' : 'duration' }).update(this.durationToString(info.duration)))
            .insert(' @ ')
            .insert(new Element('span', { 'class' : 'when' }).update(this.dateToString(info.created_at))));
        stream.insert(new Element('div', { 'class' : 'views' })
            .insert(new Element('span', { 'class' : 'count' }).update(info.views))
            .insert(' views'));

        if (info.live)
            stream.down('img.thumbnail').addClassName('live');

        if (!no_highlight && !stream.hasClassName('highlight'))
        {
            stream.addClassName('highlight');
            window.setTimeout(function () { stream.removeClassName('highlight'); }, 5000);
        }

        return stream;
    },

    /**
     * Build HTML representation of stream including author's name and return it.
     *
     * This method makes use of userCache (setUserCache should be called at first).
     *
     * @param info: information about stream
     * @type info: Object
     * @return: HTML element, describing this stream
     * @rtype: Element
     */

    buildStreamWithUser : function(info, no_highlight)
    {
        var stream = this.buildStream(info, no_highlight);

        function drawUser(user_info)
        {
            stream.insert(new Element('a', { 'href' : this.fixURLProto(user_info['profile_page']) }).update(new Element('div', { 'class' : 'user' }).update(user_info['username'].escapeHTML())));
            return user_info;
        }

        this.userCache.fetch(info.user_id).addCallback(drawUser.bind(this));

        return stream;
    },

    /**
     * Update HTML representation of stream according to new information
     *
     * @param html: previous HTML representation for this stream
     * @type html: Element
     * @param info: new information about stream
     * @type info: Object
     */

    updateStream : function(html, info)
    {
        html.down('div.title').update(info.title.escapeHTML());
        html.down('img.thumbnail').writeAttribute('src', this.fixURLProto(info.small_thumbnail_url)).writeAttribute('alt', info.title);
        html.down('div.when span.duration').update(this.durationToString(info.duration));
        html.down('div.when span.when').update(this.dateToString(info.created_at));
        html.down('div.views span.count').update(info.views);

        if (info.live)
            html.down('img.thumbnail').addClassName('live');
        else
            html.down('img.thumbnail').removeClassName('live');

        if (!html.hasClassName('highlight'))
        {
            html.addClassName('highlight');
            window.setTimeout(function () { html.removeClassName('highlight'); }, 5000);
        }

    },

    /**
     * Update HTML representation of stream (including author) according to new information
     *
     * This method makes use of userCache (setUserCache should be called at first).
     *
     * @param html: previous HTML representation for this stream
     * @type html: Element
     * @param info: new information about stream
     * @type info: Object
     */

    updateStreamWithUser : function(html, info)
    {
        this.updateStream(html, info);

        function updateUser(user_info)
        {
            html.down('div.user').update(user_info['username'].escapeHTML());
            return user_info;
        }

        this.userCache.fetch(info.user_id).addCallback(updateUser);
    },

    /**
     * Build HTML representation of timeline event and return it.
     *
     * @param info: information about timeline evcent
     * @type info: Object
     * @param no_highlight: don't highlight new events
     * @type no_highlight: Boolean
     * @return: HTML element, describing this event
     * @rtype: Element
     */

    buildTimeline : function(info, no_highlight)
    {
        var event = new Element('li', { 'class' : 'event' } ).update($H(info).toJSON().escapeHTML());

        if (!no_highlight && !event.hasClassName('highlight'))
        {
            event.addClassName('highlight');
            window.setTimeout(function () { event.removeClassName('highlight'); }, 5000);
        }

        return event;
    },

    /**
     * Update HTML representation of timeline event according to new information
     *
     * @param html: previous HTML representation for this stream
     * @type html: Element
     * @param info: new information about stream
     * @type info: Object
     */

    updateTimeline : function(html, info)
    {
        hmtl.update($H(info).toJSON().escapeHTML());

        if (!html.hasClassName('highlight'))
        {
            html.addClassName('highlight');
            window.setTimeout(function () { html.removeClassName('highlight'); }, 5000);
        }

    },

    /**
     * Draw thumbnails for users in some container.
     *
     * @param container: HTML container
     * @type container: Element
     * @param users: list of user informations
     * @type users: Array
     */

    drawUserThumbs : function(container, users)
    {
        var that = this;

        function buildUserThumb(user)
        {
            var html = new Element('a', { 'href' : that.fixURLProto(user.profile_page) }).update(new Element('img',
                        { 'src' : user.thumbnail_url, 'width' : 40, 'height' : 40, 'title' : user.username, 'alt' : user.full_name }));

            return html;
        }

        users.each(function(user) { container.insert(buildUserThumb(user)); });
    },

    /**
     * Build updater object (for QikEngine.View) for simple stream information.
     *
     * @return: updater object
     * @rtype: Object
     */

    getStreamUpdater : function(container)
    {
        var that = this;

        return {
            'clear' : function() { $(container).update(''); },
            'build' : function (info, no_highlight) { return that.buildStream(info, no_highlight); },
            'update' : function (item, info) { that.updateStream(item, info); },
            'container' : function() { return $(container); },
               };
    },

    /**
     * Build updater object (for QikEngine.View) for simple stream information plus author's name.
     *
     * @return: updater object
     * @rtype: Object
     */

    getStreamUpdaterWithUser : function(container)
    {
        var that = this;

        return {
            'clear' : function() { $(container).update(''); },
            'build' : function (info, no_highlight) { return that.buildStreamWithUser(info, no_highlight); },
            'update' : function (item, info) { that.updateStreamWithUser(item, info); },
            'container' : function() { return $(container); },
               };
    },

    /**
     * Build updater object (for QikEngine.View) for simple timeline event.
     *
     * @return: updater object
     * @rtype: Object
     */

    getTimelineUpdater : function(container)
    {
        var that = this;

        return {
            'clear' : function() { $(container).update(''); },
            'build' : function (info, no_highlight) { return that.buildTimeline(info, no_highlight); },
            'update' : function (item, info) { that.updateTimeline(item, info); },
            'container' : function() { return $(container); },
               };
    },

});

