// Copyright 1998,1999 Macromedia, Inc. All rights reserved.

//Constructs a drag and drop element
function MM_drag(theParent, theName, theInitialValue,
                theIsDraggable, theIsTarget,
                theSnapsOnMiss, theSnapsOnIncorrect) {
  // properties
  this.initialValue = theInitialValue;
  this.value = '';
  this.disabled = true;
  
  this.snapsOnMiss = theSnapsOnMiss;
  this.snapsOnIncorrect = theSnapsOnIncorrect;
  this.origPosX = '';
  this.origPosY = '';
  
  this._parent = theParent;
  this._name = theName;
  this._obj = '';
  this._self = theParent._self+".e['"+theName+"']";
  this._singleChoice = true;

  this._isDraggable = theIsDraggable;
  this._isTarget = theIsTarget;
  
  this._posX = '';
  this._posY = '';
  this._prevPosX = '';
  this._prevPosY = '';
  this._width = '';
  this._height = '';

  this.c = new Array();
  
  // member functions
  this.init = MM_dragInit;
  this.reset = MM_dragReset;
  this.enable = MM_dragEnable;
  this.disable = MM_dragDisable;
  this.setDisabled = MM_dragSetDisabled;
  this.update = MM_dragUpdate;
  this.getPosition = MM_dragGetPosition;
  this.snapTo = MM_dragSnapTo;
  this.snapBack = MM_dragSnapBack;
  this.moveToFront = MM_dragMoveToFront;
  this.updateValue = MM_dragUpdateValue;
  this.updateSources = MM_dragUpdateSources;
  this.changeValue = MM_dragChangeValue;
  this.setValue = MM_dragSetValue;
}

//Called to initialize the drag objects
function MM_dragInit() {
  with (this) {
    _obj = MM_intFindObject(_parent._self + _name);
    if (_obj) {
      if (_parent.browserIsIE && _parent.osIsMac) {
        _obj.style.width = "";
        _obj.style.height = "";
      }
      _width =  parseInt((_parent.browserIsNS)?_obj.clip.width:_obj.offsetWidth);
      _height = parseInt((_parent.browserIsNS)?_obj.clip.height:_obj.offsetHeight);
      getPosition();
      origPosX = _posX; origPosY = _posY;
      if (_isDraggable)
        MM_dragLayer(_parent._self + _name,'',0,0,0,0,true,false,-1,-1,-1,-1,false,false,0,_self+'.update()',true,_self+'.update(true)');
  } }
}

//Resets the element and its choices
function MM_dragReset() {
  var i;
  if (this._obj) with (this) {
    _parent.disabled ? disable() : enable();
    value = initialValue;
    if (_isDraggable) {
      if (!changeValue(value)) {
        snapTo(origPosX, origPosY);
        updateValue(true);
        updateSources();
  } } }
}

//Enables the element
function MM_dragEnable() {
  var i;
  if (this._obj) with (this) {
    disabled = false;
    for (i in c)  if (i != 'length') c[i].disabled = false;
    updateValue(true);
    if (_isDraggable) _obj.MM_dragOk = true;
  }
}

//Disables the element
function MM_dragDisable() {
  with (this) {
    disabled = true;
    if (_isDraggable && _obj) _obj.MM_dragOk = null;
  }
}

//Calls the approppriate disable or enable function
function MM_dragSetDisabled(theDisabled) {
  if (theDisabled) this.disable();
  else this.enable();
}

