// import Divmod
// import Nevow.Athena
// import Methanal.Util
// import FlyingCircus.Util


/**
 * A FlyingCircus quote.
 *
 * Performs actions such as voting and moderation as well as updating the
 * quote status and rating displays.
 */
FlyingCircus.Quotes.Quote = Nevow.Athena.Widget.subclass('FlyingCircus.Quotes.Quote');
FlyingCircus.Quotes.Quote.methods(
    function __init__(self, node, rating) {
        FlyingCircus.Quotes.Quote.upcall(self, '__init__', node);
        self.rating = rating[0];
        self.votes = rating[1];
        self.throbCount = 0;
    },

    function nodeInserted(self) {
        self.ratingNode = self.nodeById('rating');
        self.controlsNode = self.nodeById('controls');
        self.throbberNode = self.nodeById('throbber');
        self.statusNode = self.nodeById('status');

        self.updateRating(self.rating, self.votes);
    },

    /**
     * Start the throbber.
     */
    function startThrobber(self) {
        self.throbCount++;
        self.throbberNode.style.visibility = 'visible';
    },

    /**
     * Stop the throbber if nothing else is supposed to be throbbing.
     *
     * Before a throbber is stopped, the number of C{stopThrobber} calls
     * must be equal to the number of L{startThrobber} calls.
     */
    function stopThrobber(self) {
        self.throbCount--;
        if (self.throbCount == 0)
            self.throbberNode.style.visibility = 'hidden';
    },

    /**
     * Perform a vote action.
     *
     * @type action: C{String}
     * @param action: Name of the vote action to perform
     */
    function vote(self, action) {
        self.controlsNode.style.display = 'none';
        self.startThrobber();

        var d = self.callRemote(action)
        d.addCallback(function (result) {
            self.updateRating(result[0], result[1]);
            self.stopThrobber();
        });

        return false;
    },

    /**
     * Vote for this quote.
     */
    function plus(self) {
        return self.vote('plus');
    },

    /**
     * Vote against this quote.
     */
    function minus(self) {
        return self.vote('minus');
    },

    /**
     * Update the quote status.
     *
     * @type statusInfo: C{[String, String]}
     * @param statusInfo: C{[statusIndicator, statusClassName]}
     */
    function updateStatus(self, statusInfo) {
        Methanal.Util.replaceNodeText(self.statusNode, statusInfo[0]);
        self.statusNode.className = statusInfo[1];
    },

    /**
     * Perform a status operation.
     *
     * @type node: DOM node
     * @param node: Node to hide upon performing the action
     *
     * @type action: C{String}
     * @param action: Name of the action to status operation to perform
     */
    function statusOp(self, node, action) {
        node.style.display = 'none';
        self.startThrobber();

        var d = self.callRemote(action);
        d.addCallback(function (statusInfo) {
            self.updateStatus(statusInfo);
            self.stopThrobber();
        });

        return false;
    },

    /**
     * Request that the quote be moderated.
     */
    function moderate(self, node) {
        return self.statusOp(node, 'moderate');
    },

    /**
     * Reject the quote.
     */
    function reject(self, node) {
        return self.statusOp(node, 'reject');
    },

    /**
     * Accept the quote.
     */
    function accept(self, node) {
        return self.statusOp(node, 'accept');
    },

    /**
     * Format a rating for display purposes.
     *
     * @type rating: C{Integer}
     * @param rating: Quote rating
     *
     * @type votes: C{Integer}
     * @param votes: Total number of quote votes
     *
     * @rtype: DOM node
     */
    function formatRating(self, rating, votes) {
        var D = FlyingCircus.Util.DOMBuilder(self.node.ownerDocument);
        var className = 'quote-rating-good';
        if (rating < 0)
            className = 'quote-rating-bad';

        return D('span', {}, [
            '(',
            D('strong', {'class': className}, [rating.toString()]),
            ' / ',
            votes.toString(),
            ')']);
    },

    /**
     * Update the rating display.
     */
    function updateRating(self, rating, votes) {
        Methanal.Util.replaceNodeContent(self.ratingNode, [self.formatRating(rating, votes)]);
    });


/**
 * Quote submission.
 */
FlyingCircus.Quotes.QuoteAdder = Nevow.Athena.Widget.subclass('FlyingCircus.Quotes.QuoteAdder');
FlyingCircus.Quotes.QuoteAdder.methods(
    function __init__(self, node) {
        FlyingCircus.Quotes.QuoteAdder.upcall(self, '__init__', node);
    },

    function nodeInserted(self) {
        self.throbber = self.nodeById('throbber');
        self.submitNode = self.nodeById('submit');
        self.disableSubmit();
    },

    /**
     * Submit a quote for addition to the quote database.
     */
    function addQuote(self, node) {
        self.throbber.style.visibility = 'visible';
        var content = self.nodeById('content').value;
        var d = self.callRemote('addQuote', content);
        d.addCallback(function (url) {
            self.throbber.style.visibility = 'hidden';
            window.location = url;
        });
        self.disableSubmit();
        return false;
    },

    function disableSubmit(self, node) {
        self.submitNode.disabled = true;
        Methanal.Util.addElementClass(self.submitNode, 'methanal-submit-disabled');
    },

    function enableSubmit(self, node) {
        self.submitNode.disabled = false;
        Methanal.Util.removeElementClass(self.submitNode, 'methanal-submit-disabled');
    },

    function onKeyUp(self, node) {
        if (node.value !== null && node.value.length > 0) {
            self.enableSubmit();
        } else {
            self.disableSubmit();
        }
    });


/**
 * Paginated quote list view.
 */
FlyingCircus.Quotes.QuotePager = Nevow.Athena.Widget.subclass('FlyingCircus.Quotes.QuotePager');
FlyingCircus.Quotes.QuotePager.methods(
    function nodeInserted(self) {
        self.quoteListNode = self.nodeById('quoteList');
        self.throbberNode = self.nodeById('throbber');
    },

    /**
     * Retrieve a page of quotes from the remote side and display them.
     */
    function _page(self, action, node) {
        self.throbberNode.style.visibility = 'visible';

        var d = self.callRemote(action);
        d.addCallback(function (widgetInfo) {
            if (widgetInfo === null) {
                self.throbberNode.style.visibility = 'hidden';
                node.style.textDecoration = 'line-through';
                node.removeAttribute('href');
                node.removeAttribute('onclick');
            } else {
                var d = self.addChildWidgetFromWidgetInfo(widgetInfo);
                d.addCallback(function (widget) {
                    self.childWidgets[0].detach();
                    Methanal.Util.replaceNodeContent(self.quoteListNode, [widget.node]);
                    Methanal.Util.nodeInserted(widget);
                    self.throbberNode.style.visibility = 'hidden';
                    widget.node.parentNode.scrollIntoView(true);
                });
            }
        });

        return false;
    },

    /**
     * Display the next page of quotes.
     */
    function nextPage(self, node) {
        return self._page('nextPage', node);
    },

    /**
     * Display the previous page of quotes.
     */
    function prevPage(self, node) {
        return self._page('prevPage', node);
    });

