var
  csdHorizontal = 0,
  csdVertical = 1,
  csdHorisontal = csdHorizontal; //!!OKO obsolete

var
  cScrollbarElementState_Active = 0,
  cScrollbarElementState_Inactive = 1,
  cScrollbarElementState_Disabled = 2;


var cScrollbars = new Array();


function getAbsLeft(elem)
{
  if (elem.nodeName == "BODY")
  {
    return (elem.offsetLeft - elem.scrollLeft);
  }
  else
    return (elem.offsetLeft - elem.scrollLeft + getAbsLeft(elem.offsetParent));
}

function getAbsTop(elem)
{
  if (elem.nodeName == "BODY")
    return (elem.offsetTop - elem.scrollTop);
  else
    return (elem.offsetTop - elem.scrollTop + getAbsTop(elem.offsetParent));
}

function cScrollbar(ADirection, AButtonLowIDs, AButtonHighIDs, ABarID, ASliderID, ASliderTrackID, AClassNameActive, AClassNameInactive, AClassNameDisabled)
{
  this.barID = ABarID;
  this.buttonHighIDs;
  this.buttonLowIDs;
  this.sliderID = ASliderID;
  this.sliderTrackID = ASliderTrackID;

  if (typeof(AButtonHighIDs) == 'string')
    this.buttonHighIDs = [AButtonHighIDs];
  else
    this.buttonHighIDs = AButtonHighIDs;

  if (typeof(AButtonLowIDs) == 'string')
    this.buttonLowIDs = [AButtonLowIDs];
  else
    this.buttonLowIDs = AButtonLowIDs;

  this.className_Active = AClassNameActive;
  this.className_Disabled = AClassNameDisabled;
  this.className_Inactive = AClassNameInactive;

  this.disabled = true;

  this.bar = null;
  this.buttonsHigh = [];
  this.buttonsLow = [];
  this.slider = null;
  this.sliderTrack = null;

  this.scrollMin = 0;
  this.scrollMax = 0;
  this.scrollStep = 50;
  this.scrollValue = 0;
  
  this.sliderIsResizable = false;
  this.sliderResizeCoefficient = 0;

  this.onScroll = null;

// private
  this.eventIDs = [];
  this.sliderClicked = false;
  this.sliderMaxShift = 0;
  this.timerID = null;

  this.elementStateSet = cScrollbar__elementStateSet;
  this.elementsStateSet = cScrollbar__elementsStateSet;
  this.stateSet = cScrollbar__stateSet;

  this.disable = cScrollbar__disable;
  this.enable = cScrollbar__enable;
  
  this.eventAttach = cScrollbar__eventAttach;
  this.eventsDetach = cScrollbar__eventsDetach;

  this.init = cScrollbar__init;
  this.initButtonHigh = cScrollbar__initButtonHigh;
  this.initButtonLow = cScrollbar__initButtonLow;

  this.finalize = cScrollbar__finalize;

  this.barPositionGet = cScrollbar__barPositionGet;
  this.doSliderMove = cScrollbar__doSliderMove;
  this.resize = cScrollbar__resize;
  this.resizeInternal = cScrollbar__resizeInternal;
  this.scroll = cScrollbar__scroll;
  this.scrollHigh = cScrollbar__scrollHigh;
  this.scrollLow = cScrollbar__scrollLow;
  this.scrollStop = cScrollbar__scrollStop;
  this.scrollRangeSet = cScrollbar__scrollRangeSet;
  this.scrollRangeSetInternal = cScrollbar__scrollRangeSetInternal;
  this.scrollToValue = cScrollbar__scrollToValue;
  this.scrollValueSet = cScrollbar__scrollValueSet;
  this.sliderClickedClear = cScrollbar__sliderClickedClear;
  this.sliderClickedSet = cScrollbar__sliderClickedSet;
  this.sliderDrag = cScrollbar__sliderDrag;
  this.sliderDragStart = cScrollbar__sliderDragStart;
  this.sliderDragStop = cScrollbar__sliderDragStop;
  this.sliderMove = cScrollbar__sliderMove;
  this.sliderPositionSet = cScrollbar__sliderPositionSet;

  this.barOnClick = cScrollbar__barOnClick;

  if ((ADirection != csdHorizontal) && (ADirection != csdVertical))
    ADirection = csdHorizontal;
  this.directionGet = function () {return ADirection};

  this.id = cScrollbars.length;
  cScrollbars[this.id] = this;
}

function cScrollbar__scroll(AStep)
{
  this.scrollToValue(this.scrollValue + AStep * this.scrollStep, true);
}

