function resetCurves( ) {
    $$('.curved').each(function(el) {
        curveCorners(el);

    });
}

function curveCorners(el) {
    var wregex = /radius([0-9]+)/;
    var s;
    var styles;
    var m;

    el.setStyles({
        "position": "", "display": "", "width": "", "height": "",
        "border": "", "backgroundImage": "", "padding": "", "margin": ""
    });

    var s = {'antialias': true};
    m = el.className.match(wregex);
    var classes = ['tl','tr','br','bl'];
    var classOffsets = {'tl': 0, 'tr': 1, 'br': 2, 'bl': 3};
    var actClasses = [];
    classes.each(function(klass) {
        if(el.hasClass(klass)) actClasses.push(klass);
    });
    if(!actClasses.length) actClasses = classes;

    if(m) {
        actClasses.each(function(k) {
            s[k] = {'radius': parseInt(m[1])};
        });
    } else {
        var styles = el.getStyle("borderWidth").split(" ");
        classes.each(function(k) {
            s[k] = {'radius': styles[classOffsets[k]].toInt()};
        });
        s['tl'] = {'radius': styles[0].toInt()};
    }

    curvyCorners(s, el);
}


window.addEvent("domready", function(ev) {
    var classMap = {'dca': 0, 'hss': 1, 'faa': 3, 'cdr': 2};

    $$('div#content').setStyle("height", "auto");

    var inc = 800;
    var delay = inc;
    $$('.frontText').setOpacity(0);
    window.addEvent("load", function(ev) {
        $$('.frontText').each(function(el) {
            el.setOpacity(0);
            el.set('tween', {'duration': inc});
            (function( ) { el.tween('opacity', 1); }).delay(delay);
            if(!el.hasClass("shadow")) {
                delay += inc;
                el.addEvent("mouseenter", function(ev) {
                    var kl = classMap[this.get('class').replace("frontText", "").trim()];
                    var el =  $$('.buttonDock')[0].getElements("li")[kl];
                    el.fireEvent("mouseenter");
                    this.getElements("a").tween("color", "#fff");
                });
                el.addEvent("mouseleave", function(ev) {
                    var kl = classMap[this.get('class').replace("frontText", "").trim()];
                    var el =  $$('.buttonDock')[0].getElements("li")[kl];
                    el.fireEvent("mouseleave");
                    this.getElements("a").tween("color", "#eee");
                });
                el.addEvent("click", function(ev) {
                    var kl = classMap[this.get('class').replace("frontText", "").trim()];
                    var el =  $$('.buttonDock')[0].getElements("li")[kl];
                    el.fireEvent("click");
                });
            }
        });
    });


    $$('body')[0].store('historyManager', new HistoryManagerX()); 
    resizeNavigation( );
    resetCurves( );
    Browser.fixPNG($('tagline').getElement("img"));

    (function( ) { $$('body')[0].retrieve('historyManager').start(); }).delay(500);
    var rot;
    $$('ul.clients').each(function(el) {
        var ttip = new Element("div", {'class': 'tooltip'});
        ttip.inject($$('body')[0]);

        var pos = el.getPosition( );
        var size = el.getDimensions( );
        ttip.setStyle("width", size.x);
        ttip.setStyle("left", pos.x);
        ttip.setStyle("top", pos.y - ttip.getDimensions( ).y);
        ttip.store('dopacity', 0.8);
        ttip.store('actheight', ttip.getDimensions( ).y);
        ttip.store('dheight', ttip.getSize( ).y);
        ttip.store('dtop', ttip.getStyle("top").toInt());
        ttip.setStyle('height', 0);
        ttip.setOpacity(0);
        ttip.setStyle("top", pos.y);
        el.store('tooltip', ttip);

        rot = new ListRotator(el, {
            'scrollDelay': 30,
            'scrollSpeed': 1
			/*
            'itemCallbacks': {
                'mouseenter': function(ev) {
                    var e = new Event(ev);
                    var parent = $(e.target).getParent("ul");
                    var ttip = el.retrieve('tooltip');
    
                    if(!this.shown) {
                        ttip.store("dtop", el.getPosition( ).y - 
                            ttip.retrieve('actheight'));           
                        ttip.setStyle("top", el.getPosition( ).y);   
                        this.shown = true;
                    }
                    var tel = el.retrieve('tooltipEl');
                    var ttimer = el.retrieve('tooltipTimer');
                    if(ttimer) $clear(ttimer);
                    ttimer = showTooltip.delay(500, this, [parent, ttip, 
                        e.target]);
                    el.store('tooltipEl', e.target);
                    el.store('tooltipTimer', ttimer);

                    this.pause( );
                    new Event(ev).stop( );
                },
				
    
                'mouseleave': function(ev) {
                    var e = new Event(ev);
                    var parent = $(e.target).getParent("ul");
                    var ttip = el.retrieve('tooltip');

                    var ttimer = el.retrieve('tooltipTimer');
                    $clear(ttimer);

                    ttimer = (function( ) {
                        this.shown = false;
                        hideTooltip(1500, this, ttip);
                    }).delay(1500, this);
                    el.store('tooltipTimer', ttimer);  

                    this.resume( );    
                    new Event(ev).stop( );
                }
				
            }
			*/
        });
        rot.start( );
    });
   
    //Re re-size (??) the navigation to trim any occasional issues with
    //it not being scaled correctly.
    resizeNavigation.delay(20);
});

