/*
 *  graphic checkbox/tristate/quadstate control code, client-end part
 *  © 2001-2012, Horus Web Engineering Ltd
 *
 *  $Id: tristate.js,v 3.11 2012-02-08 15:14:34 horus Exp $
 *
 *  licensed under the terms of the GNU Lesser General Public License:
 *    http://www.opensource.org/licenses/lgpl-license.php
 *
 *  needs horus.js, dom.js
 *  uses tooltip.js if requested
 *
 */

horus.script.load('dom');


horus.tick=
  function ( tick, alt, reverse ) {
    if (this instanceof horus.tick) {
      this.$input=tick;
      this.$link=tick.parentNode;
      this.$id=this.$link.id;
      this.$imageset='clear';
      this.$wheels=2;
      this.$reverse=false;

      if (horus.tick.data) {
	var options=horus.tick.data[this.$id];
	if (typeof options=='number') options=horus.tick.opt[options];

	if (options) {
	  if ('alt' in options && !(options.alt instanceof Array))
	    options.alt=[ options.alt ];

	  for (var tag in options) this['$'+tag]=options[tag];
	}
      }

      if (horus.hasClass(this.$link, 'disabled'))
	this.$disabled=true;
      else if (this.$disabled)
	horus.addClass(this.$link, 'disabled');

      this.$subs=horus.tick.$subs[this.$wheels-1];
      this.alt(alt);
      if (arguments.length>2) this.reverse(reverse);
      tick.$tick=this;
    } else {
      if (!(tick instanceof horus.tick)) {
	tick=horus.getElement(tick);

	if (tick) {
	  var tagName=tick.tagName.toLowerCase();

	  if (tagName!='input')
	    if (tagName=='a')
	      tick=horus.firstTag(tick, 'input');
	    else if (tagName=='span')
	      tick=horus.previousTag(tick, 'input');
	    else if (tagName=='em')
	      tick=horus.previousTag(tick.parentNode, 'input');
	    else
	      throw 'page error: bad parameter ('+tagName+') passed to horus.tick()';

	  if (tick) tick=tick.$tick || new horus.tick(tick);
	}
      }

      if (tick) {
	if (arguments.length>1) tick.alt(alt);
	if (arguments.length>2) tick.reverse(reverse);
      }

      return tick;
    }
  };


horus.tick.className='horus.tick';

horus.tick.$subs=[ [ 0 ], [ 0, 1 ], [ 2, 0, 1 ], [ 3, 2, 0, 1 ] ];
horus.tick.$images=[ [ 6 ], [ 0, 2 ], [ 0, 2, 4 ], [ 0, 2, 4, 1 ] ];

horus.tick.$tags=
  [ 'unset', 'no', 'yes', 'noish', 'yesish', 'yesyes',
    'delete', 'query', 'show', 'noshow' ];


horus.tick.$create=
  function ( action, node, name, value, options ) {
    options=horus.options
      (options, { imageset: 'clear', wheels: 2, id: name },
       { string: 'imageset', number: 'wheels', 'function': 'onclick' });

    var data=new horus.hash;
    var lookup={};
    var haslookup=false;
    var i;

    if (options.wheels!=2) data.wheels=options.wheels;
    if (options.reverse) data.reverse=true;
    if (options.imageset!='clear') data.imageset=options.imageset;
    if (options.extra!=null) data.extra=options.extra;
    if (options.callback) data.callback=options.callback;

    if (options.values==null) {
      options.values=[];
      for (i=0; i<options.wheels; i++) options.values.push(i);
    }

    if (value==null)
      value=options.values[0];
    else if (typeof value=='boolean')
      value=options.values[value ? 1 : 0];

    for (i=0; i<options.values.length; i++) {
      lookup[options.values[i]]=i;
      if (options.values[i]!=i) haslookup=true;
    }

    if (haslookup) {
      data.values=options.values;
      data.lookup=lookup;
    }

    var index=lookup[value];
    var image=null;

    if (options.alt!=null) {
      var subs=horus.tick.$subs[options.wheels-1];
      if (!(options.alt instanceof Array)) options.alt=[ options.alt ];
      data.alt=[];

      for (i=0; i<options.alt.length; i++) {
	data.alt.push(horus.tick.select(options.alt[i]));
	if (subs[i]==index) image=data.alt[i];
      }
    }

    if (image==null) image=horus.tick.$images[options.wheels-1][index];

    if (!data.isEmpty()) {
      if (!horus.tick.data) horus.tick.data={};
      horus.tick.data[name]=data;
    }

    var callback=options.onclick;

    var onclick=callback ?
      function () { callback.call(horus.tick(this).cycle(), this) } :
      function () { horus.tick(this).cycle() };

    var control=
      [ 'a',
        { onclick:     onclick,
	  onkeydown:   horus.tick.key,
	  classname:   [ 'tristate', options.imageset, horus.tick.$tags[image] ],
	  style:       options.style,
	  id:          name },
	[ 'input', { type: 'hidden', name: name, value: value } ],
	[ 'span', null, [ 'em' ] ] ];

    switch (action) {

    case 'append': control=horus.appendNode(node, control);   break;
    case 'after':  control=horus.appendAfter(node, control);  break;
    case 'before': control=horus.insertBefore(control, node); break;

    }

    return control;
  };


