/*

 rubber.js -- a base class for drag/rubber-band selection in gbrowse

 Sheldon McKay <mckays@cshl.edu>
 $Id: rubber.js 22706 2010-02-17 09:53:20Z sheldon_mckay $

*/

var currentSelectArea;
var selectAreaIsActive;

// Constructor
var SelectArea = function () {
  return this;
}

// replace image or image button that will conflict with drag selection
SelectArea.prototype.replaceImage = function(image) {
  var src    = image.getAttribute('src');
  var name   = image.getAttribute('name');
  var isIE   = document.all && !window.opera; 


  var id = image.getAttribute('id');
  var width  = this.elementLocation(image,'width');
  var height = this.elementLocation(image,'height');
  var top    = this.elementLocation(image,'y1');
  var left   = this.elementLocation(image,'x1');

  var p = image.parentNode;
  p.removeChild(image);

  image = this.createAndAppend('span',p,id);
  image.setAttribute('name',name);

  // escape backslashes that may appear in the src attribute
  src = src.replace(/\\/g,"\\\\");

  YAHOO.util.Dom.setStyle(image,'background', 'url('+src+') top left no-repeat');
  YAHOO.util.Dom.setStyle(image,'width', width+'px');
  YAHOO.util.Dom.setStyle(image,'height', height+'px');
  YAHOO.util.Dom.setStyle(image,'display','block');
  YAHOO.util.Dom.setStyle(image,'cursor','text');


  if (   !document.searchform 
      || !document.searchform.drag_and_drop 
      || !document.searchform.drag_and_drop.checked) {
    var name = this.imageId+'_map';
    var map;
    
    //IE but this time it is the DOM compliant one
    if (isIE) {
      var spans  = document.getElementsByTagName('span');
      var map = new Array;
      for (var n=0;n<spans.length;n++) {
        if (spans[n].name == name) {
          map.push(spans[n]);
        }
      }
      // Why? I really don't know!
      top  = top  - 6;
      left = left - 6;
    }
    else {
      map = document.getElementsByName(name);
    }

    if (map && map.length) {
      for (var n=0;n<map.length;n++) {
        var newTop   = this.elementLocation(map[n],'y1') + top;
        var newLeft  = this.elementLocation(map[n],'x1') + left;
        YAHOO.util.Dom.setStyle(map[n],'top',newTop+'px');
        YAHOO.util.Dom.setStyle(map[n],'left',newLeft+'px');
      }
    }
  }

  return image;
}

SelectArea.prototype.recenter = function(event) {
  var self = currentSelectArea;
  self.loadSegmentInfo();
  var deltaPixelStart      = self.selectPixelStart - self.pixelStart;
  var deltaSequenceStart   = deltaPixelStart * self.pixelToDNA;

  var coord  = self.flip ? Math.round(self.segmentEnd - deltaSequenceStart)
                         : Math.round(self.segmentStart + deltaSequenceStart);

  var detailsStart = parseInt(self.detailStart);
  var detailsEnd = parseInt(self.detailEnd);
  var end  = self.segmentEnd;
  var span = Math.abs(detailsEnd - detailsStart);
  var half = Math.round(span/2);

  // don't fall off the ends
  if (coord < 0)   coord = half + 1;
  if (coord > end) coord = end - half - 1;
  var start  = coord - half;
  var end    = coord + half;

  if (start > end){ 
    var tmp = end;
    end = start;
    start = tmp;
  }
    
  self.currentSegment = self.ref + ':' + start + '..' + end;
  if (document.searchform) {
    document.searchform.name.value = self.currentSegment;
  }
  self.submit();
}

// Cross-browser element coordinates
SelectArea.prototype.elementLocation = function(el,request) {
  var region = YAHOO.util.Dom.getRegion(el);
  switch(request) {
    case ('y1') : return region.top;
    case ('y2') : return region.bottom;
    case ('x1') : return region.left;
    case ('x2') : return region.right;
    case ('width')  : return (region.right - region.left);
    case ('height') : return (region.bottom - region.top);
 }
}