function cScrollbar__scrollHigh()
{
  if (!this.timerID)
    this.timerID = setInterval('cScrollbars[' + this.id + '].scroll(1)', 50);
}

function cScrollbar__scrollToValue(ANewValue, ADoSliderMove)
{
  if (ANewValue < this.scrollMin)
    ANewValue = this.scrollMin;
  else
  if (ANewValue > this.scrollMax)
    ANewValue = this.scrollMax;

  if (!this.disabled)
  {
    this.elementsStateSet(this.buttonsLow, ((ANewValue == this.scrollMin) ? cScrollbarElementState_Inactive : cScrollbarElementState_Active));
    this.elementsStateSet(this.buttonsHigh, ((ANewValue == this.scrollMax) ? cScrollbarElementState_Inactive : cScrollbarElementState_Active));
  }

  this.scrollValue = ANewValue;

  if (ADoSliderMove)
    this.sliderMove(((this.scrollShiftMax == 0) ? 0 : (ANewValue * this.sliderMaxShift / this.scrollShiftMax)), false);

  if (this.onScroll)
    this.onScroll(this);
}

function cScrollbar__scrollLow()
{
  if (!this.timerID)
    this.timerID = setInterval('cScrollbars[' + this.id + '].scroll(-1)', 50);
}

function cScrollbar__scrollRangeSet(AValueMin, AValueMax)
{
  this.scrollRangeSetInternal(AValueMin, AValueMax);

  this.scroll(0);
}

function cScrollbar__scrollRangeSetInternal(AValueMin, AValueMax)
{
  this.scrollMin = AValueMin;
  this.scrollMax = AValueMax;
  this.scrollShiftMax = AValueMax - AValueMin;

  if (this.scrollShiftMax > 0)
    this.enable();
  else
  {
    this.scrollShiftMax = 0;
    this.disable();
  }
}

function cScrollbar__scrollStop()
{
  if (!this.timerID)
    return;

  clearInterval(this.timerID);
  this.timerID = null;
}

function cScrollbar__scrollValueSet(AValue)
{
  this.scrollToValue(AValue, true);
}

function cScrollbar__barOnClick(AEvent)
{
  if (this.sliderClicked)
    return;

  if (!AEvent)
    AEvent = this.event;
  this.doSliderMove(AEvent, this.barPositionGet());
}

function cScrollbar__barPositionGet()
{
  if ((this.bar) && (this.slider))
  {
    if (this.directionGet() == csdVertical)
      return getAbsTop(this.bar)
    else
      return getAbsLeft(this.bar);
  }
  else
    return 0
};

function  cScrollbar__disable()
{
  this.disabled = true;
  this.stateSet(cScrollbarElementState_Disabled);
}

function  cScrollbar__doSliderMove(AEvent, ABarPosition, AOffset)
{
  var LMoveToPos;
  if (this.directionGet() == csdVertical)
    LMoveToPos = AEvent.clientY - ABarPosition - ((AOffset == null) ? (this.slider.offsetHeight / 2) : AOffset);
  else
    LMoveToPos = AEvent.clientX - ABarPosition - ((AOffset == null) ? (this.slider.offsetWidth / 2) : AOffset);
  this.sliderMove(LMoveToPos, true);
}

function cScrollbar__elementStateSet(AElement, AState)
{
  if (!AElement)
    return;

  switch (AState)
  {
    case cScrollbarElementState_Active:
      if (AElement.style.display != 'block')
        AElement.style.display = 'block';

      if ((this.className_Active == null)
        && (this.className_Inactive == null)
        && (this.className_Disabled == null)
      )
        break;

      var LClassName = (this.className_Active) ? this.className_Active : '';
      if ((this.className_Inactive) && (AElement.className.indexOf(this.className_Inactive) != -1))
        AElement.className = AElement.className.replace(this.className_Inactive, LClassName);
      else
      if ((this.className_Disabled) && (AElement.className.indexOf(this.className_Disabled) != -1))
        AElement.className = AElement.className.replace(this.className_Disabled, LClassName);
      else
      if (AElement.className.indexOf(LClassName) == -1)
        AElement.className = AElement.className + LClassName;
      else
      {
        //!!oko with refresh purpose
        LClassName = AElement.className;
        AElement.className = LClassName + ' ';
        AElement.className = LClassName;
      }
      break;
    case cScrollbarElementState_Inactive:
      if (this.className_Inactive == null)
        break;

      if (AElement.className.indexOf(this.className_Inactive) != -1)
        break;

      if ((this.className_Active) && (AElement.className.indexOf(this.className_Active) != -1))
      {
        AElement.className = AElement.className.replace(this.className_Active, this.className_Inactive);
        break;
      }
      if ((this.className_Disabled) && (AElement.className.indexOf(this.className_Disabled) != -1))
        AElement.className = AElement.className.replace(this.className_Disabled, this.className_Inactive);
      else
        AElement.className = AElement.className + this.className_Inactive;
      break;
    case cScrollbarElementState_Disabled:
      if (this.className_Disabled == null)
      {
        AElement.style.display = 'none';
        break;
      }

      if (AElement.className.indexOf(this.className_Disabled) != -1)
        break;

      if ((this.className_Active) && (AElement.className.indexOf(this.className_Active) != -1))
      {
        AElement.className = AElement.className.replace(this.className_Active, this.className_Disabled);
        break;
      }

      if ((this.className_Inactive) && (AElement.className.indexOf(this.className_Inactive) != -1))
        AElement.className = AElement.className.replace(this.className_Inactive, this.className_Disabled);
      else
        AElement.className = AElement.className + this.className_Disabled;
      break;
  }
}