horus.tick.create=
  function ( name, value, options ) {
    return horus.tick.$create('create', null, name, value, options);
  };


horus.tick.appendNode=
  function ( parent, name, value, options ) {
    return horus.tick.$create('append', parent, name, value, options);
  };


horus.tick.appendAfter=
  function ( before, name, value, options ) {
    return horus.tick.$create('after', before, name, value, options);
  };


horus.tick.insertBefore=
  function ( after, name, value, options ) {
    return horus.tick.$create('before', after, name, value, options);
  };


horus.tick.prototype.label=
  function ( label ) {
    var theNode=this.$input;
    do theNode=theNode.nextSibling; while (theNode.nodeType!=3);
    var oldlabel=theNode ? theNode.nodeValue : '';

    if (label!=null)
      if (theNode)
	theNode.nodeValue=label;
      else
	this.$link.insertBefore(document.createTextNode(label), this.$input.nextSibling);

    return oldlabel;
  };


horus.tick.prototype.set=
  function ( imageset ) {
    var link=this.$link;
    var oldset=this.$imageset;

    if (imageset && imageset!=this.$imageset) {
      horus.replaceClass(link, this.$imageset, imageset);
      this.$imageset=imageset;
      if (horus.ieold) this.fixup$ie6();
    }

    return oldset;
  };


horus.tick.prototype.image=
  function () {
    if (!this.$image) {
      this.$image=this.$input;
      do this.$image=this.$image.nextSibling; while (this.$image.nodeType!=1);
    }

    return this.$image;
  };


horus.tick.prototype.check=
  function () {
    var image=this.tag();
    var link=this.$link;

    if (!horus.hasClass(link, image)) {
      horus.replaceClass(link, horus.tick.$tags, image);
      if (horus.ieold) this.fixup$ie6();
    }
  };


horus.tick.prototype.click=
  function ( val ) {
    var tick=this.$input;

    if (val==null)
      this.$link.onclick();
    else {
      tick.value=this.$value(val);
      this.check();
    }

    return this;
  };


horus.tick.prototype.$value=
  function ( val ) {
    if (this.$lookup && val in this.$lookup) return val;

    if (horus.isBoolean(val))
      val=val==true ? 1 : 0;
    else if (!horus.isNumber(val))
      return undefined;
    else if (val<0)
      val=this.$wheels-1;
    else if (val>=this.$wheels)
      val=0;

    return this.$values ? this.$values[val] : parseInt(val);
  };


horus.tick.prototype.undo=
  function () {
    if (this.$oldvalue!=null)
      this.click(this.$oldvalue);

    return this;
  };


horus.tick.prototype.reset=
  function () {
    if (this.$firstvalue!=null)
      this.click(this.$firstvalue);

    return this;
  };


horus.tick.prototype.value=
  function () {
    var value=this.$input.value;
    return /^\d+$/.test(value) ? parseInt(value) : value;
  };


horus.tick.prototype.index=
  function () {
    var value=this.$input.value;
    return this.$lookup ? this.$lookup[value] : parseInt(value);
  };


horus.tick.prototype.alt=
  function ( alt ) {
    this.$images=horus.tick.$images[this.$wheels-1].clone();

    if (alt!=null)
      if (alt instanceof Array)
	this.$alt=alt.lambda(function ( item ) { return horus.tick.select(item) });
      else
	this.$alt=[ horus.tick.select(alt) ];

    if (this.$alt)
      for (var i=0; i<this.$alt.length; i++) this.$images[this.$subs[i]]=this.$alt[i];

    this.check();
    return this;
  };


horus.tick.prototype.cycle=
  function () {
    var newvalue=this.index()+(this.$reverse ? -1 : 1);
    if (newvalue<0) newvalue=this.$wheels-1; else if (newvalue>=this.$wheels) newvalue=0;

    if (this.$callback) {
      var ok=horus.call.as(this, this.$callback, this.$value(newvalue));
      if (ok!=undefined && !ok) return this;
    }

    if (this.$wheels==1) return this;
    this.$oldvalue=this.$input.value;
    if (this.$firstvalue==null) this.$firstvalue=this.$oldvalue;
    return this.click((this.index()+(this.$reverse ? -1 : 1))%this.$wheels);
  };