// Cross-browser event coordinates
SelectArea.prototype.eventLocation = function(event,request) {
  var e = event || window.event;
  if (request == 'x') {
    return e.pageX || e.clientX + document.body.scrollLeft + document.documentElement.scrollLeft;
  }
  else if (request == 'y') {
    return e.pageY || e.clientY + document.body.scrollTop  + document.documentElement.scrollTop;
  }
  else {  
    return false;
  }
}

// Fired when there is a mousedown between the top and bottom
// of the selectable image -- horizontal position does not matter
SelectArea.prototype.startRubber = function(self,event) {
  // only one select area is active at a time, so let the subclass take possession

  self.loadSegmentInfo();

  currentSelectArea = self;

  // suppress all popup balloon while drag-select is active
  Balloon.prototype.hideTooltip(1);  
  balloonIsSuppressed = true;

  // disable help balloon after first selection is made.
  var nullfunc = function(){return false};
  self.scalebar.onmouseover = nullfunc;
 
  // set the selectbox bgcolor
  self.setOpacity(self.selectBox,self.opacity||0.5);  

  // deal with drag/select artifacts
  self.disableSelection(self.selectLayer);

  self.selectPixelStart = self.eventLocation(event,'x');

  YAHOO.util.Dom.setStyle(self.selectBox,'visibility','hidden');
  YAHOO.util.Dom.setStyle(self.selectBox,'left',self.selectPixelStart+'px');
  YAHOO.util.Dom.setStyle(self.selectBox,'width','2px');
  YAHOO.util.Dom.setStyle(self.selectBox,'text-align', 'center');	
  YAHOO.util.Dom.setStyle(self.selectMenu,'visibility','hidden');
  
  // height of select box to match height of detail panel
  var h = self.elementLocation(self.selectLayer,'height');
  YAHOO.util.Dom.setStyle(self.selectBox,'height',h+'px');
  
  // vertical offset may also need adjusting
  var t = self.elementLocation(self.selectLayer,'y1');
  YAHOO.util.Dom.setStyle(self.selectBox,'top',t+'px');

  var spanReport = self.spanReport || self.createAndAppend('p',self.selectBox,'spanReport');
  YAHOO.util.Dom.setStyle(spanReport,'color',self.fontColor||'black');
  YAHOO.util.Dom.setStyle(spanReport,'margin-top',self.marginTop||'0px');
  YAHOO.util.Dom.setStyle(spanReport,'background','transparent');
  YAHOO.util.Dom.setStyle(spanReport,'font','normal bold 14px sans-serif');

  spanReport.innerHTML = ' ';
  self.spanReport = spanReport;
  selectAreaIsActive = true;
}

SelectArea.prototype.cancelRubber = function() {
  var self = currentSelectArea || new SelectArea;
  balloonIsSuppressed = false;

  if (!self.selectBox) return false;
  
  YAHOO.util.Dom.setStyle(self.selectBox,'visibility','hidden');
  YAHOO.util.Dom.setStyle(self.selectMenu,'visibility','hidden');
  selectAreaIsActive = false;

  if (self.originalLandmark) {
    document.searchform.name.value = self.originalLandmark;
  }
  self.moved = false;
}

SelectArea.prototype.round = function(nearest,num) {
  if (num > nearest) {
    num = Math.round(num/nearest)*nearest;
  }
  return num;
} 

