﻿var _onDemandComponents = [];
var _userService, _uiService;
var _globalPollInterval = 10000;
var _userId;

var Config = {
    Paths: {
        Img: '/images/',
        Web: '/'
    }
};

var Enums = {
    // reference: Enums.cs
    DraftMethod: {
        Snake: 1,
        SalaryCap: 2,
        Auction: 3,
        ProPickem: 4
    },
    DraftMethodText: {
        1: 'Snake',
        2: 'Salary Cap',
        3: 'Auction',
        4: 'Pro Pick\'em'
    },

    ErrorText: {
        Default: 'An unexpected error has occurred.',
        
        0: 'None',

        // 100+: generic
        100: 'Unspecified',
        101: 'Not implemented',
        
        // 200+: login
        200: 'You are not logged in.',
        201: 'Invalid email address and/or password.',
        
        // 300+: registration
        301: 'The username is already registered.',
        302: 'The email address is already registered.',
        303: 'Invalid username.',
        304: 'Invalid email address.',
        305: 'Invalid password.',
        306: 'Invalid registration field.',
        307: 'You need to be at least 13 years of age to register.',
        
        // 400+: leagues
        401: 'You are not registered to this league.',
        402: 'Invalid league id.',

        // 410+: league registration
        410: 'The league\'s registration is closed.',
        411: 'Insufficient funds to join.',
        412: 'Already registered to this league.',
        413: 'You have reached the limit of free leagues that you can enter.',

        // 420+: league registration (regional restrictions)
        420: 'You need to be at least 13 years of age to play.',
        421: 'You are below the age limit to play in cash leagues from your location.',
        422: 'Due to legal restrictions, you may not play in cash leagues from your present location.',
        
        // 500+: draft generic
        500: 'The draft is not active.',
        501: 'Invalid player.',
        502: 'Player already picked.',
        503: 'You have selected the maximum number of players for this position.  In order to ensure a full roster, all position requirements must be filled.',
        599: 'Other draft error.',

        // 600+: snake
        601: 'It is not your turn to pick.',
        699: 'Other snake draft error.',

        // 700+ cap
        799: 'Other salary cap draft error.'

    },

    LeagueStatus: {
        PreReg: 1,
        RegOpen: 2,
        RegClosed: 3,
        DraftReady: 4,
        DraftActive: 5,
        DraftComplete: 6,
        ScoringStarted: 7,
        ScoringEnded: 8,
        Complete: 9,
        Cancelled: 10
    },
    
    MoneyCurrency: {
        Money: 1,
        FFPoints: 2
    },

    PlayerType: {
        Player: 1,
        Team: 2
    },
    
    ScoringPeriod: {
        Daily: 1,
        Weekly: 2
    },
    ScoringPeriodText: {
        1: 'Daily',
        2: 'Weekly'
    },

    Sport: {
        MLB: 1,
        NBA: 2,
        NFL: 3,
        NHL: 4
    },
    SportText: {
        1: 'MLB',
        2: 'NBA',
        3: 'NFL',
        4: 'NHL'
    }
    
}

var Locations = {
    _decoded: false,
    
    CountryDefs: [ 
        'CA:Canada:AB,BC,MB,NB,NL,NS,NT,NU,ON,PE,QC,SK,YT',
        'US:United States:AL,AK,AZ,AR,CA,CO,CT,DE,DC,FL,GA,HI,ID,IL,IN,IA,KS,KY,LA,MA,MD,ME,MI,MN,MO,MS,MT,NE,NC,ND,NV,NH,NJ,NM,NY,OH,OK,OR,PA,RI,SC,SD,TN,TX,UT,VA,VT,WA,WI,WV,WY'
    ],
    
    Decode: function() {
        Locations.Countries = [];

        $.each(Locations.CountryDefs, function(i, item) {
            var tokens = item.split(':');
            var c = new Object();
            c.Code = tokens[0];
            c.Name = tokens[1];
            c.RegionCodes = tokens[2].split(',');
            Locations.Countries.push(c);
        });
        
        Locations._decoded = true;
    },
    
    GetCountries: function() {
        if (!Locations._decoded)
            Locations.Decode();
        
        return Locations.Countries;
    },
    
    GetRegions: function(countryCode) {
        if (!Locations._decoded)
            Locations.Decode();

        for (var i = 0; i < Locations.Countries.length; i++)
            if (Locations.Countries[i].Code == countryCode)
                return Locations.Countries[i].RegionCodes;
    
        return [];
    }
}