//Called by MM_dragLayer when a drag object is dropped
// Do a hit test on each of the targets
function MM_dragUpdate(dragging) {
  var i,noJudge=false,origValue,x,y;
  with (this) {
    if (dragging) {
      if (this.onDrag != null) {
        x = parseInt((_parent.browserIsNS)?_obj.pageX:_obj.style.pixelLeft);
        y = parseInt((_parent.browserIsNS)?_obj.pageY:_obj.style.pixelTop);
        onDrag(_parent._self+_name, x, y);
      }
    } else {
      if (!_obj || disabled || !_isDraggable) return;

      origValue=value;
      getPosition();
      updateValue();

      if (snapsOnIncorrect && value && c[value].isCorrect == false) {
        c[value].selected = false; // turn off selected flag
        noJudge=true;
      } else if (snapsOnMiss && !value) {
        noJudge=true;
      }
      if (noJudge) {
        snapBack();
        if (origValue) {
          c[origValue].selected = true;
          value = origValue;
        }
        if (this.onDrag != null) onDrag(_parent._self+_name, _posX, _posY);
        if (this.onDrop != null) onDrop(_parent._self+_name, value);
      }

      if (!noJudge) updateSources();
      
      // call the parent's update
      _parent.update(noJudge);
  } }
}

//Gets the current position of the layer
function MM_dragGetPosition() {
  if (this._obj) with (this) {
    _prevPosX = _posX; _prevPosY = _posY;
    _posX = parseInt((_parent.browserIsNS)?_obj.pageX:_obj.style.pixelLeft);
    _posY = parseInt((_parent.browserIsNS)?_obj.pageY:_obj.style.pixelTop);
  }
}

//Moves the layer to the given position
function MM_dragSnapTo(newPosX, newPosY) {
  if (this._obj && newPosX && newPosY) with (this) {
    if (_parent.browserIsNS) {
      _obj.pageX = newPosX; _obj.pageY = newPosY;
    } else {
      _obj.style.pixelLeft = newPosX; _obj.style.pixelTop = newPosY;
    }
    _posX = newPosX; _posY = newPosY;
  }
}

//Moves the layer to its previous position
function MM_dragSnapBack() {
  with (this) snapTo(_prevPosX, _prevPosY);
}

function MM_dragMoveToFront() {
  var maxZ=0, i, aLayer, aLayerZ;
  with (this) {
    if (document.allLayers != null) {
      for (i=0; i<document.allLayers.length; i++) {
        aLayer = document.allLayers[i];
        aLayerZ = (_parent.browserIsNS)?aLayer.zIndex:aLayer.style.zIndex;
        if (aLayerZ > maxZ) maxZ = aLayerZ;
      }
      eval('_obj.'+((_parent.browserIsNS)?'':'style.')+'zIndex=maxZ+1');
  } }
}

//Update the value parameter and the choice selected flags
function MM_dragUpdateValue(checkOnly) {
  var i;
  with (this) {
    value = '';
    for (i in c) if (i != 'length') 
      if (value == '')  value = c[i].validValue(checkOnly);
      else  c[i].validValue(checkOnly);
  }
}

//Update the sources for which we are a target
function MM_dragUpdateSources() {
  var i;
  with (this) {
    if (_isTarget) {
      for (i in _parent.e)  if (i != 'length') {
        if (_parent.e[i].value == _name) {
          if (value != i) {  // update elem and choice
            _parent.e[i].value = _parent.e[i].c[_name].validValue(true); // check only
          } else {  // dropped on the element for which we were the target
            _parent.e[i].value = '';
            _parent.e[i].c[_name].selected = false;
    } } } }
    if (this.onDrag != null) onDrag(_parent._self+_name, _posX, _posY);
    if (this.onDrop != null) onDrop(_parent._self+_name, value);
  }
}

//Moves the layer to the named target
function MM_dragChangeValue(theValue) {
  var retVal = false;
  var choice, i;
  if (this._obj && theValue && this._isDraggable) with (this) {
    for (choice in c) if (choice != 'length' && choice == theValue) break;
    if (choice == theValue) {
      c[choice].setHotSpot();
      snapTo(c[choice]._hitX, c[choice]._hitY);
      moveToFront();
      updateValue();  // set our selected state
      updateSources();
      retVal = true;
  } }
  return retVal;
}