horus.tick.prototype.disabled=
  function ( disabled ) {
    var old=this.$disabled;

    if (disabled!=undefined) {
      disabled=Boolean(disabled);

      if (disabled!=old) {
	this.$disabled=disabled;
	horus.swapClass(this.$link, disabled, 'disabled');
      }
    }

    return old;
  };


horus.tick.prototype.tags=
  function () {
    var tags=[];
    for (var i=0; i<this.$wheels; i++) tags[i]=horus.tick.$tags[this.$images[i]];
    return tags;
  };


horus.tick.prototype.checked = function () { return this.index()>0 };
horus.tick.prototype.control = function () { return this.$input };
horus.tick.prototype.link    = function () { return this.$link };
horus.tick.prototype.id      = function () { return this.$id };
horus.tick.prototype.name    = function () { return this.$input.name };
horus.tick.prototype.tag     = function () { return horus.tick.$tags[this.select()] };
horus.tick.prototype.select  = function () { return this.$images[this.index()] };


horus.tick.prototype.toId=
  function ( index, tag ) {
    return horus.toId.split(this.$id, index, tag);
  };


horus.tick.prototype.reverse=
  function ( reverse ) {
    var old=this.$reverse;
    if (reverse!=undefined) this.$reverse=Boolean(reverse);
    return old;
  };


horus.tick.prototype.extra=
  function ( extra ) {
    var old=this.$extra;
    if (extra!=undefined) this.$extra=extra;
    return old;
  };


horus.tick.label   = function ( t, label )	{ return horus.tick(t).label(label) };
horus.tick.set     = function ( t, imgset )	{ return horus.tick(t).set(imgset) };
horus.tick.image   = function ( t )		{ return horus.tick(t).image() };
horus.tick.click   = function ( t, val )	{ return horus.tick(t).click(val) };
horus.tick.undo    = function ( t )		{ return horus.tick(t).undo() };
horus.tick.reset   = function ( t )		{ return horus.tick(t).reset() };
horus.tick.value   = function ( t )		{ return horus.tick(t).value() };
horus.tick.index   = function ( t, index )	{ return horus.tick(t).index(index) };
horus.tick.checked = function ( t )		{ return horus.tick(t).index()>0 };
horus.tick.control = function ( t )		{ return horus.tick(t).$input };
horus.tick.tag     = function ( index )		{ return horus.tick.$tags[index] };


horus.tick.select=
  function ( tag ) {
    if (tag!=null && typeof tag!='number') {
      if (!horus.tick.$lookup)
	horus.tick.$lookup=horus.tick.$tags.lambda
	  ('hash', function ( item ) { this.$result[item]=this.$index });

      tag=horus.tick.$lookup[tag];
    }

    return tag;
  };


horus.tick.cycle=
  function ( ticks, alt ) {
    var multi=ticks instanceof Array;
    var tick=horus.tick(multi ? ticks[0] : ticks, alt);

    if (!tick.$disabled) {
      tick.cycle();

      if (multi)
	for (var t=1; t<ticks.length; horus.tick(ticks[t++]).index(tick.$index));

    }
  };


horus.tick.key=
  function ( event ) {
    event=new horus.event(event);
    var tick=event.target;
    if (!tick.onkeyup) tick.onkeyup=horus.tick.key;

    if (event.keyCode==32 || event.keyCode==13) {
      event.preventDefault();
      if (event.type=='keyup') tick.onclick(event);
      return false;
    }

    return true;
  };


if (horus.ieold) {
  horus.tick.prototype.fixup$ie6=
    function () {
      horus.tick.fixup$ie6.adjust(this.$link, this.$images[this.index()]);
    };


  horus.tick.fixup$ie6=
    function () {
      if (!horus.ieold) return;
      var ticks=horus.getTags('.tristate');

      while (ticks.length) {
	var image=ticks.shift();
	if (image.$ie6fixed) continue;
        var classes=image.className.split(/ +/);

	while (classes.length) {
	  var select=horus.tick.select(classes.shift());
	  if (select!=null) break;
	}

	horus.tick.fixup$ie6.adjust(image, select);
	image.$ie6fixed=true;
      }
    };


  horus.tick.fixup$ie6.adjust=
    function ( image, select) {
      image=horus.firstTag(image, 'span');
      var size=image.currentStyle.height;

      if (size=='auto')
	size=image.offsetHeight;
      else
	size=parseInt(size.replace(/\D/g, ''));

      image.style.backgroundPosition='0px -'+(select*size)+'px';
    };


  horus.onLoad(horus.tick.fixup$ie6);
}


// deprecated
horus.bicycle=horus.tricycle=horus.tick.cycle;

horus.script.loaded('tristate');