function cScrollbar__elementsStateSet(AElements, AState)
{
  for (var i = 0; i < AElements.length; i++)
    this.elementStateSet(AElements[i], AState);
}

function cScrollbar__enable()
{
  this.disabled = false;
  this.stateSet(cScrollbarElementState_Active);
}

function cScrollbar__eventAttach(AEventName, AObjectFor, AMethodName)
{
  var LEventID = this.eventIDs.length;
  this.eventIDs[LEventID] = EventAttach(AEventName, AObjectFor, this, AMethodName);
}

function cScrollbar__eventsDetach()
{
  for (var i = 0; i < this.eventIDs.length; i++)
  {
    LID = this.eventIDs[i];
    if (LID == null)
      continue;
    EventDetach(LID);
    this.eventIDs[i] = null;
  }
  this.eventIDs = [];
}

function cScrollbar__finalize()
{
  this.eventsDetach();
  cScrollbars[this.id] = null;
//!!OKO think about empty indexes
}

function cScrollbar__init()
{
  this.bar = (this.barID) ? ElementGet(this.barID) : null;
  this.slider = (this.sliderID) ? ElementGet(this.sliderID) : null;
  this.sliderTrack = (this.sliderTrackID) ? ElementGet(this.sliderTrackID) : null;

  if ((this.bar) && (this.slider))
  {
  
    this.slider.style.position = 'relative';

    this.eventAttach('onclick', this.bar, 'barOnClick');
    this.eventAttach('onmousedown', this.slider, 'sliderDragStart');
  }

  if (this.buttonLowIDs)
  {
    for (var i = 0; i < this.buttonLowIDs.length; i++)
    {
      var LButton = ElementGet(this.buttonLowIDs[i]);
      if (LButton)
        this.initButtonLow(LButton);
      this.buttonsLow[i] = LButton;
    }
  }
  if (this.buttonHighIDs)
    for (var i = 0; i < this.buttonHighIDs.length; i++)
    {
      var LButton = ElementGet(this.buttonHighIDs[i]);
      if (LButton)
        this.initButtonHigh(LButton);
      this.buttonsHigh[i] = LButton;
    }

  this.resize();
}

function cScrollbar__initButtonHigh(AButton)
{
  if (!AButton)
    return;

  this.eventAttach('onmousedown', AButton, 'scrollHigh');
  this.eventAttach('onmouseup',   AButton, 'scrollStop');
  this.eventAttach('onmouseout',  AButton, 'scrollStop');
}

function cScrollbar__initButtonLow(AButton)
{
  if (!AButton)
    return;

  this.eventAttach('onmousedown', AButton, 'scrollLow');
  this.eventAttach('onmouseup',   AButton, 'scrollStop');
  this.eventAttach('onmouseout',  AButton, 'scrollStop');
}

function  cScrollbar__resize()
{
  this.resizeInternal();
  this.scroll(0);
}

function cScrollbar__resizeInternal()
{
  this.scrollRangeSetInternal(this.scrollMin, this.scrollMax);

  if (!this.slider)
    return;

  if (this.sliderIsResizable && (this.sliderResizeCoefficient > 0) && (this.sliderResizeCoefficient <= 1))
  {
    if (this.directionGet() == csdVertical)
      this.slider.style.height = this.sliderResizeCoefficient * this.bar.clientHeight;
    else
      this.slider.style.width = this.sliderResizeCoefficient * this.bar.clientWidth;
  }

  if (this.directionGet() == csdVertical)
    this.sliderMaxShift = this.bar.clientHeight - this.slider.offsetHeight;
  else
    this.sliderMaxShift = this.bar.clientWidth - this.slider.offsetWidth;
}