function showTooltip(parent, ttip, target) {
    var delay = 1;
    if(ttip.getStyle("top").toInt( ) != ttip.retrieve('dtop')) {
        ttip.morph({
            'height': ttip.retrieve('dheight'),
            'opacity': ttip.retrieve('dopacity'),
            'top': ttip.retrieve('dtop')
        });
        delay = ttip.get('morph').options.duration;
    }
    
    var m = ttip.get('morph').options.duration;
    ttip.empty( );

    (function( ) { 
        var title = target.get('title');
        var el = new Element("span", {'class': 'tooltipText'});
        el.set('html', title);
        el.inject(ttip);
        el.tween('opacity', 1);
        var a = target.getParent("a");
        if(a && a.get('href') != "#") {
            var link = new Element("a", {'class': 'tooltipLink', 
                'href': a.get('href')});
            link.set('html', target.get('alt'));
            link.inject(ttip);
            link.tween('opacity', 1);
        }
    }).delay(delay);
}

function hideTooltip(ttip) {
    ttip.morph({
        'height': 0,
        'opacity': 0,
        'top': ttip.retrieve('dtop') + ttip.getDimensions( ).y
    });
    (function( ) { ttip.empty( ); }).delay(ttip.get('morph').options.duration);
}

/**
 * HistoryManager
 * 
 * Observes back/forward button usage and saves states
 * for registered modules into the hash. This allows to
 * bookmark specific states for an application.
 * 
 * @version		1.0rc2
 * 
 * @see			Events, Options
 * 
 * @license		MIT License
 * @author		Harald Kirschner <mail [at] digitarald.de>
 * @copyright	2007 Author
 */
