﻿/* ====== Date and string extensions used in this script ====== */

Date.prototype.addDays = function(days) {
    return new Date(this.getTime() + (days * 86400000));
};

Date.prototype.getMonday = function() {
    return this.addDays(-((this.getDay() + 6) % 7));
};

String.prototype.endsWith = function(last) {
    return (this.substr(this.length-last.length) === last);
};

String.prototype.startsWith = function(first) {
    return (this.substr(0, first.length) === first);
};

Date.prototype.getDatePart = function() {
    return new Date(this.getFullYear(), this.getMonth(), this.getDate());
};


/* ====== parlycal object ====== */

function parlycal($) {

    var self = this;


    /* ====== squeeze ====== */

    /**
     * Handles the squeeze box to expand/collapse the sections.
     */

    function squeeze(e)
    {
        e.preventDefault();
        var $this = $(this);
        $this.toggleClass('collapsed');
        $this.parent().children('.calendar-daily-summary').slideToggle(350);
    }


    /* ====== parseUrl ====== */
    
    /**
     * Parses a URL into a date, house and location.
     *
     * @param A URL on the calendar website
     * @returns An object giving details of what the link represents. This has the
     *      following fields members:
     *          date:       The first selected date.
     *          lastDate:   The last selected date. For one-day links this will be the
     *                      same as date.
     *          weekly:     whether this is a weekly (true) or daily (false) link.
     *          house:      The House (Commons or Lords)
     *          location:   The location or business type
     *                      (e.g. MainChamber, SelectCommittee, Dolstagis)
     *          toString(): builds a new URL.
     */
    
    function parseUrl(fullUrl)
    {
        var url;

        /*
         * Strip off the host and domain name if present.
         * We need to do this because when you set a hyperlink's href using JavaScript,
         * IE7 and earlier convert it to an absolute URL including domain name.
         * Other browsers (including IE8 in standards mode) don't do this.
         */

        fullUrl = fullUrl.replace(/^https?\:\/\/[^\/]+/, '');

        // Parse the URL to find the last selected date.

        var appPathPos = fullUrl.indexOf(parlycal.appPath);
        if (appPathPos > -1) {
            url = fullUrl.substr(appPathPos+parlycal.appPath.length);
        }
        else {
            url = fullUrl;
        }
        
        var date;
        var lastDate;
        var weekly = false;
        var remainder;
        if (url.endsWith('/today.html')) {
            date = new Date().getDatePart();
            remainder = url.substr(0, url.length-11);
        }
        else if (url.endsWith('/thisweek.html')) {
            date = new Date().getDatePart();
            weekly = true;
            remainder = url.substr(0, url.length-14);
        }
        else if (url.endsWith('/future.html')) {
            date = new Date().addDays(7).getDatePart();
            weekly = true;
            remainder = url.substr(0, url.length-12);
        }
        else {
            var dateStr = /\/([0-9]+\/){3}([A-Za-z]+)\.html$/.exec(url);
            if (dateStr !== null) {
                dateStr = dateStr[0];
                var dateArr = dateStr.split('/');
                weekly = (dateArr[4] === 'week.html');
                date = new Date(dateArr[1], dateArr[2] - 1, dateArr[3]);
                remainder = url.substr(0, url.length-dateStr.length);
            }
            else {
                date = new Date().getDatePart();
                weekly = url.endsWith('/week.html');
                remainder = url;
            }
        }
        if (weekly) {
            date = date.getMonday();
            lastDate = date.addDays(6);
        }
        else {
            lastDate = date;
        }

        remainder = remainder.split('/');
        var house = "Commons";
        var location = "MainChamber";
        if (remainder.length > 1) {
            house = remainder[1];
            location = remainder[2];
        }

        return {
            date: date,
            lastDate: lastDate,
            weekly: weekly,
            house: house,
            location: location,
            url: fullUrl,

            toString: function() {
            return parlycal.appPath +
                '/' +
                this.house +
                '/' +
                this.location +
                '/' +
                this.date.getFullYear() +
                '/' +
                (this.date.getMonth() + 1) +
                '/' +
                this.date.getDate() +
                '/' +
                (this.weekly ? 'week.html' : 'events.html');
            }
        };
    }


    /* ====== selectDate event ====== */

    /**
     * Called when the user selects a new date.
     */

    function selectDate(e) {
        var date = parseUrl(this.href);
        if (e) {
            e.preventDefault();
            location = "#!" + date.toString();
        }
        parlycal.selectedDate = date;
        updateEvents(date);
        updateDateSelection(date);
        updateUrls(date);
        return false;
    }


    /* ====== selectLocation event ====== */
    
    /**
     * Called when the user selects a new location.
     */

    function selectLocation(e)
    {
        var date = parseUrl(this.href);
        if (e) {
            e.preventDefault();
            location = "#!" + date.toString();
        }
        parlycal.selectedDate = date;
        updateEvents(date);
        updateLocationSelection(date);
        updateUrls(date);
        return false;
    }


    /* ====== updateEvents ====== */
    
    /**
     * Updates the contents of the events panel to reflect the changed URL.
     */
    
    function updateEvents(date)
    {
        if (parlycal.errors) {return; }

        jQuery.post(
            date.toString(), 
            { ajax: 'events' },
            function(data, textStatus) {
                if (textStatus === 'success') {
                    $('#events-output').html(data);
                }
            },
            'html'
        );
    }




    /* ====== updateDateSelection ====== */
    
    /**
     * Updates the selected date (#calendar-widget and #date-selector) after the date changes.
     */
     
    function updateDateSelection(date)
    {
        if (parlycal.errors) { return; }
        // TODO: check to see if the month has updated, and only update here if the month changes.

        jQuery.post(
            date.toString(),
            { ajax: 'widget' },
            function (data, textStatus) {
                if (textStatus === 'success') {
                    $('#calendar-widget').html(data);
                }
            },
            'html'
        );
        $("#date-selector a").each(function() {
            var d = parseUrl(this.href);
            $(this).toggleClass(
                'selected',
                (d.date.getTime() === date.date.getTime() && d.weekly === date.weekly)
            );
        });
    }


    /* ====== updateLocationSelection ====== */
    
    /**
     * Updates the selected items in the location selection links (#houses and #location-selector)
     * after the location changes.
     */

    function updateLocationSelection(date)
    {
        if (parlycal.errors) { return; }
        $('#houses a').each(function() {
            var d = parseUrl(this.href);
            $(this).parent().toggleClass(
                'selected',
                (d.house === date.house)
            );
        });
        
        // Ensure that all the required tabs exist in location selector

        jQuery.post(
            date.toString(),
            { ajax: 'tabs' },
            function(data, textStatus) {
            if (textStatus === 'success') {
                    $('#location-selector').html($(data).html());
                }
            },
            'html'
        );

        // Update the location selector's selected status
        
        $('#location-selector a').each(function() {
            var d = parseUrl(this.href);
            $(this).parent().toggleClass(
                'selected',
                (d.location === date.location)
            );
        });
    }
    
    
    /* ====== updateUrls ====== */
    
    /**
     * Updates the URLs everywhere after the location changes.
     * NB: The URLs do not change after the date changes.
     */
    
    function updateUrls(date)
    {
        if (parlycal.errors) { return; }
        // Calendar widget and date selector need to update location information
        $('#calendar-widget a, #date-selector a').each(function() {
            var d = parseUrl(this.href);
            d.house = date.house;
            d.location = date.location;
            this.href = d.toString();
        });

        // House and location selectors need to update date information
        $('#houses a, #location-selector a').each(function() {
            var d = parseUrl(this.href);
            d.date = date.date;
            d.lastDate.date = date.lastDate;
            d.weekly = date.weekly;
            if ($(this).is('#location-selector a')) {
                d.house = date.house;
            }
            this.href = d.toString();
        });
    }


    /* ======= Click Delegates ====== */

    $(document).ready(function() {
        // Comment these out if you don't want to use the ajaxy stuff
        $('#events-output').delegate('.calendar-day .date-header', 'click', squeeze);
        $('#calendar-widget,#date-selector').delegate('a', 'click', selectDate);
        $('#houses,#location-selector').delegate('a', 'click', selectLocation);
        parlycal.ajaxSpinner = new Image();
        parlycal.ajaxSpinner.src = parlycal.appPath + '/Content/images/ajax-loader.gif';
    });


    /* ====== Global AJAX event handlers ====== */

    /**
     * These show and hide the spinner control in place of the date.
     */

    $(document).bind('ajaxStart', function() {
        parlycal.errors = false;
        $('#selected-date h1').html(
            '<div style="position: absolute">' +
            '<img src="' + 
            parlycal.appPath + 
            '/Content/images/ajax-loader.gif" alt="Please wait..." />' +
            '</div>' +
            '&nbsp;');
    });

    $(document).bind('ajaxStop', function() {
        if (parlycal.errors) {
            parlycal.errors = false;
            return;
        }
        var dateStr = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday']
            [parlycal.selectedDate.date.getDay()] + ' ' +
            parlycal.selectedDate.date.getDate() + ' ' +
            ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December']
            [parlycal.selectedDate.date.getMonth()] + ' ' +
            parlycal.selectedDate.date.getFullYear();
        if (parlycal.selectedDate.weekly) {
            dateStr = 'the week beginning ' + dateStr;
        }
        $('#selected-date h1').html('Parliamentary business for ' + dateStr);
    });
    
    
    $(document).bind('ajaxError', function(event, XMLHttpRequest, ajaxOptions, thrownError) {
        parlycal.errors = true;
        $('#selected-date h1').html(
            '<img src="' +
            parlycal.appPath +
            '/Content/images/error.png" alt="Error" align="absmiddle" />' +
            '&nbsp;<small>Sorry, an error occurred communicating with the server.</small>'
        );
    });

    // Expose functions
    parlycal.clientNav = function() {
        selectDate.apply(this, arguments);
        selectLocation.apply(this, arguments);
    };
    
}

parlycal.call(parlycal,jQuery);

