/* Copyright (c) 2011, Geert Bergman (geert@scrivo.nl)
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 * 3. Neither the name of "Scrivo" nor the names of its contributors may be
 *    used to endorse or promote products derived from this software without
 *    specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * $Id: ColorIntensityBar.js 616 2013-04-22 23:48:38Z geert $
 */

"use strict";

SUI.control.ColorIntensityBar = SUI.defineClass(
	/** @lends SUI.control.ColorIntensityBar.prototype */{

	/** @ignore */ baseClass: SUI.Box,

	/**
	 * @class
	 * SUI.control.ColorIntensityBar is a slider control to make a color
	 * intensity selection for a single RGB color component. The intensity
	 * selection made will be in the range 0-1.
	 *
	 * @augments SUI.Box
	 *
	 * @description
	 * Create a color intensity bar. The bar is always 256 pixels long and
	 * 20 pixels high.
	 *
	 * @constructs
	 * @param see base class
	 * @param {String} arg.color The background color of the control: "r",
	 *     "g" or "b".
	 * @param {Function} arg.onChange Listener function that is executed each
	 *     time the control's color intensity selection changes.
	 */
	initializer: function(arg) {

		SUI.control.ColorIntensityBar.initializeBase(this, arg);

		// set the width and height of the bar
		this.width(this.AXIS_LENGTH);
		this.height(this.HEIGHT);
		// the background image and color of the bar
		this.el().style.backgroundImage = "url(" + SUI.imgDir + "/"
			+ SUI.resource.rgbBar+")";
		this.el().style.backgroundColor = arg.color == "r" ? "#FF0000" :
			(arg.color == "g" ? "#00FF00" : "#0000FF");
		// the crosshair extends over the bar's edges, show it
		this.el().style.overflow = "visible";

		// conversion from length to range can be done nicely by substracting
		// the crosshair width of the length
		this._axisRange = this.AXIS_LENGTH - this.CROSSHAIR_LINE;

		// calculate the top offset of the crosshair image w.r.t. the top of
		// the bar
		this._ofsCh =
		 (this.CROSSHAIR_LINE - this.CROSSHAIR_WIDTH) / 2 | 0;
		// create the crosshair, a dragger component
		this._ch = new SUI.Dragger({
		 parent: this,
		 width: this.CROSSHAIR_WIDTH,
		 height: this.CROSSHAIR_HEIGHT,
			top: (this.HEIGHT - this.CROSSHAIR_HEIGHT) / 2 | 0,
			left: this._ofsCh
		});
		// set the range for dragging ...
		this._ch.xMin(this._ofsCh);
		this._ch.xMax(
		 this._ofsCh + this.AXIS_LENGTH - this.CROSSHAIR_LINE);
		// ... and the direction in which we may draw
		this._ch.direction(this._ch.HORIZONTAL);
		// set the crosshair background image ...
		this._ch.el().style.backgroundImage =
		 "url(" + SUI.imgDir + "/" + SUI.resource.rgbCh + ")";
		// ... and an appropriate cursor
		this._ch.el().style.cursor = "pointer";

		// start dragging on the onmousedown of the crosshair
		var that = this;
		SUI.browser.addEventListener(this._ch.el(), "mousedown",
		 function(e) {
			 if (!that._startDrag(new SUI.Event(this, e))) {
			   SUI.browser.noPropagation(e);
			 }
		 }
		);

		// set the onChange handler
		if (arg.onChange) {
		 this.addListener("onChange", arg.onChange);
		}

	},

	/**
	 * Length of the color axis.
	 */
	AXIS_LENGTH: 256,

	/**
	 * Width of the crosshair line.
	 */
	CROSSHAIR_LINE: 1,

	/**
	 * Height of the bar.
	 */
	HEIGHT: 20,

	/**
	 * Height of the crosshair image.
	 */
	CROSSHAIR_WIDTH: 15,

	/**
	 * Width of the crosshair image.
	 */
	CROSSHAIR_HEIGHT: 26,

	/**
	 * Display RGB control. Set the size and position of the bar and crosshair.
	 */
	display: function() {
		this.setDim();
		this._ch.setDim();
	},

	/**
	 * onChange event handler: is executed when the control's color selection
	 * changes. This happens continuously when the user is dragging the
	 * crosshairs.
	 * @param {String} c The color intensity selected by the control.
	 */
	onChange: function(c) {
	},

	/**
	 * Set the value of the control's currently selected color intensity
	 * and redisplay the control.
	 * @param {int} val The new value for the control's currently selected
	 *     color intensity (0 <= value <= 1), no value to use this method
	 *     as a getter.
	 * @return {int} the value of the control's currently selected color
	 *     intentsity, or null if this method is used as a setter.
	 */
	value: function(val) {
	 if (val === undefined) {
			return this._val;
	 }
	 // got here? the method is a setter
		this._val = val;
		this._ch.left((this._val * this._axisRange | 0) + this._ofsCh);
		this.display();

	 return null;
	},

	// length vs range: fi length: 128 -> range: 0-127
	_axisRange: 0,

	// dragger box for the crosshair
	_ch: null,

	// offset of the crosshair w.r.t. the left of the bar
	_ofsCh: 0,

	// current intensity setting
	_val: 0,

	// While dragging the crosshair change the selected color intensity
	// setting and call the onChange listener
	_drag: function() {
		this._val = (this._ch.left() - this._ofsCh) / this._axisRange;
	 this.callListener("onChange", this._val);
	},

	// On start dragging the crosshair initialize the onDrag handler of
	// the dragger and start dragging
	_startDrag: function(e) {
		var that = this;
		this._ch.addListener("onDrag", function() { that._drag(); });
		this._ch.start(e, this);
	}

});