/* -- PROTOTYPES -- */
// -- Array.indexOf() -- //
if (!Array.prototype.indexOf)
{
  Array.prototype.indexOf = function(elt /*, from*/)
  {
    var len = this.length;

    var from = Number(arguments[1]) || 0;
    from = (from < 0)
         ? Math.ceil(from)
         : Math.floor(from);
    if (from < 0)
      from += len;

    for (; from < len; from++)
    {
      if (from in this &&
          this[from] === elt)
        return from;
    }
    return -1;
  };
}
 


// -- String.trim() -- //
// src: http://www.somacon.com/p355.php
String.prototype.trim = function() {
	return this.replace(/^\s+|\s+$/g,"");
}
String.prototype.ltrim = function() {
	return this.replace(/^\s+/,"");
}
String.prototype.rtrim = function() {
	return this.replace(/\s+$/,"");
}





// -- GLOBAL ONLOAD -- //
$(function() {
    _userService = new FF.UserService();
    
    initForm();
    
    Locations.Decode();
});

function initForm() {
    // disable the default enter-key behaviour (form submit)
    $('form')
        .keypress(function(e) {
            if (e.keyCode == 13)
                return false;
        });
}





/* -- UTILITY -- */
function normalizeResult(result) {
    // this normalizes the result from a WCF call, converting to an object from JSON
    // -> if the returned content-type is application/json, the .NET result functions treat it as JSON (expected), so this returns it as is
    // -> if the content-type is text/html, it's treated as text, so this creates an object from JSON
    if (typeof result == 'object')
        return result;
    else
        return eval('(' + result + ')').d;
}





/* -- DIALOGS (& ERRORS) -- */
function basicDialog(title, html, close, innerWidth, closeCallback) {
    $.modal.close();
    $('#basic-dialog').remove();
    
    $('body').append('<div id="basic-dialog" style="display: none;"></div>');
    
    $('#basic-dialog')
        .ffdialog(
            {
                title: title,
                close: (close === 'undefined' ? true : close),
                innerWidth: (innerWidth === 'undefined' ? 400 : innerWidth)
            }
        );
            
    $('#basic-dialog .html')
        .html(html);
    
    $('#basic-dialog')
        .modal({
            close: (close === 'undefined' ? true : close),
            onClose: closeCallback
        });
}

function basicError(title, html, close, innerWidth, closeCallback) {
    title = (title === 'undefined' || title == null) ? 'Error' : title;
    html = (html === 'undefined' || html == null) ? 'An unexpected error has occurred.' : html;
    close = (close === 'undefined' || close == null) ? true : close;
    innerWidth = (innerWidth === 'undefined' || innerWidth == null) ? undefined : innerWidth;
    
    basicDialog(title, html, close, innerWidth, closeCallback);
}

function getErrorText(errorCode) {
    return Enums.ErrorText[errorCode];
}





/* -- LOADING ANIMATIONS -- */
function showLoader(selector, zIndex) {
    var $elem = $(selector);
    var w = $elem.width(),
        h = $elem.height(),
        o = $elem.offset(),
        left = o.left,
        top = o.top;
    
    if (zIndex == undefined)
        zIndex = 900;
    
    var html = $('<div class="loader" style="z-index: ' + zIndex + ' !important" rel="' + selector + '"><img src="' + Config.Paths.Img + 'loaders/loading-40x40a.gif" style="width: 40px; height: 40px;" alt="Please wait..."/></div>')
        .css('position', 'absolute')
        .css('background-image', 'url("' + Config.Paths.Img + 'loaders/loader-bg.png")')
        .css('background-repeat', 'repeat')
        .css('text-align', 'center')
        
        .css('width', w)
        .css('height', h)
        .css('left', left)
        .css('top', top)
        .css('visibility', 'visible');
        
    html.find('img')
        .css('margin-top', Math.round((h / 2) - 16));
        
    $('body').append(html);
}

