// Copyright (c) 2006 Niels Leenheer (http://rakaz.nl)
// 
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
// 
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.


var CSSTestCase = Class.create();
CSSTestCase.prototype = {
	
	initialize: function (ids, options) {
		this.options = Object.extend({
			onSuccess: function() {},
			onFailure: function() {}
		}, options || {});
		
		this.ids = ids;
		this.counter = 0;
		
		this.totalSelectors = 0;
		this.passedSelectors = 0;
		this.buggySelectors = 0;
		this.failedSelectors = 0;

		this.totalTests = 0;
		this.passedTests = 0;
		
		this.next();
	},
	
	success: function(test) {
		this.totalSelectors++;
		this.totalTests += test.testsTotal;
		
		if (test.testsPassed == test.testsTotal)
			this.passedSelectors++;
		else
			this.buggySelectors++;
		
		this.passedTests += test.testsPassed;
		
		this.options.onSuccess(test, this);
		this.next();
	},
	
	failure: function(test) {
		this.totalSelectors++;
		this.failedSelectors++;
		
		this.totalTests += test.testsTotal;
		this.passedTests += test.testsPassed;

		this.options.onFailure(test, this);
		this.next();
	},
	
	next: function() {
		if (this.ids.length) {
			new CSSTest(this.ids.shift(), {
				counter:   this.counter,
				onSuccess: this.success.bind(this),
				onFailure: this.failure.bind(this)
			});	
			
			this.counter++;
		}
	}
};

var CSSTest = Class.create();
CSSTest.prototype = {

	initialize: function (id, options) {
		this.options = Object.extend({
			counter:   0,
			onSuccess: function() {},
			onFailure: function() {}
		}, options || {});
	
		this.id = id;
		this.title = id;
		this.result = true;
		
		this.testsTotal = 0;
		this.testsPassed = 0;
		this.requiredTotal = 0;
		this.requiredPassed = 0;

		/* Create the iframe and run the tests */
		this.create();
	},
	
	create: function() {
		/* Generate random number */
		var random = Math.floor(Math.random()*999999)
		
		/* Create iframe */
		this.element = Builder.node('iframe', { 
			name: 		'csstest-' + this.options.counter + '-' + this.id, 
			id: 		'csstest-' + this.options.counter + '-' + this.id, 
			src: 		'test-' + this.id + '.html?r=' + random + '#' + this.id 
		});
		
		/* Position it offscreen */
		Element.setStyle(this.element, {
			position:	'absolute',
			left:		'-500px',
			width:  	'400px',
			height:		'400px',
			top:		'0px'
		});

		/* Attach onLoad event */
		this.onLoad  = this.load.bind(this);
		Event.observe(this.element, 'load', this.onLoad);
		
		/* Add it to the body element of the DOM */
		document.body.appendChild(this.element);
	},
	
	destroy: function() {
		/* Detach onLoad event and destroy the iframe */
		Event.stopObserving(this.element, 'load', this.onLoad);
		Element.remove(this.element);
	},
	
	load: function() {
		/* Make sure the CSS is properly evaluated before checking the computed styles */
		setTimeout((function() {this.check()}).bind(this), 1);	
	},
	
	check: function () {
		this.content = window.frames['csstest-' + this.options.counter + '-' + this.id].document;
	
		if (this.content) {
			this.title = this.content.title;

			var base  = document.getElementsByClassName('base', this.content)[0];
			var basecolor = this.getStyle(base, 'background-color')
			var tests = document.getElementsByClassName('test', this.content);
			
			this.testsTotal = tests.length;
			
			for (var i = 0; i < tests.length; i++) {
				
				var result  = false;

				if (Element.hasClassName(tests[i], 'float'))
				{
					var f = this.getStyle(tests[i], 'float');
					
					if (Element.hasClassName(tests[i], 'default')) {
						result = f == 'none';
					} else {
						result = f == 'right';						   
					}
				}
				else if(Element.hasClassName(tests[i], 'height')) 
				{
					var h = tests[i].clientHeight;
					
					if (tests[i].nextSibling) {
						var control = tests[i].nextSibling;
						
						while (control.nextSibling && control.nodeType != 1)
							control = control.nextSibling;
						
						control = control.clientHeight;
						if (Element.hasClassName(tests[i], 'default')) {
							result = h == control;					
						} else {
							result = h > control;					
						}
					} else {
						if (Element.hasClassName(tests[i], 'default')) {
							result = h == 0;					
						} else {
							result = h > 0;					
						}
					}
				}
				else
				{
					var c = this.getStyle(tests[i], 'background-color');
					
					if (Element.hasClassName(tests[i], 'default')) {
						result = c == 'transparent' || c == 'rgba(0, 0, 0, 0)';
					} else {
						result = c == basecolor;						   
					}
				}
				
				if (Element.hasClassName(tests[i], 'required')) {
					this.requiredTotal++;
					if (result) {
						this.requiredPassed++;	
					}
				}

				if (result) {
					this.testsPassed++;
				}
				
				this.result &= result;
			}

			/* Done testing... remove the iframe */
			this.destroy();
		
			/* Callback to the CSSTestCase object */
			if (this.result || (this.requiredTotal > 0 && this.requiredTotal == this.requiredPassed)) {
				this.options.onSuccess(this);	
			} else {
				this.options.onFailure(this);	
			}
		}
	},	

  	getStyle: function(element, style) {
    	var value = element.style[style.camelize()];
    	if (!value) {
      		if (this.content.defaultView && this.content.defaultView.getComputedStyle) {
        		var css = this.content.defaultView.getComputedStyle(element, null);
        		value = css ? css.getPropertyValue(style) : null;
      		} else if (element.currentStyle) {
        		value = element.currentStyle[style.camelize()];
      		}
   		}

	    return value == 'auto' ? null : value;
	}
};




