// Language utilities _________________________________________________________

// Use prototypes to implement a workable class system
//
function js_class(classname, superclassname, defs) {
    if (superclassname)
        defs.prototype= js_prototypes[superclassname];
    var classobj= js_classobj()
    js_prototypes[classname]=classobj.prototype= new defs;
    window[classname]= classobj;
}

function js_classobj() {
    return function() { this._init.apply(this, arguments); }
}

var js_prototypes= new Object();


// Use a closure to allow a method to be called back with 'this' pointing to
// the actual owner object. Indirect through a look-up Array to avoid the
// browser objects getting circular references (memory leaks in IE)
//
function js_callback(obj, method) {
    var i= js_callback_objects.length;
    js_callback_objects[i]= obj;
    js_callback_methods[i]= method;
    return js_callback_make(i);
}

function js_callback_make(i) {
    return function() {
        if (!window.js_callback_objects) return;
        var that= js_callback_objects[i];
        return that[js_callback_methods[i]].apply(that, arguments);
    };
};

var js_callback_objects= new Array();
var js_callback_methods= new Array();

// Trivial lambdas
//
function js_returnfalse() { return false; };
function js_returntrue() { return true; };
function js_returnnull() { return null; };


// IE fixes ___________________________________________________________________

// Work around IE CSS problems
//
var IEWIN= false;
var IE7= false;
/*@cc_on
@if (@_win32)
    IEWIN= true;
    @if (@_jscript_version>=5.7)
        IE7 = true;
    @end
@end @*/

// CSS values that IE needs help with
//
var CURSOR_POINTER= IEWIN? 'hand' : 'pointer';
var DISPLAY_ROW= IEWIN? 'block' : 'table-row';
var DISPLAY_ROWGROUP= IEWIN? 'block' : 'table-row-group';

// Constants that should be defined on Node, but aren't in IE
//
var ELEMENT_NODE= 1;
var TEXT_NODE= 3;


// Image utilities ____________________________________________________________

// KHTML's Image constructor doesn't create a DOM Node, but
// IE's createElement call doesn't create a real image. Choose which is best
//
function img_create(src, alt, title) {
    var img= IEWIN? new Image() : document.createElement('img');
    img.src= src;
    if (alt!=null) img.alt= alt;
    if (title!=null) img.title= title;
    return img;
}

// Preload images (on-page in a hidden div)
//
function img_preload(url) {
    if (img_preloads[url]) return;
    img_preloads[url]= true;
    var preload= document.getElementById('img_preload');
    if (!preload) {
        preload= document.createElement('div');
        preload.id= 'img_preload';
        preload.style.position= 'absolute'; preload.style.overflow= 'hidden';
        preload.style.left= '-128px'; preload.style.width= '64px';
        document.body.insertBefore(preload, document.body.firstChild);
    }
    preload.appendChild(img_create(url));
}

var img_preloads= new Object();

// JSS actions ________________________________________________________________

// Make an element fade in and out at a particular rate
//
js_class('OpacityThrobber', null, function() {
    this._init= function(element, period) {
        this.element= element;
        this.period= period;
        this.interval= null;
        this.epoch= 0;
    };
    this.start= function() {
        if (this.interval===null) {
            this.interval= window.setInterval(js_callback(this, 'animate'), 75);
            this.epoch= new Date().getTime();
        }
    };
    this.stop= function() {
        if (this.interval!==null) {
            window.clearInterval(this.interval);
            this.interval= null;
        }
    };
    this.animate= function() {
        var t= new Date().getTime()-this.epoch;
        var d= (Math.cos(t*2*Math.PI/this.period)+1)/2;
        if (IEWIN) {
            this.element.style.filter= 'alpha(opacity='+Math.floor(d*100)+')';
        } else
            this.element.style.opacity= ''+d;
    };
});


// Make min-height of #page work under IE5/6
//
var timeout= null;
function min_onresize() {
    if (timeout===null)
        timeout= window.setTimeout(min_resize, 10);
}
function min_resize() {
    var page= document.getElementById('page');
    var root= document.compatMode=='CSS1Compat'? document.documentElement : document.body;
    var viewportheight= root.clientHeight;
    page.style.paddingBottom= '0';
    var naturalheight= page.offsetHeight;
    var pad= viewportheight-naturalheight;
    if (pad<0) pad= 0;
    page.style.paddingBottom= pad+'px';
    document.getElementById('page-w').style.height=document.getElementById('page-e').style.height= naturalheight+pad;
    timeout= null;
}


// On contact page, hide the license agreement row when it's not needed
//
function purpose_change() {
    var select= document.getElementById('f-purpose');
    var purpose= select.options[select.selectedIndex].value;
    var license= purpose=='xmlgatewayce' || purpose=='xmlgateway' || purpose=='ssoplugin';
    document.getElementById('contact-licensing').style.display= license? DISPLAY_ROW : 'none';
}

// Navbar image preload helper
//
function jss_preloadnav(id) {
    var el= document.getElementById(id);
    if (!el) return;
    var links= el.getElementsByTagName('a');
    for (var i= links.length; i-->0;) {
        var linkid= links[i].id;
        if (linkid && linkid.substring(0, 4)=='nav-') {
            var name= linkid.substring(4);
            img_preload('/img/'+id+'/'+name+'-2.png');
    }   }
}


// Start throbber and min-height fix on full content load
//
function jss_loaded() {
    // Preload hover images
    //
    var buttons= new Array('company', 'xmlgateway', 'ssoplugin');
    for (var i= buttons.length; i-->0;) {
        var button= document.getElementById('button-'+buttons[i]);
        if (button) img_preload('/img/button/'+buttons[i]+'-2.png');
    }
    img_preload('/img/action/search-2.png');
    img_preload('/img/action/contact-2.png');
    jss_preloadnav('nav');
    jss_preloadnav('subnav');

    // Fix page height on IE
    //
    if (IEWIN && !IE7)
        (window.onresize= min_onresize)();

    // Make glow div throb. On IE, this requires some contortions to get around its inabilty to
    // apply alpha filters and alpha images to the same element. Actually even this nesting
    // solution doesn't generate "right" results - it does a 'min' of opacities instead of multiplying
    // them, but the effect still looks good. If we could really be bothered to get it "right" a
    // Compositor filter might be usable, but what a shag eh.
    //
    var glow= document.getElementById('mast-glow');
    if (glow) {
        if (IEWIN) {
            glow.style.backgroundImage= 'none';
            var backhack= document.createElement('div');
            backhack.style.position= 'absolute';
            backhack.style.left=backhack.style.top= '0';
            backhack.style.width=backhack.style.height= '100%';
            backhack.style.filter= 'progid:DXImageTransform.Microsoft.AlphaImageLoader(src=\'/img/mast/glow.png\')';
            glow.appendChild(backhack);
        }
        new OpacityThrobber(glow, 2400).start();
    }

    // Add contact page fold
    //
    if (document.getElementById('contact-licensing')) {
        document.getElementById('f-purpose').onchange= purpose_change;
        purpose_change();
    }
}
window.onload= jss_loaded;

// Old IE/Win needs CSS hacks, include them here (more reliable than using an
// HTML conditional comment due to standalone IEs,
//
if (IEWIN && !IE7)
    document.write('<link rel="stylesheet" href="/style/ie.css" type="text/css" />');