SelectArea.prototype.moveRubber = function(event) {
  if (!selectAreaIsActive) return false;

  var self = currentSelectArea;
  var selectPixelStart = self.selectPixelStart;
  var selectPixelEnd   = self.eventLocation(event,'x');
  var selectPixelWidth = Math.abs(selectPixelStart - selectPixelEnd);

  var rev, left;
  if (selectPixelStart > selectPixelEnd) {
    rev  = true;
    left = selectPixelEnd;
    self.selectPixelStart = left;
  }
  else {
    left = selectPixelStart;
  }

  // Coordinates of selected sequence
  var deltaPixelStart      = left - self.pixelStart;
  var deltaSequenceStart   = deltaPixelStart * self.pixelToDNA;
  self.selectSequenceStart = self.flip ? Math.round(self.segmentEnd - deltaSequenceStart) 
                                       : Math.round(self.segmentStart + deltaSequenceStart);
  var selectSequenceWidth  = Math.round(selectPixelWidth * self.pixelToDNA);
  self.selectSequenceEnd   = self.flip ? self.selectSequenceStart - selectSequenceWidth 
                                       : self.selectSequenceStart + selectSequenceWidth;

  var segmentLength = Math.abs(self.segmentEnd - self.segmentStart);
  
  // Round the sequence coordinates to the nearest appropriate 10x
  if (segmentLength > 1000000) {
    self.selectSequenceStart = self.round(10000,self.selectSequenceStart);
    self.selectSequenceEnd = self.round(10000,self.selectSequenceEnd);
  }
  else if (segmentLength > 50000) {
    self.selectSequenceStart = self.round(1000,self.selectSequenceStart);
    self.selectSequenceEnd = self.round(1000,self.selectSequenceEnd);
  }
  else if (segmentLength > 5000) {
    self.selectSequenceStart = self.round(100,self.selectSequenceStart);
    self.selectSequenceEnd = self.round(100,self.selectSequenceEnd);
  }
  else if (segmentLength > 500) {
    self.selectSequenceStart = self.round(10,self.selectSequenceStart);
    self.selectSequenceEnd = self.round(10,self.selectSequenceEnd);
  }
  
  selectSequenceWidth = Math.abs(self.selectSequenceEnd - self.selectSequenceStart);

  // Don't allow the start to be > the end
  if (self.selectSequenceStart > self.selectSequenceEnd){ 
    var tmp = self.selectSequenceEnd;
    self.selectSequenceEnd = self.selectSequenceStart;
    self.selectSequenceStart = tmp;
  }

  // reset the value of the 'name' input box
  self.currentSegment = self.ref +':'+self.selectSequenceStart+'..'+(self.selectSequenceEnd-1);
  if (document.searchform) {
    document.searchform.name.value = self.currentSegment;
  } 

  // size and appearance of the "rubber band" select box
  YAHOO.util.Dom.setStyle(self.selectBox,'width','1px');
  YAHOO.util.Dom.setStyle(self.selectBox,'left',left+'px');
  YAHOO.util.Dom.setStyle(self.selectBox,'width',selectPixelWidth+'px');
  YAHOO.util.Dom.setStyle(self.selectBox,'visibility','visible');

  // warning if max segment size exceeded
  var tooBig;
  if (self.max_segment && selectSequenceWidth > self.max_segment) {
    self.setOpacity(self.selectBox,self.opacity||0.5,'red');
    self.overrideAutoSubmit = true;
    tooBig = true;
  }
  else {
    self.setOpacity(self.selectBox,self.opacity||0.5);
    self.overrideAutoSubmit = false;
  }

  var unit = 'bp';
  if (selectSequenceWidth > 1000 && selectSequenceWidth < 1000000) {
    selectSequenceWidth = selectSequenceWidth/1000;
    unit = 'kbp';
  }
  else if (selectSequenceWidth > 1000000) {
    selectSequenceWidth = selectSequenceWidth/1000000;
    unit = 'Mbp';
  }

  if (Math.floor(selectSequenceWidth) != selectSequenceWidth) {
    selectSequenceWidth = selectSequenceWidth.toFixed(2);
  }

  if (selectPixelWidth > 20) {
    self.spanReport.innerHTML = selectSequenceWidth+' '+unit;
  }
  else {
    self.spanReport.innerHTML = ' ' ;
  }

  self.selectPixelStart = selectPixelStart;

  // Only count as moved if the pixel change is greater than 1
  // This is to make it easier to simply recenter
  if (selectPixelWidth > 1){
    self.moved = true;
  }
}

