// Common functionality shared by the SPI and non-SPI pages.  Stuff here should 
// generally be UI hooks that don't require Backbone functionality

window.ABS = window.ABS || {};
jQuery(function () {
    ABS.common.initialize();
});

ABS.common = (function ($) {
    var that = {};
    
    that.initialize = function () {

        ABS.librarySettings.initialize();
        
        // FIXME: this should be added via selectivizr (maybe?)
        $('li:first-child').addClass('first-child');
        $('li:last-child').addClass('last-child');
        
        // add the switchbar functionality
        $('.switchbar').click(function (e) {
            var withClass = 'with-switchbar', expire;
            if ($(e.target).is('button')) {
                expire = new Date();
                expire.setDate(expire.getDate()+14);
                e.preventDefault();
                $(this).fadeOut('fast', function () {
                    $('.' + withClass).removeClass(withClass);
                    $(window).resize();
                });
                document.cookie = 'abs_switchbar=0;expires='+expire.toUTCString();
            }
        });
        
        setupLanguageSwitcher();
        
        if ( $('#myAccount').fancierBox ) {
            $('#myAccount').fancierBox();
        }
        
        // inline 'more info' modal links
        if ( $('a.show-more').fancierBox ) {
            $('a.show-more').fancierBox();
        }
        
        setupContactUsLink();
    };
    
    // given an identifier and optional variables, do basic string replacement 
    // to substitute %s tokens until we have run out of arguments. We don't use 
    // underscore's template since it wants more complex syntax than we have in 
    // the i18n strings
    // 
    // FIXME: should we add the ability to interpolate i18n-style links 
    // (<1>foo</1>)?  Will that be needed for JS?
    that.i18n = function () {
        var str  = ABS.uistrings[_.first(arguments)], positional;
        if (!str) {
            return '';
        }
        positional = str.match(/%\d+\b/);
        _.each(_.rest(arguments), function (replacement, idx) {
            var key = positional ? ('%' + (idx+1)) : '%s';
            str = str.replace(key, replacement);
        });
        return str;
    };
    
    // Returns the url minus hashbangs that aren't handled properly by
    // mobile browsers, etc.
    that.getShareUrl = function () {
        var osisArr = ABS.verseSelector.getSelectedOsisSpans();
        var osisUrl = that.osis.toUrl(osisArr[0][0]);
        var version = ABS.spi.passagePanel.collection.first().get('version').id;
        var root = window.location.protocol + "//" + window.location.host;
        return root + "/" + version + "/" + osisUrl;
    };
    
    function setupLanguageSwitcher() {
        var timer = null;
        $('.lang-switcher>a').live('click', function (ev) {
            ev.preventDefault();
            var $list = $(this).closest('li').find('ul');
            clearTimeout(timer);
            $list.slideToggle('fast', function () {
                if ($list.is(':visible')) {
                    timer = setTimeout(function () {
                        $list.slideUp('fast');
                    }, 3000);
                }
            });
        });
    }
    
    // if zenbox is loaded and configured, replace any vanilla mailto contact 
    // links with zenbox lightbox behavior instead
    function setupContactUsLink() {
        $(function () {
            if (typeof(Zenbox) !== 'undefined') {
                $('.contactus_zenbox').each(function () {
                    $(this).attr('href', '#').click(function (e) {
                          e.preventDefault(); Zenbox.show(); return false;
                    });
                });
            }
        });
    }

    that.osis = {
        // given an OSIS ID, return "$version/$book/$chapter/$verse"
        toUrl : function(osisId) {
            return osisId.replace(/[:\.]/g, '/');
        },


        // given a hash URL, return the corresponding OSIS ID
        fromUrl : function(url) {
            var urlAfterHash = url.replace(/#/, '');
            var id = urlAfterHash.replace(/\//, ':');
            id = id.replace(/\//g, '.');
            return id;
        },

        // given an OSIS ID return "$book $chapter"
        toPseudoChapterDisplay : function(osisId) {
            var components = that.osis.getComponents(osisId);
            return components.book + " " + components.chapter;
        },
        
        // given an OSIS ID return HTML class used for that verse
        // currently of the format "v$bookOrd_$chapter_$verse"
        toHtmlClass : function(osisId) {
            var comps = that.osis.getComponents(osisId);
            var defaults = { chapter : '1', verse : '1' };
            var chapter = comps.chapter || defaults.chapter;
            var verse   = comps.verse   || defaults.verse;
            verse = _.first(verse.split('-'));
            return "v" + that.osis.toBookOrd(osisId) + '_' + chapter + '_' + verse;
        },

        // given an OSIS ID return an array of HTML classes used for the verses
        // currently of the format "v$bookOrd_$chapter_$verse"
        toHtmlClasses : function(osisId) {
            var comps = that.osis.getComponents(osisId);
            var defaults = { chapter : '1', verse : '1' };
            var chapter = comps.chapter || defaults.chapter;
            var verses  = comps.verse   || defaults.verse;

            var verseList = [verses];

            if (verses.indexOf('-') !== -1) {
                // A verse range
                var startStr = _.first(verses.split('-'));
                var endStr = _.last(verses.split('-'));

                var startNum = defaults.verse;
                if (parseInt(startStr) !== NaN) {
                    startNum = parseInt(startStr);
                }

                var endNum = defaults.verse;
                if (parseInt(endStr) !== NaN) {
                    endNum = parseInt(endStr);
                }

                if  (startNum < endNum) {
                    verseList = [];
                    for (var i = startNum; i <= endNum; i++) {
                        verseList.push(i);
                    }
                } else {
                    verseList = [startNum];
                }
            } else if (verses.indexOf(',') !== -1) {
                // A comma-separated verse list
                verseList = verses.split(',');
            }

            var retArray = [];
            var bookOrd = that.osis.toBookOrd(osisId);
            _.each(verseList, function(verse) {
                retArray.push("v" + bookOrd + '_' + chapter + '_' + verse);
            });
            return retArray;
        },

        // given an OSIS ID return the ord used in passage text
        // NOTE: this ord is used in passage markup and different from
        // book.ord in the database
        toBookOrd : function(osisId) {
            var map = {"Gen":0,"Exod":1,"Lev":2,"Num":4,"Deut":5,"Josh":6,"Judg":7,"Ruth":8,"1Sam":9,"2Sam":10,"1Kgs":11,"2Kgs":12,"1Chr":13,"2Chr":14,"Ezra":15,"Neh":16,"Esth":17,"Job":18,"Ps":19,"Prov":20,"Eccl":21,"Song":22,"Isa":23,"Jer":24,"Lam":25,"Ezek":26,"Dan":27,"Hos":28,"Joel":29,"Amos":30,"Obad":31,"Jonah":32,"Mic":33,"Nah":34,"Hab":35,"Zeph":36,"Hag":37,"Zech":38,"Mal":39,"Matt":40,"Mark":41,"Luke":42,"John":43,"Acts":44,"Rom":45,"1Cor":46,"2Cor":47,"Gal":48,"Eph":49,"Phil":50,"Col":51,"1Thess":52,"2Thess":53,"1Tim":54,"2Tim":55,"Titus":56,"Phlm":57,"Heb":58,"Jas":59,"1Pet":60,"2Pet":61,"1John":62,"2John":63,"3John":64,"Jude":65,"Rev":66,"Bar":67,"AddDan":68,"PrAzar":69,"Bel":70,"SgThree":71,"Sus":72,"1Esd":73,"2Esd":74,"AddEsth":75,"EpJer":76,"Jdt":77,"1Macc":78,"2Macc":79,"3Macc":80,"4Macc":81,"PrMan":82,"Sir":83,"Tob":84,"Wis":85};
            var comps = that.osis.getComponents(osisId);
            if (comps.book in map) {
                return map[comps.book];
            }
            else if (osisId in map) {
                return map[osisId];
            }
            else {
                return null;
            }
        },

        // given a book ord, return the osis ID for the book
        // book ords are currently used in passage text
        // NOTE: this ord is used in passage markup and different from
        // book.ord in the database
        fromBookOrd : function(ord) {
            var books = {"0":"Gen","1":"Exod","2":"Lev","4":"Num","5":"Deut","6":"Josh","7":"Judg","8":"Ruth","9":"1Sam","10":"2Sam","11":"1Kgs","12":"2Kgs","13":"1Chr","14":"2Chr","15":"Ezra","16":"Neh","17":"Esth","18":"Job","19":"Ps","20":"Prov","21":"Eccl","22":"Song","23":"Isa","24":"Jer","25":"Lam","26":"Ezek","27":"Dan","28":"Hos","29":"Joel","30":"Amos","31":"Obad","32":"Jonah","33":"Mic","34":"Nah","35":"Hab","36":"Zeph","37":"Hag","38":"Zech","39":"Mal","40":"Matt","41":"Mark","42":"Luke","43":"John","44":"Acts","45":"Rom","46":"1Cor","47":"2Cor","48":"Gal","49":"Eph","50":"Phil","51":"Col","52":"1Thess","53":"2Thess","54":"1Tim","55":"2Tim","56":"Titus","57":"Phlm","58":"Heb","59":"Jas","60":"1Pet","61":"2Pet","62":"1John","63":"2John","64":"3John","65":"Jude","66":"Rev","67":"Bar","68":"AddDan","69":"PrAzar","70":"Bel","71":"SgThree","72":"Sus","73":"1Esd","74":"2Esd","75":"AddEsth","76":"EpJer","77":"Jdt","78":"1Macc","79":"2Macc","80":"3Macc","81":"4Macc","82":"PrMan","83":"Sir","84":"Tob","85":"Wis"};
            if (ord in books) {
                return books[ord];
            }
            else {
                return null;
            }
        },

        // split an OSIS ref into it's component OSIS ids
        // 'NIV:Gen.1.1-NIV:Gen.1.4' => ['NIV:Gen.1.1', 'NIV:Gen.1.4']
        splitReference : function(osisRef) {
            // replace possible dash in version with |DASH|
            // so that we can later split on dash and not split a version ID
            var firstVersionHasDash = osisRef.match(/^\w+\-\w+:/);
            // not exactly thrilled with this algorithm
            // since it is easy to identify if the first ref has a version
            // with a dash, we'll check for that and assume second reference
            // is the same version. I think this is a safe assumption.
            if (firstVersionHasDash) {
                var version = firstVersionHasDash[0].replace(/-/, '|DASH|');
                while (osisRef.indexOf(firstVersionHasDash[0]) !== -1) {
                    osisRef = osisRef.replace(firstVersionHasDash[0], version);
                }
            }

            var refs = osisRef.split(/-/);
            _.each(refs, function(ref, index) {
                // add dash back in place
                refs[index] = ref.replace('|DASH|', '-');
            });
            return refs;
        },
        
        getComponents : function(osisId) {
            var comps = {},
                keys  = ['book', 'chapter', 'verse'],
                match = null,
                version, rest;
            match = /^([^\.]+):(.*)$/.exec(osisId);
            if (match) {
                version = match[1];
                rest = match[2];
            }
            else if (/^\w+$/.exec(osisId)) {
                comps.version = osisId;
            }
            else {
                rest = osisId;
            }
            if (version && version != osisId) {
                comps.version = version;
            }
            if (rest) {
                var pieces = rest.split('.');
                _.each(pieces, function(piece, index) {
                    if (piece !== '') {
                        comps[keys[index]] = piece;
                    }
                });
            }
            return comps;
        }
    };    

    // Functions for the custom ABS Scripture Analytics system
    that.sa = {
        osisBookIdToUSXId : function(osisId) {
            var ids = {"gen":"GEN","exod":"EXO","lev":"LEV","num":"NUM","deut":"DEU","josh":"JOS","judg":"JDG","ruth":"RUT","1sam":"1SA","2sam":"2SA","1kgs":"1KI","2kgs":"2KI","1chr":"1CH","2chr":"2CH","ezra":"EZR","neh":"NEH","esth":"EST","job":"JOB","ps":"PSA","prov":"PRO","eccl":"ECC","song":"SNG","isa":"ISA","jer":"JER","lam":"LAM","ezek":"EZK","dan":"DAN","hos":"HOS","joel":"JOL","amos":"AMO","obad":"OBA","jonah":"JON","mic":"MIC","nah":"NAM","hab":"HAB","zeph":"ZEP","hag":"HAG","zech":"ZEC","mal":"MAL","matt":"MAT","mark":"MRK","luke":"LUK","john":"JHN","acts":"ACT","rom":"ROM","1cor":"1CO","2cor":"2CO","gal":"GAL","eph":"EPH","phil":"PHP","col":"COL","1thess":"1TH","2thess":"2TH","1tim":"1TI","2tim":"2TI","titus":"TIT","phlm":"PHM","heb":"HEB","jas":"JAS","1pet":"1PE","2pet":"2PE","1john":"1JN","2john":"2JN","3john":"3JN","jude":"JUD","rev":"REV","tob":"TOB","jdt":"JDT","addesth":"ESG","wis":"WIS","sir":"SIR","bar":"BAR","epjer":"LJE","prazar":"S3Y","sus":"SUS","bel":"BEL","1macc":"1MA","2macc":"2MA","3macc":"3MA","4macc":"4MA","prman":"MAN","1esd":"1ES","2esd":"2ES","ps151":"PS2"};

            var id = osisId.toLowerCase();
            if (id in ids) {
                return ids[id];
            }
            else {
                return null;
            }
        },

        convertOsisIdToSAId : function(osisId, includeVersion) {
            if (typeof includeVersion === "undefined") {
                includeVersion = true;
            }

            var parts = that.osis.getComponents(osisId);
            var book = that.sa.osisBookIdToUSXId(parts.book);

            var version = parts.version;
            // prefix version with language for those that don't
            // already have the language included in the version ID
            if (version.split('-').length < 2) {
                if (ABS.bootstrap && ABS.bootstrap.versions) {
                    _.each(ABS.bootstrap.versions, function(ver) {
                        if (ver.version == version) {
                            var lang = ver.lang.split('-')[0];
                            version = lang + "-" + version;
                        }
                    });
                }
            }

            var saId = "";
            
            if (includeVersion) {
                saId = version + ":";
            }
            
            saId = saId + book + "." + parts.chapter;

            if (parts.verse) {
                saId = saId + "." + parts.verse;
            }

            return saId;
        },

        convertOsisIdRangeToSAIdRange : function(osisIds) {
            var retRange = "";

            var ids = ABS.common.osis.splitReference(osisIds);
            if (ids.length == 2) {
                var saId1 = that.sa.convertOsisIdToSAId(ids[0]);
                var saId2 = that.sa.convertOsisIdToSAId(ids[1], false);
                
                retRange = saId1 + '-' + saId2;
            }

            return retRange;
        },

        logRefToServer : function(osisId) {
            if (osisId) {
                this.logRefArrayToServer([osisId]);
            }
        },

        logRefArrayToServer : function(osisIds) {
            // _BAPI is the namespace of the SA functions
            if (_BAPI) {
                // Always use the same app ID
                var APP_ID = 'biblesearch';

                var saIds = [];
                _.each(osisIds, function(id) {
                    var saId = "";
                    if (ABS.common.osis.splitReference(id).length > 1) {
                        saId = that.sa.convertOsisIdRangeToSAIdRange(id);
                    }
                    else {
                        saId = that.sa.convertOsisIdToSAId(id);
                    }
                    saIds.push(saId);
                });

                // This actually sends the data to the server
                _BAPI.s(APP_ID, saIds);
            }
        }
    };
 
    return that;
    
}(jQuery));

/* Configures settings in the JS libraries we're using */
ABS.librarySettings = (function ($) {
    var that = {};
    that.initialize = function () {
        setupUnderscore();
        
        if ($.fn.fancybox) {
            setupFancybox();
        }
    };
    
    function setupUnderscore() {
        /* Use PHP-style delimiters for consistency */
        _.templateSettings = {
            "interpolate" : /\<\?\=(.+?)\?\>/g,
            "escape" : /\<\?\-(.+?)\?\>/g,
            "evaluate" : /\<\?(.+?)\?\>/g
        };
        
        // add some mixins
        _.mixin({
            capitalize: function (string) {
                return (
                    string.charAt(0).toUpperCase() + 
                    string.substring(1).toLowerCase()
                );
            },
            
            dirify: function (string) {
                return string.toLowerCase().replace(/[^a-zA-Z0-9]/, '-');
            },
            
            isDefined: function (item) {
                return !_.isUndefined(item);
            }
            
        });
    }
    
    function setupFancybox() {
        
        // a jQuery plugin to encapsulate our desired fancybox lightbox behavior
        $.fn.fancierBox = (function () {
            var lastWidth, lastHeight, lastOrig;
            
            // the key/value passed via href or form data to indicate to the 
            // backend that this is a JS request
            var jsifier = {js: 1};
            
            // setup fancybox defaults
            $.fn.fancybox.defaults = $.extend({}, $.fn.fancybox.defaults, {
                transitionIn: 'elastic',
                transitionOut: 'elastic',
                easingIn: 'easeInExpo',
                easingOut: 'easeOutExpo',
                width: 650,
                height: 550,
                autoDimensions: false,
                padding: 0,
                overlayColor: '#000000',
                onStart: function () {
                    if (lastWidth) {
                        this.width = lastWidth;
                    }
                    if (lastHeight) {
                        this.height = lastHeight;
                    }
                    if (lastOrig) {
                        this.orig = lastOrig;
                    }
                },
                onComplete: function () {
                    lastWidth  = this.width;
                    lastHeight = this.height;
                    lastOrig   = this.orig;
                },
                onClosed: function () {
                    lastWidth  = null;
                    lastHeight = null;
                    lastOrig   = null;
                }
            });
            
            // allow clicks on links to reload current fancybox
            $('#fancybox-content a').live('click', function (e) {
                var $link = $(this), href = $link.attr('href');
                if ($link.is('[target=_top]') && href.match(/^#/)) {
                    $.fancybox.close();
                    location.hash = href;
                }
                else if ($link.is(':not([target])')) {
                    prepare(e);
                    $.ajax({
                        url: jsify(href),
                        success: success
                    });
                }
            });
            
            // allow form submits to reload current fancybox
            $('#fancybox-content form').live('submit', function (e) {
                var txt = ABS.common.i18n('saving');
                prepare(e);
                $(this).find(':submit').attr(
                    {val: txt, disabled: true}
                ).text(txt);
                $(this).ajaxSubmit({data: jsifier, success: success});
            });
            
            // private functions
            function prepare(e) {
                e.preventDefault();
                $.fancybox.showActivity();
            }
            function success(data) {
                $.fancybox(data);
            }
            // append ?js=1 or &js=1 to a string, depending on what it contains
            function jsify(elem) {
                var href = elem;
                if (elem.href) {
                    href = elem.href;
                }
                if (elem.jquery) {
                    href = elem.attr('href');
                }
                return href + (href.match(/\?/) ? '&' : '?') + $.param(jsifier);
            }
            
            // plugin implementation
            return function (opts) {
                opts = $.extend({}, opts);
                return $(this).each(function () {
                    var $el    = $(this),
                        href   = $el.attr('href'),
                        myOpts = opts;
                        
                    $el.data('width') && (myOpts.width = $el.data('width'));
                    $el.data('height') && (myOpts.height = $el.data('height'));
                    
                    if (!href.match(/^#/)) {
                        myOpts = $.extend(myOpts, {href: jsify(href)});
                    }
                    $(this).fancybox(myOpts);
                });
            };
        }());
    }

    return that;
}(jQuery));