function hideLoader(selector) {
    $('.loader[rel="' + selector + '"]').remove();
}

var _globalLoaderTimeout;
function showGlobalLoader() {
    // at first, the page gets veiled but the loading animation doesn't appear until 1 second of waiting has elapsed
    $('<div class="c" id="global-loader"><img src="' + Config.Paths.Img + 'loaders/loader-140x.gif" style="width: 140px; height: 140px; display: none;" alt="Working..."></div>')
        .modal({
            opacity: 75,
            overlayCss: { backgroundColor: '#000000' },
            close: false
        });
        
    _globalLoaderTimeout = setTimeout(function() { $('#global-loader img').show() }, 1000)
}

function hideGlobalLoader() {
    $.modal.close();
    clearTimeout(_globalLoaderTimeout);
}





/* -- FORM UTILITY -- */
function saveFormFieldValues(containerSelector) {
    // form fields lose their value when modal.close() is called, so this function allows form values to be saved,
    // then reloaded into the elements (through reloadFormFieldValues) when a lightbox is redisplayed
    var ret = [];
    $(containerSelector).find('select, input').each(function() {
        ret.push({ 
            tag: this.nodeName.toLowerCase(), 
            name: $(this).attr('name'), 
            type: $(this).attr('type'), 
            val: $(this).val(), 
            checked: $(this).is(':checked') });
    });
    
    return ret;
}
    
function reloadFormFieldValues(containerSelector, fields) {
    // see saveFormFieldValues()
    var $form = $(containerSelector);
    $.each(fields, function(i, item) {
        if (item.type == 'radio') {
            var $elem = $form.find('*[name="' + item.name + '"][value="' + item.val + '"]:first');
            $elem.attr('checked', item.checked ? 'checked' : '');
        }
        else {
            var $elem = $form.find('*[name="' + item.name + '"]:first');
            if (item.type == 'checkbox')
                $elem.attr('checked', item.checked ? 'checked' : '');
            else
                $elem.val(item.val);
                
            if (item.tag == 'select')
                $elem.change();
        }
    });
}





/* -- DATE FUNCTIONS -- */
Date.fromUtc = function(dateString) 
{
    // generates and returns a date from an UTC-formatted string
    // -> yyyy-MM-dd HH:mm:ss (time is optional)
    
    var x = /(\d{4})-(\d{2})-(\d{2})(?: )?(\d{1,2})?(?::)?(\d{2})?(?::)?(\d{2})?/;
    var tokens = x.exec(dateString);

    if (tokens == null)
        return null;
    else
        return new Date(tokens[1], tokens[2] - 1, tokens[3],
            tokens[4] == null ? 0 : tokens[4], 
            tokens[5] == null ? 0 : tokens[5], 
            tokens[6] == null ? 0 : tokens[6]);
}

Date.dayNames = [ 'Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday' ];
    
Date.monthNames = [ 
    'January', 'February', 'March', 
    'April', 'May', 'June', 
    'July', 'August', 'September', 
    'October', 'November', 'December'
    ];
    
Date.prototype.toUtcTimeString = function() {
    return this.getFullYear() + '-' + pad(this.getMonth() + 1, 2) + '-' + pad(this.getDate(), 2)
        + ' ' + pad(this.getHours(), 2) + ':' + pad(this.getMinutes(), 2) + ':' + pad(this.getSeconds(), 2);
};

Date.prototype.toUtcDateString = function() {
    return this.getFullYear() + '-' + pad(this.getMonth() + 1, 2) + '-' + pad(this.getDate(), 2);
};

Date.prototype.getMonthName = function() {
    return Date.monthNames[this.getMonth()];
};

Date.prototype.getShortMonthName = function() {
    return this.getMonthName(this.getMonth()).substr(0, 3);
}

Date.prototype.getDayName = function() {
    return Date.dayNames[this.getDay()];
};