// taken from http://ajaxcookbook.org/disable-text-selection/
// prevents ugly drag select side-effects
SelectArea.prototype.disableSelection = function(el) {
    el.onselectstart = function() {
        return false;
    };
    el.unselectable = "on";
    el.style.MozUserSelect = "none";
    el.style.cursor = "default";
}


// Builds the popup menu that appears when selection is complete
SelectArea.prototype.addSelectMenu = function(view) {

  var menu =  document.getElementById(view+'SelectMenu'); 
  if (menu) {
    this.autoSubmit = false;
  }
  else {
    menu = this.createAndAppend('div',document.body,view+'SelectMenu');
  }

  // required style 
  YAHOO.util.Dom.setStyle(menu,'position','absolute');
  YAHOO.util.Dom.setStyle(menu,'display','block');
  YAHOO.util.Dom.setStyle(menu,'z-index','101');
  YAHOO.util.Dom.setStyle(menu,'visibility','hidden');

  // optional style -- check if a custom menu has styles set already
  var existingStyle = new String(menu.getAttribute('style'));
  if (existingStyle) {
    if (!existingStyle.match(/width/i))      YAHOO.util.Dom.setStyle(menu,'width',this.menuWidth||'200px');
    if (!existingStyle.match(/font/i))       YAHOO.util.Dom.setStyle(menu,'font','12px sans-serif');
    if (!existingStyle.match(/background/i)) YAHOO.util.Dom.setStyle(menu,'background','lightyellow');
    if (!existingStyle.match(/border/i))     YAHOO.util.Dom.setStyle(menu,'border','1px solid #003366');
  }

  this.selectMenu = menu;
  this.formatMenu();
}

// Initial creation of the select box
SelectArea.prototype.addSelectBox = function(view) {

  if (this.selectBox) return false;
 
  var box = this.createAndAppend('div',this.selectLayer,view+'selectBox');

  YAHOO.util.Dom.setStyle(box,'position','absolute');
// this was breaking IE for some reason
//  YAHOO.util.Dom.setStyle(box,'display', 'inline');
  YAHOO.util.Dom.setStyle(box,'visibility', 'hidden');
  YAHOO.util.Dom.setStyle(box,'top',this.top+'px');
  YAHOO.util.Dom.setStyle(box,'left','0px');
  YAHOO.util.Dom.setStyle(box,'z-index',100);
  YAHOO.util.Dom.setStyle(box,'border',this.border||'none');

  // click on scalebar initializes selection
  this.scalebar.onmousedown = this.startSelection;

  // drag and mouseup on details panel fires menu
  this.selectLayer.onmousemove   = this.moveRubber;
  this.selectLayer.onmouseup     = this.stopRubber;  

  // allows drag-back


  // 'esc' key aborts
  var abort = function(event){
    var evt = event || window.event;
    if (evt.keyCode == 27) SelectArea.prototype.cancelRubber();
    return true;
  }
  document.onkeydown        = abort;

  this.selectBox = box;
}


/////////////////////////////////////////////////////////////////////
// Create/append  elements
/////////////////////////////////////////////////////////////////////

SelectArea.prototype.createAndAppend = function(elTag,parent,id) {
  var node = this.justCreate(elTag);
  this.justAppend(node,parent);
  if (id) node.setAttribute('id',id);
  return node;
}

SelectArea.prototype.justCreate = function(elTag) {
  var tag = elTag || 'div';
  var node = document.createElement(tag);
  return node;
}

SelectArea.prototype.justAppend = function(child,parent) {
  var parentNode = parent || document.body;
  parentNode.appendChild(child);
}
  

SelectArea.prototype.stopRubber = function(event) {
  balloonIsSuppressed = false;
  if (!selectAreaIsActive) return false;
  var self = currentSelectArea;
  if (!self.moved) {
    self.cancelRubber();
    self.recenter();
    return false;
  }

  selectAreaIsActive = false;
  self.moved = false;

  // autoSubmit option will bypass the menu
  if (self.autoSubmit && !self.overrideAutoSubmit) {
    SelectArea.prototype.cancelRubber();
    //document.searchform.submit();
    self.submit();
  }
  else {
    self.showMenu(event);
  }
}