var HistoryManagerX = new Class ({

  Implements: [Options, Events],

	/**
	 * Default options - Can be overridden with setOptions
	 * 
	 * observeDelay: Duration for checking the state, default 100ms
	 * stateSeparator: Seperator for module-state join, default ';'
	 * iframeSrc: Scr for IE6/7 iframe, must exist on server!
	 * onStart: Fires on start
	 * onRegister: Fires on register
	 * onUnregister: Fires on unregister
	 * onUpdate: Fires when state changes from ...
	 * onStateChange: ... module changes
	 * onObserverChange: ... history change
	 */
	options: {
		observeDelay: 100,
		stateSeparator: ';',
		iframeSrc: 'blank.html',
		onStart: Class.empty,
		onRegister: Class.empty,
		onUnregister: Class.empty,
		onStart: Class.empty,
		onUpdate: Class.empty,
		onStateChange: Class.empty,
		onObserverChange: Class.empty
	},

	/**
	 * Default options for register
	 * 
	 * defaults: Default values array, initially empty.
	 * regexpParams: When regexp is a String, this is the second argument for new RegExp.
	 * skipDefaultMatch: default true; When true onGenerate is not called when current values are similar to the default values.
	 */
	dataOptions: {
		skipDefaultMatch: true,
		defaults: [],
		regexpParams: ''
	},

	/**
	 * Constructur - Class.initialize
	 * 
	 * Options:
	 *  - observeDelay: duration in ms, default 100 - BackBuddy observe the hash for changes periodical
	 *  - stateSeparator: char, default ';' - Separator for multiple module-states in the hash
	 *  - iframeSrc: string, default 'blank.html' - File for the iframe (IE6/7), must exist on the server!
	 *  - Events: onStart, onRegister, onStart, onUpdate, onStateChange, onObserverChange
	 * 
	 * @return	this
	 * 
	 * @param	{Object} options
	 */
	initialize: function(options) {
		if (this.modules) return this;
		this.setOptions(options);
		this.modules = $H({});
		this.count = history.length;
		this.states = [];
		this.states[this.count] = this.getHash();
		this.state = null;
		return this;
	},

	/**
	 * Start - Check hash and start observer
	 * 
	 * Call start after registering ALL modules. This start the observer,
	 * reads the state from the hash and calls onMatch for effected modules.
	 * 
	 * @return	this
	 * 
	 */
	start: function() {
		this.observe.periodical(this.options.observeDelay, this);
		this.started = true;
		this.observe();
		this.update();
		this.fireEvent('onStart', [this.state]);
		return this;
	},

	/**
	 * Registers a module
	 * 
	 * @return	{Object} Object with shortcuts for setValues, setValue, generate and unregister
	 * 
	 * @param	{String} Module key
	 * @param	{RegExp}/{String} Regular expression that matches the string updated from onGenerate
	 * @param	{Function} Will be called when the regexp matches, with the new values as argument.
	 * @param	{Function} Should return the string for the state string, values are first argument
	 * @param	{Array} default values, the input values given to onMatch and onGenerate will be complemented with these
	 * @param	{Object} (optional) options
	 */
	register: function(key, defaults, onMatch, onGenerate, regexp, options) {
		if (!this.modules) this.initialize();
		var data = $merge(this.dataOptions, options || {}, {
			defaults: defaults,
			onMatch: onMatch,
			onGenerate: onGenerate,
			regexp: regexp
		});
		data.regexp = data.regexp || key + '-([\\w_-]*)';
		if (typeof data.regexp == 'string') data.regexp = new RegExp(data.regexp, data.regexpParams);
		data.onGenerate = data.onGenerate || function(values) { return key + '-' + values[0]; };

		data.values = data.defaults.copy();
		this.modules.set(key, data);
		this.fireEvent('onUnregister', [key, data]);
		return {
			setValues: function(values) {
				return this.setValues(key, values);
			}.bind(this),
			setValue: function(index, value) {
				return this.setValue(key, index, value);
			}.bind(this),
			generate: function(values) {
				return this.generate(key, values);
			}.bind(this),
			unregister: function() {
				return this.unregister(key);
			}.bind(this)
		};
	},

	/**
	 * unregister - Removes an module from the
	 * 
	 * @param	{String} Module key
	 */
	unregister: function(key) {
		this.fireEvent('onRegister', [key]);
		this.modules.remove(key);
	},

	/**
	 * setValues - Set all values new, updates new state
	 * 
	 * @param	{String} Module key
	 * @param	{Object} Complete values
	 */
	setValues: function(key, values) {
		var data = this.modules.get(key);
		if (!data || data.values.isSimilar(values)) return this;
		data.values = values;
		this.update();
		return this;
	},

	/**
	 * setValue - Set one value, updates new state
	 * 
	 * @param	{String} Module key
	 * @param	{Number} Value index
	 * @param	{Object} Value
	 */
	setValue: function(key, index, value) {
		var data = this.modules.get(key);
		if (!data || data.values[index] == value) return this;
		data.values[index] = value;
		this.update();
		return this;
	},

	/**
	 * generate - Generates a hash from the given
	 * 
	 * @param	{String} Module key
	 * @param	{Number} Value index
	 * @param	{Object} Value
	 */
	generate: function(key, values) {
		var data = this.modules.get(key);
		var current = data.values.copy();
		data.values = values;
		var state = this.generateState();
		data.values = current;
		return '#' + state;
	},

	observe: function() {
		if (this.timeout) return;
		var state = this.getState();
		if (this.state == state) return;
		if (((Browser.Engine.trident &&(!document.querySelectorAll))) && (this.state !== null)) this.setState(state, true);
		else this.state = state;
		this.modules.each(function(data, key) {
			var bits = state.match(data.regexp);
			if (bits) {
				bits.splice(0, 1);
				bits.complement(data.defaults);
				if (!bits.isSimilar(data.defaults)) data.values = bits;
			} else data.values = data.defaults.copy();
			data.onMatch(data.values, data.defaults);
		});
		this.fireEvent('onStateChange', [state]).fireEvent('onObserverChange', [state]);
	},

	generateState: function() {
		var state = [];
		this.modules.each(function(data, key) {
			if (data.skipDefaultMatch && data.values.isSimilar(data.defaults)) return;
			state.push(data.onGenerate(data.values));
		});
		return state.join(this.options.stateSeparator);
	},

	update: function() {
		if (!this.started) return this;
		var state = this.generateState();
		if ((!this.state && !state) || (this.state == state)) return this;
		this.setState(state);
		this.fireEvent('onStateChange', [state]).fireEvent('onUpdate', [state]);
		return this;
	},

	observeTimeout: function() {
		if (this.timeout) this.timeout = $clear(this.timeout);
		else this.timeout = this.observeTimeout.delay(200, this);
	},

	getHash: function() {
		var href = top.location.href;
		var pos = href.indexOf('#') + 1;
		return (pos) ? href.substr(pos) : '';
	},

	getState: function() {
		var state = this.getHash();
		if (this.iframe) {
			var doc = this.iframe.contentWindow.document;
			if (doc && doc.body.id == 'state') {
				var istate = doc.body.innerText;
				if (this.state == state) return istate;
				this.istateOld = true;
			} else return this.istate;
		}
		/*
		if (Browser.Engine.webkit && history.length != this.count) {
			this.count = history.length;
			return $pick(this.states[this.count - 1], state);
		}
		*/
		return state;
	},

	setState: function(state, fix) {
		state = $pick(state, '');
		/* removed support for Safari 2 temporaly
		if (Browser.Engine.webkit) {
			if (!this.form) this.form = new Element('form', {method: 'get'}).injectInside(document.body);
			this.count = history.length;
			this.states[this.count] = state;
			this.observeTimeout();
			this.form.setProperty('action', '#' + state).submit();
			
		} else top.location.hash = state || '#';
		*/
		top.location.hash = state || '#';
		if (Browser.Engine.trident && (!document.querySelectorAll) && (!fix || this.istateOld)) {
			if (!this.iframe) {
				this.iframe = new Element('iframe', {
					src: this.options.iframeSrc,
					style: 'visibility: hidden;height:1px;'
				}).injectInside(document.body);
				this.istate = this.state;
			}
			try {
				var doc = this.iframe.contentWindow.document;
				doc.open();
				doc.write('<html><body id="state">' + state + '</body></html>');
				doc.close();
				this.istateOld = false;
			} catch(e) {};
		}
		this.state = state;
	},

	extend: $extend
});

