/* global $ */
/* global getOutingName, formatOutingDateRange, formatOutingTimeRange */
/* global DATE_FORMAT, MONTHS, DOW */

// treat "12345" the same as 12345 when doing set lookups
Set.prototype.hasID = function( id )
{
    return this.has( Number( id ) );
}

// render the date in a flexible format
Date.prototype.format = function( strFormat )
{
    if ( strFormat === undefined )
        strFormat = DATE_FORMAT;

    let days = this.getDate();

    if ( strFormat == "mmm d, 'YY" )
    {
        const month = MONTHS[this.getMonth()];
        let year = this.getFullYear() - 2000;
        if ( year < 10 )
            year = "0" + year;
        return month + " " + days + ", '" + year;
    }

    else if ( strFormat == "mmm d" )
    {
        const month = MONTHS[this.getMonth()];
        return month + " " + days;
    }

    else if ( strFormat == "ddd, mmm d" )
    {
        const month = MONTHS[this.getMonth()];
        const dayofweek = DOW[this.getDay()];
        return dayofweek + ", " + month + " " + days;
    }

    else if ( strFormat == "YYYY-mmm-dd" ) {
        if ( days < 10 )
            days = "0" + days;
        const month = MONTHS[this.getMonth()];
        return this.getFullYear() + "-" + month + "-" + days;
    }

    else if ( strFormat == "mm/dd/YYYY" ) {
        if ( days < 10 )
            days = "0" + days;
        let month = this.getMonth() + 1;
        if ( month < 10 )
            month = "0" + month;
        return month + "/" + days + "/" + this.getFullYear();
    }

    else if ( strFormat == "dd/mm/YYYY" ) {
        if ( days < 10 )
            days = "0" + days;
        let month = this.getMonth() + 1;
        if ( month < 10 )
            month = "0" + month;
        return days + "/" + month + "/" + this.getFullYear();
    }

    else if ( strFormat == "dd mmm YYYY" ) {
        if ( days < 10 )
            days = "0" + days;
        const month = MONTHS[this.getMonth()];
        return days + " " + month + " " + this.getFullYear();
    }

    else if ( strFormat == "H:MM" ) {
        const hours = this.getHours();
        let mins = this.getMinutes();
        if ( mins < 10 )
            mins = "0" + mins;
        return hours + ":" + mins;
    }

    else if ( strFormat == "HH:MM" ) {
        let hours = this.getHours();
        if ( hours < 10 )
            hours = "0" + hours;
        let mins = this.getMinutes();
        if ( mins < 10 )
            mins = "0" + mins;
        return hours + ":" + mins;
    }

    else  // should be YYYY-mm-dd
    {
        if ( days < 10 )
            days = "0" + days;
        let month = this.getMonth() + 1;
        if ( month < 10 )
            month = "0" + month;
        return this.getFullYear() + "-" + month + "-" + days;
    }
}

// get the number of days since January 01
Date.prototype.getDayOfYear = function()
{
    const onejan = new Date( this.getFullYear(), 0, 1 );
    return Math.ceil( (this - onejan) / 86400000 );
}

// Return a new date object that is some days later/earlier, with but with the hours/minutes/days preserved
Date.prototype.addDays = function( nDays )
{
    nDays = parseInt( nDays );
    const dateNew = new Date(this.getTime());
    dateNew.setDate( dateNew.getDate() + nDays );	// increment the day

    dateNew.setHours( this.getHours() );
    dateNew.setMinutes( this.getMinutes() );
    dateNew.setSeconds( this.getSeconds() );
    dateNew.setMilliseconds( this.getMilliseconds() );

    return dateNew;
}

// Return a new date object with the hours/minutes/days set to 12:00:00 (local time)
Date.prototype.getNoon = function()
{
    return new Date( this.getFullYear(), this.getMonth(), this.getDate(), 12, 0, 0 );
}

// Return a new date object with the hours/minutes/days set to zero (local time), i.e., the START of the current day.
//
// See also getStartOfDayTimestamp() and getEndOfTimestamp() for convenience wrappers that return timestamps.
Date.prototype.getMidnight = function()
{
    return new Date( this.getFullYear(), this.getMonth(), this.getDate(), 0, 0, 0 );
}

// Return a new timestamp that is the END of the day (23:59:59)
//
// This returns END of the specified date.  See also getStartOfDayTimestamp() which returns the START of the specified date.
Date.prototype.getEndOfDayTimestamp = function()
{
    const dateNew = new Date( this.getTime() );
    dateNew.setDate( this.getDate() + 1 );	// increment the day

    dateNew.setHours( 0 );
    dateNew.setMinutes( 0 );
    dateNew.setSeconds( 0 );
    dateNew.setMilliseconds( 0 );

    return dateNew.getTime() - 1000;		// one second prior
}

// Return a new timestamp that is the START of the day (00:00:00)
//
// This returns START of the specified date.  See also getEndOfDayTimestamp() which returns the END of the specified date.
Date.prototype.getStartOfDayTimestamp = function()
{
    const dateNew = new Date(this.getTime());
    dateNew.setDate( this.getDate() );

    dateNew.setHours( 0 );
    dateNew.setMinutes( 0 );
    dateNew.setSeconds( 0 );
    dateNew.setMilliseconds( 0 );

    return dateNew.getTime();
}

// constructor for an outing object
function Outing( outing )
{
    $.extend( true, this, outing );
}

Outing.prototype.getName = function()
{
    return getOutingName( this );
}
Outing.prototype.getDate = function()
{
    return new Date( this.date );
}
Outing.prototype.formatDate = function()
{
    return this.getDate().format();
}
Outing.prototype.formatDateRange = function()
{
    return formatOutingDateRange( this );
}
Outing.prototype.formatTimeRange = function()
{
    return formatOutingTimeRange( this );
}

// eslint-disable-next-line no-unused-vars
var createPixelGIF = (function() {

    const keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";

    // eslint-disable-next-line no-shadow
    return function createPixelGIF( hexColor )
    {
        return "data:image/gif;base64,R0lGODlhAQABAPAA" + encodeHex(hexColor) + "/yH5BAAAAAAALAAAAAABAAEAAAICRAEAOw==";
    }

    function encodeHex(hexColor)
    {
        let rgb = null;
        if ( typeof hexColor == 'string')
	{
            var s = hexColor.substring(1, 7);
            if (s.length < 6) s = s[0] + s[0] + s[1] + s[1] + s[2] + s[2];
            rgb = [ parseInt(s[0] + s[1], 16), parseInt(s[2] + s[3], 16), parseInt(s[4] + s[5], 16) ];
        }
        else
            rgb = [ (hexColor & (0xFF << 16)) >> 16, (hexColor & (0xFF << 8)) >> 8, hexColor & 0xFF ];	// eslint-disable-line no-bitwise

        return encodeRGB(rgb[0], rgb[1], rgb[2]);
    }

    function encodeRGB( r, g, b )
    {
        return encode_triplet( 0, r, g ) + encode_triplet( b, 255, 255 );
    }

    function encode_triplet( e1, e2, e3 )
    {
        const enc1 = e1 >> 2;					// eslint-disable-line no-bitwise
        const enc2 = ((e1 & 3) << 4) | (e2 >> 4);		// eslint-disable-line no-bitwise
        const enc3 = ((e2 & 15) << 2) | (e3 >> 6);		// eslint-disable-line no-bitwise
        const enc4 = e3 & 63;					// eslint-disable-line no-bitwise
        return keyStr.charAt(enc1) + keyStr.charAt(enc2) + keyStr.charAt(enc3) + keyStr.charAt(enc4);
    }

})();