function cScrollbar__sliderClickedSet()
{
  this.sliderClicked = true;
}

function cScrollbar__sliderClickedClear()
{
  this.sliderClicked = false;
}

function cScrollbar__sliderDrag(AEvent)
{
  if (!this.sliderClicked)
    return;

  if (!AEvent)
    AEvent = this.event;

  if (AEvent.preventDefault)
    AEvent.preventDefault();
  else
    AEvent.returnValue = false;

  this.doSliderMove(AEvent, this.slider.barPosition, this.slider.clickOffset);
}

function cScrollbar__sliderDragStart(AEvent)
{
  this.sliderClickedSet();

  if (!AEvent)
    AEvent = this.event;

  if (AEvent.preventDefault)
    AEvent.preventDefault();
  else
    AEvent.returnValue = false;

  var LElementCaptureSet;
  var LBarPosition = this.barPositionGet();

  var LOffset;
  if (this.directionGet() == csdVertical)
    LOffset = AEvent.clientY - LBarPosition - parseInt(this.slider.style.top);
  else
    LOffset = AEvent.clientX - LBarPosition - parseInt(this.slider.style.left);

  this.slider.barPosition = LBarPosition;
  this.slider.clickOffset = LOffset;

  if (this.slider.setCapture)
  {
    LElementCaptureSet = this.slider;
    this.slider.setCapture();
  }
  else
    LElementCaptureSet = document;

  this.slider.eventID_MouseMove = EventAttach('onmousemove', LElementCaptureSet, this, 'sliderDrag', true);
  this.slider.eventID_MouseUp = EventAttach('onmouseup', LElementCaptureSet, this, 'sliderDragStop', true);
  this.slider.eventID_Click = EventAttach('onclick', LElementCaptureSet, this, 'sliderDragStop', true);
}

function cScrollbar__sliderDragStop(AEvent)
{
  setTimeout('cScrollbars[' + this.id + '].sliderClickedClear()', 5);

  if (!AEvent)
    AEvent = this.event;

  if (AEvent.preventDefault)
    AEvent.preventDefault();
  else
    AEvent.returnValue = false;

  if (document.releaseCapture)
    document.releaseCapture();

  EventDetach(this.slider.eventID_MouseMove);
  EventDetach(this.slider.eventID_MouseUp);
  EventDetach(this.slider.eventID_Click);

  this.slider.eventID_MouseMove = null;
  this.slider.eventID_MouseUp = null;
  this.slider.eventID_Click = null;

  this.slider.barPosition = null;
  this.slider.cilckOffset = null;
}

function cScrollbar__sliderMove(APosition, ADoScroll)
{
  if (!this.slider)
    return;

  if (APosition < 0)
    APosition = 0;
  else
  if (APosition > this.sliderMaxShift)
    APosition = this.sliderMaxShift;

  this.sliderPositionSet(APosition);

  if (ADoScroll)
    this.scrollToValue((this.sliderMaxShift == 0) ? 0 : (APosition * this.scrollShiftMax / this.sliderMaxShift), false);
}

function cScrollbar__sliderPositionSet(ANewPosition)
{
  if (this.directionGet() == csdVertical)
  {
    if (this.sliderTrack)
      this.sliderTrack.style.height = ANewPosition + this.slider.offsetHeight;
    this.slider.style.top = ANewPosition + 'px';
  }
  else
  {
    if (this.sliderTrack)
      this.sliderTrack.style.width = ANewPosition + this.slider.offsetWidth;
    this.slider.style.left = ANewPosition + 'px';
  }
}

function cScrollbar__stateSet(AState)
{
  if ((AState != cScrollbarElementState_Active)
    && (AState != cScrollbarElementState_Disabled)
  )
    return;

  this.elementsStateSet(this.buttonsLow, AState);
  this.elementsStateSet(this.buttonsHigh, AState);
  this.elementStateSet(this.bar, AState);
  this.elementStateSet(this.slider, AState);
}

function ScrollbarsInit()
{
  for (var i = 0; i < cScrollbars.length; i++)
  {
    var LScrollbar = cScrollbars[i];
    if (LScrollbar)
      LScrollbar.init();
  }
}