/**
 * Extends Array with 2 helpers: isSimilar(array) and complement(array)
 * 
 */
Array.implement( {

	/**
	 * isSimilar - Returns true for similar arrays, type-insensitive
	 * 
	 * @example
	 *  [1].isSimilar(['1']) == true
	 *  [1, 2].isSimilar([1, false]) == false
	 *  
	 * @return	{Boolean}
	 * @param	{Object} Array
	 */
	isSimilar: function(array) {
		return (this.toString() == array.toString());
	},

	/**
	 * complement - Fills up empty array values from another array, length is the same
	 * 
	 * @example
	 *  [1, null].complement([3, 4]) == [1, 4]
	 *	[undefined, '1'].complement([2, 3, 4]) == [2, '1']

	 * @return	{Array} this
	 * @param	{Object} Array
	 */
	complement: function(array) {
		for (var i = 0, j = this.length; i < j; i++) this[i] = $pick(this[i], array[i] || null);
		return this;
	}, 
	
  /*
  Property: copy
    returns a copy of the array.
 
  Returns:
    a new array which is a copy of the current one.
 
  Arguments:
    start - integer; optional; the index where to start the copy, default is 0. If negative, it is taken as the offset from the end of the array.
    length - integer; optional; the number of elements to copy. By default, copies all elements from start to the end of the array.
 
  Example:
    >var letters = ["a","b","c"];
    >var copy = letters.copy();    // ["a","b","c"] (new instance)
  */
 
  copy: function(start, length){
    start = start || 0;
    if (start < 0) start = this.length + start;
    length = length || (this.length - start);
    var newArray = [];
    for (var i = 0; i < length; i++) newArray[i] = this[start++];
    return newArray;
  }
});