Date.prototype.getHours12 = function() {
    var h = this.getHours();
    return (h == 0 || h == 12) ? 12 : (h % 12);
};

Date.prototype.getPeriod12 = function() {
    return (this.getHours() < 12) ? 'AM' : 'PM';
};

Date.prototype.addDays = function(days) {
    // should be 86400000 for 24 hours; adding 25 hours to prevent st/dst problems
    return new Date(this.getTime() + days * 90000000);
};

Date.prototype.stripTime = function() {
    return new Date(this.getFullYear(), this.getMonth(), this.getDate());//
}

Date.prototype.formatTime = function() {
    var hh = (this.getHours() == 0 || this.getHours() == 12) ? '12' : format00(this.getHours() % 12);
    var mm = format00(this.getMinutes());
    var tt = this.getHours() < 12 ? 'AM' : 'PM';
    return hh + ':' + mm + ' ' + tt;
}

Date.prototype.toDefaultDateString = function() {
    return this.getShortMonthName() + ' ' + this.getDate() + ', ' + this.getFullYear();
}

Date.prototype.toDefaultTimeString = function() {
    return this.formatTime();
}

function format00(num) {
    if (num < 10)
        return '0' + num;
    else
        return num;
}





/* -- TEXT/FORMATTING -- */
function truncate(text, length) {
    return (text.length < length) ? text : (text.substr(0, length - 3) + '&#0133;');
}

function pad(number, length) {
    var len = number.toString().length;
    var ret = number.toString();
    for (var i = 0; i < length - len; i++)
        ret = '0' + ret;
    return ret;
}

function getOrdinalSuffix(num) {
    // adapted from http://www.highdots.com/forums/javascript/ordinal-st-nd-rd-th-41109-2.html
    var n = num % 100;
    var suff = ["th", "st", "nd", "rd", "th"]; // suff for suffix
    var ord= n<21?(n<4 ? suff[n]:suff[0]): (n%10>4 ? suff[0] : suff[n%10]);
    return ord;
}

function addCommas(nStr)
{
    // source: http://www.mredkj.com/javascript/nfbasic.html (2010-04-29)
    nStr += '';
    x = nStr.split('.');
    x1 = x[0];
    x2 = x.length > 1 ? '.' + x[1] : '';
    var rgx = /(\d+)(\d{3})/;
    while (rgx.test(x1)) {
        x1 = x1.replace(rgx, '$1' + ',' + '$2');
    }
    return x1 + x2;
}





// -- ON-DEMAND LOADING -- //
function load(url, contentType, method, successCallback, failureCallback) {
    // contentType: js, css, html
    if (_onDemandComponents[url + '.' + contentType] != null) {
        if (successCallback !== 'undefined')
            successCallback();
        return;
    }
    
    $.ajax({
        url: url,
        type: 'get', //method.toUpperCase(),
        success: function(data) {
            _onDemandComponents[url + '.' + contentType] = true;
            
            switch (contentType) {
                case 'js':
                    var html = '<script type="text/javascript">' + data + '<\/script>';
                    $('head').prepend(html);
                    break;
                    
                case 'css':
                    var html = '<style type="text/css">' + data + '</style>';
                    $('head').prepend(html);
                    break;

                case 'html':
                    $('body').prepend(data);
                    break;
            }
            
            if (successCallback !== 'undefined')
                successCallback();
        },
            
        error: function() {
            if (failureCallback !== 'undefined')
                failureCallback();
        }
    });
}

function loadMulti(loadArray, successCallback, failureCallback) {
    // loadMulti: should have a third callback for when objects have already been loaded previously?
    var complete = 0;
    for (var i = 0; i < loadArray.length; i++) {
        var loadObj = loadArray[i];
        load(loadObj.url, loadObj.contentType, loadObj.method,
            
            // successCallback
            function() {
                complete++;
                if (complete == loadArray.length && successCallback !== 'undefined')
                    successCallback();
            },
            
            // failureCallback
            function() {
                complete++;
                if (complete == loadArray.length && failureCallback !== 'undefined')
                    failureCallback();
            }
        );
    }
}