SelectArea.prototype.showMenu = function(event) {
  var self = currentSelectArea;
  var menu = self.selectMenu;
  menu.innerHTML = self.menuHTML.replace(/SELECTION/g,self.currentSegment);

  var pageWidth  = YAHOO.util.Dom.getViewportWidth();
  var menuWidth  = self.elementLocation(menu,'width');
  var menuHeight = self.elementLocation(menu,'height');
  var menuYHalf  = Math.round(menuHeight/2); 
  
  var left = self.eventLocation(event,'x') + 5;
  if ((left+menuWidth) > pageWidth) left -= menuWidth + 10;
  var top  = self.eventLocation(event,'y') - menuYHalf;

  YAHOO.util.Dom.setStyle(menu,'top',  top+'px'); 
  YAHOO.util.Dom.setStyle(menu,'left', left+'px');

  // Abort if there is no selection
  if (YAHOO.util.Dom.getStyle(self.selectBox,'visibility') == 'hidden') {
    self.cancelRubber;
    return false;
  }

  YAHOO.util.Dom.setStyle(menu,'visibility','visible');

}

SelectArea.prototype.hideMenu = function() {
  var self = currentSelectArea;

  YAHOO.util.Dom.setStyle(self.selectBox,'width',1);  
  YAHOO.util.Dom.setStyle(self.selectBox,'visibility','hidden');
  YAHOO.util.Dom.setStyle(self.selectMenu,'visibility','hidden');
}

SelectArea.prototype.clearAndSubmit = function(plugin,action) {
  this.hideMenu();
  if (plugin) {
    action = action || 'Go';
    var url = window.location;
    url += '?plugin='+plugin+';plugin_do='+action; 
    document.location = url;
  }
  else {
    this.submit();
  }
}

SelectArea.prototype.clearAndRecenter = function() {
  this.hideMenu();
  var self = currentSelectArea;
  self.loadSegmentInfo();
  var start   = self.detailStart+'';
  start   = start.replace(/\D+/,'') * 1;
  var end   = self.detailEnd+'';
  end   = end.replace(/\D+/,'') * 1;
  var half    = Math.round(Math.abs((end - start)/2));
  var middle  = Math.round((self.selectSequenceStart + self.selectSequenceEnd)/2);
  var newName = self.ref+':'+(middle-half)+'..'+(middle+half);
  self.currentSegment = newName;
  self.submit();
}

// Make best effort to set the opacity of the selectbox
// background color
SelectArea.prototype.setOpacity = function(el,opc,bgColor) {
  var self = currentSelectArea;
  if (!bgColor) {
    bgColor = self.background;
  }
  
  if (!(el && opc)) return false;

  // Just an outline for Konqueror
  //  if (navigator.userAgent.indexOf( 'Konqueror' ) != -1) {
  //     YAHOO.util.Dom.setStyle(el,'border','1px solid black');
  //    return false;
  //  }

  opc = parseFloat(opc);
  YAHOO.util.Dom.setStyle(el,'background',bgColor||'#BABABA');
  YAHOO.util.Dom.setStyle(el,'opacity',opc);
  YAHOO.util.Dom.setStyle(el,'filter','alpha(opacity= '+(100*opc)+')');
  YAHOO.util.Dom.setStyle(el,'MozOpacity',opc);
  YAHOO.util.Dom.setStyle(el,'KhtmlOpacity',opc);
}


SelectArea.prototype.submit = function() {
  var self = currentSelectArea;
  if (Controller.gbrowse_syn) {
    Controller.update_coordinates(self.currentSegment);
  }
  else if (self.currentSegment) {
    Controller.update_coordinates("set segment " + self.currentSegment);
  }  
}