/*
Class: Slider
        Creates a slider with two elements: a knob and a container. Returns the values.
Note:
        The Slider requires an XHTML doctype.
Arguments:
        element - the knob container
        knob - the handle
        options - see Options below
        maxknob - an optional maximum slider handle
Options:
		start - the minimum value for your slider.
		end - the maximum value for your slider.
        mode - either 'horizontal' or 'vertical'. defaults to horizontal.
        offset - relative offset for knob position. default to 0.
        knobheight - positions the max slider knob
		snap - whether the slider will slide in steps 
		numsteps - number of slide steps 
Events:
        onChange - a function to fire when the value changes.
        onComplete - a function to fire when you're done dragging.
        onTick - optionally, you can alter the onTick behavior, for example displaying an effect of the knob moving to the desired position.
                Passes as parameter the new position.
*/
var Slider = new Class({
    options: {
        onChange: Class.empty,
        onComplete: Class.empty,
        onTick: function(pos)
        {
            this.moveKnob.setStyle(this.p, pos);
        },
        start: 0,
        end: 100,
        offset: 0,
        knobheight: 20,
        knobwidth: 14,
        mode: 'horizontal',
        clip_w:0,
        clip_l:0,
        isinit:true,
        snap: false,
        range: false,
        numsteps:null
    },
    initialize: function(el, knob, bkg, options, maxknob)
    {
        this.setOptions(options);
        this.element = $(el);
        this.knob = $(knob);
        this.previousChange = this.previousEnd = this.step = -1;
        this.bkg = $(bkg);
        if (this.options.steps == null)
        {
            this.options.steps = this.options.end - this.options.start;
        }
        if (maxknob != null)
            this.maxknob = $(maxknob);
        //else
        //	this.element.addEvent('mousedown', this.clickedElement.bindWithEvent(this));
        var mod, offset;
        switch (this.options.mode)
                {
            case 'horizontal':
                this.z = 'x';
                this.p = 'left';
                mod = {'x': 'left', 'y': false};
                offset = 'offsetWidth';
                break;
            case 'vertical':
                this.z = 'y';
                this.p = 'top';
                mod = {'x': false, 'y': 'top'};
                offset = 'offsetHeight';
        }
        this.max = this.element[offset] - this.knob[offset] + (this.options.offset * 2);
        this.half = this.knob[offset] / 2;
        this.full = this.element[offset] - this.knob[offset] + (this.options.offset * 2);
        this.min = $chk(this.options.range[0]) ? this.options.range[0] : 0;
        this.getPos = this.element['get' + this.p.capitalize()].bind(this.element);
        this.knob.setStyle('position', 'relative').setStyle(this.p, - this.options.offset);

        this.range = this.max - this.min;
        this.steps = this.options.steps || this.full;
        this.stepSize = Math.abs(this.range) / this.steps;
        this.stepWidth = this.stepSize * this.full / Math.abs(this.range);


        if (maxknob != null)
        {
            this.maxPreviousChange = -1;
            this.maxPreviousEnd = -1;
            this.maxstep = this.options.end;
            this.maxknob.setStyle('position', 'relative').setStyle(this.p, + this.max - this.options.offset).setStyle('bottom', this.options.knobheight);
        }
        var lim = {};
        //status = this.z
        lim[this.z] = [- this.options.offset, this.max - this.options.offset];
        //lim[this.z] = [100, this.max - this.options.offset];

        this.drag = new Drag(this.knob, {
            limit: lim,
            modifiers: mod,
            snap: 0,
            onStart: function()
            {
                this.draggedKnob();
            }.bind(this),
            onDrag: function()
            {
                this.draggedKnob();
            }.bind(this),
            onComplete: function()
            {
                this.draggedKnob();
                this.end();
            }.bind(this)
        });
        if (maxknob != null)
        {
            this.maxdrag = new Drag(this.maxknob, {
                limit: lim,
                modifiers: mod,
                snap: 0,
                onStart: function()
                {
                    this.draggedKnob(1);
                }.bind(this),
                onDrag: function()
                {
                    this.draggedKnob(1);
                }.bind(this),
                onComplete: function()
                {
                    this.draggedKnob(1);
                    this.end();
                }.bind(this)
            });
        }

        if (this.options.snap)
        {
            //this.drag.options.grid = Math.ceil(this.stepWidth);
            this.drag.options.grid = (this.full) / this.options.numsteps;
            this.drag.options.limit[this.z][1] = this.full;
            //this.drag.options.grid = this.drag.options.grid - (this.knob[offset]/this.options.numsteps);
            status = "GRID - " + this.drag.options.grid + "  , full = " + this.full// DEBUG

        }
        if (this.options.initialize) this.options.initialize.call(this);
    },
    setMin: function(stepMin)
    {
        this.step = stepMin.limit(this.options.start, this.options.end);
        this.checkStep();
        this.end();
        this.moveKnob = this.knob;
        this.bkg.style.clip = "rect(0px " + (parseInt(this.toPosition(this.step)) + 3) + "px 10px 0px)";
        status = this.bkg.style.clip + "  vl= " + parseInt(this.toPosition(this.step));
        //Debug
        this.fireEvent('onTick', this.toPosition(this.step));
        return this;
    },
    setMax: function(stepMax)
    {
        this.maxstep = stepMax.limit(this.options.start, this.options.end);
        this.checkStep(1);
        this.end();
        this.moveKnob = this.maxknob;
        var w = Math.abs(this.toPosition(this.step) - this.toPosition(this.maxstep)) + 3 ;
        var r = parseInt(this.clip_l + w);
        this.bkg.style.clip = "rect(0px " + r + "px 10px " + this.clip_l + "px)";

        this.fireEvent('onTick', this.toPosition(this.maxstep));
        // For Init Only
        if (this.options.isinit)
        {
            var lim = {};
            var mi,mx;
            mi = - this.options.offset;
            mx = parseInt(this.maxknob.getStyle('left')) - this.options.offset - 4;
            lim[this.z] = [mi, mx];
            this.drag.options.limit = lim;
            this.options.isinit = false;
        }
        return this;
    },
    clickedElement: function(event)
    {
        var position = event.page[this.z] - this.getPos() - this.half;
        position = position.limit(-this.options.offset, this.max - this.options.offset);

        this.step = this.toStep(position);

        //this.moveKnob = this.knob;
        this.bkg.style.clip = "rect(0px " + (parseInt(this.toPosition(this.step)) + 3) + "px 10px 0px)"
        //status =this.bkg.style.clip; //Debug
        this.checkStep();
        this.end();
        this.fireEvent('onTick', position);
    },

    draggedKnob: function(mx)
    {
        var lim = {};
        var mi,mx;
        if (mx == null)
        {
            this.step = this.toStep(this.drag.value.now[this.z]);
            this.checkStep();
        }
        else
        {
            this.maxstep = this.toStep(this.maxdrag.value.now[this.z]);
            this.checkStep(1);
        }
    },
    checkStep: function(mx)
    {
        var lim = {};
        var mi,mx;
        var limm = {};
        if (mx == null)
        {
            if (this.previousChange != this.step)
            {
                this.previousChange = this.step;
            }
        }
        else
        {
            if (this.maxPreviousChange != this.maxstep)
            {
                this.maxPreviousChange = this.maxstep;
            }
        }

        if (this.maxknob != null)
        {

            mi = - this.options.offset;
            mx = parseInt(this.maxknob.getStyle('left')) - this.options.offset - 4;
            //mx= parseInt(this.maxknob.getStyle('left')) - this.options.offset ;
            lim[this.z] = [mi, mx];
            this.drag.options.limit = lim;


            mi = parseInt(this.knob.getStyle('left')) - this.options.offset + 22;
            //mi = parseInt(this.knob.getStyle('left'))-this.options.offset;

            mx = this.max - this.options.offset;
            limm[this.z] = [mi, mx];
            this.maxdrag.options.limit = limm;

            if (this.step < this.maxstep)
            {
                this.fireEvent('onChange', { minpos: this.step, maxpos: this.maxstep });
                //this.clip_l = parseInt(this.knob.getStyle('left'));
            }
            else
            {
                this.fireEvent('onChange', { minpos: this.maxstep, maxpos: this.step });
                //this.clip_l = (parseInt(this.maxknob.getStyle('left')) + 10) ;
            }
            this.clip_l = parseInt(this.knob.getStyle('left')) + 10;
            //var w = Math.abs(parseInt(this.knob.getStyle('left')) - parseInt(this.maxknob.getStyle('left'))) + 3;
            var w = Math.abs(parseInt(this.knob.getStyle('left')) - parseInt(this.maxknob.getStyle('left')));
            //if(w > 3) w = w+3;

            var r = parseInt(this.clip_l + w);
            this.bkg.style.clip = "rect(0px " + r + "px 10px " + this.clip_l + "px)"
            //status =this.bkg.style.clip  + " w= " + w //Debug

        }
        else
        {
            this.fireEvent('onChange', this.step);
            this.bkg.style.clip = "rect(0px " + (parseInt(this.drag.value.now[this.z]) + 3) + "px 10px 0px)"

        }
    },
    end: function()
    {
        if (this.previousEnd !== this.step || (this.maxknob != null && this.maxPreviousEnd != this.maxstep))
        {
            this.previousEnd = this.step;
            if (this.maxknob != null)
            {
                this.maxPreviousEnd = this.maxstep;
                if (this.step < this.maxstep)
                    this.fireEvent('onComplete', { minpos: this.step + '', maxpos: this.maxstep + '' });
                else
                    this.fireEvent('onComplete', { minpos: this.maxstep + '', maxpos: this.step + '' });
            }
            else
            {
                this.fireEvent('onComplete', this.step + '');
            }
        }
    },

    toStep: function(position)
    {
        return Math.round((position + this.options.offset) / this.max * this.options.steps) + this.options.start;
    },

    toPosition: function(step)
    {
        return (this.max * step / this.options.steps) - (this.max * this.options.start / this.options.steps) - this.options.offset;
    }

});

Slider.implement(new Events);
Slider.implement(new Options);