/**
* Represents a single axis
*/
Site.Axis = Class.create(
	{
		/**
		* Represents the dimensions of this axis
		*
		* @var Array
		*/
		dimensions: [0,0],
		
		/**
		* The type of this axis
		*
		* @var Integer
		*/
		type : 0,
		
		range : new Site.Range(1, 10),
		
		targetInterval : 20,
		
		tickHeight : 12,
		
		padding: 24,
		
		
		/**
		* Creates a new axis instance
		*
		* @param String id 	  the id of the axis element
		* @param String type  the type of the axis (Site.Axis.X or Site.Axis.Y)
		*/
		initialize : function(id, type, range) {
			this.id = id;
			if (type) {
				this.type = type;		
			}
			if (!Site.Axis.isValid(this.type)) {
				throw new Site.InvalidAxisException();
			}
			this.element = $(id);
			if (!this.element) {
				throw new Site.ElementNotFoundException(id);
			}
			
			if (range) {
				this.range = range;
			}
			this.dimensions = this.element.getDimensions();
			var spread = this.range.getSpread();
			var length = this.getLength();
			
			this.pixelsPerUnit = length / spread;
			this.tickType = Site.Axis.TickType[this.type];
			
		},
		
		/**
		* Returns the length of this axis
		*
		* @return Integer
		*/
		getLength : function() {
			return this.dimensions[Site.Axis.Dimension[this.type]] - this.padding;
		},
		
		/**
		* Converts a value to the corresponding coordinate along the
		* axis
		* 
		* @param Numeric value a value
		* @return Integer
		*/
		toCoordinate : function (value) {
			return Math.round(value * this.pixelsPerUnit)		
		},
		
		/**
		* Renders this axis
		*/
		render : function() {		
			var tickIncrement = Math.ceil(this.targetInterval / this.pixelsPerUnit);			
			if (tickIncrement > 5) {
				tickIncrement = Math.floor(tickIncrement / 5) * 5;
			}
			for (var position = this.range.minimum; position <= this.range.maximum; position += tickIncrement) {
				var tick = this.createTick(position);
				tick.render();				
			}
		},
		
		createTick : function(value) {
			return new this.tickType(this, value);
		}	
	}
);

Site.Axis.Tick = Class.create(
	{
		initialize : function(axis, value) {
			this.axis = axis;
			this.value = value;
			this.offset = Math.round(this.axis.toCoordinate(value) - (this.axis.tickHeight / 2));
		},
		
		render : function() {
			this.element = $(document.createElement('div'));
			this.element.className = 'tick';
			this.axis.element.appendChild(this.element);	
			this.position();
			this.mark = $(document.createElement('div'));		
			this.mark.className = 'mark'
			this.element.appendChild(this.mark);
			this.positionMark();
			this.textElement = document.createTextNode(this.value);
			this.element.appendChild(this.textElement);
		},
		position : function() {},
		
		positionMark : function() {}
	}
);

Site.Axis.YTick = Class.create(
	Site.Axis.Tick,
	{
		position : function() {
			this.element.style.position = 'absolute';
			this.element.style.bottom = this.offset;
			this.element.style.right = 0;
		},
		positionMark : function() {
			this.mark.style.position = 'absolute';
			this.mark.style.top = '50%';
			this.mark.style.right = 0;
		}
	}
);

Site.Axis.XTick = Class.create(
	Site.Axis.Tick,
	{
		position : function() {
			this.element.style.position = 'absolute';
			this.element.style.left = this.offset;
			this.element.style.top = 0;
		},
		positionMark : function() {
			this.mark.style.position = 'absolute';
			this.mark.style.left = '50%';
			this.mark.style.top = 0;
		}
	}
);



/**
* Represents the X (horizontal) axis
*/
Site.Axis.X = 0;

/**
* Represents the Y (vertical) axis
*/
Site.Axis.Y = 1;

Site.Axis.All = [Site.Axis.X, Site.Axis.Y];

Site.Axis.isValid = function(axis) {
	return axis == Site.Axis.X || axis == Site.Axis.Y;
}

Site.Axis.TickType = [
	Site.Axis.XTick,
	Site.Axis.YTick
]

Site.Axis.Dimension = [
	'width',
	'height'
];


Site.InvalidAxisException = Class.create(
	{
		initialize : function() {
			this.message = 'Invalid axis';			
		}
	}
);

Site.Graph = Class.create(
	{
		/**
		* The ID of the top element representing this graph
		*
		* @var String
		*/
		id : null,
		
		/**
		* The top element representing this graph
		*
		* @var HTMLElement
		*/
		element: null,
		
		axes : {},
		
		
		/**
		* Creates a new graph instance
		*
		* @var String id the ID of the graph
		*/
		initialize : function(id, renderedAxes) {
			this.id = id;
			this.element = $(id);
			this.element.graph = this;
			
			
			$H(renderedAxes).each(
				function(entry) {
					this.axes[entry.key] = new Site.Axis(
						this.id + '-' + Site.Graph.Suffix[entry.key], 
						entry.key,
						entry.value
					);
				}.bind(this)
			);
			this.render();
		},
		
		/**
		* Draws the labels on the vertical axis
		*
		* @access public
		*/
		render: function() {
			$H(this.axes).values().each(
				function(axis) {
					axis.render();
				}
			);
		}
	}
);

Site.Graph.Suffix = [
	'x-axis',
	'y-axis'
];