//Moves the layer to the named target, then updates the int
function MM_dragSetValue(theValue) {
  with (this) {
    if (changeValue(theValue))
      _parent.update(true); // update int, but don't judge
  }
}


////////////////////////////////////////
//Create a drag and drop choice object
function MM_dragTarg(theParent, theElement,
                     theTarget, theIsCorrect, theScore,
                     theTolerance, theAlignment, theOffset, theSnapsTo) {
  // properties
  this.expectedValue = theTarget;
  this.isCorrect = theIsCorrect;
  this.score = theScore;
  this.selected = false;
  this.disabled = false;
  
  this.tolerance = theTolerance;
  this.alignment = theAlignment;
  this.snapsTo = theSnapsTo;
  this.offsetX = 0;
  this.offsetY = 0
  
  this._elem = eval(theParent._self+".e['"+theElement+"']");
  this._target = eval(theParent._self+".e['"+theTarget+"']");
  this._isChoice = true;

  this._hitX = 0;
  this._hitY = 0;
  this._snapX = '';
  this._snapY = '';
  
  if (theOffset != null) {
    var  colonPos = theOffset.indexOf(":");
    if (colonPos != -1) { //if colon separated, split strings
      this.offsetX = parseInt(theOffset.substring(0,colonPos));
      this.offsetY = parseInt(theOffset.substring(colonPos+1,theOffset.length));
  } }
  
  // methods
  this.validValue = MM_dragTargValidValue;
  this.setHotSpot = MM_dragTargSetHotSpot;
  this.setSelected = MM_dragTargSetSelected;
  this.setDisabled = MM_dragTargSetDisabled;
}

function MM_dragTargValidValue(checkOnly) {
  var retVal = '';
  with (this) {
    selected = false;
    if (!disabled) {
    
      setHotSpot();

      // check if the value is within the tolerance of the hotspot
      if ((Math.pow(_hitX-_elem._posX,2) + Math.pow(_hitY-_elem._posY,2))
              <= Math.pow(tolerance,2)) {
        selected = true;
        if (snapsTo && !checkOnly) _elem.snapTo(_snapX, _snapY);
        retVal = expectedValue;
  } } }
  return retVal;
}

function MM_dragTargSetHotSpot() {
  var centerX, centerY, alignX=0, alignY=0;
  with (this) {
    // compute the center
    centerX = Math.round(0.5 * (_target._width-_elem._width));
    centerY = Math.round(0.5 * (_target._height-_elem._height));    
    
    // compute the alignment
    if (alignment != '') {
      // set to 'Center'
      alignX = centerX; alignY = centerY;
      if (alignment == 'Bottom')     alignY = _target._height;
      else if (alignment == 'Top')   alignY = -_elem._height;
      else if (alignment == 'Left')  alignX = -_elem._width;
      else if (alignment == 'Right') alignX = _target._width;
    }
  
    // update the targets position (needed for draggable targets)
    _target.getPosition();
  
    // set the snap location
    _snapX = _target._posX + alignX + offsetX;
    _snapY = _target._posY + alignY + offsetY;
    
    // set the hit location
    _hitX = _target._posX + centerX;
    _hitY = _target._posY + centerY;
    
  }
}

function MM_dragTargSetSelected(theSelected) {
  with (this) {
    if (theSelected) {
      _elem.setValue(expectedValue);
    } else {
      selected = false;
      if (_elem.value == expectedValue) _elem.value = '';
      _elem._parent.update(true);
    }
  }
}

function MM_dragTargSetDisabled(theDisabled) {
  with (this) {
    disabled = theDisabled;
    if (disabled) {
      selected = false;
      if (_elem.value == expectedValue) _elem.value = '';
    } else {
      // NOTE: the selected state won't be correct 
      //  if the snap location is outside of the tolerance
      if (_elem._obj) {
        validValue(true);
        if (selected) _elem.value = expectedValue;
      }
    }
    _elem._parent.update(true);
  }
}
